From webhook-mailer at python.org Sat Oct 1 13:42:45 2022 From: webhook-mailer at python.org (gvanrossum) Date: Sat, 01 Oct 2022 17:42:45 -0000 Subject: [Python-checkins] gh-90908: Document asyncio.Task.cancelling() and asyncio.Task.uncancel() (#95253) Message-ID: https://github.com/python/cpython/commit/f00645d5dbf4cfa0b8f382c8977724578dff191d commit: f00645d5dbf4cfa0b8f382c8977724578dff191d branch: main author: ?ukasz Langa committer: gvanrossum date: 2022-10-01T10:42:36-07:00 summary: gh-90908: Document asyncio.Task.cancelling() and asyncio.Task.uncancel() (#95253) Co-authored-by: Thomas Grainger files: M Doc/library/asyncio-task.rst M Lib/asyncio/tasks.py M Lib/test/test_asyncio/test_tasks.py diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index 221197ea40ff..ade969220ea7 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -294,11 +294,13 @@ perform clean-up logic. In case :exc:`asyncio.CancelledError` is explicitly caught, it should generally be propagated when clean-up is complete. Most code can safely ignore :exc:`asyncio.CancelledError`. -Important asyncio components, like :class:`asyncio.TaskGroup` and the -:func:`asyncio.timeout` context manager, are implemented using cancellation -internally and might misbehave if a coroutine swallows -:exc:`asyncio.CancelledError`. +The asyncio components that enable structured concurrency, like +:class:`asyncio.TaskGroup` and :func:`asyncio.timeout`, +are implemented using cancellation internally and might misbehave if +a coroutine swallows :exc:`asyncio.CancelledError`. Similarly, user code +should not call :meth:`uncancel `. +.. _taskgroups: Task Groups =========== @@ -1003,76 +1005,6 @@ Task Object Deprecation warning is emitted if *loop* is not specified and there is no running event loop. - .. method:: cancel(msg=None) - - Request the Task to be cancelled. - - This arranges for a :exc:`CancelledError` exception to be thrown - into the wrapped coroutine on the next cycle of the event loop. - - The coroutine then has a chance to clean up or even deny the - request by suppressing the exception with a :keyword:`try` ... - ... ``except CancelledError`` ... :keyword:`finally` block. - Therefore, unlike :meth:`Future.cancel`, :meth:`Task.cancel` does - not guarantee that the Task will be cancelled, although - suppressing cancellation completely is not common and is actively - discouraged. - - .. versionchanged:: 3.9 - Added the *msg* parameter. - - .. deprecated-removed:: 3.11 3.14 - *msg* parameter is ambiguous when multiple :meth:`cancel` - are called with different cancellation messages. - The argument will be removed. - - .. _asyncio_example_task_cancel: - - The following example illustrates how coroutines can intercept - the cancellation request:: - - async def cancel_me(): - print('cancel_me(): before sleep') - - try: - # Wait for 1 hour - await asyncio.sleep(3600) - except asyncio.CancelledError: - print('cancel_me(): cancel sleep') - raise - finally: - print('cancel_me(): after sleep') - - async def main(): - # Create a "cancel_me" Task - task = asyncio.create_task(cancel_me()) - - # Wait for 1 second - await asyncio.sleep(1) - - task.cancel() - try: - await task - except asyncio.CancelledError: - print("main(): cancel_me is cancelled now") - - asyncio.run(main()) - - # Expected output: - # - # cancel_me(): before sleep - # cancel_me(): cancel sleep - # cancel_me(): after sleep - # main(): cancel_me is cancelled now - - .. method:: cancelled() - - Return ``True`` if the Task is *cancelled*. - - The Task is *cancelled* when the cancellation was requested with - :meth:`cancel` and the wrapped coroutine propagated the - :exc:`CancelledError` exception thrown into it. - .. method:: done() Return ``True`` if the Task is *done*. @@ -1186,3 +1118,125 @@ Task Object in the :func:`repr` output of a task object. .. versionadded:: 3.8 + + .. method:: cancel(msg=None) + + Request the Task to be cancelled. + + This arranges for a :exc:`CancelledError` exception to be thrown + into the wrapped coroutine on the next cycle of the event loop. + + The coroutine then has a chance to clean up or even deny the + request by suppressing the exception with a :keyword:`try` ... + ... ``except CancelledError`` ... :keyword:`finally` block. + Therefore, unlike :meth:`Future.cancel`, :meth:`Task.cancel` does + not guarantee that the Task will be cancelled, although + suppressing cancellation completely is not common and is actively + discouraged. + + .. versionchanged:: 3.9 + Added the *msg* parameter. + + .. deprecated-removed:: 3.11 3.14 + *msg* parameter is ambiguous when multiple :meth:`cancel` + are called with different cancellation messages. + The argument will be removed. + + .. _asyncio_example_task_cancel: + + The following example illustrates how coroutines can intercept + the cancellation request:: + + async def cancel_me(): + print('cancel_me(): before sleep') + + try: + # Wait for 1 hour + await asyncio.sleep(3600) + except asyncio.CancelledError: + print('cancel_me(): cancel sleep') + raise + finally: + print('cancel_me(): after sleep') + + async def main(): + # Create a "cancel_me" Task + task = asyncio.create_task(cancel_me()) + + # Wait for 1 second + await asyncio.sleep(1) + + task.cancel() + try: + await task + except asyncio.CancelledError: + print("main(): cancel_me is cancelled now") + + asyncio.run(main()) + + # Expected output: + # + # cancel_me(): before sleep + # cancel_me(): cancel sleep + # cancel_me(): after sleep + # main(): cancel_me is cancelled now + + .. method:: cancelled() + + Return ``True`` if the Task is *cancelled*. + + The Task is *cancelled* when the cancellation was requested with + :meth:`cancel` and the wrapped coroutine propagated the + :exc:`CancelledError` exception thrown into it. + + .. method:: uncancel() + + Decrement the count of cancellation requests to this Task. + + Returns the remaining number of cancellation requests. + + Note that once execution of a cancelled task completed, further + calls to :meth:`uncancel` are ineffective. + + .. versionadded:: 3.11 + + This method is used by asyncio's internals and isn't expected to be + used by end-user code. In particular, if a Task gets successfully + uncancelled, this allows for elements of structured concurrency like + :ref:`taskgroups` and :func:`asyncio.timeout` to continue running, + isolating cancellation to the respective structured block. + For example:: + + async def make_request_with_timeout(): + try: + async with asyncio.timeout(1): + # Structured block affected by the timeout: + await make_request() + await make_another_request() + except TimeoutError: + log("There was a timeout") + # Outer code not affected by the timeout: + await unrelated_code() + + While the block with ``make_request()`` and ``make_another_request()`` + might get cancelled due to the timeout, ``unrelated_code()`` should + continue running even in case of the timeout. This is implemented + with :meth:`uncancel`. :class:`TaskGroup` context managers use + :func:`uncancel` in a similar fashion. + + .. method:: cancelling() + + Return the number of pending cancellation requests to this Task, i.e., + the number of calls to :meth:`cancel` less the number of + :meth:`uncancel` calls. + + Note that if this number is greater than zero but the Task is + still executing, :meth:`cancelled` will still return ``False``. + This is because this number can be lowered by calling :meth:`uncancel`, + which can lead to the task not being cancelled after all if the + cancellation requests go down to zero. + + This method is used by asyncio's internals and isn't expected to be + used by end-user code. See :meth:`uncancel` for more details. + + .. versionadded:: 3.11 diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py index 56a355cbdc70..e48da0f20088 100644 --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -243,8 +243,8 @@ def cancelling(self): def uncancel(self): """Decrement the task's count of cancellation requests. - This should be used by tasks that catch CancelledError - and wish to continue indefinitely until they are cancelled again. + This should be called by the party that called `cancel()` on the task + beforehand. Returns the remaining number of cancellation requests. """ diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py index de735ba77aae..04bdf6483131 100644 --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -521,7 +521,7 @@ async def task(): finally: loop.close() - def test_uncancel(self): + def test_uncancel_basic(self): loop = asyncio.new_event_loop() async def task(): @@ -534,17 +534,137 @@ async def task(): try: t = self.new_task(loop, task()) loop.run_until_complete(asyncio.sleep(0.01)) - self.assertTrue(t.cancel()) # Cancel first sleep + + # Cancel first sleep + self.assertTrue(t.cancel()) self.assertIn(" cancelling ", repr(t)) + self.assertEqual(t.cancelling(), 1) + self.assertFalse(t.cancelled()) # Task is still not complete loop.run_until_complete(asyncio.sleep(0.01)) - self.assertNotIn(" cancelling ", repr(t)) # after .uncancel() - self.assertTrue(t.cancel()) # Cancel second sleep + # after .uncancel() + self.assertNotIn(" cancelling ", repr(t)) + self.assertEqual(t.cancelling(), 0) + self.assertFalse(t.cancelled()) # Task is still not complete + + # Cancel second sleep + self.assertTrue(t.cancel()) + self.assertEqual(t.cancelling(), 1) + self.assertFalse(t.cancelled()) # Task is still not complete with self.assertRaises(asyncio.CancelledError): loop.run_until_complete(t) + self.assertTrue(t.cancelled()) # Finally, task complete + self.assertTrue(t.done()) + + # uncancel is no longer effective after the task is complete + t.uncancel() + self.assertTrue(t.cancelled()) + self.assertTrue(t.done()) finally: loop.close() + def test_uncancel_structured_blocks(self): + # This test recreates the following high-level structure using uncancel():: + # + # async def make_request_with_timeout(): + # try: + # async with asyncio.timeout(1): + # # Structured block affected by the timeout: + # await make_request() + # await make_another_request() + # except TimeoutError: + # pass # There was a timeout + # # Outer code not affected by the timeout: + # await unrelated_code() + + loop = asyncio.new_event_loop() + + async def make_request_with_timeout(*, sleep: float, timeout: float): + task = asyncio.current_task() + loop = task.get_loop() + + timed_out = False + structured_block_finished = False + outer_code_reached = False + + def on_timeout(): + nonlocal timed_out + timed_out = True + task.cancel() + + timeout_handle = loop.call_later(timeout, on_timeout) + try: + try: + # Structured block affected by the timeout + await asyncio.sleep(sleep) + structured_block_finished = True + finally: + timeout_handle.cancel() + if ( + timed_out + and task.uncancel() == 0 + and sys.exc_info()[0] is asyncio.CancelledError + ): + # Note the five rules that are needed here to satisfy proper + # uncancellation: + # + # 1. handle uncancellation in a `finally:` block to allow for + # plain returns; + # 2. our `timed_out` flag is set, meaning that it was our event + # that triggered the need to uncancel the task, regardless of + # what exception is raised; + # 3. we can call `uncancel()` because *we* called `cancel()` + # before; + # 4. we call `uncancel()` but we only continue converting the + # CancelledError to TimeoutError if `uncancel()` caused the + # cancellation request count go down to 0. We need to look + # at the counter vs having a simple boolean flag because our + # code might have been nested (think multiple timeouts). See + # commit 7fce1063b6e5a366f8504e039a8ccdd6944625cd for + # details. + # 5. we only convert CancelledError to TimeoutError; for other + # exceptions raised due to the cancellation (like + # a ConnectionLostError from a database client), simply + # propagate them. + # + # Those checks need to take place in this exact order to make + # sure the `cancelling()` counter always stays in sync. + # + # Additionally, the original stimulus to `cancel()` the task + # needs to be unscheduled to avoid re-cancelling the task later. + # Here we do it by cancelling `timeout_handle` in the `finally:` + # block. + raise TimeoutError + except TimeoutError: + self.assertTrue(timed_out) + + # Outer code not affected by the timeout: + outer_code_reached = True + await asyncio.sleep(0) + return timed_out, structured_block_finished, outer_code_reached + + # Test which timed out. + t1 = self.new_task(loop, make_request_with_timeout(sleep=10.0, timeout=0.1)) + timed_out, structured_block_finished, outer_code_reached = ( + loop.run_until_complete(t1) + ) + self.assertTrue(timed_out) + self.assertFalse(structured_block_finished) # it was cancelled + self.assertTrue(outer_code_reached) # task got uncancelled after leaving + # the structured block and continued until + # completion + self.assertEqual(t1.cancelling(), 0) # no pending cancellation of the outer task + + # Test which did not time out. + t2 = self.new_task(loop, make_request_with_timeout(sleep=0, timeout=10.0)) + timed_out, structured_block_finished, outer_code_reached = ( + loop.run_until_complete(t2) + ) + self.assertFalse(timed_out) + self.assertTrue(structured_block_finished) + self.assertTrue(outer_code_reached) + self.assertEqual(t2.cancelling(), 0) + def test_cancel(self): def gen(): From webhook-mailer at python.org Sat Oct 1 14:10:12 2022 From: webhook-mailer at python.org (miss-islington) Date: Sat, 01 Oct 2022 18:10:12 -0000 Subject: [Python-checkins] gh-90908: Document asyncio.Task.cancelling() and asyncio.Task.uncancel() (GH-95253) Message-ID: https://github.com/python/cpython/commit/3614bbb8eb8e0110f9df1e7cb3875e65d7959730 commit: 3614bbb8eb8e0110f9df1e7cb3875e65d7959730 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-01T11:10:04-07:00 summary: gh-90908: Document asyncio.Task.cancelling() and asyncio.Task.uncancel() (GH-95253) Co-authored-by: Thomas Grainger (cherry picked from commit f00645d5dbf4cfa0b8f382c8977724578dff191d) Co-authored-by: ?ukasz Langa files: M Doc/library/asyncio-task.rst M Lib/asyncio/tasks.py M Lib/test/test_asyncio/test_tasks.py diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index 221197ea40ff..ade969220ea7 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -294,11 +294,13 @@ perform clean-up logic. In case :exc:`asyncio.CancelledError` is explicitly caught, it should generally be propagated when clean-up is complete. Most code can safely ignore :exc:`asyncio.CancelledError`. -Important asyncio components, like :class:`asyncio.TaskGroup` and the -:func:`asyncio.timeout` context manager, are implemented using cancellation -internally and might misbehave if a coroutine swallows -:exc:`asyncio.CancelledError`. +The asyncio components that enable structured concurrency, like +:class:`asyncio.TaskGroup` and :func:`asyncio.timeout`, +are implemented using cancellation internally and might misbehave if +a coroutine swallows :exc:`asyncio.CancelledError`. Similarly, user code +should not call :meth:`uncancel `. +.. _taskgroups: Task Groups =========== @@ -1003,76 +1005,6 @@ Task Object Deprecation warning is emitted if *loop* is not specified and there is no running event loop. - .. method:: cancel(msg=None) - - Request the Task to be cancelled. - - This arranges for a :exc:`CancelledError` exception to be thrown - into the wrapped coroutine on the next cycle of the event loop. - - The coroutine then has a chance to clean up or even deny the - request by suppressing the exception with a :keyword:`try` ... - ... ``except CancelledError`` ... :keyword:`finally` block. - Therefore, unlike :meth:`Future.cancel`, :meth:`Task.cancel` does - not guarantee that the Task will be cancelled, although - suppressing cancellation completely is not common and is actively - discouraged. - - .. versionchanged:: 3.9 - Added the *msg* parameter. - - .. deprecated-removed:: 3.11 3.14 - *msg* parameter is ambiguous when multiple :meth:`cancel` - are called with different cancellation messages. - The argument will be removed. - - .. _asyncio_example_task_cancel: - - The following example illustrates how coroutines can intercept - the cancellation request:: - - async def cancel_me(): - print('cancel_me(): before sleep') - - try: - # Wait for 1 hour - await asyncio.sleep(3600) - except asyncio.CancelledError: - print('cancel_me(): cancel sleep') - raise - finally: - print('cancel_me(): after sleep') - - async def main(): - # Create a "cancel_me" Task - task = asyncio.create_task(cancel_me()) - - # Wait for 1 second - await asyncio.sleep(1) - - task.cancel() - try: - await task - except asyncio.CancelledError: - print("main(): cancel_me is cancelled now") - - asyncio.run(main()) - - # Expected output: - # - # cancel_me(): before sleep - # cancel_me(): cancel sleep - # cancel_me(): after sleep - # main(): cancel_me is cancelled now - - .. method:: cancelled() - - Return ``True`` if the Task is *cancelled*. - - The Task is *cancelled* when the cancellation was requested with - :meth:`cancel` and the wrapped coroutine propagated the - :exc:`CancelledError` exception thrown into it. - .. method:: done() Return ``True`` if the Task is *done*. @@ -1186,3 +1118,125 @@ Task Object in the :func:`repr` output of a task object. .. versionadded:: 3.8 + + .. method:: cancel(msg=None) + + Request the Task to be cancelled. + + This arranges for a :exc:`CancelledError` exception to be thrown + into the wrapped coroutine on the next cycle of the event loop. + + The coroutine then has a chance to clean up or even deny the + request by suppressing the exception with a :keyword:`try` ... + ... ``except CancelledError`` ... :keyword:`finally` block. + Therefore, unlike :meth:`Future.cancel`, :meth:`Task.cancel` does + not guarantee that the Task will be cancelled, although + suppressing cancellation completely is not common and is actively + discouraged. + + .. versionchanged:: 3.9 + Added the *msg* parameter. + + .. deprecated-removed:: 3.11 3.14 + *msg* parameter is ambiguous when multiple :meth:`cancel` + are called with different cancellation messages. + The argument will be removed. + + .. _asyncio_example_task_cancel: + + The following example illustrates how coroutines can intercept + the cancellation request:: + + async def cancel_me(): + print('cancel_me(): before sleep') + + try: + # Wait for 1 hour + await asyncio.sleep(3600) + except asyncio.CancelledError: + print('cancel_me(): cancel sleep') + raise + finally: + print('cancel_me(): after sleep') + + async def main(): + # Create a "cancel_me" Task + task = asyncio.create_task(cancel_me()) + + # Wait for 1 second + await asyncio.sleep(1) + + task.cancel() + try: + await task + except asyncio.CancelledError: + print("main(): cancel_me is cancelled now") + + asyncio.run(main()) + + # Expected output: + # + # cancel_me(): before sleep + # cancel_me(): cancel sleep + # cancel_me(): after sleep + # main(): cancel_me is cancelled now + + .. method:: cancelled() + + Return ``True`` if the Task is *cancelled*. + + The Task is *cancelled* when the cancellation was requested with + :meth:`cancel` and the wrapped coroutine propagated the + :exc:`CancelledError` exception thrown into it. + + .. method:: uncancel() + + Decrement the count of cancellation requests to this Task. + + Returns the remaining number of cancellation requests. + + Note that once execution of a cancelled task completed, further + calls to :meth:`uncancel` are ineffective. + + .. versionadded:: 3.11 + + This method is used by asyncio's internals and isn't expected to be + used by end-user code. In particular, if a Task gets successfully + uncancelled, this allows for elements of structured concurrency like + :ref:`taskgroups` and :func:`asyncio.timeout` to continue running, + isolating cancellation to the respective structured block. + For example:: + + async def make_request_with_timeout(): + try: + async with asyncio.timeout(1): + # Structured block affected by the timeout: + await make_request() + await make_another_request() + except TimeoutError: + log("There was a timeout") + # Outer code not affected by the timeout: + await unrelated_code() + + While the block with ``make_request()`` and ``make_another_request()`` + might get cancelled due to the timeout, ``unrelated_code()`` should + continue running even in case of the timeout. This is implemented + with :meth:`uncancel`. :class:`TaskGroup` context managers use + :func:`uncancel` in a similar fashion. + + .. method:: cancelling() + + Return the number of pending cancellation requests to this Task, i.e., + the number of calls to :meth:`cancel` less the number of + :meth:`uncancel` calls. + + Note that if this number is greater than zero but the Task is + still executing, :meth:`cancelled` will still return ``False``. + This is because this number can be lowered by calling :meth:`uncancel`, + which can lead to the task not being cancelled after all if the + cancellation requests go down to zero. + + This method is used by asyncio's internals and isn't expected to be + used by end-user code. See :meth:`uncancel` for more details. + + .. versionadded:: 3.11 diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py index 56a355cbdc70..e48da0f20088 100644 --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -243,8 +243,8 @@ def cancelling(self): def uncancel(self): """Decrement the task's count of cancellation requests. - This should be used by tasks that catch CancelledError - and wish to continue indefinitely until they are cancelled again. + This should be called by the party that called `cancel()` on the task + beforehand. Returns the remaining number of cancellation requests. """ diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py index 427034a1f1bc..1cc20609bebc 100644 --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -525,7 +525,7 @@ async def task(): finally: loop.close() - def test_uncancel(self): + def test_uncancel_basic(self): loop = asyncio.new_event_loop() async def task(): @@ -538,17 +538,137 @@ async def task(): try: t = self.new_task(loop, task()) loop.run_until_complete(asyncio.sleep(0.01)) - self.assertTrue(t.cancel()) # Cancel first sleep + + # Cancel first sleep + self.assertTrue(t.cancel()) self.assertIn(" cancelling ", repr(t)) + self.assertEqual(t.cancelling(), 1) + self.assertFalse(t.cancelled()) # Task is still not complete loop.run_until_complete(asyncio.sleep(0.01)) - self.assertNotIn(" cancelling ", repr(t)) # after .uncancel() - self.assertTrue(t.cancel()) # Cancel second sleep + # after .uncancel() + self.assertNotIn(" cancelling ", repr(t)) + self.assertEqual(t.cancelling(), 0) + self.assertFalse(t.cancelled()) # Task is still not complete + + # Cancel second sleep + self.assertTrue(t.cancel()) + self.assertEqual(t.cancelling(), 1) + self.assertFalse(t.cancelled()) # Task is still not complete with self.assertRaises(asyncio.CancelledError): loop.run_until_complete(t) + self.assertTrue(t.cancelled()) # Finally, task complete + self.assertTrue(t.done()) + + # uncancel is no longer effective after the task is complete + t.uncancel() + self.assertTrue(t.cancelled()) + self.assertTrue(t.done()) finally: loop.close() + def test_uncancel_structured_blocks(self): + # This test recreates the following high-level structure using uncancel():: + # + # async def make_request_with_timeout(): + # try: + # async with asyncio.timeout(1): + # # Structured block affected by the timeout: + # await make_request() + # await make_another_request() + # except TimeoutError: + # pass # There was a timeout + # # Outer code not affected by the timeout: + # await unrelated_code() + + loop = asyncio.new_event_loop() + + async def make_request_with_timeout(*, sleep: float, timeout: float): + task = asyncio.current_task() + loop = task.get_loop() + + timed_out = False + structured_block_finished = False + outer_code_reached = False + + def on_timeout(): + nonlocal timed_out + timed_out = True + task.cancel() + + timeout_handle = loop.call_later(timeout, on_timeout) + try: + try: + # Structured block affected by the timeout + await asyncio.sleep(sleep) + structured_block_finished = True + finally: + timeout_handle.cancel() + if ( + timed_out + and task.uncancel() == 0 + and sys.exc_info()[0] is asyncio.CancelledError + ): + # Note the five rules that are needed here to satisfy proper + # uncancellation: + # + # 1. handle uncancellation in a `finally:` block to allow for + # plain returns; + # 2. our `timed_out` flag is set, meaning that it was our event + # that triggered the need to uncancel the task, regardless of + # what exception is raised; + # 3. we can call `uncancel()` because *we* called `cancel()` + # before; + # 4. we call `uncancel()` but we only continue converting the + # CancelledError to TimeoutError if `uncancel()` caused the + # cancellation request count go down to 0. We need to look + # at the counter vs having a simple boolean flag because our + # code might have been nested (think multiple timeouts). See + # commit 7fce1063b6e5a366f8504e039a8ccdd6944625cd for + # details. + # 5. we only convert CancelledError to TimeoutError; for other + # exceptions raised due to the cancellation (like + # a ConnectionLostError from a database client), simply + # propagate them. + # + # Those checks need to take place in this exact order to make + # sure the `cancelling()` counter always stays in sync. + # + # Additionally, the original stimulus to `cancel()` the task + # needs to be unscheduled to avoid re-cancelling the task later. + # Here we do it by cancelling `timeout_handle` in the `finally:` + # block. + raise TimeoutError + except TimeoutError: + self.assertTrue(timed_out) + + # Outer code not affected by the timeout: + outer_code_reached = True + await asyncio.sleep(0) + return timed_out, structured_block_finished, outer_code_reached + + # Test which timed out. + t1 = self.new_task(loop, make_request_with_timeout(sleep=10.0, timeout=0.1)) + timed_out, structured_block_finished, outer_code_reached = ( + loop.run_until_complete(t1) + ) + self.assertTrue(timed_out) + self.assertFalse(structured_block_finished) # it was cancelled + self.assertTrue(outer_code_reached) # task got uncancelled after leaving + # the structured block and continued until + # completion + self.assertEqual(t1.cancelling(), 0) # no pending cancellation of the outer task + + # Test which did not time out. + t2 = self.new_task(loop, make_request_with_timeout(sleep=0, timeout=10.0)) + timed_out, structured_block_finished, outer_code_reached = ( + loop.run_until_complete(t2) + ) + self.assertFalse(timed_out) + self.assertTrue(structured_block_finished) + self.assertTrue(outer_code_reached) + self.assertEqual(t2.cancelling(), 0) + def test_cancel(self): def gen(): From webhook-mailer at python.org Sat Oct 1 19:41:14 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Sat, 01 Oct 2022 23:41:14 -0000 Subject: [Python-checkins] Fix capitalization of Unix in documentation (#96913) Message-ID: https://github.com/python/cpython/commit/bd7d0e875e6955dd69cde18a034e59a75b8b4d00 commit: bd7d0e875e6955dd69cde18a034e59a75b8b4d00 branch: main author: Will Hawkins <8715530+hawkinsw at users.noreply.github.com> committer: JelleZijlstra date: 2022-10-01T16:41:06-07:00 summary: Fix capitalization of Unix in documentation (#96913) files: M Doc/library/email.compat32-message.rst M Doc/library/email.generator.rst M Doc/library/multiprocessing.rst M Doc/library/os.path.rst M Doc/library/test.rst M Doc/whatsnew/3.3.rst diff --git a/Doc/library/email.compat32-message.rst b/Doc/library/email.compat32-message.rst index c68e773b1688..4eaa9d588ca3 100644 --- a/Doc/library/email.compat32-message.rst +++ b/Doc/library/email.compat32-message.rst @@ -83,7 +83,7 @@ Here are the methods of the :class:`Message` class: Note that this method is provided as a convenience and may not always format the message the way you want. For example, by default it does not do the mangling of lines that begin with ``From`` that is - required by the unix mbox format. For more flexibility, instantiate a + required by the Unix mbox format. For more flexibility, instantiate a :class:`~email.generator.Generator` instance and use its :meth:`~email.generator.Generator.flatten` method directly. For example:: @@ -125,7 +125,7 @@ Here are the methods of the :class:`Message` class: Note that this method is provided as a convenience and may not always format the message the way you want. For example, by default it does not do the mangling of lines that begin with ``From`` that is - required by the unix mbox format. For more flexibility, instantiate a + required by the Unix mbox format. For more flexibility, instantiate a :class:`~email.generator.BytesGenerator` instance and use its :meth:`~email.generator.BytesGenerator.flatten` method directly. For example:: diff --git a/Doc/library/email.generator.rst b/Doc/library/email.generator.rst index 2d9bae6a7ee5..34ad7b7f200a 100644 --- a/Doc/library/email.generator.rst +++ b/Doc/library/email.generator.rst @@ -55,7 +55,7 @@ To accommodate reproducible processing of SMIME-signed messages defaults to the value of the :attr:`~email.policy.Policy.mangle_from_` setting of the *policy* (which is ``True`` for the :data:`~email.policy.compat32` policy and ``False`` for all others). - *mangle_from_* is intended for use when messages are stored in unix mbox + *mangle_from_* is intended for use when messages are stored in Unix mbox format (see :mod:`mailbox` and `WHY THE CONTENT-LENGTH FORMAT IS BAD `_). @@ -156,7 +156,7 @@ to be using :class:`BytesGenerator`, and not :class:`Generator`. defaults to the value of the :attr:`~email.policy.Policy.mangle_from_` setting of the *policy* (which is ``True`` for the :data:`~email.policy.compat32` policy and ``False`` for all others). - *mangle_from_* is intended for use when messages are stored in unix mbox + *mangle_from_* is intended for use when messages are stored in Unix mbox format (see :mod:`mailbox` and `WHY THE CONTENT-LENGTH FORMAT IS BAD `_). diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst index caf24a35fdfc..d74fe92f20d0 100644 --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -144,8 +144,8 @@ to start a process. These *start methods* are subprocess. See :issue:`33725`. .. versionchanged:: 3.4 - *spawn* added on all unix platforms, and *forkserver* added for - some unix platforms. + *spawn* added on all Unix platforms, and *forkserver* added for + some Unix platforms. Child processes no longer inherit all of the parents inheritable handles on Windows. diff --git a/Doc/library/os.path.rst b/Doc/library/os.path.rst index 7c35f3cafd12..6d52a03ba957 100644 --- a/Doc/library/os.path.rst +++ b/Doc/library/os.path.rst @@ -16,7 +16,7 @@ files see :func:`open`, and for accessing the filesystem see the :mod:`os` module. The path parameters can be passed as strings, or bytes, or any object implementing the :class:`os.PathLike` protocol. -Unlike a unix shell, Python does not do any *automatic* path expansions. +Unlike a Unix shell, Python does not do any *automatic* path expansions. Functions such as :func:`expanduser` and :func:`expandvars` can be invoked explicitly when an application desires shell-like path expansion. (See also the :mod:`glob` module.) diff --git a/Doc/library/test.rst b/Doc/library/test.rst index 53bcd7c178f9..8199a27d7d9c 100644 --- a/Doc/library/test.rst +++ b/Doc/library/test.rst @@ -1128,7 +1128,7 @@ The :mod:`test.support.socket_helper` module provides support for socket tests. .. function:: bind_unix_socket(sock, addr) - Bind a unix socket, raising :exc:`unittest.SkipTest` if + Bind a Unix socket, raising :exc:`unittest.SkipTest` if :exc:`PermissionError` is raised. diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst index 1b5b6831e430..2d78f81798f2 100644 --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -1898,7 +1898,7 @@ socket family on OS X. (Contributed by Michael Goderbauer in :issue:`13777`.) * New function :func:`~socket.sethostname` allows the hostname to be set - on unix systems if the calling process has sufficient privileges. + on Unix systems if the calling process has sufficient privileges. (Contributed by Ross Lagerwall in :issue:`10866`.) From webhook-mailer at python.org Sat Oct 1 19:51:39 2022 From: webhook-mailer at python.org (miss-islington) Date: Sat, 01 Oct 2022 23:51:39 -0000 Subject: [Python-checkins] Fix capitalization of Unix in documentation (GH-96913) Message-ID: https://github.com/python/cpython/commit/35a394c556d04048f24deda879b8547c598928dc commit: 35a394c556d04048f24deda879b8547c598928dc branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-01T16:51:34-07:00 summary: Fix capitalization of Unix in documentation (GH-96913) (cherry picked from commit bd7d0e875e6955dd69cde18a034e59a75b8b4d00) Co-authored-by: Will Hawkins <8715530+hawkinsw at users.noreply.github.com> files: M Doc/library/email.compat32-message.rst M Doc/library/email.generator.rst M Doc/library/multiprocessing.rst M Doc/library/os.path.rst M Doc/library/test.rst M Doc/whatsnew/3.3.rst diff --git a/Doc/library/email.compat32-message.rst b/Doc/library/email.compat32-message.rst index c68e773b1688..4eaa9d588ca3 100644 --- a/Doc/library/email.compat32-message.rst +++ b/Doc/library/email.compat32-message.rst @@ -83,7 +83,7 @@ Here are the methods of the :class:`Message` class: Note that this method is provided as a convenience and may not always format the message the way you want. For example, by default it does not do the mangling of lines that begin with ``From`` that is - required by the unix mbox format. For more flexibility, instantiate a + required by the Unix mbox format. For more flexibility, instantiate a :class:`~email.generator.Generator` instance and use its :meth:`~email.generator.Generator.flatten` method directly. For example:: @@ -125,7 +125,7 @@ Here are the methods of the :class:`Message` class: Note that this method is provided as a convenience and may not always format the message the way you want. For example, by default it does not do the mangling of lines that begin with ``From`` that is - required by the unix mbox format. For more flexibility, instantiate a + required by the Unix mbox format. For more flexibility, instantiate a :class:`~email.generator.BytesGenerator` instance and use its :meth:`~email.generator.BytesGenerator.flatten` method directly. For example:: diff --git a/Doc/library/email.generator.rst b/Doc/library/email.generator.rst index 2d9bae6a7ee5..34ad7b7f200a 100644 --- a/Doc/library/email.generator.rst +++ b/Doc/library/email.generator.rst @@ -55,7 +55,7 @@ To accommodate reproducible processing of SMIME-signed messages defaults to the value of the :attr:`~email.policy.Policy.mangle_from_` setting of the *policy* (which is ``True`` for the :data:`~email.policy.compat32` policy and ``False`` for all others). - *mangle_from_* is intended for use when messages are stored in unix mbox + *mangle_from_* is intended for use when messages are stored in Unix mbox format (see :mod:`mailbox` and `WHY THE CONTENT-LENGTH FORMAT IS BAD `_). @@ -156,7 +156,7 @@ to be using :class:`BytesGenerator`, and not :class:`Generator`. defaults to the value of the :attr:`~email.policy.Policy.mangle_from_` setting of the *policy* (which is ``True`` for the :data:`~email.policy.compat32` policy and ``False`` for all others). - *mangle_from_* is intended for use when messages are stored in unix mbox + *mangle_from_* is intended for use when messages are stored in Unix mbox format (see :mod:`mailbox` and `WHY THE CONTENT-LENGTH FORMAT IS BAD `_). diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst index caf24a35fdfc..d74fe92f20d0 100644 --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -144,8 +144,8 @@ to start a process. These *start methods* are subprocess. See :issue:`33725`. .. versionchanged:: 3.4 - *spawn* added on all unix platforms, and *forkserver* added for - some unix platforms. + *spawn* added on all Unix platforms, and *forkserver* added for + some Unix platforms. Child processes no longer inherit all of the parents inheritable handles on Windows. diff --git a/Doc/library/os.path.rst b/Doc/library/os.path.rst index f02877ebcea9..0becb592b41e 100644 --- a/Doc/library/os.path.rst +++ b/Doc/library/os.path.rst @@ -16,7 +16,7 @@ files see :func:`open`, and for accessing the filesystem see the :mod:`os` module. The path parameters can be passed as strings, or bytes, or any object implementing the :class:`os.PathLike` protocol. -Unlike a unix shell, Python does not do any *automatic* path expansions. +Unlike a Unix shell, Python does not do any *automatic* path expansions. Functions such as :func:`expanduser` and :func:`expandvars` can be invoked explicitly when an application desires shell-like path expansion. (See also the :mod:`glob` module.) diff --git a/Doc/library/test.rst b/Doc/library/test.rst index 43362580299b..8e05ff39c109 100644 --- a/Doc/library/test.rst +++ b/Doc/library/test.rst @@ -1075,7 +1075,7 @@ The :mod:`test.support.socket_helper` module provides support for socket tests. .. function:: bind_unix_socket(sock, addr) - Bind a unix socket, raising :exc:`unittest.SkipTest` if + Bind a Unix socket, raising :exc:`unittest.SkipTest` if :exc:`PermissionError` is raised. diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst index 1b5b6831e430..2d78f81798f2 100644 --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -1898,7 +1898,7 @@ socket family on OS X. (Contributed by Michael Goderbauer in :issue:`13777`.) * New function :func:`~socket.sethostname` allows the hostname to be set - on unix systems if the calling process has sufficient privileges. + on Unix systems if the calling process has sufficient privileges. (Contributed by Ross Lagerwall in :issue:`10866`.) From webhook-mailer at python.org Sat Oct 1 19:51:47 2022 From: webhook-mailer at python.org (miss-islington) Date: Sat, 01 Oct 2022 23:51:47 -0000 Subject: [Python-checkins] Fix capitalization of Unix in documentation (GH-96913) Message-ID: https://github.com/python/cpython/commit/748b2b780dd710139fc78dd795563e917b7e8a9e commit: 748b2b780dd710139fc78dd795563e917b7e8a9e branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-01T16:51:42-07:00 summary: Fix capitalization of Unix in documentation (GH-96913) (cherry picked from commit bd7d0e875e6955dd69cde18a034e59a75b8b4d00) Co-authored-by: Will Hawkins <8715530+hawkinsw at users.noreply.github.com> files: M Doc/library/email.compat32-message.rst M Doc/library/email.generator.rst M Doc/library/multiprocessing.rst M Doc/library/os.path.rst M Doc/library/test.rst M Doc/whatsnew/3.3.rst diff --git a/Doc/library/email.compat32-message.rst b/Doc/library/email.compat32-message.rst index c68e773b1688..4eaa9d588ca3 100644 --- a/Doc/library/email.compat32-message.rst +++ b/Doc/library/email.compat32-message.rst @@ -83,7 +83,7 @@ Here are the methods of the :class:`Message` class: Note that this method is provided as a convenience and may not always format the message the way you want. For example, by default it does not do the mangling of lines that begin with ``From`` that is - required by the unix mbox format. For more flexibility, instantiate a + required by the Unix mbox format. For more flexibility, instantiate a :class:`~email.generator.Generator` instance and use its :meth:`~email.generator.Generator.flatten` method directly. For example:: @@ -125,7 +125,7 @@ Here are the methods of the :class:`Message` class: Note that this method is provided as a convenience and may not always format the message the way you want. For example, by default it does not do the mangling of lines that begin with ``From`` that is - required by the unix mbox format. For more flexibility, instantiate a + required by the Unix mbox format. For more flexibility, instantiate a :class:`~email.generator.BytesGenerator` instance and use its :meth:`~email.generator.BytesGenerator.flatten` method directly. For example:: diff --git a/Doc/library/email.generator.rst b/Doc/library/email.generator.rst index 2d9bae6a7ee5..34ad7b7f200a 100644 --- a/Doc/library/email.generator.rst +++ b/Doc/library/email.generator.rst @@ -55,7 +55,7 @@ To accommodate reproducible processing of SMIME-signed messages defaults to the value of the :attr:`~email.policy.Policy.mangle_from_` setting of the *policy* (which is ``True`` for the :data:`~email.policy.compat32` policy and ``False`` for all others). - *mangle_from_* is intended for use when messages are stored in unix mbox + *mangle_from_* is intended for use when messages are stored in Unix mbox format (see :mod:`mailbox` and `WHY THE CONTENT-LENGTH FORMAT IS BAD `_). @@ -156,7 +156,7 @@ to be using :class:`BytesGenerator`, and not :class:`Generator`. defaults to the value of the :attr:`~email.policy.Policy.mangle_from_` setting of the *policy* (which is ``True`` for the :data:`~email.policy.compat32` policy and ``False`` for all others). - *mangle_from_* is intended for use when messages are stored in unix mbox + *mangle_from_* is intended for use when messages are stored in Unix mbox format (see :mod:`mailbox` and `WHY THE CONTENT-LENGTH FORMAT IS BAD `_). diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst index 18e9b1ee8cb3..6a9ab240606f 100644 --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -142,8 +142,8 @@ to start a process. These *start methods* are subprocess. See :issue:`33725`. .. versionchanged:: 3.4 - *spawn* added on all unix platforms, and *forkserver* added for - some unix platforms. + *spawn* added on all Unix platforms, and *forkserver* added for + some Unix platforms. Child processes no longer inherit all of the parents inheritable handles on Windows. diff --git a/Doc/library/os.path.rst b/Doc/library/os.path.rst index f02877ebcea9..0becb592b41e 100644 --- a/Doc/library/os.path.rst +++ b/Doc/library/os.path.rst @@ -16,7 +16,7 @@ files see :func:`open`, and for accessing the filesystem see the :mod:`os` module. The path parameters can be passed as strings, or bytes, or any object implementing the :class:`os.PathLike` protocol. -Unlike a unix shell, Python does not do any *automatic* path expansions. +Unlike a Unix shell, Python does not do any *automatic* path expansions. Functions such as :func:`expanduser` and :func:`expandvars` can be invoked explicitly when an application desires shell-like path expansion. (See also the :mod:`glob` module.) diff --git a/Doc/library/test.rst b/Doc/library/test.rst index 594405293137..922a8f0b512f 100644 --- a/Doc/library/test.rst +++ b/Doc/library/test.rst @@ -1066,7 +1066,7 @@ The :mod:`test.support.socket_helper` module provides support for socket tests. .. function:: bind_unix_socket(sock, addr) - Bind a unix socket, raising :exc:`unittest.SkipTest` if + Bind a Unix socket, raising :exc:`unittest.SkipTest` if :exc:`PermissionError` is raised. diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst index 1b5b6831e430..2d78f81798f2 100644 --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -1898,7 +1898,7 @@ socket family on OS X. (Contributed by Michael Goderbauer in :issue:`13777`.) * New function :func:`~socket.sethostname` allows the hostname to be set - on unix systems if the calling process has sufficient privileges. + on Unix systems if the calling process has sufficient privileges. (Contributed by Ross Lagerwall in :issue:`10866`.) From webhook-mailer at python.org Sat Oct 1 20:55:48 2022 From: webhook-mailer at python.org (gpshead) Date: Sun, 02 Oct 2022 00:55:48 -0000 Subject: [Python-checkins] gh-95588: Drop the safety claim from `ast.literal_eval` docs. (#95919) Message-ID: https://github.com/python/cpython/commit/8baef8ae367041a5cfefb40b19c7b87e9bcb56a2 commit: 8baef8ae367041a5cfefb40b19c7b87e9bcb56a2 branch: main author: Gregory P. Smith committer: gpshead date: 2022-10-01T17:55:40-07:00 summary: gh-95588: Drop the safety claim from `ast.literal_eval` docs. (#95919) It was never really safe and this claim conflicts directly with the big warning in the docs about it being able to crash the interpreter. files: A Misc/NEWS.d/next/Documentation/2022-08-12-01-12-52.gh-issue-95588.PA0FI7.rst M Doc/library/ast.rst M Lib/ast.py diff --git a/Doc/library/ast.rst b/Doc/library/ast.rst index 0349130d2922..0811b3fa0e78 100644 --- a/Doc/library/ast.rst +++ b/Doc/library/ast.rst @@ -1991,20 +1991,28 @@ and classes for traversing abstract syntax trees: .. function:: literal_eval(node_or_string) - Safely evaluate an expression node or a string containing a Python literal or + Evaluate an expression node or a string containing only a Python literal or container display. The string or node provided may only consist of the following Python literal structures: strings, bytes, numbers, tuples, lists, dicts, sets, booleans, ``None`` and ``Ellipsis``. - This can be used for safely evaluating strings containing Python values from - untrusted sources without the need to parse the values oneself. It is not - capable of evaluating arbitrarily complex expressions, for example involving - operators or indexing. + This can be used for evaluating strings containing Python values without the + need to parse the values oneself. It is not capable of evaluating + arbitrarily complex expressions, for example involving operators or + indexing. + + This function had been documented as "safe" in the past without defining + what that meant. That was misleading. This is specifically designed not to + execute Python code, unlike the more general :func:`eval`. There is no + namespace, no name lookups, or ability to call out. But it is not free from + attack: A relatively small input can lead to memory exhaustion or to C stack + exhaustion, crashing the process. There is also the possibility for + excessive CPU consumption denial of service on some inputs. Calling it on + untrusted data is thus not recommended. .. warning:: - It is possible to crash the Python interpreter with a - sufficiently large/complex string due to stack depth limitations - in Python's AST compiler. + It is possible to crash the Python interpreter due to stack depth + limitations in Python's AST compiler. It can raise :exc:`ValueError`, :exc:`TypeError`, :exc:`SyntaxError`, :exc:`MemoryError` and :exc:`RecursionError` depending on the malformed diff --git a/Lib/ast.py b/Lib/ast.py index 8adb61fed453..1a94e9368c16 100644 --- a/Lib/ast.py +++ b/Lib/ast.py @@ -54,10 +54,12 @@ def parse(source, filename='', mode='exec', *, def literal_eval(node_or_string): """ - Safely evaluate an expression node or a string containing a Python + Evaluate an expression node or a string containing only a Python expression. The string or node provided may only consist of the following Python literal structures: strings, bytes, numbers, tuples, lists, dicts, sets, booleans, and None. + + Caution: A complex expression can overflow the C stack and cause a crash. """ if isinstance(node_or_string, str): node_or_string = parse(node_or_string.lstrip(" \t"), mode='eval') diff --git a/Misc/NEWS.d/next/Documentation/2022-08-12-01-12-52.gh-issue-95588.PA0FI7.rst b/Misc/NEWS.d/next/Documentation/2022-08-12-01-12-52.gh-issue-95588.PA0FI7.rst new file mode 100644 index 000000000000..c070bbc19517 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2022-08-12-01-12-52.gh-issue-95588.PA0FI7.rst @@ -0,0 +1,6 @@ +Clarified the conflicting advice given in the :mod:`ast` documentation about +:func:`ast.literal_eval` being "safe" for use on untrusted input while at +the same time warning that it can crash the process. The latter statement is +true and is deemed unfixable without a large amount of work unsuitable for a +bugfix. So we keep the warning and no longer claim that ``literal_eval`` is +safe. From webhook-mailer at python.org Sat Oct 1 21:21:27 2022 From: webhook-mailer at python.org (miss-islington) Date: Sun, 02 Oct 2022 01:21:27 -0000 Subject: [Python-checkins] gh-95588: Drop the safety claim from `ast.literal_eval` docs. (GH-95919) Message-ID: https://github.com/python/cpython/commit/9189cd6b05a32b67981d2157947d745b2d0dac88 commit: 9189cd6b05a32b67981d2157947d745b2d0dac88 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-01T18:21:15-07:00 summary: gh-95588: Drop the safety claim from `ast.literal_eval` docs. (GH-95919) It was never really safe and this claim conflicts directly with the big warning in the docs about it being able to crash the interpreter. (cherry picked from commit 8baef8ae367041a5cfefb40b19c7b87e9bcb56a2) Co-authored-by: Gregory P. Smith files: A Misc/NEWS.d/next/Documentation/2022-08-12-01-12-52.gh-issue-95588.PA0FI7.rst M Doc/library/ast.rst M Lib/ast.py diff --git a/Doc/library/ast.rst b/Doc/library/ast.rst index da0fe8c3d6b2..3ed2c4fa7370 100644 --- a/Doc/library/ast.rst +++ b/Doc/library/ast.rst @@ -1990,20 +1990,28 @@ and classes for traversing abstract syntax trees: .. function:: literal_eval(node_or_string) - Safely evaluate an expression node or a string containing a Python literal or + Evaluate an expression node or a string containing only a Python literal or container display. The string or node provided may only consist of the following Python literal structures: strings, bytes, numbers, tuples, lists, dicts, sets, booleans, ``None`` and ``Ellipsis``. - This can be used for safely evaluating strings containing Python values from - untrusted sources without the need to parse the values oneself. It is not - capable of evaluating arbitrarily complex expressions, for example involving - operators or indexing. + This can be used for evaluating strings containing Python values without the + need to parse the values oneself. It is not capable of evaluating + arbitrarily complex expressions, for example involving operators or + indexing. + + This function had been documented as "safe" in the past without defining + what that meant. That was misleading. This is specifically designed not to + execute Python code, unlike the more general :func:`eval`. There is no + namespace, no name lookups, or ability to call out. But it is not free from + attack: A relatively small input can lead to memory exhaustion or to C stack + exhaustion, crashing the process. There is also the possibility for + excessive CPU consumption denial of service on some inputs. Calling it on + untrusted data is thus not recommended. .. warning:: - It is possible to crash the Python interpreter with a - sufficiently large/complex string due to stack depth limitations - in Python's AST compiler. + It is possible to crash the Python interpreter due to stack depth + limitations in Python's AST compiler. It can raise :exc:`ValueError`, :exc:`TypeError`, :exc:`SyntaxError`, :exc:`MemoryError` and :exc:`RecursionError` depending on the malformed diff --git a/Lib/ast.py b/Lib/ast.py index b0e1c41709fa..8c10d0800220 100644 --- a/Lib/ast.py +++ b/Lib/ast.py @@ -53,10 +53,12 @@ def parse(source, filename='', mode='exec', *, def literal_eval(node_or_string): """ - Safely evaluate an expression node or a string containing a Python + Evaluate an expression node or a string containing only a Python expression. The string or node provided may only consist of the following Python literal structures: strings, bytes, numbers, tuples, lists, dicts, sets, booleans, and None. + + Caution: A complex expression can overflow the C stack and cause a crash. """ if isinstance(node_or_string, str): node_or_string = parse(node_or_string.lstrip(" \t"), mode='eval') diff --git a/Misc/NEWS.d/next/Documentation/2022-08-12-01-12-52.gh-issue-95588.PA0FI7.rst b/Misc/NEWS.d/next/Documentation/2022-08-12-01-12-52.gh-issue-95588.PA0FI7.rst new file mode 100644 index 000000000000..c070bbc19517 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2022-08-12-01-12-52.gh-issue-95588.PA0FI7.rst @@ -0,0 +1,6 @@ +Clarified the conflicting advice given in the :mod:`ast` documentation about +:func:`ast.literal_eval` being "safe" for use on untrusted input while at +the same time warning that it can crash the process. The latter statement is +true and is deemed unfixable without a large amount of work unsuitable for a +bugfix. So we keep the warning and no longer claim that ``literal_eval`` is +safe. From webhook-mailer at python.org Sat Oct 1 21:25:00 2022 From: webhook-mailer at python.org (miss-islington) Date: Sun, 02 Oct 2022 01:25:00 -0000 Subject: [Python-checkins] gh-95588: Drop the safety claim from `ast.literal_eval` docs. (GH-95919) Message-ID: https://github.com/python/cpython/commit/a4fbb949659b86b0925b20a9ef6bc2877f397252 commit: a4fbb949659b86b0925b20a9ef6bc2877f397252 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-01T18:24:55-07:00 summary: gh-95588: Drop the safety claim from `ast.literal_eval` docs. (GH-95919) It was never really safe and this claim conflicts directly with the big warning in the docs about it being able to crash the interpreter. (cherry picked from commit 8baef8ae367041a5cfefb40b19c7b87e9bcb56a2) Co-authored-by: Gregory P. Smith files: A Misc/NEWS.d/next/Documentation/2022-08-12-01-12-52.gh-issue-95588.PA0FI7.rst M Doc/library/ast.rst M Lib/ast.py diff --git a/Doc/library/ast.rst b/Doc/library/ast.rst index 65f69df4fcf9..17ab87f842d8 100644 --- a/Doc/library/ast.rst +++ b/Doc/library/ast.rst @@ -1959,20 +1959,28 @@ and classes for traversing abstract syntax trees: .. function:: literal_eval(node_or_string) - Safely evaluate an expression node or a string containing a Python literal or + Evaluate an expression node or a string containing only a Python literal or container display. The string or node provided may only consist of the following Python literal structures: strings, bytes, numbers, tuples, lists, dicts, sets, booleans, ``None`` and ``Ellipsis``. - This can be used for safely evaluating strings containing Python values from - untrusted sources without the need to parse the values oneself. It is not - capable of evaluating arbitrarily complex expressions, for example involving - operators or indexing. + This can be used for evaluating strings containing Python values without the + need to parse the values oneself. It is not capable of evaluating + arbitrarily complex expressions, for example involving operators or + indexing. + + This function had been documented as "safe" in the past without defining + what that meant. That was misleading. This is specifically designed not to + execute Python code, unlike the more general :func:`eval`. There is no + namespace, no name lookups, or ability to call out. But it is not free from + attack: A relatively small input can lead to memory exhaustion or to C stack + exhaustion, crashing the process. There is also the possibility for + excessive CPU consumption denial of service on some inputs. Calling it on + untrusted data is thus not recommended. .. warning:: - It is possible to crash the Python interpreter with a - sufficiently large/complex string due to stack depth limitations - in Python's AST compiler. + It is possible to crash the Python interpreter due to stack depth + limitations in Python's AST compiler. It can raise :exc:`ValueError`, :exc:`TypeError`, :exc:`SyntaxError`, :exc:`MemoryError` and :exc:`RecursionError` depending on the malformed diff --git a/Lib/ast.py b/Lib/ast.py index d63cb2fe80f3..6f235c2f2c67 100644 --- a/Lib/ast.py +++ b/Lib/ast.py @@ -53,10 +53,12 @@ def parse(source, filename='', mode='exec', *, def literal_eval(node_or_string): """ - Safely evaluate an expression node or a string containing a Python + Evaluate an expression node or a string containing only a Python expression. The string or node provided may only consist of the following Python literal structures: strings, bytes, numbers, tuples, lists, dicts, sets, booleans, and None. + + Caution: A complex expression can overflow the C stack and cause a crash. """ if isinstance(node_or_string, str): node_or_string = parse(node_or_string.lstrip(" \t"), mode='eval') diff --git a/Misc/NEWS.d/next/Documentation/2022-08-12-01-12-52.gh-issue-95588.PA0FI7.rst b/Misc/NEWS.d/next/Documentation/2022-08-12-01-12-52.gh-issue-95588.PA0FI7.rst new file mode 100644 index 000000000000..c070bbc19517 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2022-08-12-01-12-52.gh-issue-95588.PA0FI7.rst @@ -0,0 +1,6 @@ +Clarified the conflicting advice given in the :mod:`ast` documentation about +:func:`ast.literal_eval` being "safe" for use on untrusted input while at +the same time warning that it can crash the process. The latter statement is +true and is deemed unfixable without a large amount of work unsuitable for a +bugfix. So we keep the warning and no longer claim that ``literal_eval`` is +safe. From webhook-mailer at python.org Sat Oct 1 23:57:33 2022 From: webhook-mailer at python.org (gvanrossum) Date: Sun, 02 Oct 2022 03:57:33 -0000 Subject: [Python-checkins] gh-97591: In `Exception.__setstate__()` acquire strong references before calling `tp_hash` slot (#97700) Message-ID: https://github.com/python/cpython/commit/d63943860974f232b5f027dc6535d25d1b4d8fc0 commit: d63943860974f232b5f027dc6535d25d1b4d8fc0 branch: main author: Ofey Chan committer: gvanrossum date: 2022-10-01T20:57:17-07:00 summary: gh-97591: In `Exception.__setstate__()` acquire strong references before calling `tp_hash` slot (#97700) files: A Misc/NEWS.d/next/Core and Builtins/2022-10-01-08-55-09.gh-issue-97591.pw6kkH.rst M Lib/test/test_baseexception.py M Objects/exceptions.c diff --git a/Lib/test/test_baseexception.py b/Lib/test/test_baseexception.py index 0061b3fa8e65..4c3cf0b964ae 100644 --- a/Lib/test/test_baseexception.py +++ b/Lib/test/test_baseexception.py @@ -114,6 +114,31 @@ def test_interface_no_arg(self): [repr(exc), exc.__class__.__name__ + '()']) self.interface_test_driver(results) + def test_setstate_refcount_no_crash(self): + # gh-97591: Acquire strong reference before calling tp_hash slot + # in PyObject_SetAttr. + import gc + d = {} + class HashThisKeyWillClearTheDict(str): + def __hash__(self) -> int: + d.clear() + return super().__hash__() + class Value(str): + pass + exc = Exception() + + d[HashThisKeyWillClearTheDict()] = Value() # refcount of Value() is 1 now + + # Exception.__setstate__ should aquire a strong reference of key and + # value in the dict. Otherwise, Value()'s refcount would go below + # zero in the tp_hash call in PyObject_SetAttr(), and it would cause + # crash in GC. + exc.__setstate__(d) # __hash__() is called again here, clearing the dict. + + # This GC would crash if the refcount of Value() goes below zero. + gc.collect() + + class UsageTests(unittest.TestCase): """Test usage of exceptions""" diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-01-08-55-09.gh-issue-97591.pw6kkH.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-01-08-55-09.gh-issue-97591.pw6kkH.rst new file mode 100644 index 000000000000..d3a5867db7fc --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-01-08-55-09.gh-issue-97591.pw6kkH.rst @@ -0,0 +1,2 @@ +Fixed a missing incref/decref pair in `Exception.__setstate__()`. +Patch by Ofey Chan. diff --git a/Objects/exceptions.c b/Objects/exceptions.c index 3703fdcda4db..80e98bb4ffa4 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -167,8 +167,14 @@ BaseException_setstate(PyObject *self, PyObject *state) return NULL; } while (PyDict_Next(state, &i, &d_key, &d_value)) { - if (PyObject_SetAttr(self, d_key, d_value) < 0) + Py_INCREF(d_key); + Py_INCREF(d_value); + int res = PyObject_SetAttr(self, d_key, d_value); + Py_DECREF(d_value); + Py_DECREF(d_key); + if (res < 0) { return NULL; + } } } Py_RETURN_NONE; From webhook-mailer at python.org Sun Oct 2 00:18:43 2022 From: webhook-mailer at python.org (miss-islington) Date: Sun, 02 Oct 2022 04:18:43 -0000 Subject: [Python-checkins] gh-97591: In `Exception.__setstate__()` acquire strong references before calling `tp_hash` slot (GH-97700) Message-ID: https://github.com/python/cpython/commit/c6fcbb4928ced97df81d2cef6c5dcec6bc7dcab7 commit: c6fcbb4928ced97df81d2cef6c5dcec6bc7dcab7 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-01T21:18:38-07:00 summary: gh-97591: In `Exception.__setstate__()` acquire strong references before calling `tp_hash` slot (GH-97700) (cherry picked from commit d63943860974f232b5f027dc6535d25d1b4d8fc0) Co-authored-by: Ofey Chan files: A Misc/NEWS.d/next/Core and Builtins/2022-10-01-08-55-09.gh-issue-97591.pw6kkH.rst M Lib/test/test_baseexception.py M Objects/exceptions.c diff --git a/Lib/test/test_baseexception.py b/Lib/test/test_baseexception.py index 8db497a17285..018626e8db63 100644 --- a/Lib/test/test_baseexception.py +++ b/Lib/test/test_baseexception.py @@ -114,6 +114,31 @@ def test_interface_no_arg(self): [repr(exc), exc.__class__.__name__ + '()']) self.interface_test_driver(results) + def test_setstate_refcount_no_crash(self): + # gh-97591: Acquire strong reference before calling tp_hash slot + # in PyObject_SetAttr. + import gc + d = {} + class HashThisKeyWillClearTheDict(str): + def __hash__(self) -> int: + d.clear() + return super().__hash__() + class Value(str): + pass + exc = Exception() + + d[HashThisKeyWillClearTheDict()] = Value() # refcount of Value() is 1 now + + # Exception.__setstate__ should aquire a strong reference of key and + # value in the dict. Otherwise, Value()'s refcount would go below + # zero in the tp_hash call in PyObject_SetAttr(), and it would cause + # crash in GC. + exc.__setstate__(d) # __hash__() is called again here, clearing the dict. + + # This GC would crash if the refcount of Value() goes below zero. + gc.collect() + + class UsageTests(unittest.TestCase): """Test usage of exceptions""" diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-01-08-55-09.gh-issue-97591.pw6kkH.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-01-08-55-09.gh-issue-97591.pw6kkH.rst new file mode 100644 index 000000000000..d3a5867db7fc --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-01-08-55-09.gh-issue-97591.pw6kkH.rst @@ -0,0 +1,2 @@ +Fixed a missing incref/decref pair in `Exception.__setstate__()`. +Patch by Ofey Chan. diff --git a/Objects/exceptions.c b/Objects/exceptions.c index 9639b4436a07..5dfd1d64d8c1 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -156,8 +156,14 @@ BaseException_setstate(PyObject *self, PyObject *state) return NULL; } while (PyDict_Next(state, &i, &d_key, &d_value)) { - if (PyObject_SetAttr(self, d_key, d_value) < 0) + Py_INCREF(d_key); + Py_INCREF(d_value); + int res = PyObject_SetAttr(self, d_key, d_value); + Py_DECREF(d_value); + Py_DECREF(d_key); + if (res < 0) { return NULL; + } } } Py_RETURN_NONE; From webhook-mailer at python.org Sun Oct 2 00:20:02 2022 From: webhook-mailer at python.org (miss-islington) Date: Sun, 02 Oct 2022 04:20:02 -0000 Subject: [Python-checkins] gh-97591: In `Exception.__setstate__()` acquire strong references before calling `tp_hash` slot (GH-97700) Message-ID: https://github.com/python/cpython/commit/dbde686a49c2d0d7ce476d134f8daffd636382df commit: dbde686a49c2d0d7ce476d134f8daffd636382df branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-01T21:19:57-07:00 summary: gh-97591: In `Exception.__setstate__()` acquire strong references before calling `tp_hash` slot (GH-97700) (cherry picked from commit d63943860974f232b5f027dc6535d25d1b4d8fc0) Co-authored-by: Ofey Chan files: A Misc/NEWS.d/next/Core and Builtins/2022-10-01-08-55-09.gh-issue-97591.pw6kkH.rst M Lib/test/test_baseexception.py M Objects/exceptions.c diff --git a/Lib/test/test_baseexception.py b/Lib/test/test_baseexception.py index 0061b3fa8e65..4c3cf0b964ae 100644 --- a/Lib/test/test_baseexception.py +++ b/Lib/test/test_baseexception.py @@ -114,6 +114,31 @@ def test_interface_no_arg(self): [repr(exc), exc.__class__.__name__ + '()']) self.interface_test_driver(results) + def test_setstate_refcount_no_crash(self): + # gh-97591: Acquire strong reference before calling tp_hash slot + # in PyObject_SetAttr. + import gc + d = {} + class HashThisKeyWillClearTheDict(str): + def __hash__(self) -> int: + d.clear() + return super().__hash__() + class Value(str): + pass + exc = Exception() + + d[HashThisKeyWillClearTheDict()] = Value() # refcount of Value() is 1 now + + # Exception.__setstate__ should aquire a strong reference of key and + # value in the dict. Otherwise, Value()'s refcount would go below + # zero in the tp_hash call in PyObject_SetAttr(), and it would cause + # crash in GC. + exc.__setstate__(d) # __hash__() is called again here, clearing the dict. + + # This GC would crash if the refcount of Value() goes below zero. + gc.collect() + + class UsageTests(unittest.TestCase): """Test usage of exceptions""" diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-01-08-55-09.gh-issue-97591.pw6kkH.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-01-08-55-09.gh-issue-97591.pw6kkH.rst new file mode 100644 index 000000000000..d3a5867db7fc --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-01-08-55-09.gh-issue-97591.pw6kkH.rst @@ -0,0 +1,2 @@ +Fixed a missing incref/decref pair in `Exception.__setstate__()`. +Patch by Ofey Chan. diff --git a/Objects/exceptions.c b/Objects/exceptions.c index 319eb238ecf5..5ab4ac09e66b 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -167,8 +167,14 @@ BaseException_setstate(PyObject *self, PyObject *state) return NULL; } while (PyDict_Next(state, &i, &d_key, &d_value)) { - if (PyObject_SetAttr(self, d_key, d_value) < 0) + Py_INCREF(d_key); + Py_INCREF(d_value); + int res = PyObject_SetAttr(self, d_key, d_value); + Py_DECREF(d_value); + Py_DECREF(d_key); + if (res < 0) { return NULL; + } } } Py_RETURN_NONE; From webhook-mailer at python.org Sun Oct 2 01:13:03 2022 From: webhook-mailer at python.org (ezio-melotti) Date: Sun, 02 Oct 2022 05:13:03 -0000 Subject: [Python-checkins] gh-95975: Move except/*/finally ref labels to more precise locations (#95976) Message-ID: https://github.com/python/cpython/commit/dcc82331c8f05a6a149ac15c519d4fbae72692b2 commit: dcc82331c8f05a6a149ac15c519d4fbae72692b2 branch: main author: C.A.M. Gerlach committer: ezio-melotti date: 2022-10-02T07:12:56+02:00 summary: gh-95975: Move except/*/finally ref labels to more precise locations (#95976) * gh-95975: Move except/*/finally ref labels to more precise locations * Add section headers to fix :keyword: role and aid navigation * Move see also to the introduction rather than a particular subsection * Fix other minor Sphinx syntax issues with except Co-authored-by: Ezio Melotti * Suppress redundant link to same section for except too * Don't link try/except/else/finally keywords if in the same section * Format try/except/finally as keywords in modified sections Co-authored-by: Ezio Melotti files: M Doc/reference/compound_stmts.rst diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index 751c7c2dbcf2..d914686c0a1a 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -199,10 +199,8 @@ returns the list ``[0, 1, 2]``. .. versionchanged:: 3.11 Starred elements are now allowed in the expression list. + .. _try: -.. _except: -.. _except_star: -.. _finally: The :keyword:`!try` statement ============================= @@ -215,7 +213,7 @@ The :keyword:`!try` statement keyword: as single: : (colon); compound statement -The :keyword:`try` statement specifies exception handlers and/or cleanup code +The :keyword:`!try` statement specifies exception handlers and/or cleanup code for a group of statements: .. productionlist:: python-grammar @@ -231,40 +229,56 @@ for a group of statements: try3_stmt: "try" ":" `suite` : "finally" ":" `suite` +Additional information on exceptions can be found in section :ref:`exceptions`, +and information on using the :keyword:`raise` statement to generate exceptions +may be found in section :ref:`raise`. -The :keyword:`except` clause(s) specify one or more exception handlers. When no + +.. _except: + +:keyword:`!except` clause +------------------------- + +The :keyword:`!except` clause(s) specify one or more exception handlers. When no exception occurs in the :keyword:`try` clause, no exception handler is executed. When an exception occurs in the :keyword:`!try` suite, a search for an exception -handler is started. This search inspects the except clauses in turn until one -is found that matches the exception. An expression-less except clause, if -present, must be last; it matches any exception. For an except clause with an -expression, that expression is evaluated, and the clause matches the exception +handler is started. This search inspects the :keyword:`!except` clauses in turn +until one is found that matches the exception. +An expression-less :keyword:`!except` clause, if present, must be last; +it matches any exception. +For an :keyword:`!except` clause with an expression, +that expression is evaluated, and the clause matches the exception if the resulting object is "compatible" with the exception. An object is compatible with an exception if the object is the class or a :term:`non-virtual base class ` of the exception object, or a tuple containing an item that is the class or a non-virtual base class of the exception object. -If no except clause matches the exception, the search for an exception handler +If no :keyword:`!except` clause matches the exception, +the search for an exception handler continues in the surrounding code and on the invocation stack. [#]_ -If the evaluation of an expression in the header of an except clause raises an -exception, the original search for a handler is canceled and a search starts for +If the evaluation of an expression +in the header of an :keyword:`!except` clause raises an exception, +the original search for a handler is canceled and a search starts for the new exception in the surrounding code and on the call stack (it is treated as if the entire :keyword:`try` statement raised the exception). .. index:: single: as; except clause -When a matching except clause is found, the exception is assigned to the target -specified after the :keyword:`!as` keyword in that except clause, if present, and -the except clause's suite is executed. All except clauses must have an -executable block. When the end of this block is reached, execution continues -normally after the entire try statement. (This means that if two nested -handlers exist for the same exception, and the exception occurs in the try -clause of the inner handler, the outer handler will not handle the exception.) +When a matching :keyword:`!except` clause is found, +the exception is assigned to the target +specified after the :keyword:`!as` keyword in that :keyword:`!except` clause, +if present, and the :keyword:`!except` clause's suite is executed. +All :keyword:`!except` clauses must have an executable block. +When the end of this block is reached, execution continues +normally after the entire :keyword:`try` statement. +(This means that if two nested handlers exist for the same exception, +and the exception occurs in the :keyword:`!try` clause of the inner handler, +the outer handler will not handle the exception.) When an exception has been assigned using ``as target``, it is cleared at the -end of the except clause. This is as if :: +end of the :keyword:`!except` clause. This is as if :: except E as N: foo @@ -278,7 +292,8 @@ was translated to :: del N This means the exception must be assigned to a different name to be able to -refer to it after the except clause. Exceptions are cleared because with the +refer to it after the :keyword:`!except` clause. +Exceptions are cleared because with the traceback attached to them, they form a reference cycle with the stack frame, keeping all locals in that frame alive until the next garbage collection occurs. @@ -286,7 +301,8 @@ keeping all locals in that frame alive until the next garbage collection occurs. module: sys object: traceback -Before an except clause's suite is executed, details about the exception are +Before an :keyword:`!except` clause's suite is executed, +details about the exception are stored in the :mod:`sys` module and can be accessed via :func:`sys.exc_info`. :func:`sys.exc_info` returns a 3-tuple consisting of the exception class, the exception instance and a traceback object (see section :ref:`types`) identifying @@ -312,17 +328,24 @@ when leaving an exception handler:: >>> print(sys.exc_info()) (None, None, None) + .. index:: keyword: except_star -The :keyword:`except*` clause(s) are used for handling -:exc:`ExceptionGroup`\ s. The exception type for matching is interpreted as in +.. _except_star: + +:keyword:`!except*` clause +-------------------------- + +The :keyword:`!except*` clause(s) are used for handling +:exc:`ExceptionGroup`\s. The exception type for matching is interpreted as in the case of :keyword:`except`, but in the case of exception groups we can have partial matches when the type matches some of the exceptions in the group. -This means that multiple except* clauses can execute, each handling part of -the exception group. Each clause executes once and handles an exception group +This means that multiple :keyword:`!except*` clauses can execute, +each handling part of the exception group. +Each clause executes once and handles an exception group of all matching exceptions. Each exception in the group is handled by at most -one except* clause, the first that matches it. :: +one :keyword:`!except*` clause, the first that matches it. :: >>> try: ... raise ExceptionGroup("eg", @@ -342,15 +365,16 @@ one except* clause, the first that matches it. :: +------------------------------------ >>> - Any remaining exceptions that were not handled by any except* clause - are re-raised at the end, combined into an exception group along with - all exceptions that were raised from within except* clauses. + Any remaining exceptions that were not handled by any :keyword:`!except*` + clause are re-raised at the end, combined into an exception group along with + all exceptions that were raised from within :keyword:`!except*` clauses. - An except* clause must have a matching type, and this type cannot be a - subclass of :exc:`BaseExceptionGroup`. It is not possible to mix except - and except* in the same :keyword:`try`. :keyword:`break`, - :keyword:`continue` and :keyword:`return` cannot appear in an except* - clause. + An :keyword:`!except*` clause must have a matching type, + and this type cannot be a subclass of :exc:`BaseExceptionGroup`. + It is not possible to mix :keyword:`except` and :keyword:`!except*` + in the same :keyword:`try`. + :keyword:`break`, :keyword:`continue` and :keyword:`return` + cannot appear in an :keyword:`!except*` clause. .. index:: @@ -359,17 +383,28 @@ one except* clause, the first that matches it. :: statement: break statement: continue +.. _except_else: + +:keyword:`!else` clause +----------------------- + The optional :keyword:`!else` clause is executed if the control flow leaves the :keyword:`try` suite, no exception was raised, and no :keyword:`return`, :keyword:`continue`, or :keyword:`break` statement was executed. Exceptions in the :keyword:`!else` clause are not handled by the preceding :keyword:`except` clauses. + .. index:: keyword: finally -If :keyword:`finally` is present, it specifies a 'cleanup' handler. The +.. _finally: + +:keyword:`!finally` clause +-------------------------- + +If :keyword:`!finally` is present, it specifies a 'cleanup' handler. The :keyword:`try` clause is executed, including any :keyword:`except` and -:keyword:`!else` clauses. If an exception occurs in any of the clauses and is +:keyword:`else` clauses. If an exception occurs in any of the clauses and is not handled, the exception is temporarily saved. The :keyword:`!finally` clause is executed. If there is a saved exception it is re-raised at the end of the :keyword:`!finally` clause. If the :keyword:`!finally` clause raises another @@ -387,7 +422,7 @@ or :keyword:`continue` statement, the saved exception is discarded:: 42 The exception information is not available to the program during execution of -the :keyword:`finally` clause. +the :keyword:`!finally` clause. .. index:: statement: return @@ -396,10 +431,10 @@ the :keyword:`finally` clause. When a :keyword:`return`, :keyword:`break` or :keyword:`continue` statement is executed in the :keyword:`try` suite of a :keyword:`!try`...\ :keyword:`!finally` -statement, the :keyword:`finally` clause is also executed 'on the way out.' +statement, the :keyword:`!finally` clause is also executed 'on the way out.' The return value of a function is determined by the last :keyword:`return` -statement executed. Since the :keyword:`finally` clause always executes, a +statement executed. Since the :keyword:`!finally` clause always executes, a :keyword:`!return` statement executed in the :keyword:`!finally` clause will always be the last one executed:: @@ -412,13 +447,9 @@ always be the last one executed:: >>> foo() 'finally' -Additional information on exceptions can be found in section :ref:`exceptions`, -and information on using the :keyword:`raise` statement to generate exceptions -may be found in section :ref:`raise`. - .. versionchanged:: 3.8 Prior to Python 3.8, a :keyword:`continue` statement was illegal in the - :keyword:`finally` clause due to a problem with the implementation. + :keyword:`!finally` clause due to a problem with the implementation. .. _with: From webhook-mailer at python.org Sun Oct 2 01:20:31 2022 From: webhook-mailer at python.org (ezio-melotti) Date: Sun, 02 Oct 2022 05:20:31 -0000 Subject: [Python-checkins] gh-97607: Fix content parsing in the impl-detail reST directive (#97652) Message-ID: https://github.com/python/cpython/commit/e8165d47b852e933c176209ddc0b5836a9b0d5f4 commit: e8165d47b852e933c176209ddc0b5836a9b0d5f4 branch: main author: C.A.M. Gerlach committer: ezio-melotti date: 2022-10-02T07:20:17+02:00 summary: gh-97607: Fix content parsing in the impl-detail reST directive (#97652) * Don't parse content as arg in the impl-detail directive This does not change the (untranslated) output, but ensures that the doctree node metadata is correct. which fixes gh-97607 with the text not being translated. It also simplifies the code and logic and makes it consistant with the docutils built-in directives. * Remove unused branch from impl-detail directive handling no-content case This is not used anywhere in the docs and lacks a clear use case, and is more likely a mistake which is now flagged at build time. This simplifies the logic from two code paths to one, and makes the behavior consistant with similar built-in directives (e.g. the various admonition types). * Further simplify impl-detail reST directive code files: M Doc/tools/extensions/pyspecific.py diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py index da15abdf6372..8c3aa47ad1c7 100644 --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -100,33 +100,24 @@ def source_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): class ImplementationDetail(Directive): has_content = True - required_arguments = 0 - optional_arguments = 1 final_argument_whitespace = True # This text is copied to templates/dummy.html label_text = 'CPython implementation detail:' def run(self): + self.assert_has_content() pnode = nodes.compound(classes=['impl-detail']) label = translators['sphinx'].gettext(self.label_text) content = self.content add_text = nodes.strong(label, label) - if self.arguments: - n, m = self.state.inline_text(self.arguments[0], self.lineno) - pnode.append(nodes.paragraph('', '', *(n + m))) self.state.nested_parse(content, self.content_offset, pnode) - if pnode.children and isinstance(pnode[0], nodes.paragraph): - content = nodes.inline(pnode[0].rawsource, translatable=True) - content.source = pnode[0].source - content.line = pnode[0].line - content += pnode[0].children - pnode[0].replace_self(nodes.paragraph('', '', content, - translatable=False)) - pnode[0].insert(0, add_text) - pnode[0].insert(1, nodes.Text(' ')) - else: - pnode.insert(0, nodes.paragraph('', '', add_text)) + content = nodes.inline(pnode[0].rawsource, translatable=True) + content.source = pnode[0].source + content.line = pnode[0].line + content += pnode[0].children + pnode[0].replace_self(nodes.paragraph( + '', '', add_text, nodes.Text(' '), content, translatable=False)) return [pnode] From webhook-mailer at python.org Sun Oct 2 01:20:48 2022 From: webhook-mailer at python.org (miss-islington) Date: Sun, 02 Oct 2022 05:20:48 -0000 Subject: [Python-checkins] gh-95975: Move except/*/finally ref labels to more precise locations (GH-95976) Message-ID: https://github.com/python/cpython/commit/1fa848ac396d8eef807589bfbd5782dcb97acce9 commit: 1fa848ac396d8eef807589bfbd5782dcb97acce9 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-01T22:20:43-07:00 summary: gh-95975: Move except/*/finally ref labels to more precise locations (GH-95976) * gh-95975: Move except/*/finally ref labels to more precise locations * Add section headers to fix :keyword: role and aid navigation * Move see also to the introduction rather than a particular subsection * Fix other minor Sphinx syntax issues with except Co-authored-by: Ezio Melotti * Suppress redundant link to same section for except too * Don't link try/except/else/finally keywords if in the same section * Format try/except/finally as keywords in modified sections Co-authored-by: Ezio Melotti (cherry picked from commit dcc82331c8f05a6a149ac15c519d4fbae72692b2) Co-authored-by: C.A.M. Gerlach files: M Doc/reference/compound_stmts.rst diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index 751c7c2dbcf2..d914686c0a1a 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -199,10 +199,8 @@ returns the list ``[0, 1, 2]``. .. versionchanged:: 3.11 Starred elements are now allowed in the expression list. + .. _try: -.. _except: -.. _except_star: -.. _finally: The :keyword:`!try` statement ============================= @@ -215,7 +213,7 @@ The :keyword:`!try` statement keyword: as single: : (colon); compound statement -The :keyword:`try` statement specifies exception handlers and/or cleanup code +The :keyword:`!try` statement specifies exception handlers and/or cleanup code for a group of statements: .. productionlist:: python-grammar @@ -231,40 +229,56 @@ for a group of statements: try3_stmt: "try" ":" `suite` : "finally" ":" `suite` +Additional information on exceptions can be found in section :ref:`exceptions`, +and information on using the :keyword:`raise` statement to generate exceptions +may be found in section :ref:`raise`. -The :keyword:`except` clause(s) specify one or more exception handlers. When no + +.. _except: + +:keyword:`!except` clause +------------------------- + +The :keyword:`!except` clause(s) specify one or more exception handlers. When no exception occurs in the :keyword:`try` clause, no exception handler is executed. When an exception occurs in the :keyword:`!try` suite, a search for an exception -handler is started. This search inspects the except clauses in turn until one -is found that matches the exception. An expression-less except clause, if -present, must be last; it matches any exception. For an except clause with an -expression, that expression is evaluated, and the clause matches the exception +handler is started. This search inspects the :keyword:`!except` clauses in turn +until one is found that matches the exception. +An expression-less :keyword:`!except` clause, if present, must be last; +it matches any exception. +For an :keyword:`!except` clause with an expression, +that expression is evaluated, and the clause matches the exception if the resulting object is "compatible" with the exception. An object is compatible with an exception if the object is the class or a :term:`non-virtual base class ` of the exception object, or a tuple containing an item that is the class or a non-virtual base class of the exception object. -If no except clause matches the exception, the search for an exception handler +If no :keyword:`!except` clause matches the exception, +the search for an exception handler continues in the surrounding code and on the invocation stack. [#]_ -If the evaluation of an expression in the header of an except clause raises an -exception, the original search for a handler is canceled and a search starts for +If the evaluation of an expression +in the header of an :keyword:`!except` clause raises an exception, +the original search for a handler is canceled and a search starts for the new exception in the surrounding code and on the call stack (it is treated as if the entire :keyword:`try` statement raised the exception). .. index:: single: as; except clause -When a matching except clause is found, the exception is assigned to the target -specified after the :keyword:`!as` keyword in that except clause, if present, and -the except clause's suite is executed. All except clauses must have an -executable block. When the end of this block is reached, execution continues -normally after the entire try statement. (This means that if two nested -handlers exist for the same exception, and the exception occurs in the try -clause of the inner handler, the outer handler will not handle the exception.) +When a matching :keyword:`!except` clause is found, +the exception is assigned to the target +specified after the :keyword:`!as` keyword in that :keyword:`!except` clause, +if present, and the :keyword:`!except` clause's suite is executed. +All :keyword:`!except` clauses must have an executable block. +When the end of this block is reached, execution continues +normally after the entire :keyword:`try` statement. +(This means that if two nested handlers exist for the same exception, +and the exception occurs in the :keyword:`!try` clause of the inner handler, +the outer handler will not handle the exception.) When an exception has been assigned using ``as target``, it is cleared at the -end of the except clause. This is as if :: +end of the :keyword:`!except` clause. This is as if :: except E as N: foo @@ -278,7 +292,8 @@ was translated to :: del N This means the exception must be assigned to a different name to be able to -refer to it after the except clause. Exceptions are cleared because with the +refer to it after the :keyword:`!except` clause. +Exceptions are cleared because with the traceback attached to them, they form a reference cycle with the stack frame, keeping all locals in that frame alive until the next garbage collection occurs. @@ -286,7 +301,8 @@ keeping all locals in that frame alive until the next garbage collection occurs. module: sys object: traceback -Before an except clause's suite is executed, details about the exception are +Before an :keyword:`!except` clause's suite is executed, +details about the exception are stored in the :mod:`sys` module and can be accessed via :func:`sys.exc_info`. :func:`sys.exc_info` returns a 3-tuple consisting of the exception class, the exception instance and a traceback object (see section :ref:`types`) identifying @@ -312,17 +328,24 @@ when leaving an exception handler:: >>> print(sys.exc_info()) (None, None, None) + .. index:: keyword: except_star -The :keyword:`except*` clause(s) are used for handling -:exc:`ExceptionGroup`\ s. The exception type for matching is interpreted as in +.. _except_star: + +:keyword:`!except*` clause +-------------------------- + +The :keyword:`!except*` clause(s) are used for handling +:exc:`ExceptionGroup`\s. The exception type for matching is interpreted as in the case of :keyword:`except`, but in the case of exception groups we can have partial matches when the type matches some of the exceptions in the group. -This means that multiple except* clauses can execute, each handling part of -the exception group. Each clause executes once and handles an exception group +This means that multiple :keyword:`!except*` clauses can execute, +each handling part of the exception group. +Each clause executes once and handles an exception group of all matching exceptions. Each exception in the group is handled by at most -one except* clause, the first that matches it. :: +one :keyword:`!except*` clause, the first that matches it. :: >>> try: ... raise ExceptionGroup("eg", @@ -342,15 +365,16 @@ one except* clause, the first that matches it. :: +------------------------------------ >>> - Any remaining exceptions that were not handled by any except* clause - are re-raised at the end, combined into an exception group along with - all exceptions that were raised from within except* clauses. + Any remaining exceptions that were not handled by any :keyword:`!except*` + clause are re-raised at the end, combined into an exception group along with + all exceptions that were raised from within :keyword:`!except*` clauses. - An except* clause must have a matching type, and this type cannot be a - subclass of :exc:`BaseExceptionGroup`. It is not possible to mix except - and except* in the same :keyword:`try`. :keyword:`break`, - :keyword:`continue` and :keyword:`return` cannot appear in an except* - clause. + An :keyword:`!except*` clause must have a matching type, + and this type cannot be a subclass of :exc:`BaseExceptionGroup`. + It is not possible to mix :keyword:`except` and :keyword:`!except*` + in the same :keyword:`try`. + :keyword:`break`, :keyword:`continue` and :keyword:`return` + cannot appear in an :keyword:`!except*` clause. .. index:: @@ -359,17 +383,28 @@ one except* clause, the first that matches it. :: statement: break statement: continue +.. _except_else: + +:keyword:`!else` clause +----------------------- + The optional :keyword:`!else` clause is executed if the control flow leaves the :keyword:`try` suite, no exception was raised, and no :keyword:`return`, :keyword:`continue`, or :keyword:`break` statement was executed. Exceptions in the :keyword:`!else` clause are not handled by the preceding :keyword:`except` clauses. + .. index:: keyword: finally -If :keyword:`finally` is present, it specifies a 'cleanup' handler. The +.. _finally: + +:keyword:`!finally` clause +-------------------------- + +If :keyword:`!finally` is present, it specifies a 'cleanup' handler. The :keyword:`try` clause is executed, including any :keyword:`except` and -:keyword:`!else` clauses. If an exception occurs in any of the clauses and is +:keyword:`else` clauses. If an exception occurs in any of the clauses and is not handled, the exception is temporarily saved. The :keyword:`!finally` clause is executed. If there is a saved exception it is re-raised at the end of the :keyword:`!finally` clause. If the :keyword:`!finally` clause raises another @@ -387,7 +422,7 @@ or :keyword:`continue` statement, the saved exception is discarded:: 42 The exception information is not available to the program during execution of -the :keyword:`finally` clause. +the :keyword:`!finally` clause. .. index:: statement: return @@ -396,10 +431,10 @@ the :keyword:`finally` clause. When a :keyword:`return`, :keyword:`break` or :keyword:`continue` statement is executed in the :keyword:`try` suite of a :keyword:`!try`...\ :keyword:`!finally` -statement, the :keyword:`finally` clause is also executed 'on the way out.' +statement, the :keyword:`!finally` clause is also executed 'on the way out.' The return value of a function is determined by the last :keyword:`return` -statement executed. Since the :keyword:`finally` clause always executes, a +statement executed. Since the :keyword:`!finally` clause always executes, a :keyword:`!return` statement executed in the :keyword:`!finally` clause will always be the last one executed:: @@ -412,13 +447,9 @@ always be the last one executed:: >>> foo() 'finally' -Additional information on exceptions can be found in section :ref:`exceptions`, -and information on using the :keyword:`raise` statement to generate exceptions -may be found in section :ref:`raise`. - .. versionchanged:: 3.8 Prior to Python 3.8, a :keyword:`continue` statement was illegal in the - :keyword:`finally` clause due to a problem with the implementation. + :keyword:`!finally` clause due to a problem with the implementation. .. _with: From webhook-mailer at python.org Sun Oct 2 01:28:01 2022 From: webhook-mailer at python.org (miss-islington) Date: Sun, 02 Oct 2022 05:28:01 -0000 Subject: [Python-checkins] gh-97607: Fix content parsing in the impl-detail reST directive (GH-97652) Message-ID: https://github.com/python/cpython/commit/5ee8344aa29d3ecbebcdb1fe32ac6bb5f5e2dda3 commit: 5ee8344aa29d3ecbebcdb1fe32ac6bb5f5e2dda3 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-01T22:27:56-07:00 summary: gh-97607: Fix content parsing in the impl-detail reST directive (GH-97652) * Don't parse content as arg in the impl-detail directive This does not change the (untranslated) output, but ensures that the doctree node metadata is correct. which fixes gh-97607 with the text not being translated. It also simplifies the code and logic and makes it consistant with the docutils built-in directives. * Remove unused branch from impl-detail directive handling no-content case This is not used anywhere in the docs and lacks a clear use case, and is more likely a mistake which is now flagged at build time. This simplifies the logic from two code paths to one, and makes the behavior consistant with similar built-in directives (e.g. the various admonition types). * Further simplify impl-detail reST directive code (cherry picked from commit e8165d47b852e933c176209ddc0b5836a9b0d5f4) Co-authored-by: C.A.M. Gerlach files: M Doc/tools/extensions/pyspecific.py diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py index 915b28a561a7..9abdde0dc3b1 100644 --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -101,33 +101,24 @@ def source_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): class ImplementationDetail(Directive): has_content = True - required_arguments = 0 - optional_arguments = 1 final_argument_whitespace = True # This text is copied to templates/dummy.html label_text = 'CPython implementation detail:' def run(self): + self.assert_has_content() pnode = nodes.compound(classes=['impl-detail']) label = translators['sphinx'].gettext(self.label_text) content = self.content add_text = nodes.strong(label, label) - if self.arguments: - n, m = self.state.inline_text(self.arguments[0], self.lineno) - pnode.append(nodes.paragraph('', '', *(n + m))) self.state.nested_parse(content, self.content_offset, pnode) - if pnode.children and isinstance(pnode[0], nodes.paragraph): - content = nodes.inline(pnode[0].rawsource, translatable=True) - content.source = pnode[0].source - content.line = pnode[0].line - content += pnode[0].children - pnode[0].replace_self(nodes.paragraph('', '', content, - translatable=False)) - pnode[0].insert(0, add_text) - pnode[0].insert(1, nodes.Text(' ')) - else: - pnode.insert(0, nodes.paragraph('', '', add_text)) + content = nodes.inline(pnode[0].rawsource, translatable=True) + content.source = pnode[0].source + content.line = pnode[0].line + content += pnode[0].children + pnode[0].replace_self(nodes.paragraph( + '', '', add_text, nodes.Text(' '), content, translatable=False)) return [pnode] From webhook-mailer at python.org Sun Oct 2 01:28:59 2022 From: webhook-mailer at python.org (miss-islington) Date: Sun, 02 Oct 2022 05:28:59 -0000 Subject: [Python-checkins] gh-97607: Fix content parsing in the impl-detail reST directive (GH-97652) Message-ID: https://github.com/python/cpython/commit/8c528ef4a1804975cd7dc53db1c229bce8e6b875 commit: 8c528ef4a1804975cd7dc53db1c229bce8e6b875 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-01T22:28:54-07:00 summary: gh-97607: Fix content parsing in the impl-detail reST directive (GH-97652) * Don't parse content as arg in the impl-detail directive This does not change the (untranslated) output, but ensures that the doctree node metadata is correct. which fixes gh-97607 with the text not being translated. It also simplifies the code and logic and makes it consistant with the docutils built-in directives. * Remove unused branch from impl-detail directive handling no-content case This is not used anywhere in the docs and lacks a clear use case, and is more likely a mistake which is now flagged at build time. This simplifies the logic from two code paths to one, and makes the behavior consistant with similar built-in directives (e.g. the various admonition types). * Further simplify impl-detail reST directive code (cherry picked from commit e8165d47b852e933c176209ddc0b5836a9b0d5f4) Co-authored-by: C.A.M. Gerlach files: M Doc/tools/extensions/pyspecific.py diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py index f326e77b2632..647554d057d9 100644 --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -101,33 +101,24 @@ def source_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): class ImplementationDetail(Directive): has_content = True - required_arguments = 0 - optional_arguments = 1 final_argument_whitespace = True # This text is copied to templates/dummy.html label_text = 'CPython implementation detail:' def run(self): + self.assert_has_content() pnode = nodes.compound(classes=['impl-detail']) label = translators['sphinx'].gettext(self.label_text) content = self.content add_text = nodes.strong(label, label) - if self.arguments: - n, m = self.state.inline_text(self.arguments[0], self.lineno) - pnode.append(nodes.paragraph('', '', *(n + m))) self.state.nested_parse(content, self.content_offset, pnode) - if pnode.children and isinstance(pnode[0], nodes.paragraph): - content = nodes.inline(pnode[0].rawsource, translatable=True) - content.source = pnode[0].source - content.line = pnode[0].line - content += pnode[0].children - pnode[0].replace_self(nodes.paragraph('', '', content, - translatable=False)) - pnode[0].insert(0, add_text) - pnode[0].insert(1, nodes.Text(' ')) - else: - pnode.insert(0, nodes.paragraph('', '', add_text)) + content = nodes.inline(pnode[0].rawsource, translatable=True) + content.source = pnode[0].source + content.line = pnode[0].line + content += pnode[0].children + pnode[0].replace_self(nodes.paragraph( + '', '', add_text, nodes.Text(' '), content, translatable=False)) return [pnode] From webhook-mailer at python.org Sun Oct 2 09:26:44 2022 From: webhook-mailer at python.org (vsajip) Date: Sun, 02 Oct 2022 13:26:44 -0000 Subject: [Python-checkins] =?utf-8?q?=5Bdocs=5D_Update_logging_cookbook_w?= =?utf-8?q?ith_recipe_for_using_a_logger_like_an_output=E2=80=A6_=28GH-977?= =?utf-8?b?MzAp?= Message-ID: https://github.com/python/cpython/commit/cac2e8a51fe6412b7bc864274a60927ececfd833 commit: cac2e8a51fe6412b7bc864274a60927ececfd833 branch: main author: Vinay Sajip committer: vsajip date: 2022-10-02T14:26:14+01:00 summary: [docs] Update logging cookbook with recipe for using a logger like an output? (GH-97730) files: M Doc/howto/logging-cookbook.rst diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst index 5b079744df12..ff7ba0789608 100644 --- a/Doc/howto/logging-cookbook.rst +++ b/Doc/howto/logging-cookbook.rst @@ -3428,6 +3428,82 @@ the above handler, you'd pass structured data using something like this:: i = 1 logger.debug('Message %d', i, extra=extra) +How to treat a logger like an output stream +------------------------------------------- + +Sometimes, you need to interface to a third-party API which expects a file-like +object to write to, but you want to direct the API's output to a logger. You +can do this using a class which wraps a logger with a file-like API. +Here's a short script illustrating such a class: + +.. code-block:: python + + import logging + + class LoggerWriter: + def __init__(self, logger, level): + self.logger = logger + self.level = level + + def write(self, message): + if message != '\n': # avoid printing bare newlines, if you like + self.logger.log(self.level, message) + + def flush(self): + # doesn't actually do anything, but might be expected of a file-like + # object - so optional depending on your situation + pass + + def close(self): + # doesn't actually do anything, but might be expected of a file-like + # object - so optional depending on your situation. You might want + # to set a flag so that later calls to write raise an exception + pass + + def main(): + logging.basicConfig(level=logging.DEBUG) + logger = logging.getLogger('demo') + info_fp = LoggerWriter(logger, logging.INFO) + debug_fp = LoggerWriter(logger, logging.DEBUG) + print('An INFO message', file=info_fp) + print('A DEBUG message', file=debug_fp) + + if __name__ == "__main__": + main() + +When this script is run, it prints + +.. code-block:: text + + INFO:demo:An INFO message + DEBUG:demo:A DEBUG message + +You could also use ``LoggerWriter`` to redirect ``sys.stdout`` and +``sys.stderr`` by doing something like this: + +.. code-block:: python + + import sys + + sys.stdout = LoggerWriter(logger, logging.INFO) + sys.stderr = LoggerWriter(logger, logging.WARNING) + +You should do this *after* configuring logging for your needs. In the above +example, the :func:`~logging.basicConfig` call does this (using the +``sys.stderr`` value *before* it is overwritten by a ``LoggerWriter`` +instance). Then, you'd get this kind of result: + +.. code-block:: pycon + + >>> print('Foo') + INFO:demo:Foo + >>> print('Bar', file=sys.stderr) + WARNING:demo:Bar + >>> + +Of course, these above examples show output according to the format used by +:func:`~logging.basicConfig`, but you can use a different formatter when you +configure logging. .. patterns-to-avoid: From webhook-mailer at python.org Sun Oct 2 12:44:47 2022 From: webhook-mailer at python.org (vsajip) Date: Sun, 02 Oct 2022 16:44:47 -0000 Subject: [Python-checkins] =?utf-8?b?WzMuMTFdIFtkb2NzXSBVcGRhdGUgbG9nZ2lu?= =?utf-8?q?g_cookbook_with_recipe_for_using_a_logger_like_an_output?= =?utf-8?b?4oCmIChHSC05NzczMCkgKEdILTk3NzM1KQ==?= Message-ID: https://github.com/python/cpython/commit/011260bca044f0186c230e7a341577c2e6708001 commit: 011260bca044f0186c230e7a341577c2e6708001 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: vsajip date: 2022-10-02T17:44:42+01:00 summary: [3.11] [docs] Update logging cookbook with recipe for using a logger like an output? (GH-97730) (GH-97735) files: M Doc/howto/logging-cookbook.rst diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst index 5b079744df12..ff7ba0789608 100644 --- a/Doc/howto/logging-cookbook.rst +++ b/Doc/howto/logging-cookbook.rst @@ -3428,6 +3428,82 @@ the above handler, you'd pass structured data using something like this:: i = 1 logger.debug('Message %d', i, extra=extra) +How to treat a logger like an output stream +------------------------------------------- + +Sometimes, you need to interface to a third-party API which expects a file-like +object to write to, but you want to direct the API's output to a logger. You +can do this using a class which wraps a logger with a file-like API. +Here's a short script illustrating such a class: + +.. code-block:: python + + import logging + + class LoggerWriter: + def __init__(self, logger, level): + self.logger = logger + self.level = level + + def write(self, message): + if message != '\n': # avoid printing bare newlines, if you like + self.logger.log(self.level, message) + + def flush(self): + # doesn't actually do anything, but might be expected of a file-like + # object - so optional depending on your situation + pass + + def close(self): + # doesn't actually do anything, but might be expected of a file-like + # object - so optional depending on your situation. You might want + # to set a flag so that later calls to write raise an exception + pass + + def main(): + logging.basicConfig(level=logging.DEBUG) + logger = logging.getLogger('demo') + info_fp = LoggerWriter(logger, logging.INFO) + debug_fp = LoggerWriter(logger, logging.DEBUG) + print('An INFO message', file=info_fp) + print('A DEBUG message', file=debug_fp) + + if __name__ == "__main__": + main() + +When this script is run, it prints + +.. code-block:: text + + INFO:demo:An INFO message + DEBUG:demo:A DEBUG message + +You could also use ``LoggerWriter`` to redirect ``sys.stdout`` and +``sys.stderr`` by doing something like this: + +.. code-block:: python + + import sys + + sys.stdout = LoggerWriter(logger, logging.INFO) + sys.stderr = LoggerWriter(logger, logging.WARNING) + +You should do this *after* configuring logging for your needs. In the above +example, the :func:`~logging.basicConfig` call does this (using the +``sys.stderr`` value *before* it is overwritten by a ``LoggerWriter`` +instance). Then, you'd get this kind of result: + +.. code-block:: pycon + + >>> print('Foo') + INFO:demo:Foo + >>> print('Bar', file=sys.stderr) + WARNING:demo:Bar + >>> + +Of course, these above examples show output according to the format used by +:func:`~logging.basicConfig`, but you can use a different formatter when you +configure logging. .. patterns-to-avoid: From webhook-mailer at python.org Sun Oct 2 18:17:24 2022 From: webhook-mailer at python.org (gvanrossum) Date: Sun, 02 Oct 2022 22:17:24 -0000 Subject: [Python-checkins] GH-85447: Clarify docs about awaiting future multiple times (#97738) Message-ID: https://github.com/python/cpython/commit/9151bbefea3fb932eb6aa6ddb22d64b83f8149c7 commit: 9151bbefea3fb932eb6aa6ddb22d64b83f8149c7 branch: main author: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> committer: gvanrossum date: 2022-10-02T15:16:51-07:00 summary: GH-85447: Clarify docs about awaiting future multiple times (#97738) files: M Doc/library/asyncio-future.rst diff --git a/Doc/library/asyncio-future.rst b/Doc/library/asyncio-future.rst index 99a5d3a8287b..8e60877f0e4c 100644 --- a/Doc/library/asyncio-future.rst +++ b/Doc/library/asyncio-future.rst @@ -85,7 +85,8 @@ Future Object Future is an :term:`awaitable` object. Coroutines can await on Future objects until they either have a result or an exception - set, or until they are cancelled. + set, or until they are cancelled. A Future can be awaited multiple + times and the result is same. Typically Futures are used to enable low-level callback-based code (e.g. in protocols implemented using asyncio From webhook-mailer at python.org Sun Oct 2 18:24:35 2022 From: webhook-mailer at python.org (miss-islington) Date: Sun, 02 Oct 2022 22:24:35 -0000 Subject: [Python-checkins] GH-85447: Clarify docs about awaiting future multiple times (GH-97738) Message-ID: https://github.com/python/cpython/commit/72d445a22e4fe59f11f090762f2517a60e164f40 commit: 72d445a22e4fe59f11f090762f2517a60e164f40 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-02T15:24:29-07:00 summary: GH-85447: Clarify docs about awaiting future multiple times (GH-97738) (cherry picked from commit 9151bbefea3fb932eb6aa6ddb22d64b83f8149c7) Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> files: M Doc/library/asyncio-future.rst diff --git a/Doc/library/asyncio-future.rst b/Doc/library/asyncio-future.rst index 412304ab6148..70cec9b2f902 100644 --- a/Doc/library/asyncio-future.rst +++ b/Doc/library/asyncio-future.rst @@ -85,7 +85,8 @@ Future Object Future is an :term:`awaitable` object. Coroutines can await on Future objects until they either have a result or an exception - set, or until they are cancelled. + set, or until they are cancelled. A Future can be awaited multiple + times and the result is same. Typically Futures are used to enable low-level callback-based code (e.g. in protocols implemented using asyncio From webhook-mailer at python.org Sun Oct 2 18:27:22 2022 From: webhook-mailer at python.org (miss-islington) Date: Sun, 02 Oct 2022 22:27:22 -0000 Subject: [Python-checkins] GH-85447: Clarify docs about awaiting future multiple times (GH-97738) Message-ID: https://github.com/python/cpython/commit/b26fb3cdc6e9d2c436f28af3c9c290c4dcac23e8 commit: b26fb3cdc6e9d2c436f28af3c9c290c4dcac23e8 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-02T15:27:17-07:00 summary: GH-85447: Clarify docs about awaiting future multiple times (GH-97738) (cherry picked from commit 9151bbefea3fb932eb6aa6ddb22d64b83f8149c7) Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> files: M Doc/library/asyncio-future.rst diff --git a/Doc/library/asyncio-future.rst b/Doc/library/asyncio-future.rst index 99a5d3a8287b..8e60877f0e4c 100644 --- a/Doc/library/asyncio-future.rst +++ b/Doc/library/asyncio-future.rst @@ -85,7 +85,8 @@ Future Object Future is an :term:`awaitable` object. Coroutines can await on Future objects until they either have a result or an exception - set, or until they are cancelled. + set, or until they are cancelled. A Future can be awaited multiple + times and the result is same. Typically Futures are used to enable low-level callback-based code (e.g. in protocols implemented using asyncio From webhook-mailer at python.org Sun Oct 2 20:38:01 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Mon, 03 Oct 2022 00:38:01 -0000 Subject: [Python-checkins] gh-97706: multiprocessing tests: Delete unused variable `rand` (#97707) Message-ID: https://github.com/python/cpython/commit/14d4f68ebb495fe7ccbaf283386d861a054d8288 commit: 14d4f68ebb495fe7ccbaf283386d861a054d8288 branch: main author: Koki Saito <49419225+saito828koki at users.noreply.github.com> committer: JelleZijlstra date: 2022-10-02T17:37:36-07:00 summary: gh-97706: multiprocessing tests: Delete unused variable `rand` (#97707) files: M Lib/test/_test_multiprocessing.py diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index b78586c560a6..a35e527eea44 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -5289,13 +5289,12 @@ def test_resource_tracker(self): # Check that killing process does not leak named semaphores # cmd = '''if 1: - import time, os, tempfile + import time, os import multiprocessing as mp from multiprocessing import resource_tracker from multiprocessing.shared_memory import SharedMemory mp.set_start_method("spawn") - rand = tempfile._RandomNameSequence() def create_and_register_resource(rtype): From webhook-mailer at python.org Sun Oct 2 20:41:09 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Mon, 03 Oct 2022 00:41:09 -0000 Subject: [Python-checkins] gh-96819: multiprocessing.resource_tracker: check if length of pipe write <= 512 (#96890) Message-ID: https://github.com/python/cpython/commit/19ca114645bd8796cf4094e152b1fa9944da473d commit: 19ca114645bd8796cf4094e152b1fa9944da473d branch: main author: Koki Saito <49419225+saito828koki at users.noreply.github.com> committer: JelleZijlstra date: 2022-10-02T17:41:01-07:00 summary: gh-96819: multiprocessing.resource_tracker: check if length of pipe write <= 512 (#96890) Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> files: A Misc/NEWS.d/next/Library/2022-09-17-13-15-10.gh-issue-96819.6RfqM7.rst M Lib/multiprocessing/resource_tracker.py M Lib/test/_test_multiprocessing.py diff --git a/Lib/multiprocessing/resource_tracker.py b/Lib/multiprocessing/resource_tracker.py index cc42dbdda05b..ea369507297f 100644 --- a/Lib/multiprocessing/resource_tracker.py +++ b/Lib/multiprocessing/resource_tracker.py @@ -161,10 +161,10 @@ def unregister(self, name, rtype): def _send(self, cmd, name, rtype): self.ensure_running() msg = '{0}:{1}:{2}\n'.format(cmd, name, rtype).encode('ascii') - if len(name) > 512: + if len(msg) > 512: # posix guarantees that writes to a pipe of less than PIPE_BUF # bytes are atomic, and that PIPE_BUF >= 512 - raise ValueError('name too long') + raise ValueError('msg too long') nbytes = os.write(self._fd, msg) assert nbytes == len(msg), "nbytes {0:n} but len(msg) {1:n}".format( nbytes, len(msg)) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index a35e527eea44..f74d8d7fbd72 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -5432,6 +5432,14 @@ def test_resource_tracker_reused(self): self.assertTrue(is_resource_tracker_reused) + def test_too_long_name_resource(self): + # gh-96819: Resource names that will make the length of a write to a pipe + # greater than PIPE_BUF are not allowed + rtype = "shared_memory" + too_long_name_resource = "a" * (512 - len(rtype)) + with self.assertRaises(ValueError): + resource_tracker.register(too_long_name_resource, rtype) + class TestSimpleQueue(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2022-09-17-13-15-10.gh-issue-96819.6RfqM7.rst b/Misc/NEWS.d/next/Library/2022-09-17-13-15-10.gh-issue-96819.6RfqM7.rst new file mode 100644 index 000000000000..07b62a883b85 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-09-17-13-15-10.gh-issue-96819.6RfqM7.rst @@ -0,0 +1 @@ +Fixed check in :mod:`multiprocessing.resource_tracker` that guarantees that the length of a write to a pipe is not greater than ``PIPE_BUF``. From webhook-mailer at python.org Sun Oct 2 21:10:16 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 03 Oct 2022 01:10:16 -0000 Subject: [Python-checkins] gh-96819: multiprocessing.resource_tracker: check if length of pipe write <= 512 (GH-96890) Message-ID: https://github.com/python/cpython/commit/f59506780a60b870f6c6ccba1991f444dd241e59 commit: f59506780a60b870f6c6ccba1991f444dd241e59 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-02T18:09:58-07:00 summary: gh-96819: multiprocessing.resource_tracker: check if length of pipe write <= 512 (GH-96890) Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> (cherry picked from commit 19ca114645bd8796cf4094e152b1fa9944da473d) Co-authored-by: Koki Saito <49419225+saito828koki at users.noreply.github.com> files: A Misc/NEWS.d/next/Library/2022-09-17-13-15-10.gh-issue-96819.6RfqM7.rst M Lib/multiprocessing/resource_tracker.py M Lib/test/_test_multiprocessing.py diff --git a/Lib/multiprocessing/resource_tracker.py b/Lib/multiprocessing/resource_tracker.py index cc42dbdda05b..ea369507297f 100644 --- a/Lib/multiprocessing/resource_tracker.py +++ b/Lib/multiprocessing/resource_tracker.py @@ -161,10 +161,10 @@ def unregister(self, name, rtype): def _send(self, cmd, name, rtype): self.ensure_running() msg = '{0}:{1}:{2}\n'.format(cmd, name, rtype).encode('ascii') - if len(name) > 512: + if len(msg) > 512: # posix guarantees that writes to a pipe of less than PIPE_BUF # bytes are atomic, and that PIPE_BUF >= 512 - raise ValueError('name too long') + raise ValueError('msg too long') nbytes = os.write(self._fd, msg) assert nbytes == len(msg), "nbytes {0:n} but len(msg) {1:n}".format( nbytes, len(msg)) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index 599c3f2abf33..3117b110db09 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -5438,6 +5438,14 @@ def test_resource_tracker_reused(self): self.assertTrue(is_resource_tracker_reused) + def test_too_long_name_resource(self): + # gh-96819: Resource names that will make the length of a write to a pipe + # greater than PIPE_BUF are not allowed + rtype = "shared_memory" + too_long_name_resource = "a" * (512 - len(rtype)) + with self.assertRaises(ValueError): + resource_tracker.register(too_long_name_resource, rtype) + class TestSimpleQueue(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2022-09-17-13-15-10.gh-issue-96819.6RfqM7.rst b/Misc/NEWS.d/next/Library/2022-09-17-13-15-10.gh-issue-96819.6RfqM7.rst new file mode 100644 index 000000000000..07b62a883b85 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-09-17-13-15-10.gh-issue-96819.6RfqM7.rst @@ -0,0 +1 @@ +Fixed check in :mod:`multiprocessing.resource_tracker` that guarantees that the length of a write to a pipe is not greater than ``PIPE_BUF``. From webhook-mailer at python.org Sun Oct 2 21:11:23 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 03 Oct 2022 01:11:23 -0000 Subject: [Python-checkins] gh-96819: multiprocessing.resource_tracker: check if length of pipe write <= 512 (GH-96890) Message-ID: https://github.com/python/cpython/commit/c2d3f73da780ce4d568f541fb7f55917a814d65c commit: c2d3f73da780ce4d568f541fb7f55917a814d65c branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-02T18:11:17-07:00 summary: gh-96819: multiprocessing.resource_tracker: check if length of pipe write <= 512 (GH-96890) Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> (cherry picked from commit 19ca114645bd8796cf4094e152b1fa9944da473d) Co-authored-by: Koki Saito <49419225+saito828koki at users.noreply.github.com> files: A Misc/NEWS.d/next/Library/2022-09-17-13-15-10.gh-issue-96819.6RfqM7.rst M Lib/multiprocessing/resource_tracker.py M Lib/test/_test_multiprocessing.py diff --git a/Lib/multiprocessing/resource_tracker.py b/Lib/multiprocessing/resource_tracker.py index cc42dbdda05b..ea369507297f 100644 --- a/Lib/multiprocessing/resource_tracker.py +++ b/Lib/multiprocessing/resource_tracker.py @@ -161,10 +161,10 @@ def unregister(self, name, rtype): def _send(self, cmd, name, rtype): self.ensure_running() msg = '{0}:{1}:{2}\n'.format(cmd, name, rtype).encode('ascii') - if len(name) > 512: + if len(msg) > 512: # posix guarantees that writes to a pipe of less than PIPE_BUF # bytes are atomic, and that PIPE_BUF >= 512 - raise ValueError('name too long') + raise ValueError('msg too long') nbytes = os.write(self._fd, msg) assert nbytes == len(msg), "nbytes {0:n} but len(msg) {1:n}".format( nbytes, len(msg)) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index 8dced90c5383..be174aae3d63 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -5377,6 +5377,14 @@ def test_resource_tracker_reused(self): self.assertTrue(is_resource_tracker_reused) + def test_too_long_name_resource(self): + # gh-96819: Resource names that will make the length of a write to a pipe + # greater than PIPE_BUF are not allowed + rtype = "shared_memory" + too_long_name_resource = "a" * (512 - len(rtype)) + with self.assertRaises(ValueError): + resource_tracker.register(too_long_name_resource, rtype) + class TestSimpleQueue(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2022-09-17-13-15-10.gh-issue-96819.6RfqM7.rst b/Misc/NEWS.d/next/Library/2022-09-17-13-15-10.gh-issue-96819.6RfqM7.rst new file mode 100644 index 000000000000..07b62a883b85 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-09-17-13-15-10.gh-issue-96819.6RfqM7.rst @@ -0,0 +1 @@ +Fixed check in :mod:`multiprocessing.resource_tracker` that guarantees that the length of a write to a pipe is not greater than ``PIPE_BUF``. From webhook-mailer at python.org Sun Oct 2 23:51:31 2022 From: webhook-mailer at python.org (ezio-melotti) Date: Mon, 03 Oct 2022 03:51:31 -0000 Subject: [Python-checkins] gh-97740: Fix bang in Sphinx C domain ref target syntax (#97741) Message-ID: https://github.com/python/cpython/commit/9148c0d893c7807331fd7be0997261e289074bc5 commit: 9148c0d893c7807331fd7be0997261e289074bc5 branch: main author: C.A.M. Gerlach committer: ezio-melotti date: 2022-10-03T05:51:22+02:00 summary: gh-97740: Fix bang in Sphinx C domain ref target syntax (#97741) * gh-97740: Fix bang in Sphinx C domain ref target syntax Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> * Add NEWS entry for C domain bang fix Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> files: A Misc/NEWS.d/next/Documentation/2022-10-02-10-58-52.gh-issue-97741.39l023.rst M Doc/conf.py diff --git a/Doc/conf.py b/Doc/conf.py index 0a436d7affcd..909f992d9d82 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -249,3 +249,18 @@ # bpo-40204: Disable warnings on Sphinx 2 syntax of the C domain since the # documentation is built with -W (warnings treated as errors). c_warn_on_allowed_pre_v3 = False + +# Fix '!' not working with C domain when pre_v3 is enabled +import sphinx + +if sphinx.version_info[:2] < (5, 3): + from sphinx.domains.c import CXRefRole + + original_run = CXRefRole.run + + def new_run(self): + if self.disabled: + return super(CXRefRole, self).run() + return original_run(self) + + CXRefRole.run = new_run diff --git a/Misc/NEWS.d/next/Documentation/2022-10-02-10-58-52.gh-issue-97741.39l023.rst b/Misc/NEWS.d/next/Documentation/2022-10-02-10-58-52.gh-issue-97741.39l023.rst new file mode 100644 index 000000000000..8da9c92f6fd8 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2022-10-02-10-58-52.gh-issue-97741.39l023.rst @@ -0,0 +1,2 @@ +Fix ``!`` in c domain ref target syntax via a ``conf.py`` patch, so it works +as intended to disable ref target resolution. From webhook-mailer at python.org Sun Oct 2 23:59:52 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 03 Oct 2022 03:59:52 -0000 Subject: [Python-checkins] gh-97740: Fix bang in Sphinx C domain ref target syntax (GH-97741) Message-ID: https://github.com/python/cpython/commit/a1711ef030d0b637da75ff5a870ac1a3fd959c04 commit: a1711ef030d0b637da75ff5a870ac1a3fd959c04 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-02T20:59:46-07:00 summary: gh-97740: Fix bang in Sphinx C domain ref target syntax (GH-97741) * gh-97740: Fix bang in Sphinx C domain ref target syntax Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> * Add NEWS entry for C domain bang fix Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> (cherry picked from commit 9148c0d893c7807331fd7be0997261e289074bc5) Co-authored-by: C.A.M. Gerlach files: A Misc/NEWS.d/next/Documentation/2022-10-02-10-58-52.gh-issue-97741.39l023.rst M Doc/conf.py diff --git a/Doc/conf.py b/Doc/conf.py index 8fdff7965d92..aff26f9c9058 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -244,3 +244,18 @@ # bpo-40204: Disable warnings on Sphinx 2 syntax of the C domain since the # documentation is built with -W (warnings treated as errors). c_warn_on_allowed_pre_v3 = False + +# Fix '!' not working with C domain when pre_v3 is enabled +import sphinx + +if sphinx.version_info[:2] < (5, 3): + from sphinx.domains.c import CXRefRole + + original_run = CXRefRole.run + + def new_run(self): + if self.disabled: + return super(CXRefRole, self).run() + return original_run(self) + + CXRefRole.run = new_run diff --git a/Misc/NEWS.d/next/Documentation/2022-10-02-10-58-52.gh-issue-97741.39l023.rst b/Misc/NEWS.d/next/Documentation/2022-10-02-10-58-52.gh-issue-97741.39l023.rst new file mode 100644 index 000000000000..8da9c92f6fd8 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2022-10-02-10-58-52.gh-issue-97741.39l023.rst @@ -0,0 +1,2 @@ +Fix ``!`` in c domain ref target syntax via a ``conf.py`` patch, so it works +as intended to disable ref target resolution. From webhook-mailer at python.org Mon Oct 3 00:02:51 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 03 Oct 2022 04:02:51 -0000 Subject: [Python-checkins] gh-97740: Fix bang in Sphinx C domain ref target syntax (GH-97741) Message-ID: https://github.com/python/cpython/commit/827f77e5f1933b10e86ea5acb0d6d8e3c8166729 commit: 827f77e5f1933b10e86ea5acb0d6d8e3c8166729 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-02T21:02:46-07:00 summary: gh-97740: Fix bang in Sphinx C domain ref target syntax (GH-97741) * gh-97740: Fix bang in Sphinx C domain ref target syntax Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> * Add NEWS entry for C domain bang fix Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> (cherry picked from commit 9148c0d893c7807331fd7be0997261e289074bc5) Co-authored-by: C.A.M. Gerlach files: A Misc/NEWS.d/next/Documentation/2022-10-02-10-58-52.gh-issue-97741.39l023.rst M Doc/conf.py diff --git a/Doc/conf.py b/Doc/conf.py index 2e670e5a8569..e5c989da0b36 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -244,3 +244,18 @@ # bpo-40204: Disable warnings on Sphinx 2 syntax of the C domain since the # documentation is built with -W (warnings treated as errors). c_warn_on_allowed_pre_v3 = False + +# Fix '!' not working with C domain when pre_v3 is enabled +import sphinx + +if sphinx.version_info[:2] < (5, 3): + from sphinx.domains.c import CXRefRole + + original_run = CXRefRole.run + + def new_run(self): + if self.disabled: + return super(CXRefRole, self).run() + return original_run(self) + + CXRefRole.run = new_run diff --git a/Misc/NEWS.d/next/Documentation/2022-10-02-10-58-52.gh-issue-97741.39l023.rst b/Misc/NEWS.d/next/Documentation/2022-10-02-10-58-52.gh-issue-97741.39l023.rst new file mode 100644 index 000000000000..8da9c92f6fd8 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2022-10-02-10-58-52.gh-issue-97741.39l023.rst @@ -0,0 +1,2 @@ +Fix ``!`` in c domain ref target syntax via a ``conf.py`` patch, so it works +as intended to disable ref target resolution. From webhook-mailer at python.org Mon Oct 3 00:04:18 2022 From: webhook-mailer at python.org (ezio-melotti) Date: Mon, 03 Oct 2022 04:04:18 -0000 Subject: [Python-checkins] gh-95913: Copyedit/improve New Modules What's New section (#97721) Message-ID: https://github.com/python/cpython/commit/bd00112a99af44c6ef82ee45b4072ec3bbc82fef commit: bd00112a99af44c6ef82ee45b4072ec3bbc82fef branch: main author: C.A.M. Gerlach committer: ezio-melotti date: 2022-10-03T06:04:10+02:00 summary: gh-95913: Copyedit/improve New Modules What's New section (#97721) * Link TOML & WSGI in New Modules section, refine text & add ref label * Further reformat new modules & add PEP link to tomllib files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 0cd281edbe5b..cb4aa2f47119 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -512,14 +512,17 @@ Other CPython Implementation Changes (Contributed by ?ric Araujo in :issue:`46142`.) +.. _whatsnew311-new-modules: + New Modules =========== -* A new module, :mod:`tomllib`, was added for parsing TOML. +* :mod:`tomllib`: For parsing `TOML `_. + See :pep:`680` for more details. (Contributed by Taneli Hukkinen in :issue:`40059`.) -* :mod:`wsgiref.types`, containing WSGI-specific types for static type - checking, was added. +* :mod:`wsgiref.types`: + :pep:`WSGI <3333>`-specific types for static type checking. (Contributed by Sebastian Rittau in :issue:`42012`.) From webhook-mailer at python.org Mon Oct 3 00:11:10 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 03 Oct 2022 04:11:10 -0000 Subject: [Python-checkins] gh-95913: Copyedit/improve New Modules What's New section (GH-97721) Message-ID: https://github.com/python/cpython/commit/2049c9db15a17f25405fb50d0a77702c5844e137 commit: 2049c9db15a17f25405fb50d0a77702c5844e137 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-02T21:11:05-07:00 summary: gh-95913: Copyedit/improve New Modules What's New section (GH-97721) * Link TOML & WSGI in New Modules section, refine text & add ref label * Further reformat new modules & add PEP link to tomllib (cherry picked from commit bd00112a99af44c6ef82ee45b4072ec3bbc82fef) Co-authored-by: C.A.M. Gerlach files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index a84bfde5c482..51df73736475 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -523,14 +523,17 @@ Other CPython Implementation Changes is 4300 digits in string form. +.. _whatsnew311-new-modules: + New Modules =========== -* A new module, :mod:`tomllib`, was added for parsing TOML. +* :mod:`tomllib`: For parsing `TOML `_. + See :pep:`680` for more details. (Contributed by Taneli Hukkinen in :issue:`40059`.) -* :mod:`wsgiref.types`, containing WSGI-specific types for static type - checking, was added. +* :mod:`wsgiref.types`: + :pep:`WSGI <3333>`-specific types for static type checking. (Contributed by Sebastian Rittau in :issue:`42012`.) From webhook-mailer at python.org Mon Oct 3 00:12:45 2022 From: webhook-mailer at python.org (ezio-melotti) Date: Mon, 03 Oct 2022 04:12:45 -0000 Subject: [Python-checkins] gh-95913: Fix PEP number in PEP 678 What's New ref label (#97739) Message-ID: https://github.com/python/cpython/commit/e738b5190bfa63086b5e8169189e9b05302873c8 commit: e738b5190bfa63086b5e8169189e9b05302873c8 branch: main author: C.A.M. Gerlach committer: ezio-melotti date: 2022-10-03T06:12:37+02:00 summary: gh-95913: Fix PEP number in PEP 678 What's New ref label (#97739) What's New: Fix PEP number in PEP 678 ref target label files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index cb4aa2f47119..19821e1b6029 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -191,7 +191,7 @@ See :pep:`654` for more details. Irit Katriel, Yury Selivanov and Guido van Rossum.) -.. _whatsnew311-pep670: +.. _whatsnew311-pep678: PEP 678: Exceptions can be enriched with notes ---------------------------------------------- From webhook-mailer at python.org Mon Oct 3 00:21:52 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 03 Oct 2022 04:21:52 -0000 Subject: [Python-checkins] gh-95913: Fix PEP number in PEP 678 What's New ref label (GH-97739) Message-ID: https://github.com/python/cpython/commit/3db036888c4c6a963659ab2708158c4e1ec41adb commit: 3db036888c4c6a963659ab2708158c4e1ec41adb branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-02T21:21:46-07:00 summary: gh-95913: Fix PEP number in PEP 678 What's New ref label (GH-97739) What's New: Fix PEP number in PEP 678 ref target label (cherry picked from commit e738b5190bfa63086b5e8169189e9b05302873c8) Co-authored-by: C.A.M. Gerlach files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 51df73736475..60e2d794e6c1 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -191,7 +191,7 @@ See :pep:`654` for more details. Irit Katriel, Yury Selivanov and Guido van Rossum.) -.. _whatsnew311-pep670: +.. _whatsnew311-pep678: PEP 678: Exceptions can be enriched with notes ---------------------------------------------- From webhook-mailer at python.org Mon Oct 3 03:43:04 2022 From: webhook-mailer at python.org (serhiy-storchaka) Date: Mon, 03 Oct 2022 07:43:04 -0000 Subject: [Python-checkins] gh-97728: Argument Clinic: Fix uninitialized variable in the Py_UNICODE converter (GH-97729) Message-ID: https://github.com/python/cpython/commit/0ee9619a4cba58730c45e65d22288fadbf7680de commit: 0ee9619a4cba58730c45e65d22288fadbf7680de branch: main author: Serhiy Storchaka committer: serhiy-storchaka date: 2022-10-03T10:42:54+03:00 summary: gh-97728: Argument Clinic: Fix uninitialized variable in the Py_UNICODE converter (GH-97729) It affects function os.system() on Windows and Windows-specific modules winreg, _winapi, _overlapped, and _msi. files: A Misc/NEWS.d/next/Windows/2022-10-02-11-59-23.gh-issue-97728.dIdlPE.rst M Lib/test/clinic.test M Modules/clinic/_winapi.c.h M Modules/clinic/overlapped.c.h M Modules/clinic/posixmodule.c.h M PC/clinic/_msi.c.h M PC/clinic/winreg.c.h M Tools/clinic/clinic.py diff --git a/Lib/test/clinic.test b/Lib/test/clinic.test index c73a75b163fa..47e3e02490c8 100644 --- a/Lib/test/clinic.test +++ b/Lib/test/clinic.test @@ -1803,12 +1803,12 @@ static PyObject * test_Py_UNICODE_converter(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - const Py_UNICODE *a; - const Py_UNICODE *b; - const Py_UNICODE *c; - const Py_UNICODE *d; + const Py_UNICODE *a = NULL; + const Py_UNICODE *b = NULL; + const Py_UNICODE *c = NULL; + const Py_UNICODE *d = NULL; Py_ssize_t d_length; - const Py_UNICODE *e; + const Py_UNICODE *e = NULL; Py_ssize_t e_length; if (!_PyArg_ParseStack(args, nargs, "O&O&O&u#Z#:test_Py_UNICODE_converter", @@ -1833,7 +1833,7 @@ test_Py_UNICODE_converter_impl(PyObject *module, const Py_UNICODE *a, const Py_UNICODE *b, const Py_UNICODE *c, const Py_UNICODE *d, Py_ssize_t d_length, const Py_UNICODE *e, Py_ssize_t e_length) -/*[clinic end generated code: output=4d426808cdbb3ea3 input=064a3b68ad7f04b0]*/ +/*[clinic end generated code: output=9f34a249b3071fdd input=064a3b68ad7f04b0]*/ /*[clinic input] diff --git a/Misc/NEWS.d/next/Windows/2022-10-02-11-59-23.gh-issue-97728.dIdlPE.rst b/Misc/NEWS.d/next/Windows/2022-10-02-11-59-23.gh-issue-97728.dIdlPE.rst new file mode 100644 index 000000000000..2a6a253a52ae --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2022-10-02-11-59-23.gh-issue-97728.dIdlPE.rst @@ -0,0 +1,3 @@ +Fix possible crashes caused by the use of uninitialized variables when pass +invalid arguments in :func:`os.system` on Windows and in Windows-specific +modules (like ``winreg``). diff --git a/Modules/clinic/_winapi.c.h b/Modules/clinic/_winapi.c.h index 53d5cccdd7db..cc1a5881e0bf 100644 --- a/Modules/clinic/_winapi.c.h +++ b/Modules/clinic/_winapi.c.h @@ -221,7 +221,7 @@ _winapi_CreateFileMapping(PyObject *module, PyObject *const *args, Py_ssize_t na DWORD protect; DWORD max_size_high; DWORD max_size_low; - LPCWSTR name; + LPCWSTR name = NULL; HANDLE _return_value; if (!_PyArg_ParseStack(args, nargs, "" F_HANDLE "" F_POINTER "kkkO&:CreateFileMapping", @@ -260,8 +260,8 @@ static PyObject * _winapi_CreateJunction(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - LPCWSTR src_path; - LPCWSTR dst_path; + LPCWSTR src_path = NULL; + LPCWSTR dst_path = NULL; if (!_PyArg_CheckPositional("CreateJunction", nargs, 2, 2)) { goto exit; @@ -409,14 +409,14 @@ static PyObject * _winapi_CreateProcess(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - const Py_UNICODE *application_name; + const Py_UNICODE *application_name = NULL; PyObject *command_line; PyObject *proc_attrs; PyObject *thread_attrs; BOOL inherit_handles; DWORD creation_flags; PyObject *env_mapping; - const Py_UNICODE *current_directory; + const Py_UNICODE *current_directory = NULL; PyObject *startup_info; if (!_PyArg_ParseStack(args, nargs, "O&OOOikOO&O:CreateProcess", @@ -760,7 +760,7 @@ _winapi_OpenFileMapping(PyObject *module, PyObject *const *args, Py_ssize_t narg PyObject *return_value = NULL; DWORD desired_access; BOOL inherit_handle; - LPCWSTR name; + LPCWSTR name = NULL; HANDLE _return_value; if (!_PyArg_ParseStack(args, nargs, "kiO&:OpenFileMapping", @@ -890,9 +890,9 @@ _winapi_LCMapStringEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, .kwtuple = KWTUPLE, }; #undef KWTUPLE - LPCWSTR locale; + LPCWSTR locale = NULL; DWORD flags; - LPCWSTR src; + LPCWSTR src = NULL; if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, _PyUnicode_WideCharString_Converter, &locale, &flags, _PyUnicode_WideCharString_Converter, &src)) { @@ -1345,4 +1345,4 @@ _winapi__mimetypes_read_windows_registry(PyObject *module, PyObject *const *args exit: return return_value; } -/*[clinic end generated code: output=3e51e0b2ea3fea5a input=a9049054013a1b77]*/ +/*[clinic end generated code: output=83c4a3f0e70e7775 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/overlapped.c.h b/Modules/clinic/overlapped.c.h index cc0c74cc1d29..e8c2fe5653d1 100644 --- a/Modules/clinic/overlapped.c.h +++ b/Modules/clinic/overlapped.c.h @@ -282,7 +282,7 @@ _overlapped_CreateEvent(PyObject *module, PyObject *const *args, Py_ssize_t narg PyObject *EventAttributes; BOOL ManualReset; BOOL InitialState; - const Py_UNICODE *Name; + const Py_UNICODE *Name = NULL; if (!_PyArg_CheckPositional("CreateEvent", nargs, 4, 4)) { goto exit; @@ -1047,7 +1047,7 @@ static PyObject * _overlapped_Overlapped_ConnectPipe(OverlappedObject *self, PyObject *arg) { PyObject *return_value = NULL; - const Py_UNICODE *Address; + const Py_UNICODE *Address = NULL; if (!PyUnicode_Check(arg)) { _PyArg_BadArgument("ConnectPipe", "argument", "str", arg); @@ -1254,4 +1254,4 @@ _overlapped_Overlapped_WSARecvFromInto(OverlappedObject *self, PyObject *const * return return_value; } -/*[clinic end generated code: output=ed7ca699b5cf6260 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=e0f866222bd5873b input=a9049054013a1b77]*/ diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h index a26cb8261083..7fac07804686 100644 --- a/Modules/clinic/posixmodule.c.h +++ b/Modules/clinic/posixmodule.c.h @@ -2399,7 +2399,7 @@ os_system(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *k }; #undef KWTUPLE PyObject *argsbuf[1]; - const Py_UNICODE *command; + const Py_UNICODE *command = NULL; long _return_value; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); @@ -11367,4 +11367,4 @@ os_waitstatus_to_exitcode(PyObject *module, PyObject *const *args, Py_ssize_t na #ifndef OS_WAITSTATUS_TO_EXITCODE_METHODDEF #define OS_WAITSTATUS_TO_EXITCODE_METHODDEF #endif /* !defined(OS_WAITSTATUS_TO_EXITCODE_METHODDEF) */ -/*[clinic end generated code: output=dc71eece3fc988a7 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=dd43d388b442c96d input=a9049054013a1b77]*/ diff --git a/PC/clinic/_msi.c.h b/PC/clinic/_msi.c.h index 1b7234aa03be..c77f0703927e 100644 --- a/PC/clinic/_msi.c.h +++ b/PC/clinic/_msi.c.h @@ -201,7 +201,7 @@ _msi_Record_SetString(msiobj *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int field; - const Py_UNICODE *value; + const Py_UNICODE *value = NULL; if (!_PyArg_CheckPositional("SetString", nargs, 2, 2)) { goto exit; @@ -244,7 +244,7 @@ _msi_Record_SetStream(msiobj *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int field; - const Py_UNICODE *value; + const Py_UNICODE *value = NULL; if (!_PyArg_CheckPositional("SetStream", nargs, 2, 2)) { goto exit; @@ -549,7 +549,7 @@ static PyObject * _msi_Database_OpenView(msiobj *self, PyObject *arg) { PyObject *return_value = NULL; - const Py_UNICODE *sql; + const Py_UNICODE *sql = NULL; if (!PyUnicode_Check(arg)) { _PyArg_BadArgument("OpenView", "argument", "str", arg); @@ -638,7 +638,7 @@ static PyObject * _msi_OpenDatabase(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - const Py_UNICODE *path; + const Py_UNICODE *path = NULL; int persist; if (!_PyArg_CheckPositional("OpenDatabase", nargs, 2, 2)) { @@ -695,4 +695,4 @@ _msi_CreateRecord(PyObject *module, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=583505220fadb52b input=a9049054013a1b77]*/ +/*[clinic end generated code: output=7d083c61679eed83 input=a9049054013a1b77]*/ diff --git a/PC/clinic/winreg.c.h b/PC/clinic/winreg.c.h index dc78274e062b..2834d9967a77 100644 --- a/PC/clinic/winreg.c.h +++ b/PC/clinic/winreg.c.h @@ -177,7 +177,7 @@ static PyObject * winreg_ConnectRegistry(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - const Py_UNICODE *computer_name; + const Py_UNICODE *computer_name = NULL; HKEY key; HKEY _return_value; @@ -243,7 +243,7 @@ winreg_CreateKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; HKEY key; - const Py_UNICODE *sub_key; + const Py_UNICODE *sub_key = NULL; HKEY _return_value; if (!_PyArg_CheckPositional("CreateKey", nargs, 2, 2)) { @@ -343,7 +343,7 @@ winreg_CreateKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py PyObject *argsbuf[4]; Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 2; HKEY key; - const Py_UNICODE *sub_key; + const Py_UNICODE *sub_key = NULL; int reserved = 0; REGSAM access = KEY_WRITE; HKEY _return_value; @@ -427,7 +427,7 @@ winreg_DeleteKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; HKEY key; - const Py_UNICODE *sub_key; + const Py_UNICODE *sub_key = NULL; if (!_PyArg_CheckPositional("DeleteKey", nargs, 2, 2)) { goto exit; @@ -520,7 +520,7 @@ winreg_DeleteKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py PyObject *argsbuf[4]; Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 2; HKEY key; - const Py_UNICODE *sub_key; + const Py_UNICODE *sub_key = NULL; REGSAM access = KEY_WOW64_64KEY; int reserved = 0; @@ -587,7 +587,7 @@ winreg_DeleteValue(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; HKEY key; - const Py_UNICODE *value; + const Py_UNICODE *value = NULL; if (!_PyArg_CheckPositional("DeleteValue", nargs, 2, 2)) { goto exit; @@ -731,7 +731,7 @@ static PyObject * winreg_ExpandEnvironmentStrings(PyObject *module, PyObject *arg) { PyObject *return_value = NULL; - const Py_UNICODE *string; + const Py_UNICODE *string = NULL; if (!PyUnicode_Check(arg)) { _PyArg_BadArgument("ExpandEnvironmentStrings", "argument", "str", arg); @@ -830,8 +830,8 @@ winreg_LoadKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; HKEY key; - const Py_UNICODE *sub_key; - const Py_UNICODE *file_name; + const Py_UNICODE *sub_key = NULL; + const Py_UNICODE *file_name = NULL; if (!_PyArg_CheckPositional("LoadKey", nargs, 3, 3)) { goto exit; @@ -924,7 +924,7 @@ winreg_OpenKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObje PyObject *argsbuf[4]; Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 2; HKEY key; - const Py_UNICODE *sub_key; + const Py_UNICODE *sub_key = NULL; int reserved = 0; REGSAM access = KEY_READ; HKEY _return_value; @@ -1037,7 +1037,7 @@ winreg_OpenKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyOb PyObject *argsbuf[4]; Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 2; HKEY key; - const Py_UNICODE *sub_key; + const Py_UNICODE *sub_key = NULL; int reserved = 0; REGSAM access = KEY_READ; HKEY _return_value; @@ -1159,7 +1159,7 @@ winreg_QueryValue(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; HKEY key; - const Py_UNICODE *sub_key; + const Py_UNICODE *sub_key = NULL; if (!_PyArg_CheckPositional("QueryValue", nargs, 2, 2)) { goto exit; @@ -1216,7 +1216,7 @@ winreg_QueryValueEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; HKEY key; - const Py_UNICODE *name; + const Py_UNICODE *name = NULL; if (!_PyArg_CheckPositional("QueryValueEx", nargs, 2, 2)) { goto exit; @@ -1278,7 +1278,7 @@ winreg_SaveKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; HKEY key; - const Py_UNICODE *file_name; + const Py_UNICODE *file_name = NULL; if (!_PyArg_CheckPositional("SaveKey", nargs, 2, 2)) { goto exit; @@ -1341,7 +1341,7 @@ winreg_SetValue(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; HKEY key; - const Py_UNICODE *sub_key; + const Py_UNICODE *sub_key = NULL; DWORD type; PyObject *value_obj; @@ -1440,7 +1440,7 @@ winreg_SetValueEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; HKEY key; - const Py_UNICODE *value_name; + const Py_UNICODE *value_name = NULL; PyObject *reserved; DWORD type; PyObject *value; @@ -1579,4 +1579,4 @@ winreg_QueryReflectionKey(PyObject *module, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=5dfd7dbce8ccb392 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=7e817dc5edc914d3 input=a9049054013a1b77]*/ diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 805bdcb43654..30a676328706 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -3586,6 +3586,7 @@ def converter_init(self, *, accept={str}, zeroes=False): self.converter = '_PyUnicode_WideCharString_Opt_Converter' else: fail("Py_UNICODE_converter: illegal 'accept' argument " + repr(accept)) + self.c_default = "NULL" def cleanup(self): if not self.length: From webhook-mailer at python.org Mon Oct 3 08:02:15 2022 From: webhook-mailer at python.org (serhiy-storchaka) Date: Mon, 03 Oct 2022 12:02:15 -0000 Subject: [Python-checkins] [3.11] gh-97728: Argument Clinic: Fix uninitialized variable in the Py_UNICODE converter (GH-97729) (GH-97757) Message-ID: https://github.com/python/cpython/commit/f07ee4147980e20abe710e917b62258637b13c62 commit: f07ee4147980e20abe710e917b62258637b13c62 branch: 3.11 author: Serhiy Storchaka committer: serhiy-storchaka date: 2022-10-03T15:01:54+03:00 summary: [3.11] gh-97728: Argument Clinic: Fix uninitialized variable in the Py_UNICODE converter (GH-97729) (GH-97757) It affects function os.system() on Windows and Windows-specific modules winreg, _winapi, _overlapped, and _msi. (cherry picked from commit 0ee9619a4cba58730c45e65d22288fadbf7680de) files: A Misc/NEWS.d/next/Windows/2022-10-02-11-59-23.gh-issue-97728.dIdlPE.rst M Lib/test/clinic.test M Modules/clinic/_winapi.c.h M Modules/clinic/overlapped.c.h M Modules/clinic/posixmodule.c.h M PC/clinic/_msi.c.h M PC/clinic/winreg.c.h M Tools/clinic/clinic.py diff --git a/Lib/test/clinic.test b/Lib/test/clinic.test index 9016cffba95c..0228d6be0326 100644 --- a/Lib/test/clinic.test +++ b/Lib/test/clinic.test @@ -1803,12 +1803,12 @@ static PyObject * test_Py_UNICODE_converter(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - const Py_UNICODE *a; - const Py_UNICODE *b; - const Py_UNICODE *c; - const Py_UNICODE *d; + const Py_UNICODE *a = NULL; + const Py_UNICODE *b = NULL; + const Py_UNICODE *c = NULL; + const Py_UNICODE *d = NULL; Py_ssize_t d_length; - const Py_UNICODE *e; + const Py_UNICODE *e = NULL; Py_ssize_t e_length; if (!_PyArg_ParseStack(args, nargs, "O&O&O&u#Z#:test_Py_UNICODE_converter", @@ -1839,7 +1839,7 @@ test_Py_UNICODE_converter_impl(PyObject *module, const Py_UNICODE *a, const Py_UNICODE *b, const Py_UNICODE *c, const Py_UNICODE *d, Py_ssize_t d_length, const Py_UNICODE *e, Py_ssize_t e_length) -/*[clinic end generated code: output=45e92604de227552 input=064a3b68ad7f04b0]*/ +/*[clinic end generated code: output=9d41b3a38a0f6f2f input=064a3b68ad7f04b0]*/ /*[clinic input] diff --git a/Misc/NEWS.d/next/Windows/2022-10-02-11-59-23.gh-issue-97728.dIdlPE.rst b/Misc/NEWS.d/next/Windows/2022-10-02-11-59-23.gh-issue-97728.dIdlPE.rst new file mode 100644 index 000000000000..2a6a253a52ae --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2022-10-02-11-59-23.gh-issue-97728.dIdlPE.rst @@ -0,0 +1,3 @@ +Fix possible crashes caused by the use of uninitialized variables when pass +invalid arguments in :func:`os.system` on Windows and in Windows-specific +modules (like ``winreg``). diff --git a/Modules/clinic/_winapi.c.h b/Modules/clinic/_winapi.c.h index 87f624f9816d..118e7bfd29fe 100644 --- a/Modules/clinic/_winapi.c.h +++ b/Modules/clinic/_winapi.c.h @@ -192,7 +192,7 @@ _winapi_CreateFileMapping(PyObject *module, PyObject *const *args, Py_ssize_t na DWORD protect; DWORD max_size_high; DWORD max_size_low; - LPCWSTR name; + LPCWSTR name = NULL; HANDLE _return_value; if (!_PyArg_ParseStack(args, nargs, "" F_HANDLE "" F_POINTER "kkkO&:CreateFileMapping", @@ -233,8 +233,8 @@ static PyObject * _winapi_CreateJunction(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - LPCWSTR src_path; - LPCWSTR dst_path; + LPCWSTR src_path = NULL; + LPCWSTR dst_path = NULL; if (!_PyArg_CheckPositional("CreateJunction", nargs, 2, 2)) { goto exit; @@ -394,14 +394,14 @@ static PyObject * _winapi_CreateProcess(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - const Py_UNICODE *application_name; + const Py_UNICODE *application_name = NULL; PyObject *command_line; PyObject *proc_attrs; PyObject *thread_attrs; BOOL inherit_handles; DWORD creation_flags; PyObject *env_mapping; - const Py_UNICODE *current_directory; + const Py_UNICODE *current_directory = NULL; PyObject *startup_info; if (!_PyArg_ParseStack(args, nargs, "O&OOOikOO&O:CreateProcess", @@ -749,7 +749,7 @@ _winapi_OpenFileMapping(PyObject *module, PyObject *const *args, Py_ssize_t narg PyObject *return_value = NULL; DWORD desired_access; BOOL inherit_handle; - LPCWSTR name; + LPCWSTR name = NULL; HANDLE _return_value; if (!_PyArg_ParseStack(args, nargs, "kiO&:OpenFileMapping", @@ -1216,4 +1216,4 @@ _winapi__mimetypes_read_windows_registry(PyObject *module, PyObject *const *args exit: return return_value; } -/*[clinic end generated code: output=dfbccec8f11b7433 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=60b036183b92659e input=a9049054013a1b77]*/ diff --git a/Modules/clinic/overlapped.c.h b/Modules/clinic/overlapped.c.h index 286133831749..2f0520d3df4a 100644 --- a/Modules/clinic/overlapped.c.h +++ b/Modules/clinic/overlapped.c.h @@ -220,7 +220,7 @@ _overlapped_CreateEvent(PyObject *module, PyObject *const *args, Py_ssize_t narg PyObject *EventAttributes; BOOL ManualReset; BOOL InitialState; - const Py_UNICODE *Name; + const Py_UNICODE *Name = NULL; if (!_PyArg_ParseStack(args, nargs, "OiiO&:CreateEvent", &EventAttributes, &ManualReset, &InitialState, _PyUnicode_WideCharString_Opt_Converter, &Name)) { @@ -806,7 +806,7 @@ static PyObject * _overlapped_Overlapped_ConnectPipe(OverlappedObject *self, PyObject *arg) { PyObject *return_value = NULL; - const Py_UNICODE *Address; + const Py_UNICODE *Address = NULL; if (!PyUnicode_Check(arg)) { _PyArg_BadArgument("ConnectPipe", "argument", "str", arg); @@ -968,4 +968,4 @@ _overlapped_Overlapped_WSARecvFromInto(OverlappedObject *self, PyObject *const * return return_value; } -/*[clinic end generated code: output=b0f15f5c09f1147e input=a9049054013a1b77]*/ +/*[clinic end generated code: output=8532bc0e4e1958ac input=a9049054013a1b77]*/ diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h index ca2699b4e366..e636f8b94ff7 100644 --- a/Modules/clinic/posixmodule.c.h +++ b/Modules/clinic/posixmodule.c.h @@ -1749,7 +1749,7 @@ os_system(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *k static const char * const _keywords[] = {"command", NULL}; static _PyArg_Parser _parser = {NULL, _keywords, "system", 0}; PyObject *argsbuf[1]; - const Py_UNICODE *command; + const Py_UNICODE *command = NULL; long _return_value; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); @@ -9378,4 +9378,4 @@ os_waitstatus_to_exitcode(PyObject *module, PyObject *const *args, Py_ssize_t na #ifndef OS_WAITSTATUS_TO_EXITCODE_METHODDEF #define OS_WAITSTATUS_TO_EXITCODE_METHODDEF #endif /* !defined(OS_WAITSTATUS_TO_EXITCODE_METHODDEF) */ -/*[clinic end generated code: output=3032d9c5c3aaa165 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=836be9d51f01140e input=a9049054013a1b77]*/ diff --git a/PC/clinic/_msi.c.h b/PC/clinic/_msi.c.h index fd2114215831..b717192b4833 100644 --- a/PC/clinic/_msi.c.h +++ b/PC/clinic/_msi.c.h @@ -195,7 +195,7 @@ _msi_Record_SetString(msiobj *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int field; - const Py_UNICODE *value; + const Py_UNICODE *value = NULL; if (!_PyArg_CheckPositional("SetString", nargs, 2, 2)) { goto exit; @@ -244,7 +244,7 @@ _msi_Record_SetStream(msiobj *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int field; - const Py_UNICODE *value; + const Py_UNICODE *value = NULL; if (!_PyArg_CheckPositional("SetStream", nargs, 2, 2)) { goto exit; @@ -555,7 +555,7 @@ static PyObject * _msi_Database_OpenView(msiobj *self, PyObject *arg) { PyObject *return_value = NULL; - const Py_UNICODE *sql; + const Py_UNICODE *sql = NULL; if (!PyUnicode_Check(arg)) { _PyArg_BadArgument("OpenView", "argument", "str", arg); @@ -650,7 +650,7 @@ static PyObject * _msi_OpenDatabase(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - const Py_UNICODE *path; + const Py_UNICODE *path = NULL; int persist; if (!_PyArg_CheckPositional("OpenDatabase", nargs, 2, 2)) { @@ -713,4 +713,4 @@ _msi_CreateRecord(PyObject *module, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=d7eb07e6bfcdc13f input=a9049054013a1b77]*/ +/*[clinic end generated code: output=276175d60fbfc956 input=a9049054013a1b77]*/ diff --git a/PC/clinic/winreg.c.h b/PC/clinic/winreg.c.h index 2507e46e2633..a413dec5dda5 100644 --- a/PC/clinic/winreg.c.h +++ b/PC/clinic/winreg.c.h @@ -148,7 +148,7 @@ static PyObject * winreg_ConnectRegistry(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - const Py_UNICODE *computer_name; + const Py_UNICODE *computer_name = NULL; HKEY key; HKEY _return_value; @@ -220,7 +220,7 @@ winreg_CreateKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; HKEY key; - const Py_UNICODE *sub_key; + const Py_UNICODE *sub_key = NULL; HKEY _return_value; if (!_PyArg_CheckPositional("CreateKey", nargs, 2, 2)) { @@ -301,7 +301,7 @@ winreg_CreateKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py static const char * const _keywords[] = {"key", "sub_key", "reserved", "access", NULL}; static _PyArg_Parser _parser = {"O&O&|ii:CreateKeyEx", _keywords, 0}; HKEY key; - const Py_UNICODE *sub_key; + const Py_UNICODE *sub_key = NULL; int reserved = 0; REGSAM access = KEY_WRITE; HKEY _return_value; @@ -354,7 +354,7 @@ winreg_DeleteKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; HKEY key; - const Py_UNICODE *sub_key; + const Py_UNICODE *sub_key = NULL; if (!_PyArg_CheckPositional("DeleteKey", nargs, 2, 2)) { goto exit; @@ -428,7 +428,7 @@ winreg_DeleteKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py static const char * const _keywords[] = {"key", "sub_key", "access", "reserved", NULL}; static _PyArg_Parser _parser = {"O&O&|ii:DeleteKeyEx", _keywords, 0}; HKEY key; - const Py_UNICODE *sub_key; + const Py_UNICODE *sub_key = NULL; REGSAM access = KEY_WOW64_64KEY; int reserved = 0; @@ -469,7 +469,7 @@ winreg_DeleteValue(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; HKEY key; - const Py_UNICODE *value; + const Py_UNICODE *value = NULL; if (!_PyArg_CheckPositional("DeleteValue", nargs, 2, 2)) { goto exit; @@ -619,7 +619,7 @@ static PyObject * winreg_ExpandEnvironmentStrings(PyObject *module, PyObject *arg) { PyObject *return_value = NULL; - const Py_UNICODE *string; + const Py_UNICODE *string = NULL; if (!PyUnicode_Check(arg)) { _PyArg_BadArgument("ExpandEnvironmentStrings", "argument", "str", arg); @@ -724,8 +724,8 @@ winreg_LoadKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; HKEY key; - const Py_UNICODE *sub_key; - const Py_UNICODE *file_name; + const Py_UNICODE *sub_key = NULL; + const Py_UNICODE *file_name = NULL; if (!_PyArg_CheckPositional("LoadKey", nargs, 3, 3)) { goto exit; @@ -805,7 +805,7 @@ winreg_OpenKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObje static const char * const _keywords[] = {"key", "sub_key", "reserved", "access", NULL}; static _PyArg_Parser _parser = {"O&O&|ii:OpenKey", _keywords, 0}; HKEY key; - const Py_UNICODE *sub_key; + const Py_UNICODE *sub_key = NULL; int reserved = 0; REGSAM access = KEY_READ; HKEY _return_value; @@ -862,7 +862,7 @@ winreg_OpenKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyOb static const char * const _keywords[] = {"key", "sub_key", "reserved", "access", NULL}; static _PyArg_Parser _parser = {"O&O&|ii:OpenKeyEx", _keywords, 0}; HKEY key; - const Py_UNICODE *sub_key; + const Py_UNICODE *sub_key = NULL; int reserved = 0; REGSAM access = KEY_READ; HKEY _return_value; @@ -953,7 +953,7 @@ winreg_QueryValue(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; HKEY key; - const Py_UNICODE *sub_key; + const Py_UNICODE *sub_key = NULL; if (!_PyArg_CheckPositional("QueryValue", nargs, 2, 2)) { goto exit; @@ -1016,7 +1016,7 @@ winreg_QueryValueEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; HKEY key; - const Py_UNICODE *name; + const Py_UNICODE *name = NULL; if (!_PyArg_CheckPositional("QueryValueEx", nargs, 2, 2)) { goto exit; @@ -1084,7 +1084,7 @@ winreg_SaveKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; HKEY key; - const Py_UNICODE *file_name; + const Py_UNICODE *file_name = NULL; if (!_PyArg_CheckPositional("SaveKey", nargs, 2, 2)) { goto exit; @@ -1153,7 +1153,7 @@ winreg_SetValue(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; HKEY key; - const Py_UNICODE *sub_key; + const Py_UNICODE *sub_key = NULL; DWORD type; PyObject *value_obj; @@ -1228,7 +1228,7 @@ winreg_SetValueEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; HKEY key; - const Py_UNICODE *value_name; + const Py_UNICODE *value_name = NULL; PyObject *reserved; DWORD type; PyObject *value; @@ -1349,4 +1349,4 @@ winreg_QueryReflectionKey(PyObject *module, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=7ad1db69bc42cab4 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=e83bdaabb4fa2167 input=a9049054013a1b77]*/ diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index cd0446dc4f05..97d8d0a9410b 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -3522,6 +3522,7 @@ def converter_init(self, *, accept={str}, zeroes=False): self.converter = '_PyUnicode_WideCharString_Opt_Converter' else: fail("Py_UNICODE_converter: illegal 'accept' argument " + repr(accept)) + self.c_default = "NULL" def cleanup(self): if not self.length: From webhook-mailer at python.org Mon Oct 3 09:11:15 2022 From: webhook-mailer at python.org (jaraco) Date: Mon, 03 Oct 2022 13:11:15 -0000 Subject: [Python-checkins] [3.10] gh-96845: Fix docs around importlib.abc.Traversable (GH-97515) Message-ID: https://github.com/python/cpython/commit/bead571e6a2752d111f4995bcd4a0c2c3b19c6b6 commit: bead571e6a2752d111f4995bcd4a0c2c3b19c6b6 branch: 3.10 author: Jason R. Coombs committer: jaraco date: 2022-10-03T09:11:06-04:00 summary: [3.10] gh-96845: Fix docs around importlib.abc.Traversable (GH-97515) * [3.10] gh-96845: Correct reference to Traversable* classes. * [3.10] gh-96845: Add a note about the pending move of resources.abcs. files: M Doc/library/importlib.rst diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst index 3981cc6f2d96..1addba3fb47f 100644 --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -854,6 +854,8 @@ ABC hierarchy:: Read contents of self as text. + Note: In Python 3.11 and later, this class is found in ``importlib.resources.abc``. + .. class:: TraversableResources @@ -868,6 +870,8 @@ ABC hierarchy:: .. versionadded:: 3.9 + Note: In Python 3.11 and later, this class is found in ``importlib.resources.abc``. + :mod:`importlib.resources` -- Resources --------------------------------------- @@ -930,7 +934,7 @@ The following functions are available. .. function:: files(package) - Returns an :class:`importlib.resources.abc.Traversable` object + Returns an :class:`importlib.abc.Traversable` object representing the resource container for the package (think directory) and its resources (think files). A Traversable may contain other containers (think subdirectories). @@ -942,7 +946,7 @@ The following functions are available. .. function:: as_file(traversable) - Given a :class:`importlib.resources.abc.Traversable` object representing + Given a :class:`importlib.abc.Traversable` object representing a file, typically from :func:`importlib.resources.files`, return a context manager for use in a :keyword:`with` statement. The context manager provides a :class:`pathlib.Path` object. From webhook-mailer at python.org Mon Oct 3 09:35:50 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Mon, 03 Oct 2022 13:35:50 -0000 Subject: [Python-checkins] Fix typo in unittest docs (#97742) Message-ID: https://github.com/python/cpython/commit/e6f9ec5c031bd996fcd5f463c407beef0b743b49 commit: e6f9ec5c031bd996fcd5f463c407beef0b743b49 branch: main author: annonm committer: JelleZijlstra date: 2022-10-03T06:35:40-07:00 summary: Fix typo in unittest docs (#97742) files: M Doc/library/unittest.rst diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst index 38be6b82b492..7f48146ca830 100644 --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -1760,7 +1760,7 @@ Loading and running tests A list of the non-fatal errors encountered while loading tests. Not reset by the loader at any point. Fatal errors are signalled by the relevant - a method raising an exception to the caller. Non-fatal errors are also + method raising an exception to the caller. Non-fatal errors are also indicated by a synthetic test that will raise the original error when run. From webhook-mailer at python.org Mon Oct 3 09:42:53 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 03 Oct 2022 13:42:53 -0000 Subject: [Python-checkins] Fix typo in unittest docs (GH-97742) Message-ID: https://github.com/python/cpython/commit/e1cbb6f62fba1f87222a35f451b9765c77ba508e commit: e1cbb6f62fba1f87222a35f451b9765c77ba508e branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-03T06:42:42-07:00 summary: Fix typo in unittest docs (GH-97742) (cherry picked from commit e6f9ec5c031bd996fcd5f463c407beef0b743b49) Co-authored-by: annonm files: M Doc/library/unittest.rst diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst index 0c3fc31b93a9..fa4383b2d992 100644 --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -1738,7 +1738,7 @@ Loading and running tests A list of the non-fatal errors encountered while loading tests. Not reset by the loader at any point. Fatal errors are signalled by the relevant - a method raising an exception to the caller. Non-fatal errors are also + method raising an exception to the caller. Non-fatal errors are also indicated by a synthetic test that will raise the original error when run. From webhook-mailer at python.org Mon Oct 3 09:43:36 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 03 Oct 2022 13:43:36 -0000 Subject: [Python-checkins] Fix typo in unittest docs (GH-97742) Message-ID: https://github.com/python/cpython/commit/096e39637b74d669dea3132442eccb2d65e8b6da commit: 096e39637b74d669dea3132442eccb2d65e8b6da branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-03T06:43:31-07:00 summary: Fix typo in unittest docs (GH-97742) (cherry picked from commit e6f9ec5c031bd996fcd5f463c407beef0b743b49) Co-authored-by: annonm files: M Doc/library/unittest.rst diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst index 87571d896e11..42d17db3a3a2 100644 --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -1797,7 +1797,7 @@ Loading and running tests A list of the non-fatal errors encountered while loading tests. Not reset by the loader at any point. Fatal errors are signalled by the relevant - a method raising an exception to the caller. Non-fatal errors are also + method raising an exception to the caller. Non-fatal errors are also indicated by a synthetic test that will raise the original error when run. From webhook-mailer at python.org Mon Oct 3 09:59:34 2022 From: webhook-mailer at python.org (serhiy-storchaka) Date: Mon, 03 Oct 2022 13:59:34 -0000 Subject: [Python-checkins] [3.10] gh-97728: Argument Clinic: Fix uninitialized variable in the Py_UNICODE converter (GH-97729) (GH-97760) Message-ID: https://github.com/python/cpython/commit/769b9dccd2f796ffd0a75c1d088f2023c3ca28f7 commit: 769b9dccd2f796ffd0a75c1d088f2023c3ca28f7 branch: 3.10 author: Serhiy Storchaka committer: serhiy-storchaka date: 2022-10-03T16:59:21+03:00 summary: [3.10] gh-97728: Argument Clinic: Fix uninitialized variable in the Py_UNICODE converter (GH-97729) (GH-97760) It affects function os.system() on Windows and Windows-specific modules winreg, _winapi, _overlapped, and _msi. (cherry picked from commit 0ee9619a4cba58730c45e65d22288fadbf7680de) files: A Misc/NEWS.d/next/Windows/2022-10-02-11-59-23.gh-issue-97728.dIdlPE.rst M Lib/test/clinic.test M Modules/clinic/_winapi.c.h M Modules/clinic/overlapped.c.h M Modules/clinic/posixmodule.c.h M PC/clinic/_msi.c.h M PC/clinic/winreg.c.h M Tools/clinic/clinic.py diff --git a/Lib/test/clinic.test b/Lib/test/clinic.test index 0f5c651f214f..3a3fbd174d86 100644 --- a/Lib/test/clinic.test +++ b/Lib/test/clinic.test @@ -1805,12 +1805,12 @@ static PyObject * test_Py_UNICODE_converter(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - const Py_UNICODE *a; - const Py_UNICODE *b; - const Py_UNICODE *c; - const Py_UNICODE *d; + const Py_UNICODE *a = NULL; + const Py_UNICODE *b = NULL; + const Py_UNICODE *c = NULL; + const Py_UNICODE *d = NULL; Py_ssize_clean_t d_length; - const Py_UNICODE *e; + const Py_UNICODE *e = NULL; Py_ssize_clean_t e_length; if (!_PyArg_ParseStack(args, nargs, "O&O&O&u#Z#:test_Py_UNICODE_converter", @@ -1843,7 +1843,7 @@ test_Py_UNICODE_converter_impl(PyObject *module, const Py_UNICODE *a, Py_ssize_clean_t d_length, const Py_UNICODE *e, Py_ssize_clean_t e_length) -/*[clinic end generated code: output=ef45e982fedf0b3d input=064a3b68ad7f04b0]*/ +/*[clinic end generated code: output=e45007c49e77ad4a input=064a3b68ad7f04b0]*/ /*[clinic input] diff --git a/Misc/NEWS.d/next/Windows/2022-10-02-11-59-23.gh-issue-97728.dIdlPE.rst b/Misc/NEWS.d/next/Windows/2022-10-02-11-59-23.gh-issue-97728.dIdlPE.rst new file mode 100644 index 000000000000..2a6a253a52ae --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2022-10-02-11-59-23.gh-issue-97728.dIdlPE.rst @@ -0,0 +1,3 @@ +Fix possible crashes caused by the use of uninitialized variables when pass +invalid arguments in :func:`os.system` on Windows and in Windows-specific +modules (like ``winreg``). diff --git a/Modules/clinic/_winapi.c.h b/Modules/clinic/_winapi.c.h index ac73789d799c..f568357142d3 100644 --- a/Modules/clinic/_winapi.c.h +++ b/Modules/clinic/_winapi.c.h @@ -192,7 +192,7 @@ _winapi_CreateFileMapping(PyObject *module, PyObject *const *args, Py_ssize_t na DWORD protect; DWORD max_size_high; DWORD max_size_low; - LPCWSTR name; + LPCWSTR name = NULL; HANDLE _return_value; if (!_PyArg_ParseStack(args, nargs, "" F_HANDLE "" F_POINTER "kkkO&:CreateFileMapping", @@ -233,8 +233,8 @@ static PyObject * _winapi_CreateJunction(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - LPCWSTR src_path; - LPCWSTR dst_path; + LPCWSTR src_path = NULL; + LPCWSTR dst_path = NULL; if (!_PyArg_CheckPositional("CreateJunction", nargs, 2, 2)) { goto exit; @@ -394,14 +394,14 @@ static PyObject * _winapi_CreateProcess(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - const Py_UNICODE *application_name; + const Py_UNICODE *application_name = NULL; PyObject *command_line; PyObject *proc_attrs; PyObject *thread_attrs; BOOL inherit_handles; DWORD creation_flags; PyObject *env_mapping; - const Py_UNICODE *current_directory; + const Py_UNICODE *current_directory = NULL; PyObject *startup_info; if (!_PyArg_ParseStack(args, nargs, "O&OOOikOO&O:CreateProcess", @@ -749,7 +749,7 @@ _winapi_OpenFileMapping(PyObject *module, PyObject *const *args, Py_ssize_t narg PyObject *return_value = NULL; DWORD desired_access; BOOL inherit_handle; - LPCWSTR name; + LPCWSTR name = NULL; HANDLE _return_value; if (!_PyArg_ParseStack(args, nargs, "kiO&:OpenFileMapping", @@ -1216,4 +1216,4 @@ _winapi__mimetypes_read_windows_registry(PyObject *module, PyObject *const *args exit: return return_value; } -/*[clinic end generated code: output=8e13179bf25bdea5 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=d76d0a5901db2e2a input=a9049054013a1b77]*/ diff --git a/Modules/clinic/overlapped.c.h b/Modules/clinic/overlapped.c.h index efecd9028b77..43e14a9724b0 100644 --- a/Modules/clinic/overlapped.c.h +++ b/Modules/clinic/overlapped.c.h @@ -220,7 +220,7 @@ _overlapped_CreateEvent(PyObject *module, PyObject *const *args, Py_ssize_t narg PyObject *EventAttributes; BOOL ManualReset; BOOL InitialState; - const Py_UNICODE *Name; + const Py_UNICODE *Name = NULL; if (!_PyArg_ParseStack(args, nargs, "OiiO&:CreateEvent", &EventAttributes, &ManualReset, &InitialState, _PyUnicode_WideCharString_Opt_Converter, &Name)) { @@ -786,7 +786,7 @@ static PyObject * _overlapped_Overlapped_ConnectPipe(OverlappedObject *self, PyObject *arg) { PyObject *return_value = NULL; - const Py_UNICODE *Address; + const Py_UNICODE *Address = NULL; if (!PyUnicode_Check(arg)) { _PyArg_BadArgument("ConnectPipe", "argument", "str", arg); @@ -905,4 +905,4 @@ _overlapped_Overlapped_WSARecvFrom(OverlappedObject *self, PyObject *const *args exit: return return_value; } -/*[clinic end generated code: output=ee2ec2f93c8d334b input=a9049054013a1b77]*/ +/*[clinic end generated code: output=d3215a6ca589735a input=a9049054013a1b77]*/ diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h index a3d06328c903..1c3e9bc6d613 100644 --- a/Modules/clinic/posixmodule.c.h +++ b/Modules/clinic/posixmodule.c.h @@ -1717,7 +1717,7 @@ os_system(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *k static const char * const _keywords[] = {"command", NULL}; static _PyArg_Parser _parser = {NULL, _keywords, "system", 0}; PyObject *argsbuf[1]; - const Py_UNICODE *command; + const Py_UNICODE *command = NULL; long _return_value; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); @@ -9291,4 +9291,4 @@ os_waitstatus_to_exitcode(PyObject *module, PyObject *const *args, Py_ssize_t na #ifndef OS_WAITSTATUS_TO_EXITCODE_METHODDEF #define OS_WAITSTATUS_TO_EXITCODE_METHODDEF #endif /* !defined(OS_WAITSTATUS_TO_EXITCODE_METHODDEF) */ -/*[clinic end generated code: output=73be33fa0000a6d1 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=ddc35c3177c3b3ed input=a9049054013a1b77]*/ diff --git a/PC/clinic/_msi.c.h b/PC/clinic/_msi.c.h index 85c4d226ee40..4b82a1b14e9a 100644 --- a/PC/clinic/_msi.c.h +++ b/PC/clinic/_msi.c.h @@ -195,7 +195,7 @@ _msi_Record_SetString(msiobj *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int field; - const Py_UNICODE *value; + const Py_UNICODE *value = NULL; if (!_PyArg_CheckPositional("SetString", nargs, 2, 2)) { goto exit; @@ -244,7 +244,7 @@ _msi_Record_SetStream(msiobj *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int field; - const Py_UNICODE *value; + const Py_UNICODE *value = NULL; if (!_PyArg_CheckPositional("SetStream", nargs, 2, 2)) { goto exit; @@ -555,7 +555,7 @@ static PyObject * _msi_Database_OpenView(msiobj *self, PyObject *arg) { PyObject *return_value = NULL; - const Py_UNICODE *sql; + const Py_UNICODE *sql = NULL; if (!PyUnicode_Check(arg)) { _PyArg_BadArgument("OpenView", "argument", "str", arg); @@ -650,7 +650,7 @@ static PyObject * _msi_OpenDatabase(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - const Py_UNICODE *path; + const Py_UNICODE *path = NULL; int persist; if (!_PyArg_CheckPositional("OpenDatabase", nargs, 2, 2)) { @@ -713,4 +713,4 @@ _msi_CreateRecord(PyObject *module, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=49debf733ee5cab2 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=19b24ee4e6420dcd input=a9049054013a1b77]*/ diff --git a/PC/clinic/winreg.c.h b/PC/clinic/winreg.c.h index 3051bcccf0db..91f27f2d5ffa 100644 --- a/PC/clinic/winreg.c.h +++ b/PC/clinic/winreg.c.h @@ -148,7 +148,7 @@ static PyObject * winreg_ConnectRegistry(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - const Py_UNICODE *computer_name; + const Py_UNICODE *computer_name = NULL; HKEY key; HKEY _return_value; @@ -220,7 +220,7 @@ winreg_CreateKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; HKEY key; - const Py_UNICODE *sub_key; + const Py_UNICODE *sub_key = NULL; HKEY _return_value; if (!_PyArg_CheckPositional("CreateKey", nargs, 2, 2)) { @@ -301,7 +301,7 @@ winreg_CreateKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py static const char * const _keywords[] = {"key", "sub_key", "reserved", "access", NULL}; static _PyArg_Parser _parser = {"O&O&|ii:CreateKeyEx", _keywords, 0}; HKEY key; - const Py_UNICODE *sub_key; + const Py_UNICODE *sub_key = NULL; int reserved = 0; REGSAM access = KEY_WRITE; HKEY _return_value; @@ -354,7 +354,7 @@ winreg_DeleteKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; HKEY key; - const Py_UNICODE *sub_key; + const Py_UNICODE *sub_key = NULL; if (!_PyArg_CheckPositional("DeleteKey", nargs, 2, 2)) { goto exit; @@ -428,7 +428,7 @@ winreg_DeleteKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py static const char * const _keywords[] = {"key", "sub_key", "access", "reserved", NULL}; static _PyArg_Parser _parser = {"O&O&|ii:DeleteKeyEx", _keywords, 0}; HKEY key; - const Py_UNICODE *sub_key; + const Py_UNICODE *sub_key = NULL; REGSAM access = KEY_WOW64_64KEY; int reserved = 0; @@ -469,7 +469,7 @@ winreg_DeleteValue(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; HKEY key; - const Py_UNICODE *value; + const Py_UNICODE *value = NULL; if (!_PyArg_CheckPositional("DeleteValue", nargs, 2, 2)) { goto exit; @@ -619,7 +619,7 @@ static PyObject * winreg_ExpandEnvironmentStrings(PyObject *module, PyObject *arg) { PyObject *return_value = NULL; - const Py_UNICODE *string; + const Py_UNICODE *string = NULL; if (!PyUnicode_Check(arg)) { _PyArg_BadArgument("ExpandEnvironmentStrings", "argument", "str", arg); @@ -724,8 +724,8 @@ winreg_LoadKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; HKEY key; - const Py_UNICODE *sub_key; - const Py_UNICODE *file_name; + const Py_UNICODE *sub_key = NULL; + const Py_UNICODE *file_name = NULL; if (!_PyArg_CheckPositional("LoadKey", nargs, 3, 3)) { goto exit; @@ -805,7 +805,7 @@ winreg_OpenKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObje static const char * const _keywords[] = {"key", "sub_key", "reserved", "access", NULL}; static _PyArg_Parser _parser = {"O&O&|ii:OpenKey", _keywords, 0}; HKEY key; - const Py_UNICODE *sub_key; + const Py_UNICODE *sub_key = NULL; int reserved = 0; REGSAM access = KEY_READ; HKEY _return_value; @@ -862,7 +862,7 @@ winreg_OpenKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyOb static const char * const _keywords[] = {"key", "sub_key", "reserved", "access", NULL}; static _PyArg_Parser _parser = {"O&O&|ii:OpenKeyEx", _keywords, 0}; HKEY key; - const Py_UNICODE *sub_key; + const Py_UNICODE *sub_key = NULL; int reserved = 0; REGSAM access = KEY_READ; HKEY _return_value; @@ -953,7 +953,7 @@ winreg_QueryValue(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; HKEY key; - const Py_UNICODE *sub_key; + const Py_UNICODE *sub_key = NULL; if (!_PyArg_CheckPositional("QueryValue", nargs, 2, 2)) { goto exit; @@ -1016,7 +1016,7 @@ winreg_QueryValueEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; HKEY key; - const Py_UNICODE *name; + const Py_UNICODE *name = NULL; if (!_PyArg_CheckPositional("QueryValueEx", nargs, 2, 2)) { goto exit; @@ -1084,7 +1084,7 @@ winreg_SaveKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; HKEY key; - const Py_UNICODE *file_name; + const Py_UNICODE *file_name = NULL; if (!_PyArg_CheckPositional("SaveKey", nargs, 2, 2)) { goto exit; @@ -1153,7 +1153,7 @@ winreg_SetValue(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; HKEY key; - const Py_UNICODE *sub_key; + const Py_UNICODE *sub_key = NULL; DWORD type; PyObject *value_obj; @@ -1228,7 +1228,7 @@ winreg_SetValueEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; HKEY key; - const Py_UNICODE *value_name; + const Py_UNICODE *value_name = NULL; PyObject *reserved; DWORD type; PyObject *value; @@ -1349,4 +1349,4 @@ winreg_QueryReflectionKey(PyObject *module, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=8ce6fb3b6cd46242 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=1c96481d6be5c0d8 input=a9049054013a1b77]*/ diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 1ad9807862cd..1a59fa57ac41 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -3449,6 +3449,7 @@ def converter_init(self, *, accept={str}, zeroes=False): self.converter = '_PyUnicode_WideCharString_Opt_Converter' else: fail("Py_UNICODE_converter: illegal 'accept' argument " + repr(accept)) + self.c_default = "NULL" def cleanup(self): if not self.length: From webhook-mailer at python.org Mon Oct 3 11:09:13 2022 From: webhook-mailer at python.org (vstinner) Date: Mon, 03 Oct 2022 15:09:13 -0000 Subject: [Python-checkins] gh-97681: Remove Tools/demo/ directory (#97682) Message-ID: https://github.com/python/cpython/commit/64fe34371722d90448e0d1a0c04e7ed106f5f70a commit: 64fe34371722d90448e0d1a0c04e7ed106f5f70a branch: main author: Victor Stinner committer: vstinner date: 2022-10-03T17:09:02+02:00 summary: gh-97681: Remove Tools/demo/ directory (#97682) Remove the Tools/demo/ directory which contained old demo scripts. A copy can be found in the old-demos project: https://github.com/gvanrossum/old-demos Remove the following old demo scripts: * beer.py * eiffel.py * hanoi.py * life.py * markov.py * mcast.py * queens.py * redemo.py * rpython.py * rpythond.py * sortvisu.py * spreadsheet.py * vector.py Changes: * Remove a reference to the redemo.py script in the regex howto documentation. * Remove a reference to the removed Tools/demo/ directory in the curses documentation. * Update PC/layout/ to remove the reference to Tools/demo/ directory. files: A Misc/NEWS.d/next/Tools-Demos/2022-09-30-18-35-11.gh-issue-97681.-KO1Ba.rst D Tools/demo/README D Tools/demo/beer.py D Tools/demo/eiffel.py D Tools/demo/hanoi.py D Tools/demo/life.py D Tools/demo/markov.py D Tools/demo/mcast.py D Tools/demo/queens.py D Tools/demo/redemo.py D Tools/demo/rpython.py D Tools/demo/rpythond.py D Tools/demo/sortvisu.py D Tools/demo/spreadsheet.py D Tools/demo/vector.py M Doc/howto/regex.rst M Doc/library/curses.rst M Doc/whatsnew/3.12.rst M PC/layout/main.py M Tools/README diff --git a/Doc/howto/regex.rst b/Doc/howto/regex.rst index 5cd6140f19ca..655df59e27b6 100644 --- a/Doc/howto/regex.rst +++ b/Doc/howto/regex.rst @@ -378,11 +378,7 @@ containing information about the match: where it starts and ends, the substring it matched, and more. You can learn about this by interactively experimenting with the :mod:`re` -module. If you have :mod:`tkinter` available, you may also want to look at -:source:`Tools/demo/redemo.py`, a demonstration program included with the -Python distribution. It allows you to enter REs and strings, and displays -whether the RE matches or fails. :file:`redemo.py` can be quite useful when -trying to debug a complicated RE. +module. This HOWTO uses the standard Python interpreter for its examples. First, run the Python interpreter, import the :mod:`re` module, and compile a RE:: diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst index a7cc49527780..bb203c48f19f 100644 --- a/Doc/library/curses.rst +++ b/Doc/library/curses.rst @@ -42,9 +42,6 @@ Linux and the BSD variants of Unix. Tutorial material on using curses with Python, by Andrew Kuchling and Eric Raymond. - The :source:`Tools/demo/` directory in the Python source distribution contains - some example programs using the curses bindings provided by this module. - .. _curses-functions: diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index e14a2bd0133b..1d68e84983fe 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -170,6 +170,15 @@ CPython bytecode changes (Contributed by Ken Jin in :gh:`93429`.) +Demos and Tools +=============== + +* Remove the ``Tools/demo/`` directory which contained old demo scripts. A copy + can be found in the `old-demos project + `_. + (Contributed by Victor Stinner in :gh:`97681`.) + + Deprecated ========== diff --git a/Misc/NEWS.d/next/Tools-Demos/2022-09-30-18-35-11.gh-issue-97681.-KO1Ba.rst b/Misc/NEWS.d/next/Tools-Demos/2022-09-30-18-35-11.gh-issue-97681.-KO1Ba.rst new file mode 100644 index 000000000000..6f1ec12ce0c3 --- /dev/null +++ b/Misc/NEWS.d/next/Tools-Demos/2022-09-30-18-35-11.gh-issue-97681.-KO1Ba.rst @@ -0,0 +1,3 @@ +Remove the ``Tools/demo/`` directory which contained old demo scripts. A copy +can be found in the `old-demos project +`_. Patch by Victor Stinner. diff --git a/PC/layout/main.py b/PC/layout/main.py index 923483ad4a3f..17d27bba6640 100644 --- a/PC/layout/main.py +++ b/PC/layout/main.py @@ -58,7 +58,7 @@ DATA_DIRS = FileNameSet("data") -TOOLS_DIRS = FileNameSet("scripts", "i18n", "demo", "parser") +TOOLS_DIRS = FileNameSet("scripts", "i18n", "parser") TOOLS_FILES = FileSuffixSet(".py", ".pyw", ".txt") diff --git a/Tools/README b/Tools/README index f8bfbc047958..04612b8013db 100644 --- a/Tools/README +++ b/Tools/README @@ -5,8 +5,6 @@ buildbot Batchfiles for running on Windows buildbot workers. ccbench A Python threads-based concurrency benchmark. (*) -demo Several Python programming demos. - freeze Create a stand-alone executable from a Python program. gdb Python code to be run inside gdb, to make it easier to diff --git a/Tools/demo/README b/Tools/demo/README deleted file mode 100644 index 9fccb97d956c..000000000000 --- a/Tools/demo/README +++ /dev/null @@ -1,16 +0,0 @@ -This directory contains a collection of demonstration scripts for -various aspects of Python programming. - -beer.py Well-known programming example: Bottles of beer. -eiffel.py Python advanced magic: A metaclass for Eiffel post/preconditions. -hanoi.py Well-known programming example: Towers of Hanoi. -life.py Curses programming: Simple game-of-life. -markov.py Algorithms: Markov chain simulation. -mcast.py Network programming: Send and receive UDP multicast packets. -queens.py Well-known programming example: N-Queens problem. -redemo.py Regular Expressions: GUI script to test regexes. -rpython.py Network programming: Small client for remote code execution. -rpythond.py Network programming: Small server for remote code execution. -sortvisu.py GUI programming: Visualization of different sort algorithms. -spreadsheet.py GUI/Application programming: A simple spreadsheet application. -vector.py Python basics: A vector class demonstrating special methods. diff --git a/Tools/demo/beer.py b/Tools/demo/beer.py deleted file mode 100755 index af58380e0f5a..000000000000 --- a/Tools/demo/beer.py +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env python3 - -""" -A Python version of the classic "bottles of beer on the wall" programming -example. - -By Guido van Rossum, demystified after a version by Fredrik Lundh. -""" - -import sys - -n = 100 -if sys.argv[1:]: - n = int(sys.argv[1]) - -def bottle(n): - if n == 0: return "no more bottles of beer" - if n == 1: return "one bottle of beer" - return str(n) + " bottles of beer" - -for i in range(n, 0, -1): - print(bottle(i), "on the wall,") - print(bottle(i) + ".") - print("Take one down, pass it around,") - print(bottle(i-1), "on the wall.") diff --git a/Tools/demo/eiffel.py b/Tools/demo/eiffel.py deleted file mode 100755 index a76c2324dd6a..000000000000 --- a/Tools/demo/eiffel.py +++ /dev/null @@ -1,146 +0,0 @@ -#!/usr/bin/env python3 - -""" -Support Eiffel-style preconditions and postconditions for functions. - -An example for Python metaclasses. -""" - -import unittest -from types import FunctionType as function - -class EiffelBaseMetaClass(type): - - def __new__(meta, name, bases, dict): - meta.convert_methods(dict) - return super(EiffelBaseMetaClass, meta).__new__( - meta, name, bases, dict) - - @classmethod - def convert_methods(cls, dict): - """Replace functions in dict with EiffelMethod wrappers. - - The dict is modified in place. - - If a method ends in _pre or _post, it is removed from the dict - regardless of whether there is a corresponding method. - """ - # find methods with pre or post conditions - methods = [] - for k, v in dict.items(): - if k.endswith('_pre') or k.endswith('_post'): - assert isinstance(v, function) - elif isinstance(v, function): - methods.append(k) - for m in methods: - pre = dict.get("%s_pre" % m) - post = dict.get("%s_post" % m) - if pre or post: - dict[m] = cls.make_eiffel_method(dict[m], pre, post) - - -class EiffelMetaClass1(EiffelBaseMetaClass): - # an implementation of the "eiffel" meta class that uses nested functions - - @staticmethod - def make_eiffel_method(func, pre, post): - def method(self, *args, **kwargs): - if pre: - pre(self, *args, **kwargs) - rv = func(self, *args, **kwargs) - if post: - post(self, rv, *args, **kwargs) - return rv - - if func.__doc__: - method.__doc__ = func.__doc__ - - return method - - -class EiffelMethodWrapper: - - def __init__(self, inst, descr): - self._inst = inst - self._descr = descr - - def __call__(self, *args, **kwargs): - return self._descr.callmethod(self._inst, args, kwargs) - - -class EiffelDescriptor: - - def __init__(self, func, pre, post): - self._func = func - self._pre = pre - self._post = post - - self.__name__ = func.__name__ - self.__doc__ = func.__doc__ - - def __get__(self, obj, cls=None): - return EiffelMethodWrapper(obj, self) - - def callmethod(self, inst, args, kwargs): - if self._pre: - self._pre(inst, *args, **kwargs) - x = self._func(inst, *args, **kwargs) - if self._post: - self._post(inst, x, *args, **kwargs) - return x - - -class EiffelMetaClass2(EiffelBaseMetaClass): - # an implementation of the "eiffel" meta class that uses descriptors - - make_eiffel_method = EiffelDescriptor - - -class Tests(unittest.TestCase): - - def testEiffelMetaClass1(self): - self._test(EiffelMetaClass1) - - def testEiffelMetaClass2(self): - self._test(EiffelMetaClass2) - - def _test(self, metaclass): - class Eiffel(metaclass=metaclass): - pass - - class Test(Eiffel): - def m(self, arg): - """Make it a little larger""" - return arg + 1 - - def m2(self, arg): - """Make it a little larger""" - return arg + 1 - - def m2_pre(self, arg): - assert arg > 0 - - def m2_post(self, result, arg): - assert result > arg - - class Sub(Test): - def m2(self, arg): - return arg**2 - - def m2_post(self, Result, arg): - super(Sub, self).m2_post(Result, arg) - assert Result < 100 - - t = Test() - self.assertEqual(t.m(1), 2) - self.assertEqual(t.m2(1), 2) - self.assertRaises(AssertionError, t.m2, 0) - - s = Sub() - self.assertRaises(AssertionError, s.m2, 1) - self.assertRaises(AssertionError, s.m2, 10) - self.assertEqual(s.m2(5), 25) - - -if __name__ == "__main__": - unittest.main() diff --git a/Tools/demo/hanoi.py b/Tools/demo/hanoi.py deleted file mode 100755 index 8db895c24458..000000000000 --- a/Tools/demo/hanoi.py +++ /dev/null @@ -1,154 +0,0 @@ -#!/usr/bin/env python3 - -""" -Animated Towers of Hanoi using Tk with optional bitmap file in background. - -Usage: hanoi.py [n [bitmapfile]] - -n is the number of pieces to animate; default is 4, maximum 15. - -The bitmap file can be any X11 bitmap file (look in /usr/include/X11/bitmaps for -samples); it is displayed as the background of the animation. Default is no -bitmap. -""" - -from tkinter import Tk, Canvas - -# Basic Towers-of-Hanoi algorithm: move n pieces from a to b, using c -# as temporary. For each move, call report() -def hanoi(n, a, b, c, report): - if n <= 0: return - hanoi(n-1, a, c, b, report) - report(n, a, b) - hanoi(n-1, c, b, a, report) - - -# The graphical interface -class Tkhanoi: - - # Create our objects - def __init__(self, n, bitmap=None): - self.n = n - self.tk = tk = Tk() - self.canvas = c = Canvas(tk) - c.pack() - width, height = tk.getint(c['width']), tk.getint(c['height']) - - # Add background bitmap - if bitmap: - self.bitmap = c.create_bitmap(width//2, height//2, - bitmap=bitmap, - foreground='blue') - - # Generate pegs - pegwidth = 10 - pegheight = height//2 - pegdist = width//3 - x1, y1 = (pegdist-pegwidth)//2, height*1//3 - x2, y2 = x1+pegwidth, y1+pegheight - self.pegs = [] - p = c.create_rectangle(x1, y1, x2, y2, fill='black') - self.pegs.append(p) - x1, x2 = x1+pegdist, x2+pegdist - p = c.create_rectangle(x1, y1, x2, y2, fill='black') - self.pegs.append(p) - x1, x2 = x1+pegdist, x2+pegdist - p = c.create_rectangle(x1, y1, x2, y2, fill='black') - self.pegs.append(p) - self.tk.update() - - # Generate pieces - pieceheight = pegheight//16 - maxpiecewidth = pegdist*2//3 - minpiecewidth = 2*pegwidth - self.pegstate = [[], [], []] - self.pieces = {} - x1, y1 = (pegdist-maxpiecewidth)//2, y2-pieceheight-2 - x2, y2 = x1+maxpiecewidth, y1+pieceheight - dx = (maxpiecewidth-minpiecewidth) // (2*max(1, n-1)) - for i in range(n, 0, -1): - p = c.create_rectangle(x1, y1, x2, y2, fill='red') - self.pieces[i] = p - self.pegstate[0].append(i) - x1, x2 = x1 + dx, x2-dx - y1, y2 = y1 - pieceheight-2, y2-pieceheight-2 - self.tk.update() - self.tk.after(25) - - # Run -- never returns - def run(self): - while True: - hanoi(self.n, 0, 1, 2, self.report) - hanoi(self.n, 1, 2, 0, self.report) - hanoi(self.n, 2, 0, 1, self.report) - hanoi(self.n, 0, 2, 1, self.report) - hanoi(self.n, 2, 1, 0, self.report) - hanoi(self.n, 1, 0, 2, self.report) - - # Reporting callback for the actual hanoi function - def report(self, i, a, b): - if self.pegstate[a][-1] != i: raise RuntimeError # Assertion - del self.pegstate[a][-1] - p = self.pieces[i] - c = self.canvas - - # Lift the piece above peg a - ax1, ay1, ax2, ay2 = c.bbox(self.pegs[a]) - while True: - x1, y1, x2, y2 = c.bbox(p) - if y2 < ay1: break - c.move(p, 0, -1) - self.tk.update() - - # Move it towards peg b - bx1, by1, bx2, by2 = c.bbox(self.pegs[b]) - newcenter = (bx1+bx2)//2 - while True: - x1, y1, x2, y2 = c.bbox(p) - center = (x1+x2)//2 - if center == newcenter: break - if center > newcenter: c.move(p, -1, 0) - else: c.move(p, 1, 0) - self.tk.update() - - # Move it down on top of the previous piece - pieceheight = y2-y1 - newbottom = by2 - pieceheight*len(self.pegstate[b]) - 2 - while True: - x1, y1, x2, y2 = c.bbox(p) - if y2 >= newbottom: break - c.move(p, 0, 1) - self.tk.update() - - # Update peg state - self.pegstate[b].append(i) - - -def main(): - import sys - - # First argument is number of pegs, default 4 - if sys.argv[1:]: - n = int(sys.argv[1]) - else: - n = 4 - - # Second argument is bitmap file, default none - if sys.argv[2:]: - bitmap = sys.argv[2] - # Reverse meaning of leading '@' compared to Tk - if bitmap[0] == '@': bitmap = bitmap[1:] - else: bitmap = '@' + bitmap - else: - bitmap = None - - # Create the graphical objects... - h = Tkhanoi(n, bitmap) - - # ...and run! - h.run() - - -# Call main when run as script -if __name__ == '__main__': - main() diff --git a/Tools/demo/life.py b/Tools/demo/life.py deleted file mode 100755 index fc4cb4952dce..000000000000 --- a/Tools/demo/life.py +++ /dev/null @@ -1,262 +0,0 @@ -#!/usr/bin/env python3 - -""" -A curses-based version of Conway's Game of Life. - -An empty board will be displayed, and the following commands are available: - E : Erase the board - R : Fill the board randomly - S : Step for a single generation - C : Update continuously until a key is struck - Q : Quit - Cursor keys : Move the cursor around the board - Space or Enter : Toggle the contents of the cursor's position - -Contributed by Andrew Kuchling, Mouse support and color by Dafydd Crosby. -""" - -import curses -import random - - -class LifeBoard: - """Encapsulates a Life board - - Attributes: - X,Y : horizontal and vertical size of the board - state : dictionary mapping (x,y) to 0 or 1 - - Methods: - display(update_board) -- If update_board is true, compute the - next generation. Then display the state - of the board and refresh the screen. - erase() -- clear the entire board - make_random() -- fill the board randomly - set(y,x) -- set the given cell to Live; doesn't refresh the screen - toggle(y,x) -- change the given cell from live to dead, or vice - versa, and refresh the screen display - - """ - def __init__(self, scr, char=ord('*')): - """Create a new LifeBoard instance. - - scr -- curses screen object to use for display - char -- character used to render live cells (default: '*') - """ - self.state = {} - self.scr = scr - Y, X = self.scr.getmaxyx() - self.X, self.Y = X - 2, Y - 2 - 1 - self.char = char - self.scr.clear() - - # Draw a border around the board - border_line = '+' + (self.X * '-') + '+' - self.scr.addstr(0, 0, border_line) - self.scr.addstr(self.Y + 1, 0, border_line) - for y in range(0, self.Y): - self.scr.addstr(1 + y, 0, '|') - self.scr.addstr(1 + y, self.X + 1, '|') - self.scr.refresh() - - def set(self, y, x): - """Set a cell to the live state""" - if x < 0 or self.X <= x or y < 0 or self.Y <= y: - raise ValueError("Coordinates out of range %i,%i" % (y, x)) - self.state[x, y] = 1 - - def toggle(self, y, x): - """Toggle a cell's state between live and dead""" - if x < 0 or self.X <= x or y < 0 or self.Y <= y: - raise ValueError("Coordinates out of range %i,%i" % (y, x)) - if (x, y) in self.state: - del self.state[x, y] - self.scr.addch(y + 1, x + 1, ' ') - else: - self.state[x, y] = 1 - if curses.has_colors(): - # Let's pick a random color! - self.scr.attrset(curses.color_pair(random.randrange(1, 7))) - self.scr.addch(y + 1, x + 1, self.char) - self.scr.attrset(0) - self.scr.refresh() - - def erase(self): - """Clear the entire board and update the board display""" - self.state = {} - self.display(update_board=False) - - def display(self, update_board=True): - """Display the whole board, optionally computing one generation""" - M, N = self.X, self.Y - if not update_board: - for i in range(0, M): - for j in range(0, N): - if (i, j) in self.state: - self.scr.addch(j + 1, i + 1, self.char) - else: - self.scr.addch(j + 1, i + 1, ' ') - self.scr.refresh() - return - - d = {} - self.boring = 1 - for i in range(0, M): - L = range(max(0, i - 1), min(M, i + 2)) - for j in range(0, N): - s = 0 - live = (i, j) in self.state - for k in range(max(0, j - 1), min(N, j + 2)): - for l in L: - if (l, k) in self.state: - s += 1 - s -= live - if s == 3: - # Birth - d[i, j] = 1 - if curses.has_colors(): - # Let's pick a random color! - self.scr.attrset(curses.color_pair( - random.randrange(1, 7))) - self.scr.addch(j + 1, i + 1, self.char) - self.scr.attrset(0) - if not live: - self.boring = 0 - elif s == 2 and live: - # Survival - d[i, j] = 1 - elif live: - # Death - self.scr.addch(j + 1, i + 1, ' ') - self.boring = 0 - self.state = d - self.scr.refresh() - - def make_random(self): - "Fill the board with a random pattern" - self.state = {} - for i in range(0, self.X): - for j in range(0, self.Y): - if random.random() > 0.5: - self.set(j, i) - - -def erase_menu(stdscr, menu_y): - "Clear the space where the menu resides" - stdscr.move(menu_y, 0) - stdscr.clrtoeol() - stdscr.move(menu_y + 1, 0) - stdscr.clrtoeol() - - -def display_menu(stdscr, menu_y): - "Display the menu of possible keystroke commands" - erase_menu(stdscr, menu_y) - - # If color, then light the menu up :-) - if curses.has_colors(): - stdscr.attrset(curses.color_pair(1)) - stdscr.addstr(menu_y, 4, - 'Use the cursor keys to move, and space or Enter to toggle a cell.') - stdscr.addstr(menu_y + 1, 4, - 'E)rase the board, R)andom fill, S)tep once or C)ontinuously, Q)uit') - stdscr.attrset(0) - - -def keyloop(stdscr): - # Clear the screen and display the menu of keys - stdscr.clear() - stdscr_y, stdscr_x = stdscr.getmaxyx() - menu_y = (stdscr_y - 3) - 1 - display_menu(stdscr, menu_y) - - # If color, then initialize the color pairs - if curses.has_colors(): - curses.init_pair(1, curses.COLOR_BLUE, 0) - curses.init_pair(2, curses.COLOR_CYAN, 0) - curses.init_pair(3, curses.COLOR_GREEN, 0) - curses.init_pair(4, curses.COLOR_MAGENTA, 0) - curses.init_pair(5, curses.COLOR_RED, 0) - curses.init_pair(6, curses.COLOR_YELLOW, 0) - curses.init_pair(7, curses.COLOR_WHITE, 0) - - # Set up the mask to listen for mouse events - curses.mousemask(curses.BUTTON1_CLICKED) - - # Allocate a subwindow for the Life board and create the board object - subwin = stdscr.subwin(stdscr_y - 3, stdscr_x, 0, 0) - board = LifeBoard(subwin, char=ord('*')) - board.display(update_board=False) - - # xpos, ypos are the cursor's position - xpos, ypos = board.X // 2, board.Y // 2 - - # Main loop: - while True: - stdscr.move(1 + ypos, 1 + xpos) # Move the cursor - c = stdscr.getch() # Get a keystroke - if 0 < c < 256: - c = chr(c) - if c in ' \n': - board.toggle(ypos, xpos) - elif c in 'Cc': - erase_menu(stdscr, menu_y) - stdscr.addstr(menu_y, 6, ' Hit any key to stop continuously ' - 'updating the screen.') - stdscr.refresh() - # Activate nodelay mode; getch() will return -1 - # if no keystroke is available, instead of waiting. - stdscr.nodelay(1) - while True: - c = stdscr.getch() - if c != -1: - break - stdscr.addstr(0, 0, '/') - stdscr.refresh() - board.display() - stdscr.addstr(0, 0, '+') - stdscr.refresh() - - stdscr.nodelay(0) # Disable nodelay mode - display_menu(stdscr, menu_y) - - elif c in 'Ee': - board.erase() - elif c in 'Qq': - break - elif c in 'Rr': - board.make_random() - board.display(update_board=False) - elif c in 'Ss': - board.display() - else: - # Ignore incorrect keys - pass - elif c == curses.KEY_UP and ypos > 0: - ypos -= 1 - elif c == curses.KEY_DOWN and ypos + 1 < board.Y: - ypos += 1 - elif c == curses.KEY_LEFT and xpos > 0: - xpos -= 1 - elif c == curses.KEY_RIGHT and xpos + 1 < board.X: - xpos += 1 - elif c == curses.KEY_MOUSE: - mouse_id, mouse_x, mouse_y, mouse_z, button_state = curses.getmouse() - if (mouse_x > 0 and mouse_x < board.X + 1 and - mouse_y > 0 and mouse_y < board.Y + 1): - xpos = mouse_x - 1 - ypos = mouse_y - 1 - board.toggle(ypos, xpos) - else: - # They've clicked outside the board - curses.flash() - else: - # Ignore incorrect keys - pass - - -def main(stdscr): - keyloop(stdscr) # Enter the main loop - -if __name__ == '__main__': - curses.wrapper(main) diff --git a/Tools/demo/markov.py b/Tools/demo/markov.py deleted file mode 100755 index 9729f3820fa0..000000000000 --- a/Tools/demo/markov.py +++ /dev/null @@ -1,125 +0,0 @@ -#!/usr/bin/env python3 - -""" -Markov chain simulation of words or characters. -""" - -class Markov: - def __init__(self, histsize, choice): - self.histsize = histsize - self.choice = choice - self.trans = {} - - def add(self, state, next): - self.trans.setdefault(state, []).append(next) - - def put(self, seq): - n = self.histsize - add = self.add - add(None, seq[:0]) - for i in range(len(seq)): - add(seq[max(0, i-n):i], seq[i:i+1]) - add(seq[len(seq)-n:], None) - - def get(self): - choice = self.choice - trans = self.trans - n = self.histsize - seq = choice(trans[None]) - while True: - subseq = seq[max(0, len(seq)-n):] - options = trans[subseq] - next = choice(options) - if not next: - break - seq += next - return seq - - -def test(): - import sys, random, getopt - args = sys.argv[1:] - try: - opts, args = getopt.getopt(args, '0123456789cdwq') - except getopt.error: - print('Usage: %s [-#] [-cddqw] [file] ...' % sys.argv[0]) - print('Options:') - print('-#: 1-digit history size (default 2)') - print('-c: characters (default)') - print('-w: words') - print('-d: more debugging output') - print('-q: no debugging output') - print('Input files (default stdin) are split in paragraphs') - print('separated blank lines and each paragraph is split') - print('in words by whitespace, then reconcatenated with') - print('exactly one space separating words.') - print('Output consists of paragraphs separated by blank') - print('lines, where lines are no longer than 72 characters.') - sys.exit(2) - histsize = 2 - do_words = False - debug = 1 - for o, a in opts: - if '-0' <= o <= '-9': histsize = int(o[1:]) - if o == '-c': do_words = False - if o == '-d': debug += 1 - if o == '-q': debug = 0 - if o == '-w': do_words = True - if not args: - args = ['-'] - - m = Markov(histsize, random.choice) - try: - for filename in args: - if filename == '-': - f = sys.stdin - if f.isatty(): - print('Sorry, need stdin from file') - continue - else: - f = open(filename, 'r') - with f: - if debug: print('processing', filename, '...') - text = f.read() - paralist = text.split('\n\n') - for para in paralist: - if debug > 1: print('feeding ...') - words = para.split() - if words: - if do_words: - data = tuple(words) - else: - data = ' '.join(words) - m.put(data) - except KeyboardInterrupt: - print('Interrupted -- continue with data read so far') - if not m.trans: - print('No valid input files') - return - if debug: print('done.') - - if debug > 1: - for key in m.trans.keys(): - if key is None or len(key) < histsize: - print(repr(key), m.trans[key]) - if histsize == 0: print(repr(''), m.trans['']) - print() - while True: - data = m.get() - if do_words: - words = data - else: - words = data.split() - n = 0 - limit = 72 - for w in words: - if n + len(w) > limit: - print() - n = 0 - print(w, end=' ') - n += len(w) + 1 - print() - print() - -if __name__ == "__main__": - test() diff --git a/Tools/demo/mcast.py b/Tools/demo/mcast.py deleted file mode 100755 index 924c7c3e80e7..000000000000 --- a/Tools/demo/mcast.py +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env python3 - -""" -Send/receive UDP multicast packets. -Requires that your OS kernel supports IP multicast. - -Usage: - mcast -s (sender, IPv4) - mcast -s -6 (sender, IPv6) - mcast (receivers, IPv4) - mcast -6 (receivers, IPv6) -""" - -MYPORT = 8123 -MYGROUP_4 = '225.0.0.250' -MYGROUP_6 = 'ff15:7079:7468:6f6e:6465:6d6f:6d63:6173' -MYTTL = 1 # Increase to reach other networks - -import time -import struct -import socket -import sys - -def main(): - group = MYGROUP_6 if "-6" in sys.argv[1:] else MYGROUP_4 - - if "-s" in sys.argv[1:]: - sender(group) - else: - receiver(group) - - -def sender(group): - addrinfo = socket.getaddrinfo(group, None)[0] - - s = socket.socket(addrinfo[0], socket.SOCK_DGRAM) - - # Set Time-to-live (optional) - ttl_bin = struct.pack('@i', MYTTL) - if addrinfo[0] == socket.AF_INET: # IPv4 - s.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, ttl_bin) - else: - s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_HOPS, ttl_bin) - - while True: - data = repr(time.time()).encode('utf-8') + b'\0' - s.sendto(data, (addrinfo[4][0], MYPORT)) - time.sleep(1) - - -def receiver(group): - # Look up multicast group address in name server and find out IP version - addrinfo = socket.getaddrinfo(group, None)[0] - - # Create a socket - s = socket.socket(addrinfo[0], socket.SOCK_DGRAM) - - # Allow multiple copies of this program on one machine - # (not strictly needed) - s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - - # Bind it to the port - s.bind(('', MYPORT)) - - group_bin = socket.inet_pton(addrinfo[0], addrinfo[4][0]) - # Join group - if addrinfo[0] == socket.AF_INET: # IPv4 - mreq = group_bin + struct.pack('=I', socket.INADDR_ANY) - s.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq) - else: - mreq = group_bin + struct.pack('@I', 0) - s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mreq) - - # Loop, printing any data we receive - while True: - data, sender = s.recvfrom(1500) - while data[-1:] == '\0': data = data[:-1] # Strip trailing \0's - print(str(sender) + ' ' + repr(data)) - - -if __name__ == '__main__': - main() diff --git a/Tools/demo/queens.py b/Tools/demo/queens.py deleted file mode 100755 index dcc1bae1ab33..000000000000 --- a/Tools/demo/queens.py +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/env python3 - -""" -N queens problem. - -The (well-known) problem is due to Niklaus Wirth. - -This solution is inspired by Dijkstra (Structured Programming). It is -a classic recursive backtracking approach. -""" - -N = 8 # Default; command line overrides - -class Queens: - - def __init__(self, n=N): - self.n = n - self.reset() - - def reset(self): - n = self.n - self.y = [None] * n # Where is the queen in column x - self.row = [0] * n # Is row[y] safe? - self.up = [0] * (2*n-1) # Is upward diagonal[x-y] safe? - self.down = [0] * (2*n-1) # Is downward diagonal[x+y] safe? - self.nfound = 0 # Instrumentation - - def solve(self, x=0): # Recursive solver - for y in range(self.n): - if self.safe(x, y): - self.place(x, y) - if x+1 == self.n: - self.display() - else: - self.solve(x+1) - self.remove(x, y) - - def safe(self, x, y): - return not self.row[y] and not self.up[x-y] and not self.down[x+y] - - def place(self, x, y): - self.y[x] = y - self.row[y] = 1 - self.up[x-y] = 1 - self.down[x+y] = 1 - - def remove(self, x, y): - self.y[x] = None - self.row[y] = 0 - self.up[x-y] = 0 - self.down[x+y] = 0 - - silent = 0 # If true, count solutions only - - def display(self): - self.nfound = self.nfound + 1 - if self.silent: - return - print('+-' + '--'*self.n + '+') - for y in range(self.n-1, -1, -1): - print('|', end=' ') - for x in range(self.n): - if self.y[x] == y: - print("Q", end=' ') - else: - print(".", end=' ') - print('|') - print('+-' + '--'*self.n + '+') - -def main(): - import sys - silent = 0 - n = N - if sys.argv[1:2] == ['-n']: - silent = 1 - del sys.argv[1] - if sys.argv[1:]: - n = int(sys.argv[1]) - q = Queens(n) - q.silent = silent - q.solve() - print("Found", q.nfound, "solutions.") - -if __name__ == "__main__": - main() diff --git a/Tools/demo/redemo.py b/Tools/demo/redemo.py deleted file mode 100755 index f801dfce5fe1..000000000000 --- a/Tools/demo/redemo.py +++ /dev/null @@ -1,171 +0,0 @@ -#!/usr/bin/env python3 - -"""Basic regular expression demonstration facility (Perl style syntax).""" - -from tkinter import * -import re - -class ReDemo: - - def __init__(self, master): - self.master = master - - self.promptdisplay = Label(self.master, anchor=W, - text="Enter a Perl-style regular expression:") - self.promptdisplay.pack(side=TOP, fill=X) - - self.regexdisplay = Entry(self.master) - self.regexdisplay.pack(fill=X) - self.regexdisplay.focus_set() - - self.addoptions() - - self.statusdisplay = Label(self.master, text="", anchor=W) - self.statusdisplay.pack(side=TOP, fill=X) - - self.labeldisplay = Label(self.master, anchor=W, - text="Enter a string to search:") - self.labeldisplay.pack(fill=X) - self.labeldisplay.pack(fill=X) - - self.showframe = Frame(master) - self.showframe.pack(fill=X, anchor=W) - - self.showvar = StringVar(master) - self.showvar.set("first") - - self.showfirstradio = Radiobutton(self.showframe, - text="Highlight first match", - variable=self.showvar, - value="first", - command=self.recompile) - self.showfirstradio.pack(side=LEFT) - - self.showallradio = Radiobutton(self.showframe, - text="Highlight all matches", - variable=self.showvar, - value="all", - command=self.recompile) - self.showallradio.pack(side=LEFT) - - self.stringdisplay = Text(self.master, width=60, height=4) - self.stringdisplay.pack(fill=BOTH, expand=1) - self.stringdisplay.tag_configure("hit", background="yellow") - - self.grouplabel = Label(self.master, text="Groups:", anchor=W) - self.grouplabel.pack(fill=X) - - self.grouplist = Listbox(self.master) - self.grouplist.pack(expand=1, fill=BOTH) - - self.regexdisplay.bind('', self.recompile) - self.stringdisplay.bind('', self.reevaluate) - - self.compiled = None - self.recompile() - - btags = self.regexdisplay.bindtags() - self.regexdisplay.bindtags(btags[1:] + btags[:1]) - - btags = self.stringdisplay.bindtags() - self.stringdisplay.bindtags(btags[1:] + btags[:1]) - - def addoptions(self): - self.frames = [] - self.boxes = [] - self.vars = [] - for name in ('IGNORECASE', - 'MULTILINE', - 'DOTALL', - 'VERBOSE'): - if len(self.boxes) % 3 == 0: - frame = Frame(self.master) - frame.pack(fill=X) - self.frames.append(frame) - val = getattr(re, name).value - var = IntVar() - box = Checkbutton(frame, - variable=var, text=name, - offvalue=0, onvalue=val, - command=self.recompile) - box.pack(side=LEFT) - self.boxes.append(box) - self.vars.append(var) - - def getflags(self): - flags = 0 - for var in self.vars: - flags = flags | var.get() - return flags - - def recompile(self, event=None): - try: - self.compiled = re.compile(self.regexdisplay.get(), - self.getflags()) - bg = self.promptdisplay['background'] - self.statusdisplay.config(text="", background=bg) - except re.error as msg: - self.compiled = None - self.statusdisplay.config( - text="re.error: %s" % str(msg), - background="red") - self.reevaluate() - - def reevaluate(self, event=None): - try: - self.stringdisplay.tag_remove("hit", "1.0", END) - except TclError: - pass - try: - self.stringdisplay.tag_remove("hit0", "1.0", END) - except TclError: - pass - self.grouplist.delete(0, END) - if not self.compiled: - return - self.stringdisplay.tag_configure("hit", background="yellow") - self.stringdisplay.tag_configure("hit0", background="orange") - text = self.stringdisplay.get("1.0", END) - last = 0 - nmatches = 0 - while last <= len(text): - m = self.compiled.search(text, last) - if m is None: - break - first, last = m.span() - if last == first: - last = first+1 - tag = "hit0" - else: - tag = "hit" - pfirst = "1.0 + %d chars" % first - plast = "1.0 + %d chars" % last - self.stringdisplay.tag_add(tag, pfirst, plast) - if nmatches == 0: - self.stringdisplay.yview_pickplace(pfirst) - groups = list(m.groups()) - groups.insert(0, m.group()) - for i in range(len(groups)): - g = "%2d: %r" % (i, groups[i]) - self.grouplist.insert(END, g) - nmatches = nmatches + 1 - if self.showvar.get() == "first": - break - - if nmatches == 0: - self.statusdisplay.config(text="(no match)", - background="yellow") - else: - self.statusdisplay.config(text="") - - -# Main function, run when invoked as a stand-alone Python program. - -def main(): - root = Tk() - demo = ReDemo(root) - root.protocol('WM_DELETE_WINDOW', root.quit) - root.mainloop() - -if __name__ == '__main__': - main() diff --git a/Tools/demo/rpython.py b/Tools/demo/rpython.py deleted file mode 100755 index 11f72cb3dd26..000000000000 --- a/Tools/demo/rpython.py +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env python3 - -""" -Remote python client. -Execute Python commands remotely and send output back. -""" - -import sys -from socket import socket, AF_INET, SOCK_STREAM, SHUT_WR - -PORT = 4127 -BUFSIZE = 1024 - -def main(): - if len(sys.argv) < 3: - print("usage: rpython host command") - sys.exit(2) - host = sys.argv[1] - port = PORT - i = host.find(':') - if i >= 0: - port = int(host[i+1:]) - host = host[:i] - command = ' '.join(sys.argv[2:]) - with socket(AF_INET, SOCK_STREAM) as s: - s.connect((host, port)) - s.send(command.encode()) - s.shutdown(SHUT_WR) - reply = b'' - while True: - data = s.recv(BUFSIZE) - if not data: - break - reply += data - print(reply.decode(), end=' ') - -main() diff --git a/Tools/demo/rpythond.py b/Tools/demo/rpythond.py deleted file mode 100755 index 4e47fb9ec415..000000000000 --- a/Tools/demo/rpythond.py +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env python3 - -""" -Remote python server. -Execute Python commands remotely and send output back. - -WARNING: This version has a gaping security hole -- it accepts requests -from any host on the internet! -""" - -import sys -from socket import socket, AF_INET, SOCK_STREAM -import io -import traceback - -PORT = 4127 -BUFSIZE = 1024 - -def main(): - if len(sys.argv) > 1: - port = int(sys.argv[1]) - else: - port = PORT - s = socket(AF_INET, SOCK_STREAM) - s.bind(('', port)) - s.listen(1) - while True: - conn, (remotehost, remoteport) = s.accept() - with conn: - print('connection from', remotehost, remoteport) - request = b'' - while True: - data = conn.recv(BUFSIZE) - if not data: - break - request += data - reply = execute(request.decode()) - conn.send(reply.encode()) - -def execute(request): - stdout = sys.stdout - stderr = sys.stderr - sys.stdout = sys.stderr = fakefile = io.StringIO() - try: - try: - exec(request, {}, {}) - except: - print() - traceback.print_exc(100) - finally: - sys.stderr = stderr - sys.stdout = stdout - return fakefile.getvalue() - -try: - main() -except KeyboardInterrupt: - pass diff --git a/Tools/demo/sortvisu.py b/Tools/demo/sortvisu.py deleted file mode 100755 index 056a0e05fb1e..000000000000 --- a/Tools/demo/sortvisu.py +++ /dev/null @@ -1,635 +0,0 @@ -#!/usr/bin/env python3 - -""" -Sorting algorithms visualizer using Tkinter. - -This module is comprised of three ``components'': - -- an array visualizer with methods that implement basic sorting -operations (compare, swap) as well as methods for ``annotating'' the -sorting algorithm (e.g. to show the pivot element); - -- a number of sorting algorithms (currently quicksort, insertion sort, -selection sort and bubble sort, as well as a randomization function), -all using the array visualizer for its basic operations and with calls -to its annotation methods; - -- and a ``driver'' class which can be used as a Grail applet or as a -stand-alone application. -""" - -from tkinter import * -import random - -XGRID = 10 -YGRID = 10 -WIDTH = 6 - - -class Array: - - class Cancelled(BaseException): - pass - - def __init__(self, master, data=None): - self.master = master - self.frame = Frame(self.master) - self.frame.pack(fill=X) - self.label = Label(self.frame) - self.label.pack() - self.canvas = Canvas(self.frame) - self.canvas.pack() - self.report = Label(self.frame) - self.report.pack() - self.left = self.canvas.create_line(0, 0, 0, 0) - self.right = self.canvas.create_line(0, 0, 0, 0) - self.pivot = self.canvas.create_line(0, 0, 0, 0) - self.items = [] - self.size = self.maxvalue = 0 - if data: - self.setdata(data) - - def setdata(self, data): - olditems = self.items - self.items = [] - for item in olditems: - item.delete() - self.size = len(data) - self.maxvalue = max(data) - self.canvas.config(width=(self.size+1)*XGRID, - height=(self.maxvalue+1)*YGRID) - for i in range(self.size): - self.items.append(ArrayItem(self, i, data[i])) - self.reset("Sort demo, size %d" % self.size) - - speed = "normal" - - def setspeed(self, speed): - self.speed = speed - - def destroy(self): - self.frame.destroy() - - in_mainloop = 0 - stop_mainloop = 0 - - def cancel(self): - self.stop_mainloop = 1 - if self.in_mainloop: - self.master.quit() - - def step(self): - if self.in_mainloop: - self.master.quit() - - def wait(self, msecs): - if self.speed == "fastest": - msecs = 0 - elif self.speed == "fast": - msecs = msecs//10 - elif self.speed == "single-step": - msecs = 1000000000 - if not self.stop_mainloop: - self.master.update() - id = self.master.after(msecs, self.master.quit) - self.in_mainloop = 1 - self.master.mainloop() - self.master.after_cancel(id) - self.in_mainloop = 0 - if self.stop_mainloop: - self.stop_mainloop = 0 - self.message("Cancelled") - raise Array.Cancelled - - def getsize(self): - return self.size - - def show_partition(self, first, last): - for i in range(self.size): - item = self.items[i] - if first <= i < last: - self.canvas.itemconfig(item, fill='red') - else: - self.canvas.itemconfig(item, fill='orange') - self.hide_left_right_pivot() - - def hide_partition(self): - for i in range(self.size): - item = self.items[i] - self.canvas.itemconfig(item, fill='red') - self.hide_left_right_pivot() - - def show_left(self, left): - if not 0 <= left < self.size: - self.hide_left() - return - x1, y1, x2, y2 = self.items[left].position() -## top, bot = HIRO - self.canvas.coords(self.left, (x1 - 2, 0, x1 - 2, 9999)) - self.master.update() - - def show_right(self, right): - if not 0 <= right < self.size: - self.hide_right() - return - x1, y1, x2, y2 = self.items[right].position() - self.canvas.coords(self.right, (x2 + 2, 0, x2 + 2, 9999)) - self.master.update() - - def hide_left_right_pivot(self): - self.hide_left() - self.hide_right() - self.hide_pivot() - - def hide_left(self): - self.canvas.coords(self.left, (0, 0, 0, 0)) - - def hide_right(self): - self.canvas.coords(self.right, (0, 0, 0, 0)) - - def show_pivot(self, pivot): - x1, y1, x2, y2 = self.items[pivot].position() - self.canvas.coords(self.pivot, (0, y1 - 2, 9999, y1 - 2)) - - def hide_pivot(self): - self.canvas.coords(self.pivot, (0, 0, 0, 0)) - - def swap(self, i, j): - if i == j: return - self.countswap() - item = self.items[i] - other = self.items[j] - self.items[i], self.items[j] = other, item - item.swapwith(other) - - def compare(self, i, j): - self.countcompare() - item = self.items[i] - other = self.items[j] - return item.compareto(other) - - def reset(self, msg): - self.ncompares = 0 - self.nswaps = 0 - self.message(msg) - self.updatereport() - self.hide_partition() - - def message(self, msg): - self.label.config(text=msg) - - def countswap(self): - self.nswaps = self.nswaps + 1 - self.updatereport() - - def countcompare(self): - self.ncompares = self.ncompares + 1 - self.updatereport() - - def updatereport(self): - text = "%d cmps, %d swaps" % (self.ncompares, self.nswaps) - self.report.config(text=text) - - -class ArrayItem: - - def __init__(self, array, index, value): - self.array = array - self.index = index - self.value = value - self.canvas = array.canvas - x1, y1, x2, y2 = self.position() - self.item_id = array.canvas.create_rectangle(x1, y1, x2, y2, - fill='red', outline='black', width=1) - self.canvas.tag_bind(self.item_id, '', self.mouse_down) - self.canvas.tag_bind(self.item_id, '', self.mouse_move) - self.canvas.tag_bind(self.item_id, '', self.mouse_up) - - def delete(self): - item_id = self.item_id - self.array = None - self.item_id = None - self.canvas.delete(item_id) - - def mouse_down(self, event): - self.lastx = event.x - self.lasty = event.y - self.origx = event.x - self.origy = event.y - self.canvas.tag_raise(self.item_id) - - def mouse_move(self, event): - self.canvas.move(self.item_id, - event.x - self.lastx, event.y - self.lasty) - self.lastx = event.x - self.lasty = event.y - - def mouse_up(self, event): - i = self.nearestindex(event.x) - if i >= self.array.getsize(): - i = self.array.getsize() - 1 - if i < 0: - i = 0 - other = self.array.items[i] - here = self.index - self.array.items[here], self.array.items[i] = other, self - self.index = i - x1, y1, x2, y2 = self.position() - self.canvas.coords(self.item_id, (x1, y1, x2, y2)) - other.setindex(here) - - def setindex(self, index): - nsteps = steps(self.index, index) - if not nsteps: return - if self.array.speed == "fastest": - nsteps = 0 - oldpts = self.position() - self.index = index - newpts = self.position() - trajectory = interpolate(oldpts, newpts, nsteps) - self.canvas.tag_raise(self.item_id) - for pts in trajectory: - self.canvas.coords(self.item_id, pts) - self.array.wait(50) - - def swapwith(self, other): - nsteps = steps(self.index, other.index) - if not nsteps: return - if self.array.speed == "fastest": - nsteps = 0 - myoldpts = self.position() - otheroldpts = other.position() - self.index, other.index = other.index, self.index - mynewpts = self.position() - othernewpts = other.position() - myfill = self.canvas.itemcget(self.item_id, 'fill') - otherfill = self.canvas.itemcget(other.item_id, 'fill') - self.canvas.itemconfig(self.item_id, fill='green') - self.canvas.itemconfig(other.item_id, fill='yellow') - self.array.master.update() - if self.array.speed == "single-step": - self.canvas.coords(self.item_id, mynewpts) - self.canvas.coords(other.item_id, othernewpts) - self.array.master.update() - self.canvas.itemconfig(self.item_id, fill=myfill) - self.canvas.itemconfig(other.item_id, fill=otherfill) - self.array.wait(0) - return - mytrajectory = interpolate(myoldpts, mynewpts, nsteps) - othertrajectory = interpolate(otheroldpts, othernewpts, nsteps) - if self.value > other.value: - self.canvas.tag_raise(self.item_id) - self.canvas.tag_raise(other.item_id) - else: - self.canvas.tag_raise(other.item_id) - self.canvas.tag_raise(self.item_id) - try: - for i in range(len(mytrajectory)): - mypts = mytrajectory[i] - otherpts = othertrajectory[i] - self.canvas.coords(self.item_id, mypts) - self.canvas.coords(other.item_id, otherpts) - self.array.wait(50) - finally: - mypts = mytrajectory[-1] - otherpts = othertrajectory[-1] - self.canvas.coords(self.item_id, mypts) - self.canvas.coords(other.item_id, otherpts) - self.canvas.itemconfig(self.item_id, fill=myfill) - self.canvas.itemconfig(other.item_id, fill=otherfill) - - def compareto(self, other): - myfill = self.canvas.itemcget(self.item_id, 'fill') - otherfill = self.canvas.itemcget(other.item_id, 'fill') - if self.value < other.value: - myflash = 'white' - otherflash = 'black' - outcome = -1 - elif self.value > other.value: - myflash = 'black' - otherflash = 'white' - outcome = 1 - else: - myflash = otherflash = 'grey' - outcome = 0 - try: - self.canvas.itemconfig(self.item_id, fill=myflash) - self.canvas.itemconfig(other.item_id, fill=otherflash) - self.array.wait(500) - finally: - self.canvas.itemconfig(self.item_id, fill=myfill) - self.canvas.itemconfig(other.item_id, fill=otherfill) - return outcome - - def position(self): - x1 = (self.index+1)*XGRID - WIDTH//2 - x2 = x1+WIDTH - y2 = (self.array.maxvalue+1)*YGRID - y1 = y2 - (self.value)*YGRID - return x1, y1, x2, y2 - - def nearestindex(self, x): - return int(round(float(x)/XGRID)) - 1 - - -# Subroutines that don't need an object - -def steps(here, there): - nsteps = abs(here - there) - if nsteps <= 3: - nsteps = nsteps * 3 - elif nsteps <= 5: - nsteps = nsteps * 2 - elif nsteps > 10: - nsteps = 10 - return nsteps - -def interpolate(oldpts, newpts, n): - if len(oldpts) != len(newpts): - raise ValueError("can't interpolate arrays of different length") - pts = [0]*len(oldpts) - res = [tuple(oldpts)] - for i in range(1, n): - for k in range(len(pts)): - pts[k] = oldpts[k] + (newpts[k] - oldpts[k])*i//n - res.append(tuple(pts)) - res.append(tuple(newpts)) - return res - - -# Various (un)sorting algorithms - -def uniform(array): - size = array.getsize() - array.setdata([(size+1)//2] * size) - array.reset("Uniform data, size %d" % size) - -def distinct(array): - size = array.getsize() - array.setdata(range(1, size+1)) - array.reset("Distinct data, size %d" % size) - -def randomize(array): - array.reset("Randomizing") - n = array.getsize() - for i in range(n): - j = random.randint(0, n-1) - array.swap(i, j) - array.message("Randomized") - -def insertionsort(array): - size = array.getsize() - array.reset("Insertion sort") - for i in range(1, size): - j = i-1 - while j >= 0: - if array.compare(j, j+1) <= 0: - break - array.swap(j, j+1) - j = j-1 - array.message("Sorted") - -def selectionsort(array): - size = array.getsize() - array.reset("Selection sort") - try: - for i in range(size): - array.show_partition(i, size) - for j in range(i+1, size): - if array.compare(i, j) > 0: - array.swap(i, j) - array.message("Sorted") - finally: - array.hide_partition() - -def bubblesort(array): - size = array.getsize() - array.reset("Bubble sort") - for i in range(size): - for j in range(1, size): - if array.compare(j-1, j) > 0: - array.swap(j-1, j) - array.message("Sorted") - -def quicksort(array): - size = array.getsize() - array.reset("Quicksort") - try: - stack = [(0, size)] - while stack: - first, last = stack[-1] - del stack[-1] - array.show_partition(first, last) - if last-first < 5: - array.message("Insertion sort") - for i in range(first+1, last): - j = i-1 - while j >= first: - if array.compare(j, j+1) <= 0: - break - array.swap(j, j+1) - j = j-1 - continue - array.message("Choosing pivot") - j, i, k = first, (first+last) // 2, last-1 - if array.compare(k, i) < 0: - array.swap(k, i) - if array.compare(k, j) < 0: - array.swap(k, j) - if array.compare(j, i) < 0: - array.swap(j, i) - pivot = j - array.show_pivot(pivot) - array.message("Pivot at left of partition") - array.wait(1000) - left = first - right = last - while True: - array.message("Sweep right pointer") - right = right-1 - array.show_right(right) - while right > first and array.compare(right, pivot) >= 0: - right = right-1 - array.show_right(right) - array.message("Sweep left pointer") - left = left+1 - array.show_left(left) - while left < last and array.compare(left, pivot) <= 0: - left = left+1 - array.show_left(left) - if left > right: - array.message("End of partition") - break - array.message("Swap items") - array.swap(left, right) - array.message("Swap pivot back") - array.swap(pivot, right) - n1 = right-first - n2 = last-left - if n1 > 1: stack.append((first, right)) - if n2 > 1: stack.append((left, last)) - array.message("Sorted") - finally: - array.hide_partition() - -def demosort(array): - while True: - for alg in [quicksort, insertionsort, selectionsort, bubblesort]: - randomize(array) - alg(array) - - -# Sort demo class -- usable as a Grail applet - -class SortDemo: - - def __init__(self, master, size=15): - self.master = master - self.size = size - self.busy = 0 - self.array = Array(self.master) - - self.botframe = Frame(master) - self.botframe.pack(side=BOTTOM) - self.botleftframe = Frame(self.botframe) - self.botleftframe.pack(side=LEFT, fill=Y) - self.botrightframe = Frame(self.botframe) - self.botrightframe.pack(side=RIGHT, fill=Y) - - self.b_qsort = Button(self.botleftframe, - text="Quicksort", command=self.c_qsort) - self.b_qsort.pack(fill=X) - self.b_isort = Button(self.botleftframe, - text="Insertion sort", command=self.c_isort) - self.b_isort.pack(fill=X) - self.b_ssort = Button(self.botleftframe, - text="Selection sort", command=self.c_ssort) - self.b_ssort.pack(fill=X) - self.b_bsort = Button(self.botleftframe, - text="Bubble sort", command=self.c_bsort) - self.b_bsort.pack(fill=X) - - # Terrible hack to overcome limitation of OptionMenu... - class MyIntVar(IntVar): - def __init__(self, master, demo): - self.demo = demo - IntVar.__init__(self, master) - def set(self, value): - IntVar.set(self, value) - if str(value) != '0': - self.demo.resize(value) - - self.v_size = MyIntVar(self.master, self) - self.v_size.set(size) - sizes = [1, 2, 3, 4] + list(range(5, 55, 5)) - if self.size not in sizes: - sizes.append(self.size) - sizes.sort() - self.m_size = OptionMenu(self.botleftframe, self.v_size, *sizes) - self.m_size.pack(fill=X) - - self.v_speed = StringVar(self.master) - self.v_speed.set("normal") - self.m_speed = OptionMenu(self.botleftframe, self.v_speed, - "single-step", "normal", "fast", "fastest") - self.m_speed.pack(fill=X) - - self.b_step = Button(self.botleftframe, - text="Step", command=self.c_step) - self.b_step.pack(fill=X) - - self.b_randomize = Button(self.botrightframe, - text="Randomize", command=self.c_randomize) - self.b_randomize.pack(fill=X) - self.b_uniform = Button(self.botrightframe, - text="Uniform", command=self.c_uniform) - self.b_uniform.pack(fill=X) - self.b_distinct = Button(self.botrightframe, - text="Distinct", command=self.c_distinct) - self.b_distinct.pack(fill=X) - self.b_demo = Button(self.botrightframe, - text="Demo", command=self.c_demo) - self.b_demo.pack(fill=X) - self.b_cancel = Button(self.botrightframe, - text="Cancel", command=self.c_cancel) - self.b_cancel.pack(fill=X) - self.b_cancel.config(state=DISABLED) - self.b_quit = Button(self.botrightframe, - text="Quit", command=self.c_quit) - self.b_quit.pack(fill=X) - - def resize(self, newsize): - if self.busy: - self.master.bell() - return - self.size = newsize - self.array.setdata(range(1, self.size+1)) - - def c_qsort(self): - self.run(quicksort) - - def c_isort(self): - self.run(insertionsort) - - def c_ssort(self): - self.run(selectionsort) - - def c_bsort(self): - self.run(bubblesort) - - def c_demo(self): - self.run(demosort) - - def c_randomize(self): - self.run(randomize) - - def c_uniform(self): - self.run(uniform) - - def c_distinct(self): - self.run(distinct) - - def run(self, func): - if self.busy: - self.master.bell() - return - self.busy = 1 - self.array.setspeed(self.v_speed.get()) - self.b_cancel.config(state=NORMAL) - try: - func(self.array) - except Array.Cancelled: - pass - self.b_cancel.config(state=DISABLED) - self.busy = 0 - - def c_cancel(self): - if not self.busy: - self.master.bell() - return - self.array.cancel() - - def c_step(self): - if not self.busy: - self.master.bell() - return - self.v_speed.set("single-step") - self.array.setspeed("single-step") - self.array.step() - - def c_quit(self): - if self.busy: - self.array.cancel() - self.master.after_idle(self.master.quit) - - -# Main program -- for stand-alone operation outside Grail - -def main(): - root = Tk() - demo = SortDemo(root) - root.protocol('WM_DELETE_WINDOW', demo.c_quit) - root.mainloop() - -if __name__ == '__main__': - main() diff --git a/Tools/demo/spreadsheet.py b/Tools/demo/spreadsheet.py deleted file mode 100755 index bf88820dca34..000000000000 --- a/Tools/demo/spreadsheet.py +++ /dev/null @@ -1,829 +0,0 @@ -#!/usr/bin/env python3 - -""" -SS1 -- a spreadsheet-like application. -""" - -import os -import re -import sys -from xml.parsers import expat -from xml.sax.saxutils import escape - -LEFT, CENTER, RIGHT = "LEFT", "CENTER", "RIGHT" - -def ljust(x, n): - return x.ljust(n) -def center(x, n): - return x.center(n) -def rjust(x, n): - return x.rjust(n) -align2action = {LEFT: ljust, CENTER: center, RIGHT: rjust} - -align2xml = {LEFT: "left", CENTER: "center", RIGHT: "right"} -xml2align = {"left": LEFT, "center": CENTER, "right": RIGHT} - -align2anchor = {LEFT: "w", CENTER: "center", RIGHT: "e"} - -def sum(seq): - total = 0 - for x in seq: - if x is not None: - total += x - return total - -class Sheet: - - def __init__(self): - self.cells = {} # {(x, y): cell, ...} - self.ns = dict( - cell = self.cellvalue, - cells = self.multicellvalue, - sum = sum, - ) - - def cellvalue(self, x, y): - cell = self.getcell(x, y) - if hasattr(cell, 'recalc'): - return cell.recalc(self.ns) - else: - return cell - - def multicellvalue(self, x1, y1, x2, y2): - if x1 > x2: - x1, x2 = x2, x1 - if y1 > y2: - y1, y2 = y2, y1 - seq = [] - for y in range(y1, y2+1): - for x in range(x1, x2+1): - seq.append(self.cellvalue(x, y)) - return seq - - def getcell(self, x, y): - return self.cells.get((x, y)) - - def setcell(self, x, y, cell): - assert x > 0 and y > 0 - assert isinstance(cell, BaseCell) - self.cells[x, y] = cell - - def clearcell(self, x, y): - try: - del self.cells[x, y] - except KeyError: - pass - - def clearcells(self, x1, y1, x2, y2): - for xy in self.selectcells(x1, y1, x2, y2): - del self.cells[xy] - - def clearrows(self, y1, y2): - self.clearcells(0, y1, sys.maxsize, y2) - - def clearcolumns(self, x1, x2): - self.clearcells(x1, 0, x2, sys.maxsize) - - def selectcells(self, x1, y1, x2, y2): - if x1 > x2: - x1, x2 = x2, x1 - if y1 > y2: - y1, y2 = y2, y1 - return [(x, y) for x, y in self.cells - if x1 <= x <= x2 and y1 <= y <= y2] - - def movecells(self, x1, y1, x2, y2, dx, dy): - if dx == 0 and dy == 0: - return - if x1 > x2: - x1, x2 = x2, x1 - if y1 > y2: - y1, y2 = y2, y1 - assert x1+dx > 0 and y1+dy > 0 - new = {} - for x, y in self.cells: - cell = self.cells[x, y] - if hasattr(cell, 'renumber'): - cell = cell.renumber(x1, y1, x2, y2, dx, dy) - if x1 <= x <= x2 and y1 <= y <= y2: - x += dx - y += dy - new[x, y] = cell - self.cells = new - - def insertrows(self, y, n): - assert n > 0 - self.movecells(0, y, sys.maxsize, sys.maxsize, 0, n) - - def deleterows(self, y1, y2): - if y1 > y2: - y1, y2 = y2, y1 - self.clearrows(y1, y2) - self.movecells(0, y2+1, sys.maxsize, sys.maxsize, 0, y1-y2-1) - - def insertcolumns(self, x, n): - assert n > 0 - self.movecells(x, 0, sys.maxsize, sys.maxsize, n, 0) - - def deletecolumns(self, x1, x2): - if x1 > x2: - x1, x2 = x2, x1 - self.clearcells(x1, x2) - self.movecells(x2+1, 0, sys.maxsize, sys.maxsize, x1-x2-1, 0) - - def getsize(self): - maxx = maxy = 0 - for x, y in self.cells: - maxx = max(maxx, x) - maxy = max(maxy, y) - return maxx, maxy - - def reset(self): - for cell in self.cells.values(): - if hasattr(cell, 'reset'): - cell.reset() - - def recalc(self): - self.reset() - for cell in self.cells.values(): - if hasattr(cell, 'recalc'): - cell.recalc(self.ns) - - def display(self): - maxx, maxy = self.getsize() - width, height = maxx+1, maxy+1 - colwidth = [1] * width - full = {} - # Add column heading labels in row 0 - for x in range(1, width): - full[x, 0] = text, alignment = colnum2name(x), RIGHT - colwidth[x] = max(colwidth[x], len(text)) - # Add row labels in column 0 - for y in range(1, height): - full[0, y] = text, alignment = str(y), RIGHT - colwidth[0] = max(colwidth[0], len(text)) - # Add sheet cells in columns with x>0 and y>0 - for (x, y), cell in self.cells.items(): - if x <= 0 or y <= 0: - continue - if hasattr(cell, 'recalc'): - cell.recalc(self.ns) - if hasattr(cell, 'format'): - text, alignment = cell.format() - assert isinstance(text, str) - assert alignment in (LEFT, CENTER, RIGHT) - else: - text = str(cell) - if isinstance(cell, str): - alignment = LEFT - else: - alignment = RIGHT - full[x, y] = (text, alignment) - colwidth[x] = max(colwidth[x], len(text)) - # Calculate the horizontal separator line (dashes and dots) - sep = "" - for x in range(width): - if sep: - sep += "+" - sep += "-"*colwidth[x] - # Now print The full grid - for y in range(height): - line = "" - for x in range(width): - text, alignment = full.get((x, y)) or ("", LEFT) - text = align2action[alignment](text, colwidth[x]) - if line: - line += '|' - line += text - print(line) - if y == 0: - print(sep) - - def xml(self): - out = [''] - for (x, y), cell in self.cells.items(): - if hasattr(cell, 'xml'): - cellxml = cell.xml() - else: - cellxml = '%s' % escape(cell) - out.append('\n %s\n' % - (y, x, cellxml)) - out.append('') - return '\n'.join(out) - - def save(self, filename): - text = self.xml() - with open(filename, "w", encoding='utf-8') as f: - f.write(text) - if text and not text.endswith('\n'): - f.write('\n') - - def load(self, filename): - with open(filename, 'rb') as f: - SheetParser(self).parsefile(f) - -class SheetParser: - - def __init__(self, sheet): - self.sheet = sheet - - def parsefile(self, f): - parser = expat.ParserCreate() - parser.StartElementHandler = self.startelement - parser.EndElementHandler = self.endelement - parser.CharacterDataHandler = self.data - parser.ParseFile(f) - - def startelement(self, tag, attrs): - method = getattr(self, 'start_'+tag, None) - if method: - method(attrs) - self.texts = [] - - def data(self, text): - self.texts.append(text) - - def endelement(self, tag): - method = getattr(self, 'end_'+tag, None) - if method: - method("".join(self.texts)) - - def start_cell(self, attrs): - self.y = int(attrs.get("row")) - self.x = int(attrs.get("col")) - - def start_value(self, attrs): - self.fmt = attrs.get('format') - self.alignment = xml2align.get(attrs.get('align')) - - start_formula = start_value - - def end_int(self, text): - try: - self.value = int(text) - except (TypeError, ValueError): - self.value = None - - end_long = end_int - - def end_double(self, text): - try: - self.value = float(text) - except (TypeError, ValueError): - self.value = None - - def end_complex(self, text): - try: - self.value = complex(text) - except (TypeError, ValueError): - self.value = None - - def end_string(self, text): - self.value = text - - def end_value(self, text): - if isinstance(self.value, BaseCell): - self.cell = self.value - elif isinstance(self.value, str): - self.cell = StringCell(self.value, - self.fmt or "%s", - self.alignment or LEFT) - else: - self.cell = NumericCell(self.value, - self.fmt or "%s", - self.alignment or RIGHT) - - def end_formula(self, text): - self.cell = FormulaCell(text, - self.fmt or "%s", - self.alignment or RIGHT) - - def end_cell(self, text): - self.sheet.setcell(self.x, self.y, self.cell) - -class BaseCell: - __init__ = None # Must provide - """Abstract base class for sheet cells. - - Subclasses may but needn't provide the following APIs: - - cell.reset() -- prepare for recalculation - cell.recalc(ns) -> value -- recalculate formula - cell.format() -> (value, alignment) -- return formatted value - cell.xml() -> string -- return XML - """ - -class NumericCell(BaseCell): - - def __init__(self, value, fmt="%s", alignment=RIGHT): - assert isinstance(value, (int, float, complex)) - assert alignment in (LEFT, CENTER, RIGHT) - self.value = value - self.fmt = fmt - self.alignment = alignment - - def recalc(self, ns): - return self.value - - def format(self): - try: - text = self.fmt % self.value - except: - text = str(self.value) - return text, self.alignment - - def xml(self): - method = getattr(self, '_xml_' + type(self.value).__name__) - return '%s' % ( - align2xml[self.alignment], - self.fmt, - method()) - - def _xml_int(self): - if -2**31 <= self.value < 2**31: - return '%s' % self.value - else: - return '%s' % self.value - - def _xml_float(self): - return '%r' % self.value - - def _xml_complex(self): - return '%r' % self.value - -class StringCell(BaseCell): - - def __init__(self, text, fmt="%s", alignment=LEFT): - assert isinstance(text, str) - assert alignment in (LEFT, CENTER, RIGHT) - self.text = text - self.fmt = fmt - self.alignment = alignment - - def recalc(self, ns): - return self.text - - def format(self): - return self.text, self.alignment - - def xml(self): - s = '%s' - return s % ( - align2xml[self.alignment], - self.fmt, - escape(self.text)) - -class FormulaCell(BaseCell): - - def __init__(self, formula, fmt="%s", alignment=RIGHT): - assert alignment in (LEFT, CENTER, RIGHT) - self.formula = formula - self.translated = translate(self.formula) - self.fmt = fmt - self.alignment = alignment - self.reset() - - def reset(self): - self.value = None - - def recalc(self, ns): - if self.value is None: - try: - self.value = eval(self.translated, ns) - except: - exc = sys.exc_info()[0] - if hasattr(exc, "__name__"): - self.value = exc.__name__ - else: - self.value = str(exc) - return self.value - - def format(self): - try: - text = self.fmt % self.value - except: - text = str(self.value) - return text, self.alignment - - def xml(self): - return '%s' % ( - align2xml[self.alignment], - self.fmt, - escape(self.formula)) - - def renumber(self, x1, y1, x2, y2, dx, dy): - out = [] - for part in re.split(r'(\w+)', self.formula): - m = re.match('^([A-Z]+)([1-9][0-9]*)$', part) - if m is not None: - sx, sy = m.groups() - x = colname2num(sx) - y = int(sy) - if x1 <= x <= x2 and y1 <= y <= y2: - part = cellname(x+dx, y+dy) - out.append(part) - return FormulaCell("".join(out), self.fmt, self.alignment) - -def translate(formula): - """Translate a formula containing fancy cell names to valid Python code. - - Examples: - B4 -> cell(2, 4) - B4:Z100 -> cells(2, 4, 26, 100) - """ - out = [] - for part in re.split(r"(\w+(?::\w+)?)", formula): - m = re.match(r"^([A-Z]+)([1-9][0-9]*)(?::([A-Z]+)([1-9][0-9]*))?$", part) - if m is None: - out.append(part) - else: - x1, y1, x2, y2 = m.groups() - x1 = colname2num(x1) - if x2 is None: - s = "cell(%s, %s)" % (x1, y1) - else: - x2 = colname2num(x2) - s = "cells(%s, %s, %s, %s)" % (x1, y1, x2, y2) - out.append(s) - return "".join(out) - -def cellname(x, y): - "Translate a cell coordinate to a fancy cell name (e.g. (1, 1)->'A1')." - assert x > 0 # Column 0 has an empty name, so can't use that - return colnum2name(x) + str(y) - -def colname2num(s): - "Translate a column name to number (e.g. 'A'->1, 'Z'->26, 'AA'->27)." - s = s.upper() - n = 0 - for c in s: - assert 'A' <= c <= 'Z' - n = n*26 + ord(c) - ord('A') + 1 - return n - -def colnum2name(n): - "Translate a column number to name (e.g. 1->'A', etc.)." - assert n > 0 - s = "" - while n: - n, m = divmod(n-1, 26) - s = chr(m+ord('A')) + s - return s - -import tkinter as Tk - -class SheetGUI: - - """Beginnings of a GUI for a spreadsheet. - - TO DO: - - clear multiple cells - - Insert, clear, remove rows or columns - - Show new contents while typing - - Scroll bars - - Grow grid when window is grown - - Proper menus - - Undo, redo - - Cut, copy and paste - - Formatting and alignment - """ - - def __init__(self, filename="sheet1.xml", rows=10, columns=5): - """Constructor. - - Load the sheet from the filename argument. - Set up the Tk widget tree. - """ - # Create and load the sheet - self.filename = filename - self.sheet = Sheet() - if os.path.isfile(filename): - self.sheet.load(filename) - # Calculate the needed grid size - maxx, maxy = self.sheet.getsize() - rows = max(rows, maxy) - columns = max(columns, maxx) - # Create the widgets - self.root = Tk.Tk() - self.root.wm_title("Spreadsheet: %s" % self.filename) - self.beacon = Tk.Label(self.root, text="A1", - font=('helvetica', 16, 'bold')) - self.entry = Tk.Entry(self.root) - self.savebutton = Tk.Button(self.root, text="Save", - command=self.save) - self.cellgrid = Tk.Frame(self.root) - # Configure the widget lay-out - self.cellgrid.pack(side="bottom", expand=1, fill="both") - self.beacon.pack(side="left") - self.savebutton.pack(side="right") - self.entry.pack(side="left", expand=1, fill="x") - # Bind some events - self.entry.bind("", self.return_event) - self.entry.bind("", self.shift_return_event) - self.entry.bind("", self.tab_event) - self.entry.bind("", self.shift_tab_event) - self.entry.bind("", self.delete_event) - self.entry.bind("", self.escape_event) - # Now create the cell grid - self.makegrid(rows, columns) - # Select the top-left cell - self.currentxy = None - self.cornerxy = None - self.setcurrent(1, 1) - # Copy the sheet cells to the GUI cells - self.sync() - - def delete_event(self, event): - if self.cornerxy != self.currentxy and self.cornerxy is not None: - self.sheet.clearcells(*(self.currentxy + self.cornerxy)) - else: - self.sheet.clearcell(*self.currentxy) - self.sync() - self.entry.delete(0, 'end') - return "break" - - def escape_event(self, event): - x, y = self.currentxy - self.load_entry(x, y) - - def load_entry(self, x, y): - cell = self.sheet.getcell(x, y) - if cell is None: - text = "" - elif isinstance(cell, FormulaCell): - text = '=' + cell.formula - else: - text, alignment = cell.format() - self.entry.delete(0, 'end') - self.entry.insert(0, text) - self.entry.selection_range(0, 'end') - - def makegrid(self, rows, columns): - """Helper to create the grid of GUI cells. - - The edge (x==0 or y==0) is filled with labels; the rest is real cells. - """ - self.rows = rows - self.columns = columns - self.gridcells = {} - # Create the top left corner cell (which selects all) - cell = Tk.Label(self.cellgrid, relief='raised') - cell.grid_configure(column=0, row=0, sticky='NSWE') - cell.bind("", self.selectall) - # Create the top row of labels, and configure the grid columns - for x in range(1, columns+1): - self.cellgrid.grid_columnconfigure(x, minsize=64) - cell = Tk.Label(self.cellgrid, text=colnum2name(x), relief='raised') - cell.grid_configure(column=x, row=0, sticky='WE') - self.gridcells[x, 0] = cell - cell.__x = x - cell.__y = 0 - cell.bind("", self.selectcolumn) - cell.bind("", self.extendcolumn) - cell.bind("", self.extendcolumn) - cell.bind("", self.extendcolumn) - # Create the leftmost column of labels - for y in range(1, rows+1): - cell = Tk.Label(self.cellgrid, text=str(y), relief='raised') - cell.grid_configure(column=0, row=y, sticky='WE') - self.gridcells[0, y] = cell - cell.__x = 0 - cell.__y = y - cell.bind("", self.selectrow) - cell.bind("", self.extendrow) - cell.bind("", self.extendrow) - cell.bind("", self.extendrow) - # Create the real cells - for x in range(1, columns+1): - for y in range(1, rows+1): - cell = Tk.Label(self.cellgrid, relief='sunken', - bg='white', fg='black') - cell.grid_configure(column=x, row=y, sticky='NSWE') - self.gridcells[x, y] = cell - cell.__x = x - cell.__y = y - # Bind mouse events - cell.bind("", self.press) - cell.bind("", self.motion) - cell.bind("", self.release) - cell.bind("", self.release) - - def selectall(self, event): - self.setcurrent(1, 1) - self.setcorner(sys.maxsize, sys.maxsize) - - def selectcolumn(self, event): - x, y = self.whichxy(event) - self.setcurrent(x, 1) - self.setcorner(x, sys.maxsize) - - def extendcolumn(self, event): - x, y = self.whichxy(event) - if x > 0: - self.setcurrent(self.currentxy[0], 1) - self.setcorner(x, sys.maxsize) - - def selectrow(self, event): - x, y = self.whichxy(event) - self.setcurrent(1, y) - self.setcorner(sys.maxsize, y) - - def extendrow(self, event): - x, y = self.whichxy(event) - if y > 0: - self.setcurrent(1, self.currentxy[1]) - self.setcorner(sys.maxsize, y) - - def press(self, event): - x, y = self.whichxy(event) - if x > 0 and y > 0: - self.setcurrent(x, y) - - def motion(self, event): - x, y = self.whichxy(event) - if x > 0 and y > 0: - self.setcorner(x, y) - - release = motion - - def whichxy(self, event): - w = self.cellgrid.winfo_containing(event.x_root, event.y_root) - if w is not None and isinstance(w, Tk.Label): - try: - return w.__x, w.__y - except AttributeError: - pass - return 0, 0 - - def save(self): - self.sheet.save(self.filename) - - def setcurrent(self, x, y): - "Make (x, y) the current cell." - if self.currentxy is not None: - self.change_cell() - self.clearfocus() - self.beacon['text'] = cellname(x, y) - self.load_entry(x, y) - self.entry.focus_set() - self.currentxy = x, y - self.cornerxy = None - gridcell = self.gridcells.get(self.currentxy) - if gridcell is not None: - gridcell['bg'] = 'yellow' - - def setcorner(self, x, y): - if self.currentxy is None or self.currentxy == (x, y): - self.setcurrent(x, y) - return - self.clearfocus() - self.cornerxy = x, y - x1, y1 = self.currentxy - x2, y2 = self.cornerxy or self.currentxy - if x1 > x2: - x1, x2 = x2, x1 - if y1 > y2: - y1, y2 = y2, y1 - for (x, y), cell in self.gridcells.items(): - if x1 <= x <= x2 and y1 <= y <= y2: - cell['bg'] = 'lightBlue' - gridcell = self.gridcells.get(self.currentxy) - if gridcell is not None: - gridcell['bg'] = 'yellow' - self.setbeacon(x1, y1, x2, y2) - - def setbeacon(self, x1, y1, x2, y2): - if x1 == y1 == 1 and x2 == y2 == sys.maxsize: - name = ":" - elif (x1, x2) == (1, sys.maxsize): - if y1 == y2: - name = "%d" % y1 - else: - name = "%d:%d" % (y1, y2) - elif (y1, y2) == (1, sys.maxsize): - if x1 == x2: - name = "%s" % colnum2name(x1) - else: - name = "%s:%s" % (colnum2name(x1), colnum2name(x2)) - else: - name1 = cellname(*self.currentxy) - name2 = cellname(*self.cornerxy) - name = "%s:%s" % (name1, name2) - self.beacon['text'] = name - - - def clearfocus(self): - if self.currentxy is not None: - x1, y1 = self.currentxy - x2, y2 = self.cornerxy or self.currentxy - if x1 > x2: - x1, x2 = x2, x1 - if y1 > y2: - y1, y2 = y2, y1 - for (x, y), cell in self.gridcells.items(): - if x1 <= x <= x2 and y1 <= y <= y2: - cell['bg'] = 'white' - - def return_event(self, event): - "Callback for the Return key." - self.change_cell() - x, y = self.currentxy - self.setcurrent(x, y+1) - return "break" - - def shift_return_event(self, event): - "Callback for the Return key with Shift modifier." - self.change_cell() - x, y = self.currentxy - self.setcurrent(x, max(1, y-1)) - return "break" - - def tab_event(self, event): - "Callback for the Tab key." - self.change_cell() - x, y = self.currentxy - self.setcurrent(x+1, y) - return "break" - - def shift_tab_event(self, event): - "Callback for the Tab key with Shift modifier." - self.change_cell() - x, y = self.currentxy - self.setcurrent(max(1, x-1), y) - return "break" - - def change_cell(self): - "Set the current cell from the entry widget." - x, y = self.currentxy - text = self.entry.get() - cell = None - if text.startswith('='): - cell = FormulaCell(text[1:]) - else: - for cls in int, float, complex: - try: - value = cls(text) - except (TypeError, ValueError): - continue - else: - cell = NumericCell(value) - break - if cell is None and text: - cell = StringCell(text) - if cell is None: - self.sheet.clearcell(x, y) - else: - self.sheet.setcell(x, y, cell) - self.sync() - - def sync(self): - "Fill the GUI cells from the sheet cells." - self.sheet.recalc() - for (x, y), gridcell in self.gridcells.items(): - if x == 0 or y == 0: - continue - cell = self.sheet.getcell(x, y) - if cell is None: - gridcell['text'] = "" - else: - if hasattr(cell, 'format'): - text, alignment = cell.format() - else: - text, alignment = str(cell), LEFT - gridcell['text'] = text - gridcell['anchor'] = align2anchor[alignment] - - -def test_basic(): - "Basic non-gui self-test." - a = Sheet() - for x in range(1, 11): - for y in range(1, 11): - if x == 1: - cell = NumericCell(y) - elif y == 1: - cell = NumericCell(x) - else: - c1 = cellname(x, 1) - c2 = cellname(1, y) - formula = "%s*%s" % (c1, c2) - cell = FormulaCell(formula) - a.setcell(x, y, cell) -## if os.path.isfile("sheet1.xml"): -## print "Loading from sheet1.xml" -## a.load("sheet1.xml") - a.display() - a.save("sheet1.xml") - -def test_gui(): - "GUI test." - if sys.argv[1:]: - filename = sys.argv[1] - else: - filename = "sheet1.xml" - g = SheetGUI(filename) - g.root.mainloop() - -if __name__ == '__main__': - #test_basic() - test_gui() diff --git a/Tools/demo/vector.py b/Tools/demo/vector.py deleted file mode 100755 index 6df1f50a8998..000000000000 --- a/Tools/demo/vector.py +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env python3 - -""" -A demonstration of classes and their special methods in Python. -""" - -class Vec: - """A simple vector class. - - Instances of the Vec class can be constructed from numbers - - >>> a = Vec(1, 2, 3) - >>> b = Vec(3, 2, 1) - - added - >>> a + b - Vec(4, 4, 4) - - subtracted - >>> a - b - Vec(-2, 0, 2) - - and multiplied by a scalar on the left - >>> 3.0 * a - Vec(3.0, 6.0, 9.0) - - or on the right - >>> a * 3.0 - Vec(3.0, 6.0, 9.0) - - and dot product - >>> a.dot(b) - 10 - - and printed in vector notation - >>> print(a) - <1 2 3> - - """ - - def __init__(self, *v): - self.v = list(v) - - @classmethod - def fromlist(cls, v): - if not isinstance(v, list): - raise TypeError - inst = cls() - inst.v = v - return inst - - def __repr__(self): - args = ', '.join([repr(x) for x in self.v]) - return f'{type(self).__name__}({args})' - - def __str__(self): - components = ' '.join([str(x) for x in self.v]) - return f'<{components}>' - - def __len__(self): - return len(self.v) - - def __getitem__(self, i): - return self.v[i] - - def __add__(self, other): - "Element-wise addition" - v = [x + y for x, y in zip(self.v, other.v)] - return Vec.fromlist(v) - - def __sub__(self, other): - "Element-wise subtraction" - v = [x - y for x, y in zip(self.v, other.v)] - return Vec.fromlist(v) - - def __mul__(self, scalar): - "Multiply by scalar" - v = [x * scalar for x in self.v] - return Vec.fromlist(v) - - __rmul__ = __mul__ - - def dot(self, other): - "Vector dot product" - if not isinstance(other, Vec): - raise TypeError - return sum(x_i * y_i for (x_i, y_i) in zip(self, other)) - - -def test(): - import doctest - doctest.testmod() - -test() From webhook-mailer at python.org Mon Oct 3 14:36:24 2022 From: webhook-mailer at python.org (markshannon) Date: Mon, 03 Oct 2022 18:36:24 -0000 Subject: [Python-checkins] gh-94808: `_PyLineTable_StartsLine` was not used (GH-96609) Message-ID: https://github.com/python/cpython/commit/e990c6af086e00dedc877d12b74c1ceedec511d1 commit: e990c6af086e00dedc877d12b74c1ceedec511d1 branch: main author: Nikita Sobolev committer: markshannon date: 2022-10-03T19:35:43+01:00 summary: gh-94808: `_PyLineTable_StartsLine` was not used (GH-96609) files: M Objects/codeobject.c diff --git a/Objects/codeobject.c b/Objects/codeobject.c index 72712f40e42c..7d0d038f489a 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -1011,33 +1011,6 @@ _PyLineTable_NextAddressRange(PyCodeAddressRange *range) return 1; } -int -_PyLineTable_StartsLine(PyCodeAddressRange *range) -{ - if (range->ar_start <= 0) { - return 0; - } - const uint8_t *ptr = range->opaque.lo_next; - do { - ptr--; - } while (((*ptr) & 128) == 0); - int code = ((*ptr)>> 3) & 15; - switch(code) { - case PY_CODE_LOCATION_INFO_LONG: - return 0; - case PY_CODE_LOCATION_INFO_NO_COLUMNS: - case PY_CODE_LOCATION_INFO_NONE: - return ptr[1] != 0; - case PY_CODE_LOCATION_INFO_ONE_LINE0: - return 0; - case PY_CODE_LOCATION_INFO_ONE_LINE1: - case PY_CODE_LOCATION_INFO_ONE_LINE2: - return 1; - default: - return 0; - } -} - static int emit_pair(PyObject **bytes, int *offset, int a, int b) { From webhook-mailer at python.org Mon Oct 3 15:09:13 2022 From: webhook-mailer at python.org (benjaminp) Date: Mon, 03 Oct 2022 19:09:13 -0000 Subject: [Python-checkins] Fix typos in `bltinmodule.c`. (GH-97766) Message-ID: https://github.com/python/cpython/commit/873a2f25272ca9fb027866a9730c44ba627b30cc commit: 873a2f25272ca9fb027866a9730c44ba627b30cc branch: main author: Nikita Sobolev committer: benjaminp date: 2022-10-03T12:09:03-07:00 summary: Fix typos in `bltinmodule.c`. (GH-97766) files: M Python/bltinmodule.c M Python/clinic/bltinmodule.c.h diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 6284bbdf9746..551e4f39b27a 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -261,8 +261,8 @@ importlib.import_module() to programmatically import a module. The globals argument is only used to determine the context; they are not modified. The locals argument is unused. The fromlist -should be a list of names to emulate ``from name import ...'', or an -empty list to emulate ``import name''. +should be a list of names to emulate ``from name import ...``, or an +empty list to emulate ``import name``. When importing a module from a package, note that __import__('A.B', ...) returns package A when fromlist is empty, but its submodule B when fromlist is not empty. The level argument is used to determine whether to @@ -273,7 +273,7 @@ is the number of parent directories to search relative to the current module. static PyObject * builtin___import___impl(PyObject *module, PyObject *name, PyObject *globals, PyObject *locals, PyObject *fromlist, int level) -/*[clinic end generated code: output=4febeda88a0cd245 input=35e9a6460412430f]*/ +/*[clinic end generated code: output=4febeda88a0cd245 input=73f4b960ea5b9dd6]*/ { return PyImport_ImportModuleLevelObject(name, globals, locals, fromlist, level); @@ -1510,13 +1510,13 @@ setattr as builtin_setattr Sets the named attribute on the given object to the specified value. -setattr(x, 'y', v) is equivalent to ``x.y = v'' +setattr(x, 'y', v) is equivalent to ``x.y = v`` [clinic start generated code]*/ static PyObject * builtin_setattr_impl(PyObject *module, PyObject *obj, PyObject *name, PyObject *value) -/*[clinic end generated code: output=dc2ce1d1add9acb4 input=bd2b7ca6875a1899]*/ +/*[clinic end generated code: output=dc2ce1d1add9acb4 input=5e26417f2e8598d4]*/ { if (PyObject_SetAttr(obj, name, value) != 0) return NULL; @@ -1533,12 +1533,12 @@ delattr as builtin_delattr Deletes the named attribute from the given object. -delattr(x, 'y') is equivalent to ``del x.y'' +delattr(x, 'y') is equivalent to ``del x.y`` [clinic start generated code]*/ static PyObject * builtin_delattr_impl(PyObject *module, PyObject *obj, PyObject *name) -/*[clinic end generated code: output=85134bc58dff79fa input=db16685d6b4b9410]*/ +/*[clinic end generated code: output=85134bc58dff79fa input=164865623abe7216]*/ { if (PyObject_SetAttr(obj, name, (PyObject *)NULL) != 0) return NULL; diff --git a/Python/clinic/bltinmodule.c.h b/Python/clinic/bltinmodule.c.h index abe5476b283b..0feba5742df2 100644 --- a/Python/clinic/bltinmodule.c.h +++ b/Python/clinic/bltinmodule.c.h @@ -21,8 +21,8 @@ PyDoc_STRVAR(builtin___import____doc__, "\n" "The globals argument is only used to determine the context;\n" "they are not modified. The locals argument is unused. The fromlist\n" -"should be a list of names to emulate ``from name import ...\'\', or an\n" -"empty list to emulate ``import name\'\'.\n" +"should be a list of names to emulate ``from name import ...``, or an\n" +"empty list to emulate ``import name``.\n" "When importing a module from a package, note that __import__(\'A.B\', ...)\n" "returns package A when fromlist is empty, but its submodule B when\n" "fromlist is not empty. The level argument is used to determine whether to\n" @@ -614,7 +614,7 @@ PyDoc_STRVAR(builtin_setattr__doc__, "\n" "Sets the named attribute on the given object to the specified value.\n" "\n" -"setattr(x, \'y\', v) is equivalent to ``x.y = v\'\'"); +"setattr(x, \'y\', v) is equivalent to ``x.y = v``"); #define BUILTIN_SETATTR_METHODDEF \ {"setattr", _PyCFunction_CAST(builtin_setattr), METH_FASTCALL, builtin_setattr__doc__}, @@ -649,7 +649,7 @@ PyDoc_STRVAR(builtin_delattr__doc__, "\n" "Deletes the named attribute from the given object.\n" "\n" -"delattr(x, \'y\') is equivalent to ``del x.y\'\'"); +"delattr(x, \'y\') is equivalent to ``del x.y``"); #define BUILTIN_DELATTR_METHODDEF \ {"delattr", _PyCFunction_CAST(builtin_delattr), METH_FASTCALL, builtin_delattr__doc__}, @@ -1212,4 +1212,4 @@ builtin_issubclass(PyObject *module, PyObject *const *args, Py_ssize_t nargs) exit: return return_value; } -/*[clinic end generated code: output=919725bf5d400acf input=a9049054013a1b77]*/ +/*[clinic end generated code: output=f3da5510745785af input=a9049054013a1b77]*/ From webhook-mailer at python.org Mon Oct 3 16:10:37 2022 From: webhook-mailer at python.org (benjaminp) Date: Mon, 03 Oct 2022 20:10:37 -0000 Subject: [Python-checkins] [3.11] Fix typos in `bltinmodule.c`. (GH-97789) Message-ID: https://github.com/python/cpython/commit/4d4b1e6c0b4b71cdf0438279ee11f1f49104e422 commit: 4d4b1e6c0b4b71cdf0438279ee11f1f49104e422 branch: 3.11 author: Benjamin Peterson committer: benjaminp date: 2022-10-03T13:10:14-07:00 summary: [3.11] Fix typos in `bltinmodule.c`. (GH-97789) (cherry picked from commit 873a2f25272ca9fb027866a9730c44ba627b30cc) Co-authored-by: Nikita Sobolev files: M Python/bltinmodule.c M Python/clinic/bltinmodule.c.h diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 072bf75bf8d6..94a7819c252e 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -260,8 +260,8 @@ importlib.import_module() to programmatically import a module. The globals argument is only used to determine the context; they are not modified. The locals argument is unused. The fromlist -should be a list of names to emulate ``from name import ...'', or an -empty list to emulate ``import name''. +should be a list of names to emulate ``from name import ...``, or an +empty list to emulate ``import name``. When importing a module from a package, note that __import__('A.B', ...) returns package A when fromlist is empty, but its submodule B when fromlist is not empty. The level argument is used to determine whether to @@ -272,7 +272,7 @@ is the number of parent directories to search relative to the current module. static PyObject * builtin___import___impl(PyObject *module, PyObject *name, PyObject *globals, PyObject *locals, PyObject *fromlist, int level) -/*[clinic end generated code: output=4febeda88a0cd245 input=35e9a6460412430f]*/ +/*[clinic end generated code: output=4febeda88a0cd245 input=73f4b960ea5b9dd6]*/ { return PyImport_ImportModuleLevelObject(name, globals, locals, fromlist, level); @@ -1509,13 +1509,13 @@ setattr as builtin_setattr Sets the named attribute on the given object to the specified value. -setattr(x, 'y', v) is equivalent to ``x.y = v'' +setattr(x, 'y', v) is equivalent to ``x.y = v`` [clinic start generated code]*/ static PyObject * builtin_setattr_impl(PyObject *module, PyObject *obj, PyObject *name, PyObject *value) -/*[clinic end generated code: output=dc2ce1d1add9acb4 input=bd2b7ca6875a1899]*/ +/*[clinic end generated code: output=dc2ce1d1add9acb4 input=5e26417f2e8598d4]*/ { if (PyObject_SetAttr(obj, name, value) != 0) return NULL; @@ -1532,12 +1532,12 @@ delattr as builtin_delattr Deletes the named attribute from the given object. -delattr(x, 'y') is equivalent to ``del x.y'' +delattr(x, 'y') is equivalent to ``del x.y`` [clinic start generated code]*/ static PyObject * builtin_delattr_impl(PyObject *module, PyObject *obj, PyObject *name) -/*[clinic end generated code: output=85134bc58dff79fa input=db16685d6b4b9410]*/ +/*[clinic end generated code: output=85134bc58dff79fa input=164865623abe7216]*/ { if (PyObject_SetAttr(obj, name, (PyObject *)NULL) != 0) return NULL; diff --git a/Python/clinic/bltinmodule.c.h b/Python/clinic/bltinmodule.c.h index 48f65091164d..5d9a16a7b682 100644 --- a/Python/clinic/bltinmodule.c.h +++ b/Python/clinic/bltinmodule.c.h @@ -15,8 +15,8 @@ PyDoc_STRVAR(builtin___import____doc__, "\n" "The globals argument is only used to determine the context;\n" "they are not modified. The locals argument is unused. The fromlist\n" -"should be a list of names to emulate ``from name import ...\'\', or an\n" -"empty list to emulate ``import name\'\'.\n" +"should be a list of names to emulate ``from name import ...``, or an\n" +"empty list to emulate ``import name``.\n" "When importing a module from a package, note that __import__(\'A.B\', ...)\n" "returns package A when fromlist is empty, but its submodule B when\n" "fromlist is not empty. The level argument is used to determine whether to\n" @@ -539,7 +539,7 @@ PyDoc_STRVAR(builtin_setattr__doc__, "\n" "Sets the named attribute on the given object to the specified value.\n" "\n" -"setattr(x, \'y\', v) is equivalent to ``x.y = v\'\'"); +"setattr(x, \'y\', v) is equivalent to ``x.y = v``"); #define BUILTIN_SETATTR_METHODDEF \ {"setattr", _PyCFunction_CAST(builtin_setattr), METH_FASTCALL, builtin_setattr__doc__}, @@ -574,7 +574,7 @@ PyDoc_STRVAR(builtin_delattr__doc__, "\n" "Deletes the named attribute from the given object.\n" "\n" -"delattr(x, \'y\') is equivalent to ``del x.y\'\'"); +"delattr(x, \'y\') is equivalent to ``del x.y``"); #define BUILTIN_DELATTR_METHODDEF \ {"delattr", _PyCFunction_CAST(builtin_delattr), METH_FASTCALL, builtin_delattr__doc__}, @@ -1045,4 +1045,4 @@ builtin_issubclass(PyObject *module, PyObject *const *args, Py_ssize_t nargs) exit: return return_value; } -/*[clinic end generated code: output=a2c5c53e8aead7c3 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=cc844ea007c1241f input=a9049054013a1b77]*/ From webhook-mailer at python.org Mon Oct 3 16:34:45 2022 From: webhook-mailer at python.org (gvanrossum) Date: Mon, 03 Oct 2022 20:34:45 -0000 Subject: [Python-checkins] gh-94732: Fix KeyboardInterrupt race in asyncio run_forever() (#97765) Message-ID: https://github.com/python/cpython/commit/3a49dbb98ccc1b90554ed181386316efa38adfba commit: 3a49dbb98ccc1b90554ed181386316efa38adfba branch: main author: hetmankp <728670+hetmankp at users.noreply.github.com> committer: gvanrossum date: 2022-10-03T13:34:35-07:00 summary: gh-94732: Fix KeyboardInterrupt race in asyncio run_forever() (#97765) Ensure that the event loop's `_thread_id` attribute and the asyncgen hooks set by `sys.set_asyncgen_hooks()` are always restored no matter where a KeyboardInterrupt exception is raised. files: M Lib/asyncio/base_events.py diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index 2df9dcac8f72..66202f09794d 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -606,12 +606,13 @@ def run_forever(self): self._check_closed() self._check_running() self._set_coroutine_origin_tracking(self._debug) - self._thread_id = threading.get_ident() old_agen_hooks = sys.get_asyncgen_hooks() - sys.set_asyncgen_hooks(firstiter=self._asyncgen_firstiter_hook, - finalizer=self._asyncgen_finalizer_hook) try: + self._thread_id = threading.get_ident() + sys.set_asyncgen_hooks(firstiter=self._asyncgen_firstiter_hook, + finalizer=self._asyncgen_finalizer_hook) + events._set_running_loop(self) while True: self._run_once() From webhook-mailer at python.org Mon Oct 3 16:37:23 2022 From: webhook-mailer at python.org (orsenthil) Date: Mon, 03 Oct 2022 20:37:23 -0000 Subject: [Python-checkins] gh-94808: Add test coverage for PyObject_HasAttrString (#96627) Message-ID: https://github.com/python/cpython/commit/9302e331c7e2edf1bb42f6b31085408a315195f5 commit: 9302e331c7e2edf1bb42f6b31085408a315195f5 branch: main author: MonadChains committer: orsenthil date: 2022-10-03T13:37:15-07:00 summary: gh-94808: Add test coverage for PyObject_HasAttrString (#96627) * gh-94808: Add test for HasAttrString * Harmonize to Python C code style guidelines * Add check to verify no exception thrown files: M Lib/test/test_class.py M Modules/_testcapimodule.c diff --git a/Lib/test/test_class.py b/Lib/test/test_class.py index 91c53b7c894c..61df81b16977 100644 --- a/Lib/test/test_class.py +++ b/Lib/test/test_class.py @@ -445,6 +445,20 @@ def __delattr__(self, *args): del testme.cardinal self.assertCallStack([('__delattr__', (testme, "cardinal"))]) + def testHasAttrString(self): + import sys + from test.support import import_helper + _testcapi = import_helper.import_module('_testcapi') + + class A: + def __init__(self): + self.attr = 1 + + a = A() + self.assertEqual(_testcapi.hasattr_string(a, "attr"), True) + self.assertEqual(_testcapi.hasattr_string(a, "noattr"), False) + self.assertEqual(sys.exc_info(), (None, None, None)) + def testDel(self): x = [] diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index b8f71d47ed52..3d6535f50be9 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -4846,6 +4846,31 @@ sequence_setitem(PyObject *self, PyObject *args) } +static PyObject * +hasattr_string(PyObject *self, PyObject* args) +{ + PyObject* obj; + PyObject* attr_name; + + if (!PyArg_UnpackTuple(args, "hasattr_string", 2, 2, &obj, &attr_name)) { + return NULL; + } + + if (!PyUnicode_Check(attr_name)) { + PyErr_SetString(PyExc_TypeError, "attribute name must a be string"); + return PyErr_Occurred(); + } + + const char *name_str = PyUnicode_AsUTF8(attr_name); + if (PyObject_HasAttrString(obj, name_str)) { + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } +} + + /* Functions for testing C calling conventions (METH_*) are named meth_*, * e.g. "meth_varargs" for METH_VARARGS. * @@ -5707,6 +5732,7 @@ static PyMethodDef TestMethods[] = { {"write_unraisable_exc", test_write_unraisable_exc, METH_VARARGS}, {"sequence_getitem", sequence_getitem, METH_VARARGS}, {"sequence_setitem", sequence_setitem, METH_VARARGS}, + {"hasattr_string", hasattr_string, METH_VARARGS}, {"meth_varargs", meth_varargs, METH_VARARGS}, {"meth_varargs_keywords", _PyCFunction_CAST(meth_varargs_keywords), METH_VARARGS|METH_KEYWORDS}, {"meth_o", meth_o, METH_O}, From webhook-mailer at python.org Mon Oct 3 16:50:38 2022 From: webhook-mailer at python.org (orsenthil) Date: Mon, 03 Oct 2022 20:50:38 -0000 Subject: [Python-checkins] gh-94808: Coverage: Check picklablability of calliter (#95923) Message-ID: https://github.com/python/cpython/commit/cfbc7dd91059cb663c7fe13c661665943495ed7f commit: cfbc7dd91059cb663c7fe13c661665943495ed7f branch: main author: Michael Droettboom committer: orsenthil date: 2022-10-03T13:50:30-07:00 summary: gh-94808: Coverage: Check picklablability of calliter (#95923) files: M Lib/test/test_iter.py diff --git a/Lib/test/test_iter.py b/Lib/test/test_iter.py index 554f602f6252..acbdcb5f3020 100644 --- a/Lib/test/test_iter.py +++ b/Lib/test/test_iter.py @@ -81,6 +81,16 @@ class BadIterableClass: def __iter__(self): raise ZeroDivisionError +class CallableIterClass: + def __init__(self): + self.i = 0 + def __call__(self): + i = self.i + self.i = i + 1 + if i > 100: + raise IndexError # Emergency stop + return i + # Main test suite class TestCase(unittest.TestCase): @@ -237,16 +247,7 @@ def __iter__(self): # Test two-argument iter() with callable instance def test_iter_callable(self): - class C: - def __init__(self): - self.i = 0 - def __call__(self): - i = self.i - self.i = i + 1 - if i > 100: - raise IndexError # Emergency stop - return i - self.check_iterator(iter(C(), 10), list(range(10)), pickle=False) + self.check_iterator(iter(CallableIterClass(), 10), list(range(10)), pickle=True) # Test two-argument iter() with function def test_iter_function(self): From webhook-mailer at python.org Mon Oct 3 16:55:54 2022 From: webhook-mailer at python.org (gpshead) Date: Mon, 03 Oct 2022 20:55:54 -0000 Subject: [Python-checkins] gh-96512: Move int_max_str_digits setting to PyConfig (#96944) Message-ID: https://github.com/python/cpython/commit/b0f89cb4311b696f875e58f14258ce315be09bce commit: b0f89cb4311b696f875e58f14258ce315be09bce branch: main author: Gregory P. Smith committer: gpshead date: 2022-10-03T13:55:45-07:00 summary: gh-96512: Move int_max_str_digits setting to PyConfig (#96944) It had to live as a global outside of PyConfig for stable ABI reasons in the pre-3.12 backports. This removes the `_Py_global_config_int_max_str_digits` and gets rid of the equivalent field in the internal `struct _is PyInterpreterState` as code can just use the existing nested config struct within that. Adds tests to verify unique settings and configs in subinterpreters. files: A Misc/NEWS.d/next/C API/2022-09-20-01-04-57.gh-issue-96512.msZTjF.rst M Doc/c-api/init_config.rst M Include/cpython/initconfig.h M Include/internal/pycore_initconfig.h M Include/internal/pycore_interp.h M Lib/test/test_capi.py M Lib/test/test_cmd_line.py M Lib/test/test_embed.py M Lib/test/test_int.py M Objects/longobject.c M Programs/_testembed.c M Python/initconfig.c M Python/sysmodule.c diff --git a/Doc/c-api/init_config.rst b/Doc/c-api/init_config.rst index c4a342ee811c..ea76315fc09b 100644 --- a/Doc/c-api/init_config.rst +++ b/Doc/c-api/init_config.rst @@ -828,6 +828,24 @@ PyConfig Default: ``0``. + .. c:member:: int int_max_str_digits + + Configures the :ref:`integer string conversion length limitation + `. An initial value of ``-1`` means the value will + be taken from the command line or environment or otherwise default to + 4300 (:data:`sys.int_info.default_max_str_digits`). A value of ``0`` + disables the limitation. Values greater than zero but less than 640 + (:data:`sys.int_info.str_digits_check_threshold`) are unsupported and + will produce an error. + + Configured by the :option:`-X int_max_str_digits <-X>` command line + flag or the :envvar:`PYTHONINTMAXSTRDIGITS` environment varable. + + Default: ``-1`` in Python mode. 4300 + (:data:`sys.int_info.default_max_str_digits`) in isolated mode. + + .. versionadded:: 3.12 + .. c:member:: int isolated If greater than ``0``, enable isolated mode: diff --git a/Include/cpython/initconfig.h b/Include/cpython/initconfig.h index c6057a4c3ed9..c22c8d52b4f2 100644 --- a/Include/cpython/initconfig.h +++ b/Include/cpython/initconfig.h @@ -178,6 +178,7 @@ typedef struct PyConfig { wchar_t *check_hash_pycs_mode; int use_frozen_modules; int safe_path; + int int_max_str_digits; /* --- Path configuration inputs ------------ */ int pathconfig_warnings; diff --git a/Include/internal/pycore_initconfig.h b/Include/internal/pycore_initconfig.h index 6e491261d55c..69f88d7d1d46 100644 --- a/Include/internal/pycore_initconfig.h +++ b/Include/internal/pycore_initconfig.h @@ -170,8 +170,6 @@ extern void _Py_DumpPathConfig(PyThreadState *tstate); PyAPI_FUNC(PyObject*) _Py_Get_Getpath_CodeObject(void); -extern int _Py_global_config_int_max_str_digits; // TODO(gpshead): move this into PyConfig in 3.12 after the backports ship. - /* --- Function used for testing ---------------------------------- */ diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index e7f914ec2fe5..b21708a388b3 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -175,8 +175,6 @@ struct _is { struct types_state types; struct callable_cache callable_cache; - int int_max_str_digits; - /* The following fields are here to avoid allocation during init. The data is exposed through PyInterpreterState pointer fields. These fields should not be accessed directly outside of init. diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py index 94f080978b03..2c6fe34d3b78 100644 --- a/Lib/test/test_capi.py +++ b/Lib/test/test_capi.py @@ -999,6 +999,39 @@ async def foo(arg): return await arg # Py 3.5 self.assertEqual(ret, 0) self.assertEqual(pickle.load(f), {'a': '123x', 'b': '123'}) + def test_py_config_isoloated_per_interpreter(self): + # A config change in one interpreter must not leak to out to others. + # + # This test could verify ANY config value, it just happens to have been + # written around the time of int_max_str_digits. Refactoring is okay. + code = """if 1: + import sys, _testinternalcapi + + # Any config value would do, this happens to be the one being + # double checked at the time this test was written. + config = _testinternalcapi.get_config() + config['int_max_str_digits'] = 55555 + _testinternalcapi.set_config(config) + sub_value = _testinternalcapi.get_config()['int_max_str_digits'] + assert sub_value == 55555, sub_value + """ + before_config = _testinternalcapi.get_config() + assert before_config['int_max_str_digits'] != 55555 + self.assertEqual(support.run_in_subinterp(code), 0, + 'subinterp code failure, check stderr.') + after_config = _testinternalcapi.get_config() + self.assertIsNot( + before_config, after_config, + "Expected get_config() to return a new dict on each call") + self.assertEqual(before_config, after_config, + "CAUTION: Tests executed after this may be " + "running under an altered config.") + # try:...finally: calling set_config(before_config) not done + # as that results in sys.argv, sys.path, and sys.warnoptions + # "being modified by test_capi" per test.regrtest. So if this + # test fails, assume that the environment in this process may + # be altered and suspect. + def test_mutate_exception(self): """ Exceptions saved in global module state get shared between diff --git a/Lib/test/test_cmd_line.py b/Lib/test/test_cmd_line.py index 3de8c3d4b11f..942980030635 100644 --- a/Lib/test/test_cmd_line.py +++ b/Lib/test/test_cmd_line.py @@ -882,7 +882,8 @@ def res2int(res): return tuple(int(i) for i in out.split()) res = assert_python_ok('-c', code) - self.assertEqual(res2int(res), (-1, sys.get_int_max_str_digits())) + current_max = sys.get_int_max_str_digits() + self.assertEqual(res2int(res), (current_max, current_max)) res = assert_python_ok('-X', 'int_max_str_digits=0', '-c', code) self.assertEqual(res2int(res), (0, 0)) res = assert_python_ok('-X', 'int_max_str_digits=4000', '-c', code) diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py index 6b5d48547b8a..c5aeb9459848 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -434,6 +434,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase): 'install_signal_handlers': 1, 'use_hash_seed': 0, 'hash_seed': 0, + 'int_max_str_digits': sys.int_info.default_max_str_digits, 'faulthandler': 0, 'tracemalloc': 0, 'perf_profiling': 0, @@ -876,6 +877,7 @@ def test_init_from_config(self): 'platlibdir': 'my_platlibdir', 'module_search_paths': self.IGNORE_CONFIG, 'safe_path': 1, + 'int_max_str_digits': 31337, 'check_hash_pycs_mode': 'always', 'pathconfig_warnings': 0, @@ -912,6 +914,7 @@ def test_init_compat_env(self): 'platlibdir': 'env_platlibdir', 'module_search_paths': self.IGNORE_CONFIG, 'safe_path': 1, + 'int_max_str_digits': 4567, } self.check_all_configs("test_init_compat_env", config, preconfig, api=API_COMPAT) @@ -944,6 +947,7 @@ def test_init_python_env(self): 'platlibdir': 'env_platlibdir', 'module_search_paths': self.IGNORE_CONFIG, 'safe_path': 1, + 'int_max_str_digits': 4567, } self.check_all_configs("test_init_python_env", config, preconfig, api=API_PYTHON) diff --git a/Lib/test/test_int.py b/Lib/test/test_int.py index c972b8afb48d..625c388cd947 100644 --- a/Lib/test/test_int.py +++ b/Lib/test/test_int.py @@ -770,6 +770,26 @@ def test_int_from_other_bases(self): with self.subTest(base=base): self._other_base_helper(base) + def test_int_max_str_digits_is_per_interpreter(self): + # Changing the limit in one interpreter does not change others. + code = """if 1: + # Subinterpreters maintain and enforce their own limit + import sys + sys.set_int_max_str_digits(2323) + try: + int('3'*3333) + except ValueError: + pass + else: + raise AssertionError('Expected a int max str digits ValueError.') + """ + with support.adjust_int_max_str_digits(4000): + before_value = sys.get_int_max_str_digits() + self.assertEqual(support.run_in_subinterp(code), 0, + 'subinterp code failure, check stderr.') + after_value = sys.get_int_max_str_digits() + self.assertEqual(before_value, after_value) + class IntSubclassStrDigitLimitsTests(IntStrDigitLimitsTests): int_class = IntSubclass diff --git a/Misc/NEWS.d/next/C API/2022-09-20-01-04-57.gh-issue-96512.msZTjF.rst b/Misc/NEWS.d/next/C API/2022-09-20-01-04-57.gh-issue-96512.msZTjF.rst new file mode 100644 index 000000000000..787bee3ee23b --- /dev/null +++ b/Misc/NEWS.d/next/C API/2022-09-20-01-04-57.gh-issue-96512.msZTjF.rst @@ -0,0 +1,2 @@ +Configuration for the :ref:`integer string conversion length limitation +` now lives in the PyConfig C API struct. diff --git a/Objects/longobject.c b/Objects/longobject.c index 77a8782d8a67..d9f3d393b998 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -1767,7 +1767,7 @@ long_to_decimal_string_internal(PyObject *aa, if (size_a >= 10 * _PY_LONG_MAX_STR_DIGITS_THRESHOLD / (3 * PyLong_SHIFT) + 2) { PyInterpreterState *interp = _PyInterpreterState_GET(); - int max_str_digits = interp->int_max_str_digits; + int max_str_digits = interp->config.int_max_str_digits; if ((max_str_digits > 0) && (max_str_digits / (3 * PyLong_SHIFT) <= (size_a - 11) / 10)) { PyErr_Format(PyExc_ValueError, _MAX_STR_DIGITS_ERROR_FMT_TO_STR, @@ -1837,7 +1837,7 @@ long_to_decimal_string_internal(PyObject *aa, } if (strlen > _PY_LONG_MAX_STR_DIGITS_THRESHOLD) { PyInterpreterState *interp = _PyInterpreterState_GET(); - int max_str_digits = interp->int_max_str_digits; + int max_str_digits = interp->config.int_max_str_digits; Py_ssize_t strlen_nosign = strlen - negative; if ((max_str_digits > 0) && (strlen_nosign > max_str_digits)) { Py_DECREF(scratch); @@ -2578,7 +2578,7 @@ long_from_string_base(const char **str, int base, PyLongObject **res) * quadratic algorithm. */ if (digits > _PY_LONG_MAX_STR_DIGITS_THRESHOLD) { PyInterpreterState *interp = _PyInterpreterState_GET(); - int max_str_digits = interp->int_max_str_digits; + int max_str_digits = interp->config.int_max_str_digits; if ((max_str_digits > 0) && (digits > max_str_digits)) { PyErr_Format(PyExc_ValueError, _MAX_STR_DIGITS_ERROR_FMT_TO_INT, max_str_digits, digits); @@ -6235,10 +6235,6 @@ _PyLong_InitTypes(PyInterpreterState *interp) return _PyStatus_ERR("can't init int info type"); } } - interp->int_max_str_digits = _Py_global_config_int_max_str_digits; - if (interp->int_max_str_digits == -1) { - interp->int_max_str_digits = _PY_LONG_DEFAULT_MAX_STR_DIGITS; - } return _PyStatus_OK(); } diff --git a/Programs/_testembed.c b/Programs/_testembed.c index e5b138ce84bb..d635c5a4abe3 100644 --- a/Programs/_testembed.c +++ b/Programs/_testembed.c @@ -683,6 +683,9 @@ static int test_init_from_config(void) config._isolated_interpreter = 1; + putenv("PYTHONINTMAXSTRDIGITS=6666"); + config.int_max_str_digits = 31337; + init_from_config_clear(&config); dump_config(); @@ -748,6 +751,7 @@ static void set_most_env_vars(void) putenv("PYTHONIOENCODING=iso8859-1:replace"); putenv("PYTHONPLATLIBDIR=env_platlibdir"); putenv("PYTHONSAFEPATH=1"); + putenv("PYTHONINTMAXSTRDIGITS=4567"); } diff --git a/Python/initconfig.c b/Python/initconfig.c index bfbb7dbacf90..bbc2ebb09fd0 100644 --- a/Python/initconfig.c +++ b/Python/initconfig.c @@ -695,6 +695,7 @@ config_check_consistency(const PyConfig *config) assert(config->pathconfig_warnings >= 0); assert(config->_is_python_build >= 0); assert(config->safe_path >= 0); + assert(config->int_max_str_digits >= 0); // config->use_frozen_modules is initialized later // by _PyConfig_InitImportConfig(). return 1; @@ -789,14 +790,11 @@ _PyConfig_InitCompatConfig(PyConfig *config) config->use_frozen_modules = 1; #endif config->safe_path = 0; + config->int_max_str_digits = -1; config->_is_python_build = 0; config->code_debug_ranges = 1; } -/* Excluded from public struct PyConfig for backporting reasons. */ -/* default to unconfigured, _PyLong_InitTypes() does the rest */ -int _Py_global_config_int_max_str_digits = -1; - static void config_init_defaults(PyConfig *config) @@ -849,6 +847,7 @@ PyConfig_InitIsolatedConfig(PyConfig *config) config->faulthandler = 0; config->tracemalloc = 0; config->perf_profiling = 0; + config->int_max_str_digits = _PY_LONG_DEFAULT_MAX_STR_DIGITS; config->safe_path = 1; config->pathconfig_warnings = 0; #ifdef MS_WINDOWS @@ -1021,6 +1020,7 @@ _PyConfig_Copy(PyConfig *config, const PyConfig *config2) COPY_ATTR(safe_path); COPY_WSTRLIST(orig_argv); COPY_ATTR(_is_python_build); + COPY_ATTR(int_max_str_digits); #undef COPY_ATTR #undef COPY_WSTR_ATTR @@ -1128,6 +1128,7 @@ _PyConfig_AsDict(const PyConfig *config) SET_ITEM_INT(use_frozen_modules); SET_ITEM_INT(safe_path); SET_ITEM_INT(_is_python_build); + SET_ITEM_INT(int_max_str_digits); return dict; @@ -1317,6 +1318,12 @@ _PyConfig_FromDict(PyConfig *config, PyObject *dict) } \ CHECK_VALUE(#KEY, config->KEY >= 0); \ } while (0) +#define GET_INT(KEY) \ + do { \ + if (config_dict_get_int(dict, #KEY, &config->KEY) < 0) { \ + return -1; \ + } \ + } while (0) #define GET_WSTR(KEY) \ do { \ if (config_dict_get_wstr(dict, #KEY, config, &config->KEY) < 0) { \ @@ -1415,9 +1422,11 @@ _PyConfig_FromDict(PyConfig *config, PyObject *dict) GET_UINT(use_frozen_modules); GET_UINT(safe_path); GET_UINT(_is_python_build); + GET_INT(int_max_str_digits); #undef CHECK_VALUE #undef GET_UINT +#undef GET_INT #undef GET_WSTR #undef GET_WSTR_OPT return 0; @@ -1782,7 +1791,7 @@ config_init_int_max_str_digits(PyConfig *config) const char *env = config_get_env(config, "PYTHONINTMAXSTRDIGITS"); if (env) { - int valid = 0; + bool valid = 0; if (!_Py_str_to_int(env, &maxdigits)) { valid = ((maxdigits == 0) || (maxdigits >= _PY_LONG_MAX_STR_DIGITS_THRESHOLD)); } @@ -1794,13 +1803,13 @@ config_init_int_max_str_digits(PyConfig *config) STRINGIFY(_PY_LONG_MAX_STR_DIGITS_THRESHOLD) " or 0 for unlimited."); } - _Py_global_config_int_max_str_digits = maxdigits; + config->int_max_str_digits = maxdigits; } const wchar_t *xoption = config_get_xoption(config, L"int_max_str_digits"); if (xoption) { const wchar_t *sep = wcschr(xoption, L'='); - int valid = 0; + bool valid = 0; if (sep) { if (!config_wstr_to_int(sep + 1, &maxdigits)) { valid = ((maxdigits == 0) || (maxdigits >= _PY_LONG_MAX_STR_DIGITS_THRESHOLD)); @@ -1814,7 +1823,10 @@ config_init_int_max_str_digits(PyConfig *config) #undef _STRINGIFY #undef STRINGIFY } - _Py_global_config_int_max_str_digits = maxdigits; + config->int_max_str_digits = maxdigits; + } + if (config->int_max_str_digits < 0) { + config->int_max_str_digits = _PY_LONG_DEFAULT_MAX_STR_DIGITS; } return _PyStatus_OK(); } @@ -1882,7 +1894,7 @@ config_read_complex_options(PyConfig *config) } } - if (_Py_global_config_int_max_str_digits < 0) { + if (config->int_max_str_digits < 0) { status = config_init_int_max_str_digits(config); if (_PyStatus_EXCEPTION(status)) { return status; diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 653b5a55e885..584a8be7094b 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1717,7 +1717,7 @@ sys_get_int_max_str_digits_impl(PyObject *module) /*[clinic end generated code: output=0042f5e8ae0e8631 input=8dab13e2023e60d5]*/ { PyInterpreterState *interp = _PyInterpreterState_GET(); - return PyLong_FromSsize_t(interp->int_max_str_digits); + return PyLong_FromLong(interp->config.int_max_str_digits); } /*[clinic input] @@ -1734,7 +1734,7 @@ sys_set_int_max_str_digits_impl(PyObject *module, int maxdigits) { PyThreadState *tstate = _PyThreadState_GET(); if ((!maxdigits) || (maxdigits >= _PY_LONG_MAX_STR_DIGITS_THRESHOLD)) { - tstate->interp->int_max_str_digits = maxdigits; + tstate->interp->config.int_max_str_digits = maxdigits; Py_RETURN_NONE; } else { PyErr_Format( @@ -2810,7 +2810,7 @@ set_flags_from_config(PyInterpreterState *interp, PyObject *flags) SetFlag(preconfig->utf8_mode); SetFlag(config->warn_default_encoding); SetFlagObj(PyBool_FromLong(config->safe_path)); - SetFlag(_Py_global_config_int_max_str_digits); + SetFlag(config->int_max_str_digits); #undef SetFlagObj #undef SetFlag return 0; From webhook-mailer at python.org Mon Oct 3 17:25:54 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 03 Oct 2022 21:25:54 -0000 Subject: [Python-checkins] gh-94808: Coverage: Check picklablability of calliter (GH-95923) Message-ID: https://github.com/python/cpython/commit/fe99b64bef012cdf90b84a7cfe62a1d1a550ce55 commit: fe99b64bef012cdf90b84a7cfe62a1d1a550ce55 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-03T14:25:48-07:00 summary: gh-94808: Coverage: Check picklablability of calliter (GH-95923) (cherry picked from commit cfbc7dd91059cb663c7fe13c661665943495ed7f) Co-authored-by: Michael Droettboom files: M Lib/test/test_iter.py diff --git a/Lib/test/test_iter.py b/Lib/test/test_iter.py index 554f602f6252..acbdcb5f3020 100644 --- a/Lib/test/test_iter.py +++ b/Lib/test/test_iter.py @@ -81,6 +81,16 @@ class BadIterableClass: def __iter__(self): raise ZeroDivisionError +class CallableIterClass: + def __init__(self): + self.i = 0 + def __call__(self): + i = self.i + self.i = i + 1 + if i > 100: + raise IndexError # Emergency stop + return i + # Main test suite class TestCase(unittest.TestCase): @@ -237,16 +247,7 @@ def __iter__(self): # Test two-argument iter() with callable instance def test_iter_callable(self): - class C: - def __init__(self): - self.i = 0 - def __call__(self): - i = self.i - self.i = i + 1 - if i > 100: - raise IndexError # Emergency stop - return i - self.check_iterator(iter(C(), 10), list(range(10)), pickle=False) + self.check_iterator(iter(CallableIterClass(), 10), list(range(10)), pickle=True) # Test two-argument iter() with function def test_iter_function(self): From webhook-mailer at python.org Mon Oct 3 17:39:43 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 03 Oct 2022 21:39:43 -0000 Subject: [Python-checkins] gh-94732: Fix KeyboardInterrupt race in asyncio run_forever() (GH-97765) Message-ID: https://github.com/python/cpython/commit/4420da0aefc31b066f3b0d80ceed8ce0edbcc7c2 commit: 4420da0aefc31b066f3b0d80ceed8ce0edbcc7c2 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-03T14:39:24-07:00 summary: gh-94732: Fix KeyboardInterrupt race in asyncio run_forever() (GH-97765) Ensure that the event loop's `_thread_id` attribute and the asyncgen hooks set by `sys.set_asyncgen_hooks()` are always restored no matter where a KeyboardInterrupt exception is raised. (cherry picked from commit 3a49dbb98ccc1b90554ed181386316efa38adfba) Co-authored-by: hetmankp <728670+hetmankp at users.noreply.github.com> files: M Lib/asyncio/base_events.py diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index 7c06e48a671a..9b8167d7a139 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -595,12 +595,13 @@ def run_forever(self): self._check_closed() self._check_running() self._set_coroutine_origin_tracking(self._debug) - self._thread_id = threading.get_ident() old_agen_hooks = sys.get_asyncgen_hooks() - sys.set_asyncgen_hooks(firstiter=self._asyncgen_firstiter_hook, - finalizer=self._asyncgen_finalizer_hook) try: + self._thread_id = threading.get_ident() + sys.set_asyncgen_hooks(firstiter=self._asyncgen_firstiter_hook, + finalizer=self._asyncgen_finalizer_hook) + events._set_running_loop(self) while True: self._run_once() From webhook-mailer at python.org Mon Oct 3 17:39:49 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 03 Oct 2022 21:39:49 -0000 Subject: [Python-checkins] gh-94732: Fix KeyboardInterrupt race in asyncio run_forever() (GH-97765) Message-ID: https://github.com/python/cpython/commit/a7e281150e9d4ad04f4b7276eb25870a0d37fbda commit: a7e281150e9d4ad04f4b7276eb25870a0d37fbda branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-03T14:39:44-07:00 summary: gh-94732: Fix KeyboardInterrupt race in asyncio run_forever() (GH-97765) Ensure that the event loop's `_thread_id` attribute and the asyncgen hooks set by `sys.set_asyncgen_hooks()` are always restored no matter where a KeyboardInterrupt exception is raised. (cherry picked from commit 3a49dbb98ccc1b90554ed181386316efa38adfba) Co-authored-by: hetmankp <728670+hetmankp at users.noreply.github.com> files: M Lib/asyncio/base_events.py diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index 1cc26ee7ccf0..23849852eb98 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -591,12 +591,13 @@ def run_forever(self): self._check_closed() self._check_running() self._set_coroutine_origin_tracking(self._debug) - self._thread_id = threading.get_ident() old_agen_hooks = sys.get_asyncgen_hooks() - sys.set_asyncgen_hooks(firstiter=self._asyncgen_firstiter_hook, - finalizer=self._asyncgen_finalizer_hook) try: + self._thread_id = threading.get_ident() + sys.set_asyncgen_hooks(firstiter=self._asyncgen_firstiter_hook, + finalizer=self._asyncgen_finalizer_hook) + events._set_running_loop(self) while True: self._run_once() From webhook-mailer at python.org Mon Oct 3 18:08:03 2022 From: webhook-mailer at python.org (orsenthil) Date: Mon, 03 Oct 2022 22:08:03 -0000 Subject: [Python-checkins] Document that MozillaCookieJar works for curl's cookie files (#91852) Message-ID: https://github.com/python/cpython/commit/0ea8b925d096629852d1045c2c53ff6ad63199cc commit: 0ea8b925d096629852d1045c2c53ff6ad63199cc branch: main author: Boris Verkhovskiy committer: orsenthil date: 2022-10-03T15:07:54-07:00 summary: Document that MozillaCookieJar works for curl's cookie files (#91852) MozillaCookieJar works for curl's cookies files: M Doc/library/http.cookiejar.rst M Lib/http/cookiejar.py diff --git a/Doc/library/http.cookiejar.rst b/Doc/library/http.cookiejar.rst index 53b3087a4b99..eb31315438f6 100644 --- a/Doc/library/http.cookiejar.rst +++ b/Doc/library/http.cookiejar.rst @@ -320,8 +320,8 @@ writing. .. class:: MozillaCookieJar(filename, delayload=None, policy=None) A :class:`FileCookieJar` that can load from and save cookies to disk in the - Mozilla ``cookies.txt`` file format (which is also used by the Lynx and Netscape - browsers). + Mozilla ``cookies.txt`` file format (which is also used by curl and the Lynx + and Netscape browsers). .. note:: diff --git a/Lib/http/cookiejar.py b/Lib/http/cookiejar.py index c514e0d382cb..65c45e2b17df 100644 --- a/Lib/http/cookiejar.py +++ b/Lib/http/cookiejar.py @@ -1985,7 +1985,7 @@ class MozillaCookieJar(FileCookieJar): This class differs from CookieJar only in the format it uses to save and load cookies to and from a file. This class uses the Mozilla/Netscape - `cookies.txt' format. lynx uses this file format, too. + `cookies.txt' format. curl and lynx use this file format, too. Don't expect cookies saved while the browser is running to be noticed by the browser (in fact, Mozilla on unix will overwrite your saved cookies if From webhook-mailer at python.org Mon Oct 3 18:28:10 2022 From: webhook-mailer at python.org (ericvsmith) Date: Mon, 03 Oct 2022 22:28:10 -0000 Subject: [Python-checkins] gh-96526: Clarify format and __format__ docstrings (gh-96648) Message-ID: https://github.com/python/cpython/commit/07b8e85d0e29bc59a7a7d7d662db500c93980edb commit: 07b8e85d0e29bc59a7a7d7d662db500c93980edb branch: main author: Michael <216956+mikez at users.noreply.github.com> committer: ericvsmith date: 2022-10-03T15:28:02-07:00 summary: gh-96526: Clarify format and __format__ docstrings (gh-96648) files: M Objects/clinic/longobject.c.h M Objects/clinic/typeobject.c.h M Objects/longobject.c M Objects/typeobject.c M Python/bltinmodule.c M Python/clinic/bltinmodule.c.h diff --git a/Objects/clinic/longobject.c.h b/Objects/clinic/longobject.c.h index 1cf5b4318859..dde49099cf95 100644 --- a/Objects/clinic/longobject.c.h +++ b/Objects/clinic/longobject.c.h @@ -88,7 +88,8 @@ int___getnewargs__(PyObject *self, PyObject *Py_UNUSED(ignored)) PyDoc_STRVAR(int___format____doc__, "__format__($self, format_spec, /)\n" "--\n" -"\n"); +"\n" +"Convert to a string according to format_spec."); #define INT___FORMAT___METHODDEF \ {"__format__", (PyCFunction)int___format__, METH_O, int___format____doc__}, @@ -466,4 +467,4 @@ int_from_bytes(PyTypeObject *type, PyObject *const *args, Py_ssize_t nargs, PyOb exit: return return_value; } -/*[clinic end generated code: output=b29b4afc65e3290e input=a9049054013a1b77]*/ +/*[clinic end generated code: output=bf6074ecf2f32cf4 input=a9049054013a1b77]*/ diff --git a/Objects/clinic/typeobject.c.h b/Objects/clinic/typeobject.c.h index f2864297b0f4..dc9746abfbe9 100644 --- a/Objects/clinic/typeobject.c.h +++ b/Objects/clinic/typeobject.c.h @@ -204,7 +204,9 @@ PyDoc_STRVAR(object___format____doc__, "__format__($self, format_spec, /)\n" "--\n" "\n" -"Default object formatter."); +"Default object formatter.\n" +"\n" +"Return str(self) if format_spec is empty. Raise TypeError otherwise."); #define OBJECT___FORMAT___METHODDEF \ {"__format__", (PyCFunction)object___format__, METH_O, object___format____doc__}, @@ -267,4 +269,4 @@ object___dir__(PyObject *self, PyObject *Py_UNUSED(ignored)) { return object___dir___impl(self); } -/*[clinic end generated code: output=3312f873c970bfd1 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=d2fc52440a89f2fa input=a9049054013a1b77]*/ diff --git a/Objects/longobject.c b/Objects/longobject.c index d9f3d393b998..8b13df4181ec 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -5528,11 +5528,13 @@ int.__format__ format_spec: unicode / + +Convert to a string according to format_spec. [clinic start generated code]*/ static PyObject * int___format___impl(PyObject *self, PyObject *format_spec) -/*[clinic end generated code: output=b4929dee9ae18689 input=e31944a9b3e428b7]*/ +/*[clinic end generated code: output=b4929dee9ae18689 input=d5e1254a47e8d1dc]*/ { _PyUnicodeWriter writer; int ret; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 5aa5cbbd5402..196a6aee4993 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -5824,11 +5824,13 @@ object.__format__ / Default object formatter. + +Return str(self) if format_spec is empty. Raise TypeError otherwise. [clinic start generated code]*/ static PyObject * object___format___impl(PyObject *self, PyObject *format_spec) -/*[clinic end generated code: output=34897efb543a974b input=7c3b3bc53a6fb7fa]*/ +/*[clinic end generated code: output=34897efb543a974b input=b94d8feb006689ea]*/ { /* Issue 7994: If we're converting to a string, we should reject format specifications */ diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 551e4f39b27a..2809b03d4a93 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -677,16 +677,19 @@ format as builtin_format format_spec: unicode(c_default="NULL") = '' / -Return value.__format__(format_spec) +Return type(value).__format__(value, format_spec) -format_spec defaults to the empty string. -See the Format Specification Mini-Language section of help('FORMATTING') for -details. +Many built-in types implement format_spec according to the +Format Specification Mini-language. See help('FORMATTING'). + +If type(value) does not supply a method named __format__ +and format_spec is empty, then str(value) is returned. +See also help('SPECIALMETHODS'). [clinic start generated code]*/ static PyObject * builtin_format_impl(PyObject *module, PyObject *value, PyObject *format_spec) -/*[clinic end generated code: output=2f40bdfa4954b077 input=88339c93ea522b33]*/ +/*[clinic end generated code: output=2f40bdfa4954b077 input=45ef3934b86d5624]*/ { return PyObject_Format(value, format_spec); } diff --git a/Python/clinic/bltinmodule.c.h b/Python/clinic/bltinmodule.c.h index 0feba5742df2..19930a519be0 100644 --- a/Python/clinic/bltinmodule.c.h +++ b/Python/clinic/bltinmodule.c.h @@ -183,11 +183,14 @@ PyDoc_STRVAR(builtin_format__doc__, "format($module, value, format_spec=\'\', /)\n" "--\n" "\n" -"Return value.__format__(format_spec)\n" +"Return type(value).__format__(value, format_spec)\n" "\n" -"format_spec defaults to the empty string.\n" -"See the Format Specification Mini-Language section of help(\'FORMATTING\') for\n" -"details."); +"Many built-in types implement format_spec according to the\n" +"Format Specification Mini-language. See help(\'FORMATTING\').\n" +"\n" +"If type(value) does not supply a method named __format__\n" +"and format_spec is empty, then str(value) is returned.\n" +"See also help(\'SPECIALMETHODS\')."); #define BUILTIN_FORMAT_METHODDEF \ {"format", _PyCFunction_CAST(builtin_format), METH_FASTCALL, builtin_format__doc__}, @@ -1212,4 +1215,4 @@ builtin_issubclass(PyObject *module, PyObject *const *args, Py_ssize_t nargs) exit: return return_value; } -/*[clinic end generated code: output=f3da5510745785af input=a9049054013a1b77]*/ +/*[clinic end generated code: output=3c9497e0ffeb8a30 input=a9049054013a1b77]*/ From webhook-mailer at python.org Mon Oct 3 18:41:16 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Mon, 03 Oct 2022 22:41:16 -0000 Subject: [Python-checkins] multiprocessing docs: Remove extra option ELLIPSIS from section with code (#96625) Message-ID: https://github.com/python/cpython/commit/d78aa4e11a80653588229cc97119afae693d1c06 commit: d78aa4e11a80653588229cc97119afae693d1c06 branch: main author: Ivan Kapeykin <5349983 at gmail.com> committer: JelleZijlstra date: 2022-10-03T15:41:08-07:00 summary: multiprocessing docs: Remove extra option ELLIPSIS from section with code (#96625) files: M Doc/library/multiprocessing.rst diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst index d74fe92f20d0..6f6e7881598b 100644 --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -674,7 +674,6 @@ The :mod:`multiprocessing` package mostly replicates the API of the Example usage of some of the methods of :class:`Process`: .. doctest:: - :options: +ELLIPSIS >>> import multiprocessing, time, signal >>> p = multiprocessing.Process(target=time.sleep, args=(1000,)) From webhook-mailer at python.org Mon Oct 3 18:46:17 2022 From: webhook-mailer at python.org (larryhastings) Date: Mon, 03 Oct 2022 22:46:17 -0000 Subject: [Python-checkins] gh-97799: use inspect.get_annotations in dataclass (#97800) Message-ID: https://github.com/python/cpython/commit/00b5a08c807ebebf4180c06aac0c9b5c7d6c547f commit: 00b5a08c807ebebf4180c06aac0c9b5c7d6c547f branch: main author: larryhastings committer: larryhastings date: 2022-10-03T15:46:09-07:00 summary: gh-97799: use inspect.get_annotations in dataclass (#97800) dataclass used to get the annotations on a class object using cls.__dict__.get('__annotations__'). Now that it always imports inspect, it can use inspect.get_annotations, which is modern best practice for coping with annotations. files: A Misc/NEWS.d/next/Library/2022-10-03-14-42-13.gh-issue-97799.Y1iJvf.rst M Lib/dataclasses.py diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index a567a33d646f..05d62b625760 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -920,10 +920,7 @@ def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen, if getattr(b, _PARAMS).frozen: any_frozen_base = True - # Annotations that are defined in this class (not in base - # classes). If __annotations__ isn't present, then this class - # adds no new annotations. We use this to compute fields that are - # added by this class. + # Annotations defined specifically in this class (not in base classes). # # Fields are found from cls_annotations, which is guaranteed to be # ordered. Default values are from class attributes, if a field @@ -932,7 +929,7 @@ def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen, # actual default value. Pseudo-fields ClassVars and InitVars are # included, despite the fact that they're not real fields. That's # dealt with later. - cls_annotations = cls.__dict__.get('__annotations__', {}) + cls_annotations = inspect.get_annotations(cls) # Now find fields in our class. While doing so, validate some # things, and set the default values (as class attributes) where diff --git a/Misc/NEWS.d/next/Library/2022-10-03-14-42-13.gh-issue-97799.Y1iJvf.rst b/Misc/NEWS.d/next/Library/2022-10-03-14-42-13.gh-issue-97799.Y1iJvf.rst new file mode 100644 index 000000000000..71097d29d344 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-03-14-42-13.gh-issue-97799.Y1iJvf.rst @@ -0,0 +1,2 @@ +:mod:`dataclass` now uses :func:`inspect.get_annotations` to examine the +annotations on class objects. From webhook-mailer at python.org Mon Oct 3 18:46:29 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 03 Oct 2022 22:46:29 -0000 Subject: [Python-checkins] Document that MozillaCookieJar works for curl's cookie files (GH-91852) Message-ID: https://github.com/python/cpython/commit/d07428607ab48f1cfafafec6bd1958f828645295 commit: d07428607ab48f1cfafafec6bd1958f828645295 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-03T15:46:23-07:00 summary: Document that MozillaCookieJar works for curl's cookie files (GH-91852) MozillaCookieJar works for curl's cookies (cherry picked from commit 0ea8b925d096629852d1045c2c53ff6ad63199cc) Co-authored-by: Boris Verkhovskiy files: M Doc/library/http.cookiejar.rst M Lib/http/cookiejar.py diff --git a/Doc/library/http.cookiejar.rst b/Doc/library/http.cookiejar.rst index 53b3087a4b99..eb31315438f6 100644 --- a/Doc/library/http.cookiejar.rst +++ b/Doc/library/http.cookiejar.rst @@ -320,8 +320,8 @@ writing. .. class:: MozillaCookieJar(filename, delayload=None, policy=None) A :class:`FileCookieJar` that can load from and save cookies to disk in the - Mozilla ``cookies.txt`` file format (which is also used by the Lynx and Netscape - browsers). + Mozilla ``cookies.txt`` file format (which is also used by curl and the Lynx + and Netscape browsers). .. note:: diff --git a/Lib/http/cookiejar.py b/Lib/http/cookiejar.py index c514e0d382cb..65c45e2b17df 100644 --- a/Lib/http/cookiejar.py +++ b/Lib/http/cookiejar.py @@ -1985,7 +1985,7 @@ class MozillaCookieJar(FileCookieJar): This class differs from CookieJar only in the format it uses to save and load cookies to and from a file. This class uses the Mozilla/Netscape - `cookies.txt' format. lynx uses this file format, too. + `cookies.txt' format. curl and lynx use this file format, too. Don't expect cookies saved while the browser is running to be noticed by the browser (in fact, Mozilla on unix will overwrite your saved cookies if From webhook-mailer at python.org Mon Oct 3 18:48:05 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 03 Oct 2022 22:48:05 -0000 Subject: [Python-checkins] multiprocessing docs: Remove extra option ELLIPSIS from section with code (GH-96625) Message-ID: https://github.com/python/cpython/commit/ca05666fed52badba9a7348d68f2bdc63100f689 commit: ca05666fed52badba9a7348d68f2bdc63100f689 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-03T15:48:00-07:00 summary: multiprocessing docs: Remove extra option ELLIPSIS from section with code (GH-96625) (cherry picked from commit d78aa4e11a80653588229cc97119afae693d1c06) Co-authored-by: Ivan Kapeykin <5349983 at gmail.com> files: M Doc/library/multiprocessing.rst diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst index d74fe92f20d0..6f6e7881598b 100644 --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -674,7 +674,6 @@ The :mod:`multiprocessing` package mostly replicates the API of the Example usage of some of the methods of :class:`Process`: .. doctest:: - :options: +ELLIPSIS >>> import multiprocessing, time, signal >>> p = multiprocessing.Process(target=time.sleep, args=(1000,)) From webhook-mailer at python.org Mon Oct 3 18:49:21 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 03 Oct 2022 22:49:21 -0000 Subject: [Python-checkins] multiprocessing docs: Remove extra option ELLIPSIS from section with code (GH-96625) Message-ID: https://github.com/python/cpython/commit/17b49be00320be43566b862f61de5aac5109dbdd commit: 17b49be00320be43566b862f61de5aac5109dbdd branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-03T15:49:16-07:00 summary: multiprocessing docs: Remove extra option ELLIPSIS from section with code (GH-96625) (cherry picked from commit d78aa4e11a80653588229cc97119afae693d1c06) Co-authored-by: Ivan Kapeykin <5349983 at gmail.com> files: M Doc/library/multiprocessing.rst diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst index 6a9ab240606f..48bccabe6a31 100644 --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -657,7 +657,6 @@ The :mod:`multiprocessing` package mostly replicates the API of the Example usage of some of the methods of :class:`Process`: .. doctest:: - :options: +ELLIPSIS >>> import multiprocessing, time, signal >>> p = multiprocessing.Process(target=time.sleep, args=(1000,)) From webhook-mailer at python.org Mon Oct 3 19:00:46 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 03 Oct 2022 23:00:46 -0000 Subject: [Python-checkins] Document that MozillaCookieJar works for curl's cookie files (GH-91852) Message-ID: https://github.com/python/cpython/commit/f8a3c4cb83ec277d6a4ee1392165960d3bd56426 commit: f8a3c4cb83ec277d6a4ee1392165960d3bd56426 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-03T16:00:40-07:00 summary: Document that MozillaCookieJar works for curl's cookie files (GH-91852) MozillaCookieJar works for curl's cookies (cherry picked from commit 0ea8b925d096629852d1045c2c53ff6ad63199cc) Co-authored-by: Boris Verkhovskiy files: M Doc/library/http.cookiejar.rst M Lib/http/cookiejar.py diff --git a/Doc/library/http.cookiejar.rst b/Doc/library/http.cookiejar.rst index ba2fa018499c..1ce24c676182 100644 --- a/Doc/library/http.cookiejar.rst +++ b/Doc/library/http.cookiejar.rst @@ -320,8 +320,8 @@ writing. .. class:: MozillaCookieJar(filename, delayload=None, policy=None) A :class:`FileCookieJar` that can load from and save cookies to disk in the - Mozilla ``cookies.txt`` file format (which is also used by the Lynx and Netscape - browsers). + Mozilla ``cookies.txt`` file format (which is also used by curl and the Lynx + and Netscape browsers). .. note:: diff --git a/Lib/http/cookiejar.py b/Lib/http/cookiejar.py index eaa76c26b9c5..0380d9f1096c 100644 --- a/Lib/http/cookiejar.py +++ b/Lib/http/cookiejar.py @@ -1990,7 +1990,7 @@ class MozillaCookieJar(FileCookieJar): This class differs from CookieJar only in the format it uses to save and load cookies to and from a file. This class uses the Mozilla/Netscape - `cookies.txt' format. lynx uses this file format, too. + `cookies.txt' format. curl and lynx use this file format, too. Don't expect cookies saved while the browser is running to be noticed by the browser (in fact, Mozilla on unix will overwrite your saved cookies if From webhook-mailer at python.org Mon Oct 3 19:18:45 2022 From: webhook-mailer at python.org (orsenthil) Date: Mon, 03 Oct 2022 23:18:45 -0000 Subject: [Python-checkins] Update http.client.rst (#24803) Message-ID: https://github.com/python/cpython/commit/0c91a125116b21e91d0d1cca457da830348f0806 commit: 0c91a125116b21e91d0d1cca457da830348f0806 branch: main author: G?ry Ogam committer: orsenthil date: 2022-10-03T16:18:36-07:00 summary: Update http.client.rst (#24803) * Update http.client.rst * Apply suggestions from code review Co-authored-by: ?ric * Update http.client.rst Co-authored-by: ?ric Co-authored-by: Senthil Kumaran files: M Doc/library/http.client.rst diff --git a/Doc/library/http.client.rst b/Doc/library/http.client.rst index 16823ec67b01..b7c94c92d557 100644 --- a/Doc/library/http.client.rst +++ b/Doc/library/http.client.rst @@ -61,7 +61,7 @@ The module provides the following classes: .. versionchanged:: 3.4 The *strict* parameter was removed. HTTP 0.9-style "Simple Responses" are - not longer supported. + no longer supported. .. versionchanged:: 3.7 *blocksize* parameter was added. @@ -474,7 +474,7 @@ statement. Return the value of the header *name*, or *default* if there is no header matching *name*. If there is more than one header with the name *name*, - return all of the values joined by ', '. If 'default' is any iterable other + return all of the values joined by ', '. If *default* is any iterable other than a single string, its elements are similarly returned joined by commas. .. method:: HTTPResponse.getheaders() @@ -578,7 +578,7 @@ Here is an example session that uses the ``HEAD`` method. Note that the >>> data == b'' True -Here is an example session that shows how to ``POST`` requests:: +Here is an example session that uses the ``POST`` method:: >>> import http.client, urllib.parse >>> params = urllib.parse.urlencode({'@number': 12524, '@type': 'issue', '@action': 'show'}) @@ -594,14 +594,13 @@ Here is an example session that shows how to ``POST`` requests:: b'Redirecting to https://bugs.python.org/issue12524' >>> conn.close() -Client side ``HTTP PUT`` requests are very similar to ``POST`` requests. The -difference lies only the server side where HTTP server will allow resources to -be created via ``PUT`` request. It should be noted that custom HTTP methods +Client side HTTP ``PUT`` requests are very similar to ``POST`` requests. The +difference lies only on the server side where HTTP servers will allow resources to +be created via ``PUT`` requests. It should be noted that custom HTTP methods are also handled in :class:`urllib.request.Request` by setting the appropriate -method attribute. Here is an example session that shows how to send a ``PUT`` -request using http.client:: +method attribute. Here is an example session that uses the ``PUT`` method:: - >>> # This creates an HTTP message + >>> # This creates an HTTP request >>> # with the content of BODY as the enclosed representation >>> # for the resource http://localhost:8080/file ... From webhook-mailer at python.org Mon Oct 3 19:19:47 2022 From: webhook-mailer at python.org (orsenthil) Date: Mon, 03 Oct 2022 23:19:47 -0000 Subject: [Python-checkins] Minor grammar changes to http.client docs (#96221) Message-ID: https://github.com/python/cpython/commit/d053c47bfde1b3d8779546b980849708662f2660 commit: d053c47bfde1b3d8779546b980849708662f2660 branch: main author: Rohan Shah <57906961+rshah713 at users.noreply.github.com> committer: orsenthil date: 2022-10-03T16:19:39-07:00 summary: Minor grammar changes to http.client docs (#96221) Minor grammar changes files: M Doc/library/http.client.rst diff --git a/Doc/library/http.client.rst b/Doc/library/http.client.rst index b7c94c92d557..06f92510a5e4 100644 --- a/Doc/library/http.client.rst +++ b/Doc/library/http.client.rst @@ -14,7 +14,7 @@ -------------- -This module defines classes which implement the client side of the HTTP and +This module defines classes that implement the client side of the HTTP and HTTPS protocols. It is normally not used directly --- the module :mod:`urllib.request` uses it to handle URLs that use HTTP and HTTPS. @@ -37,7 +37,7 @@ The module provides the following classes: blocksize=8192) An :class:`HTTPConnection` instance represents one transaction with an HTTP - server. It should be instantiated passing it a host and optional port + server. It should be instantiated by passing it a host and optional port number. If no port number is passed, the port is extracted from the host string if it has the form ``host:port``, else the default HTTP port (80) is used. If the optional *timeout* parameter is given, blocking From webhook-mailer at python.org Mon Oct 3 19:30:12 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 03 Oct 2022 23:30:12 -0000 Subject: [Python-checkins] Minor grammar changes to http.client docs (GH-96221) Message-ID: https://github.com/python/cpython/commit/541265fd7c2cb43c26a1413e008f32eda1634e6b commit: 541265fd7c2cb43c26a1413e008f32eda1634e6b branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-03T16:30:07-07:00 summary: Minor grammar changes to http.client docs (GH-96221) Minor grammar changes (cherry picked from commit d053c47bfde1b3d8779546b980849708662f2660) Co-authored-by: Rohan Shah <57906961+rshah713 at users.noreply.github.com> files: M Doc/library/http.client.rst diff --git a/Doc/library/http.client.rst b/Doc/library/http.client.rst index 16823ec67b01..0a895ebddf4f 100644 --- a/Doc/library/http.client.rst +++ b/Doc/library/http.client.rst @@ -14,7 +14,7 @@ -------------- -This module defines classes which implement the client side of the HTTP and +This module defines classes that implement the client side of the HTTP and HTTPS protocols. It is normally not used directly --- the module :mod:`urllib.request` uses it to handle URLs that use HTTP and HTTPS. @@ -37,7 +37,7 @@ The module provides the following classes: blocksize=8192) An :class:`HTTPConnection` instance represents one transaction with an HTTP - server. It should be instantiated passing it a host and optional port + server. It should be instantiated by passing it a host and optional port number. If no port number is passed, the port is extracted from the host string if it has the form ``host:port``, else the default HTTP port (80) is used. If the optional *timeout* parameter is given, blocking From webhook-mailer at python.org Mon Oct 3 19:30:20 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 03 Oct 2022 23:30:20 -0000 Subject: [Python-checkins] Minor grammar changes to http.client docs (GH-96221) Message-ID: https://github.com/python/cpython/commit/280bf3fb1669b4a83127acea91654be241f0d6dc commit: 280bf3fb1669b4a83127acea91654be241f0d6dc branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-03T16:30:14-07:00 summary: Minor grammar changes to http.client docs (GH-96221) Minor grammar changes (cherry picked from commit d053c47bfde1b3d8779546b980849708662f2660) Co-authored-by: Rohan Shah <57906961+rshah713 at users.noreply.github.com> files: M Doc/library/http.client.rst diff --git a/Doc/library/http.client.rst b/Doc/library/http.client.rst index 380f52b2558f..be10e4b62f43 100644 --- a/Doc/library/http.client.rst +++ b/Doc/library/http.client.rst @@ -14,7 +14,7 @@ -------------- -This module defines classes which implement the client side of the HTTP and +This module defines classes that implement the client side of the HTTP and HTTPS protocols. It is normally not used directly --- the module :mod:`urllib.request` uses it to handle URLs that use HTTP and HTTPS. @@ -35,7 +35,7 @@ The module provides the following classes: blocksize=8192) An :class:`HTTPConnection` instance represents one transaction with an HTTP - server. It should be instantiated passing it a host and optional port + server. It should be instantiated by passing it a host and optional port number. If no port number is passed, the port is extracted from the host string if it has the form ``host:port``, else the default HTTP port (80) is used. If the optional *timeout* parameter is given, blocking From webhook-mailer at python.org Mon Oct 3 19:35:16 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 03 Oct 2022 23:35:16 -0000 Subject: [Python-checkins] Update http.client.rst (GH-24803) Message-ID: https://github.com/python/cpython/commit/789d5bc80a8d3ac84be523ac3f5ac0df4f6534e1 commit: 789d5bc80a8d3ac84be523ac3f5ac0df4f6534e1 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-03T16:35:10-07:00 summary: Update http.client.rst (GH-24803) * Update http.client.rst * Apply suggestions from code review Co-authored-by: ?ric * Update http.client.rst Co-authored-by: ?ric Co-authored-by: Senthil Kumaran (cherry picked from commit 0c91a125116b21e91d0d1cca457da830348f0806) Co-authored-by: G?ry Ogam files: M Doc/library/http.client.rst diff --git a/Doc/library/http.client.rst b/Doc/library/http.client.rst index 0a895ebddf4f..06f92510a5e4 100644 --- a/Doc/library/http.client.rst +++ b/Doc/library/http.client.rst @@ -61,7 +61,7 @@ The module provides the following classes: .. versionchanged:: 3.4 The *strict* parameter was removed. HTTP 0.9-style "Simple Responses" are - not longer supported. + no longer supported. .. versionchanged:: 3.7 *blocksize* parameter was added. @@ -474,7 +474,7 @@ statement. Return the value of the header *name*, or *default* if there is no header matching *name*. If there is more than one header with the name *name*, - return all of the values joined by ', '. If 'default' is any iterable other + return all of the values joined by ', '. If *default* is any iterable other than a single string, its elements are similarly returned joined by commas. .. method:: HTTPResponse.getheaders() @@ -578,7 +578,7 @@ Here is an example session that uses the ``HEAD`` method. Note that the >>> data == b'' True -Here is an example session that shows how to ``POST`` requests:: +Here is an example session that uses the ``POST`` method:: >>> import http.client, urllib.parse >>> params = urllib.parse.urlencode({'@number': 12524, '@type': 'issue', '@action': 'show'}) @@ -594,14 +594,13 @@ Here is an example session that shows how to ``POST`` requests:: b'Redirecting to https://bugs.python.org/issue12524' >>> conn.close() -Client side ``HTTP PUT`` requests are very similar to ``POST`` requests. The -difference lies only the server side where HTTP server will allow resources to -be created via ``PUT`` request. It should be noted that custom HTTP methods +Client side HTTP ``PUT`` requests are very similar to ``POST`` requests. The +difference lies only on the server side where HTTP servers will allow resources to +be created via ``PUT`` requests. It should be noted that custom HTTP methods are also handled in :class:`urllib.request.Request` by setting the appropriate -method attribute. Here is an example session that shows how to send a ``PUT`` -request using http.client:: +method attribute. Here is an example session that uses the ``PUT`` method:: - >>> # This creates an HTTP message + >>> # This creates an HTTP request >>> # with the content of BODY as the enclosed representation >>> # for the resource http://localhost:8080/file ... From webhook-mailer at python.org Mon Oct 3 19:35:22 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 03 Oct 2022 23:35:22 -0000 Subject: [Python-checkins] Update http.client.rst (GH-24803) Message-ID: https://github.com/python/cpython/commit/656983741faae983c7a8e6367423c24f2e7d15bc commit: 656983741faae983c7a8e6367423c24f2e7d15bc branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-03T16:35:17-07:00 summary: Update http.client.rst (GH-24803) * Update http.client.rst * Apply suggestions from code review Co-authored-by: ?ric * Update http.client.rst Co-authored-by: ?ric Co-authored-by: Senthil Kumaran (cherry picked from commit 0c91a125116b21e91d0d1cca457da830348f0806) Co-authored-by: G?ry Ogam files: M Doc/library/http.client.rst diff --git a/Doc/library/http.client.rst b/Doc/library/http.client.rst index be10e4b62f43..dd7a0c459acc 100644 --- a/Doc/library/http.client.rst +++ b/Doc/library/http.client.rst @@ -59,7 +59,7 @@ The module provides the following classes: .. versionchanged:: 3.4 The *strict* parameter was removed. HTTP 0.9-style "Simple Responses" are - not longer supported. + no longer supported. .. versionchanged:: 3.7 *blocksize* parameter was added. @@ -472,7 +472,7 @@ statement. Return the value of the header *name*, or *default* if there is no header matching *name*. If there is more than one header with the name *name*, - return all of the values joined by ', '. If 'default' is any iterable other + return all of the values joined by ', '. If *default* is any iterable other than a single string, its elements are similarly returned joined by commas. .. method:: HTTPResponse.getheaders() @@ -576,7 +576,7 @@ Here is an example session that uses the ``HEAD`` method. Note that the >>> data == b'' True -Here is an example session that shows how to ``POST`` requests:: +Here is an example session that uses the ``POST`` method:: >>> import http.client, urllib.parse >>> params = urllib.parse.urlencode({'@number': 12524, '@type': 'issue', '@action': 'show'}) @@ -592,14 +592,13 @@ Here is an example session that shows how to ``POST`` requests:: b'Redirecting to https://bugs.python.org/issue12524' >>> conn.close() -Client side ``HTTP PUT`` requests are very similar to ``POST`` requests. The -difference lies only the server side where HTTP server will allow resources to -be created via ``PUT`` request. It should be noted that custom HTTP methods +Client side HTTP ``PUT`` requests are very similar to ``POST`` requests. The +difference lies only on the server side where HTTP servers will allow resources to +be created via ``PUT`` requests. It should be noted that custom HTTP methods are also handled in :class:`urllib.request.Request` by setting the appropriate -method attribute. Here is an example session that shows how to send a ``PUT`` -request using http.client:: +method attribute. Here is an example session that uses the ``PUT`` method:: - >>> # This creates an HTTP message + >>> # This creates an HTTP request >>> # with the content of BODY as the enclosed representation >>> # for the resource http://localhost:8080/file ... From webhook-mailer at python.org Mon Oct 3 19:37:00 2022 From: webhook-mailer at python.org (markshannon) Date: Mon, 03 Oct 2022 23:37:00 -0000 Subject: [Python-checkins] GH-97752: Clear the `previous` member of newly-created generator/coroutine frames (GH-97795) Message-ID: https://github.com/python/cpython/commit/93fcc1f4133e177882850177c2c047d46019b812 commit: 93fcc1f4133e177882850177c2c047d46019b812 branch: main author: Brandt Bucher committer: markshannon date: 2022-10-04T00:36:52+01:00 summary: GH-97752: Clear the `previous` member of newly-created generator/coroutine frames (GH-97795) files: A Misc/NEWS.d/next/Core and Builtins/2022-10-03-13-35-48.gh-issue-97752.0xTjJY.rst M Lib/test/test_generators.py M Python/frame.c diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py index fb2d9ced0633..42cc20c46766 100644 --- a/Lib/test/test_generators.py +++ b/Lib/test/test_generators.py @@ -206,6 +206,25 @@ def __del__(self): finally: gc.set_threshold(*thresholds) + def test_ag_frame_f_back(self): + async def f(): + yield + ag = f() + self.assertIsNone(ag.ag_frame.f_back) + + def test_cr_frame_f_back(self): + async def f(): + pass + cr = f() + self.assertIsNone(cr.cr_frame.f_back) + cr.close() # Suppress RuntimeWarning. + + def test_gi_frame_f_back(self): + def f(): + yield + gi = f() + self.assertIsNone(gi.gi_frame.f_back) + class ExceptionTest(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-03-13-35-48.gh-issue-97752.0xTjJY.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-03-13-35-48.gh-issue-97752.0xTjJY.rst new file mode 100644 index 000000000000..c65635070348 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-03-13-35-48.gh-issue-97752.0xTjJY.rst @@ -0,0 +1,2 @@ +Fix possible data corruption or crashes when accessing the ``f_back`` member +of newly-created generator or coroutine frames. diff --git a/Python/frame.c b/Python/frame.c index 14464df0a8d5..05a8cffcb8a7 100644 --- a/Python/frame.c +++ b/Python/frame.c @@ -54,6 +54,9 @@ _PyFrame_Copy(_PyInterpreterFrame *src, _PyInterpreterFrame *dest) assert(src->stacktop >= src->f_code->co_nlocalsplus); Py_ssize_t size = ((char*)&src->localsplus[src->stacktop]) - (char *)src; memcpy(dest, src, size); + // Don't leave a dangling pointer to the old frame when creating generators + // and coroutines: + dest->previous = NULL; } From webhook-mailer at python.org Mon Oct 3 19:45:26 2022 From: webhook-mailer at python.org (ezio-melotti) Date: Mon, 03 Oct 2022 23:45:26 -0000 Subject: [Python-checkins] Add `sprint` issues to the Sprint 2022 project. (#97788) Message-ID: https://github.com/python/cpython/commit/231a905c5f4c29c04307b83577977a17d2e089ac commit: 231a905c5f4c29c04307b83577977a17d2e089ac branch: main author: Ezio Melotti committer: ezio-melotti date: 2022-10-04T01:45:18+02:00 summary: Add `sprint` issues to the Sprint 2022 project. (#97788) files: M .github/workflows/project-updater.yml diff --git a/.github/workflows/project-updater.yml b/.github/workflows/project-updater.yml index ea98700e7fae..77e55ed019b2 100644 --- a/.github/workflows/project-updater.yml +++ b/.github/workflows/project-updater.yml @@ -18,6 +18,7 @@ jobs: - { project: 2, label: "release-blocker, deferred-blocker" } - { project: 3, label: expert-subinterpreters } - { project: 29, label: expert-asyncio } + - { project: 32, label: sprint } steps: - uses: actions/add-to-project at v0.1.0 From webhook-mailer at python.org Mon Oct 3 20:12:47 2022 From: webhook-mailer at python.org (miss-islington) Date: Tue, 04 Oct 2022 00:12:47 -0000 Subject: [Python-checkins] Remove space. (GH-97807) Message-ID: https://github.com/python/cpython/commit/9e8b86de4e7a65b6fc6389caf4fa506ebcf538f6 commit: 9e8b86de4e7a65b6fc6389caf4fa506ebcf538f6 branch: main author: Benjamin Peterson committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-03T17:12:36-07:00 summary: Remove space. (GH-97807) Automerge-Triggered-By: GH:benjaminp files: M Lib/test/test_time.py diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py index 884b14231f57..02cc3f43a66a 100644 --- a/Lib/test/test_time.py +++ b/Lib/test/test_time.py @@ -848,7 +848,7 @@ def convert_values(ns_timestamps): # test rounding ns_timestamps = self._rounding_values(use_float) valid_values = convert_values(ns_timestamps) - for time_rnd, decimal_rnd in ROUNDING_MODES : + for time_rnd, decimal_rnd in ROUNDING_MODES: with decimal.localcontext() as context: context.rounding = decimal_rnd From webhook-mailer at python.org Mon Oct 3 20:30:12 2022 From: webhook-mailer at python.org (ericvsmith) Date: Tue, 04 Oct 2022 00:30:12 -0000 Subject: [Python-checkins] Add comment to subtle dataclass code (gh-96133) Message-ID: https://github.com/python/cpython/commit/72b5a55bc80676d57e492520d39aaf3fb6f186df commit: 72b5a55bc80676d57e492520d39aaf3fb6f186df branch: main author: Shantanu <12621235+hauntsaninja at users.noreply.github.com> committer: ericvsmith date: 2022-10-03T17:30:04-07:00 summary: Add comment to subtle dataclass code (gh-96133) In the PR that made this change, 1st1 left a "note to self: add a comment explaining this". This comment was never added. https://github.com/python/cpython/pull/9518/files#r280608117 I was reading this code and it wasn't obvious to me why we weren't exec-ing directly into locals. So I got to learn something new :-) https://docs.python.org/3/reference/executionmodel.html#interaction-with-dynamic-features files: M Lib/dataclasses.py diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index 05d62b625760..efd83467bfa9 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -429,6 +429,10 @@ def _create_fn(name, args, body, *, globals=None, locals=None, # Compute the text of the entire function. txt = f' def {name}({args}){return_annotation}:\n{body}' + # Free variables in exec are resolved in the global namespace. + # The global namespace we have is user-provided, so we can't modify it for + # our purposes. So we put the things we need into locals and introduce a + # scope to allow the function we're creating to close over them. local_vars = ', '.join(locals.keys()) txt = f"def __create_fn__({local_vars}):\n{txt}\n return {name}" ns = {} From webhook-mailer at python.org Mon Oct 3 20:41:37 2022 From: webhook-mailer at python.org (orsenthil) Date: Tue, 04 Oct 2022 00:41:37 -0000 Subject: [Python-checkins] gh-97639: Remove `tokenize.NL` check from `tabnanny` (#97640) Message-ID: https://github.com/python/cpython/commit/06016845dcca1d444a6db6d70ce9fe6274d551d3 commit: 06016845dcca1d444a6db6d70ce9fe6274d551d3 branch: main author: Nikita Sobolev committer: orsenthil date: 2022-10-03T17:41:29-07:00 summary: gh-97639: Remove `tokenize.NL` check from `tabnanny` (#97640) * gh-97639: Remove `tokenize.NL` check from `tabnanny` * ?? Added by blurb_it. Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> files: A Misc/NEWS.d/next/Library/2022-09-29-08-15-55.gh-issue-97639.JSjWYW.rst M Lib/tabnanny.py diff --git a/Lib/tabnanny.py b/Lib/tabnanny.py index 7973f26f98b8..a47f5a96b897 100755 --- a/Lib/tabnanny.py +++ b/Lib/tabnanny.py @@ -23,8 +23,6 @@ import os import sys import tokenize -if not hasattr(tokenize, 'NL'): - raise ValueError("tokenize.NL doesn't exist -- tokenize module too old") __all__ = ["check", "NannyNag", "process_tokens"] diff --git a/Misc/NEWS.d/next/Library/2022-09-29-08-15-55.gh-issue-97639.JSjWYW.rst b/Misc/NEWS.d/next/Library/2022-09-29-08-15-55.gh-issue-97639.JSjWYW.rst new file mode 100644 index 000000000000..65c3105f3bc3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-09-29-08-15-55.gh-issue-97639.JSjWYW.rst @@ -0,0 +1 @@ +Remove ``tokenize.NL`` check from :mod:`tabnanny`. From webhook-mailer at python.org Mon Oct 3 21:46:40 2022 From: webhook-mailer at python.org (ezio-melotti) Date: Tue, 04 Oct 2022 01:46:40 -0000 Subject: [Python-checkins] gh-93738: Documentation C syntax (:c:data:`0` -> ``0``) (#97771) Message-ID: https://github.com/python/cpython/commit/5e997cff3e1dea24241726338457611beb8882ec commit: 5e997cff3e1dea24241726338457611beb8882ec branch: main author: Adam Turner <9087854+AA-Turner at users.noreply.github.com> committer: ezio-melotti date: 2022-10-04T03:46:30+02:00 summary: gh-93738: Documentation C syntax (:c:data:`0` -> ``0``) (#97771) :c:data:`0` -> ``0`` files: M Doc/c-api/exceptions.rst diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index 02ec1da1c340..df73f23d2de2 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -189,7 +189,7 @@ For convenience, some of these functions will always return a .. c:function:: PyObject* PyErr_SetFromWindowsErr(int ierr) This is a convenience function to raise :exc:`WindowsError`. If called with - *ierr* of :c:data:`0`, the error code returned by a call to :c:func:`GetLastError` + *ierr* of ``0``, the error code returned by a call to :c:func:`GetLastError` is used instead. It calls the Win32 function :c:func:`FormatMessage` to retrieve the Windows description of error code given by *ierr* or :c:func:`GetLastError`, then it constructs a tuple object whose first item is the *ierr* value and whose From webhook-mailer at python.org Mon Oct 3 21:55:19 2022 From: webhook-mailer at python.org (miss-islington) Date: Tue, 04 Oct 2022 01:55:19 -0000 Subject: [Python-checkins] gh-93738: Documentation C syntax (:c:data:`0` -> ``0``) (GH-97771) Message-ID: https://github.com/python/cpython/commit/82ce586f10257c3176c1e92745f6e19f3787c9f1 commit: 82ce586f10257c3176c1e92745f6e19f3787c9f1 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-03T18:55:08-07:00 summary: gh-93738: Documentation C syntax (:c:data:`0` -> ``0``) (GH-97771) :c:data:`0` -> ``0`` (cherry picked from commit 5e997cff3e1dea24241726338457611beb8882ec) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> files: M Doc/c-api/exceptions.rst diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index fc90fa2b746e..40759f7b0305 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -189,7 +189,7 @@ For convenience, some of these functions will always return a .. c:function:: PyObject* PyErr_SetFromWindowsErr(int ierr) This is a convenience function to raise :exc:`WindowsError`. If called with - *ierr* of :c:data:`0`, the error code returned by a call to :c:func:`GetLastError` + *ierr* of ``0``, the error code returned by a call to :c:func:`GetLastError` is used instead. It calls the Win32 function :c:func:`FormatMessage` to retrieve the Windows description of error code given by *ierr* or :c:func:`GetLastError`, then it constructs a tuple object whose first item is the *ierr* value and whose From webhook-mailer at python.org Mon Oct 3 21:55:19 2022 From: webhook-mailer at python.org (miss-islington) Date: Tue, 04 Oct 2022 01:55:19 -0000 Subject: [Python-checkins] gh-93738: Documentation C syntax (:c:data:`0` -> ``0``) (GH-97771) Message-ID: https://github.com/python/cpython/commit/e34b00cc3ea9d4fdcb146050336ea6ce0d22cf85 commit: e34b00cc3ea9d4fdcb146050336ea6ce0d22cf85 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-03T18:55:04-07:00 summary: gh-93738: Documentation C syntax (:c:data:`0` -> ``0``) (GH-97771) :c:data:`0` -> ``0`` (cherry picked from commit 5e997cff3e1dea24241726338457611beb8882ec) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> files: M Doc/c-api/exceptions.rst diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index 02ec1da1c340..df73f23d2de2 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -189,7 +189,7 @@ For convenience, some of these functions will always return a .. c:function:: PyObject* PyErr_SetFromWindowsErr(int ierr) This is a convenience function to raise :exc:`WindowsError`. If called with - *ierr* of :c:data:`0`, the error code returned by a call to :c:func:`GetLastError` + *ierr* of ``0``, the error code returned by a call to :c:func:`GetLastError` is used instead. It calls the Win32 function :c:func:`FormatMessage` to retrieve the Windows description of error code given by *ierr* or :c:func:`GetLastError`, then it constructs a tuple object whose first item is the *ierr* value and whose From webhook-mailer at python.org Mon Oct 3 22:07:17 2022 From: webhook-mailer at python.org (miss-islington) Date: Tue, 04 Oct 2022 02:07:17 -0000 Subject: [Python-checkins] gh-97639: Remove `tokenize.NL` check from `tabnanny` (GH-97640) Message-ID: https://github.com/python/cpython/commit/40e56f3191a2fd242b2c03d483fe23c960fb8c22 commit: 40e56f3191a2fd242b2c03d483fe23c960fb8c22 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-03T19:07:10-07:00 summary: gh-97639: Remove `tokenize.NL` check from `tabnanny` (GH-97640) * gh-97639: Remove `tokenize.NL` check from `tabnanny` * ?? Added by blurb_it. Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> (cherry picked from commit 06016845dcca1d444a6db6d70ce9fe6274d551d3) Co-authored-by: Nikita Sobolev files: A Misc/NEWS.d/next/Library/2022-09-29-08-15-55.gh-issue-97639.JSjWYW.rst M Lib/tabnanny.py diff --git a/Lib/tabnanny.py b/Lib/tabnanny.py index 7973f26f98b8..a47f5a96b897 100755 --- a/Lib/tabnanny.py +++ b/Lib/tabnanny.py @@ -23,8 +23,6 @@ import os import sys import tokenize -if not hasattr(tokenize, 'NL'): - raise ValueError("tokenize.NL doesn't exist -- tokenize module too old") __all__ = ["check", "NannyNag", "process_tokens"] diff --git a/Misc/NEWS.d/next/Library/2022-09-29-08-15-55.gh-issue-97639.JSjWYW.rst b/Misc/NEWS.d/next/Library/2022-09-29-08-15-55.gh-issue-97639.JSjWYW.rst new file mode 100644 index 000000000000..65c3105f3bc3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-09-29-08-15-55.gh-issue-97639.JSjWYW.rst @@ -0,0 +1 @@ +Remove ``tokenize.NL`` check from :mod:`tabnanny`. From webhook-mailer at python.org Mon Oct 3 22:10:05 2022 From: webhook-mailer at python.org (miss-islington) Date: Tue, 04 Oct 2022 02:10:05 -0000 Subject: [Python-checkins] gh-97639: Remove `tokenize.NL` check from `tabnanny` (GH-97640) Message-ID: https://github.com/python/cpython/commit/0e3a046b4849155f0c0890d18d4529a75be6a525 commit: 0e3a046b4849155f0c0890d18d4529a75be6a525 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-03T19:10:00-07:00 summary: gh-97639: Remove `tokenize.NL` check from `tabnanny` (GH-97640) * gh-97639: Remove `tokenize.NL` check from `tabnanny` * ?? Added by blurb_it. Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> (cherry picked from commit 06016845dcca1d444a6db6d70ce9fe6274d551d3) Co-authored-by: Nikita Sobolev files: A Misc/NEWS.d/next/Library/2022-09-29-08-15-55.gh-issue-97639.JSjWYW.rst M Lib/tabnanny.py diff --git a/Lib/tabnanny.py b/Lib/tabnanny.py index 7973f26f98b8..a47f5a96b897 100755 --- a/Lib/tabnanny.py +++ b/Lib/tabnanny.py @@ -23,8 +23,6 @@ import os import sys import tokenize -if not hasattr(tokenize, 'NL'): - raise ValueError("tokenize.NL doesn't exist -- tokenize module too old") __all__ = ["check", "NannyNag", "process_tokens"] diff --git a/Misc/NEWS.d/next/Library/2022-09-29-08-15-55.gh-issue-97639.JSjWYW.rst b/Misc/NEWS.d/next/Library/2022-09-29-08-15-55.gh-issue-97639.JSjWYW.rst new file mode 100644 index 000000000000..65c3105f3bc3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-09-29-08-15-55.gh-issue-97639.JSjWYW.rst @@ -0,0 +1 @@ +Remove ``tokenize.NL`` check from :mod:`tabnanny`. From webhook-mailer at python.org Tue Oct 4 00:03:43 2022 From: webhook-mailer at python.org (brandtbucher) Date: Tue, 04 Oct 2022 04:03:43 -0000 Subject: [Python-checkins] [3.11] GH-97752: Clear the previous member of newly-created generator/coroutine frames (GH-97812) Message-ID: https://github.com/python/cpython/commit/4591dae421cc1415bcf982cccbf5de4f787df030 commit: 4591dae421cc1415bcf982cccbf5de4f787df030 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: brandtbucher date: 2022-10-03T21:03:26-07:00 summary: [3.11] GH-97752: Clear the previous member of newly-created generator/coroutine frames (GH-97812) (cherry picked from commit 93fcc1f4133e177882850177c2c047d46019b812) files: A Misc/NEWS.d/next/Core and Builtins/2022-10-03-13-35-48.gh-issue-97752.0xTjJY.rst M Lib/test/test_generators.py M Python/frame.c diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py index e5aa7da1e0df..353073dbfce0 100644 --- a/Lib/test/test_generators.py +++ b/Lib/test/test_generators.py @@ -206,6 +206,25 @@ def __del__(self): finally: gc.set_threshold(*thresholds) + def test_ag_frame_f_back(self): + async def f(): + yield + ag = f() + self.assertIsNone(ag.ag_frame.f_back) + + def test_cr_frame_f_back(self): + async def f(): + pass + cr = f() + self.assertIsNone(cr.cr_frame.f_back) + cr.close() # Suppress RuntimeWarning. + + def test_gi_frame_f_back(self): + def f(): + yield + gi = f() + self.assertIsNone(gi.gi_frame.f_back) + class ExceptionTest(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-03-13-35-48.gh-issue-97752.0xTjJY.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-03-13-35-48.gh-issue-97752.0xTjJY.rst new file mode 100644 index 000000000000..c65635070348 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-03-13-35-48.gh-issue-97752.0xTjJY.rst @@ -0,0 +1,2 @@ +Fix possible data corruption or crashes when accessing the ``f_back`` member +of newly-created generator or coroutine frames. diff --git a/Python/frame.c b/Python/frame.c index c4e93492e081..45072da04269 100644 --- a/Python/frame.c +++ b/Python/frame.c @@ -52,6 +52,9 @@ _PyFrame_Copy(_PyInterpreterFrame *src, _PyInterpreterFrame *dest) assert(src->stacktop >= src->f_code->co_nlocalsplus); Py_ssize_t size = ((char*)&src->localsplus[src->stacktop]) - (char *)src; memcpy(dest, src, size); + // Don't leave a dangling pointer to the old frame when creating generators + // and coroutines: + dest->previous = NULL; } From webhook-mailer at python.org Tue Oct 4 01:29:55 2022 From: webhook-mailer at python.org (gpshead) Date: Tue, 04 Oct 2022 05:29:55 -0000 Subject: [Python-checkins] gh-97816: Remove unused variables in `mutliprocessing.managers.Server` (#97817) Message-ID: https://github.com/python/cpython/commit/27e59afa2ad98e6bfe26c6b2b7f6294fa561680c commit: 27e59afa2ad98e6bfe26c6b2b7f6294fa561680c branch: main author: Koki Saito <49419225+saito828koki at users.noreply.github.com> committer: gpshead date: 2022-10-03T22:29:17-07:00 summary: gh-97816: Remove unused variables in `mutliprocessing.managers.Server` (#97817) Remove unused local variables. files: M Lib/multiprocessing/managers.py M Misc/ACKS diff --git a/Lib/multiprocessing/managers.py b/Lib/multiprocessing/managers.py index 3f6479b7e3a6..b6534939b4d9 100644 --- a/Lib/multiprocessing/managers.py +++ b/Lib/multiprocessing/managers.py @@ -433,7 +433,6 @@ def incref(self, c, ident): self.id_to_refcount[ident] = 1 self.id_to_obj[ident] = \ self.id_to_local_proxy_obj[ident] - obj, exposed, gettypeid = self.id_to_obj[ident] util.debug('Server re-enabled tracking & INCREF %r', ident) else: raise ke diff --git a/Misc/ACKS b/Misc/ACKS index fc0e745e28ce..6a14b546f691 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1559,6 +1559,7 @@ Patrick Sabin S?bastien Sabl? Amit Saha Suman Saha +Koki Saito Hajime Saitou George Sakkis Victor Salgado From webhook-mailer at python.org Tue Oct 4 01:34:11 2022 From: webhook-mailer at python.org (gpshead) Date: Tue, 04 Oct 2022 05:34:11 -0000 Subject: [Python-checkins] gh-97709: Included newline separator in Mandelbrot set (#97737) Message-ID: https://github.com/python/cpython/commit/49802605f8e47c5c7ddc8a6cecdf4afe44765586 commit: 49802605f8e47c5c7ddc8a6cecdf4afe44765586 branch: main author: matheusja committer: gpshead date: 2022-10-03T22:34:02-07:00 summary: gh-97709: Included newline separator in Mandelbrot set (#97737) Included newline separator in Mandelbrot set Now the Mandelbrot set one-liner example on separates the lines with a '\n' character. files: M Doc/faq/programming.rst diff --git a/Doc/faq/programming.rst b/Doc/faq/programming.rst index 572a24d7fa3e..ad281f826dd4 100644 --- a/Doc/faq/programming.rst +++ b/Doc/faq/programming.rst @@ -735,7 +735,7 @@ Is it possible to write obfuscated one-liners in Python? -------------------------------------------------------- Yes. Usually this is done by nesting :keyword:`lambda` within -:keyword:`!lambda`. See the following three examples, due to Ulf Bartelt:: +:keyword:`!lambda`. See the following three examples, slightly adapted from Ulf Bartelt:: from functools import reduce @@ -748,7 +748,7 @@ Yes. Usually this is done by nesting :keyword:`lambda` within f(x,f), range(10)))) # Mandelbrot set - print((lambda Ru,Ro,Iu,Io,IM,Sx,Sy:reduce(lambda x,y:x+y,map(lambda y, + print((lambda Ru,Ro,Iu,Io,IM,Sx,Sy:reduce(lambda x,y:x+'\n'+y,map(lambda y, Iu=Iu,Io=Io,Ru=Ru,Ro=Ro,Sy=Sy,L=lambda yc,Iu=Iu,Io=Io,Ru=Ru,Ro=Ro,i=IM, Sx=Sx,Sy=Sy:reduce(lambda x,y:x+y,map(lambda x,xc=Ru,yc=yc,Ru=Ru,Ro=Ro, i=i,Sx=Sx,F=lambda xc,yc,x,y,k,f=lambda xc,yc,x,y,k,f:(k<=0)or (x*x+y*y From webhook-mailer at python.org Tue Oct 4 01:43:05 2022 From: webhook-mailer at python.org (miss-islington) Date: Tue, 04 Oct 2022 05:43:05 -0000 Subject: [Python-checkins] gh-97709: Included newline separator in Mandelbrot set (GH-97737) Message-ID: https://github.com/python/cpython/commit/c62be23f0438e1b3d76c08251e12094e657e7d3f commit: c62be23f0438e1b3d76c08251e12094e657e7d3f branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-03T22:43:00-07:00 summary: gh-97709: Included newline separator in Mandelbrot set (GH-97737) Included newline separator in Mandelbrot set Now the Mandelbrot set one-liner example on separates the lines with a '\n' character. (cherry picked from commit 49802605f8e47c5c7ddc8a6cecdf4afe44765586) Co-authored-by: matheusja files: M Doc/faq/programming.rst diff --git a/Doc/faq/programming.rst b/Doc/faq/programming.rst index 572a24d7fa3e..ad281f826dd4 100644 --- a/Doc/faq/programming.rst +++ b/Doc/faq/programming.rst @@ -735,7 +735,7 @@ Is it possible to write obfuscated one-liners in Python? -------------------------------------------------------- Yes. Usually this is done by nesting :keyword:`lambda` within -:keyword:`!lambda`. See the following three examples, due to Ulf Bartelt:: +:keyword:`!lambda`. See the following three examples, slightly adapted from Ulf Bartelt:: from functools import reduce @@ -748,7 +748,7 @@ Yes. Usually this is done by nesting :keyword:`lambda` within f(x,f), range(10)))) # Mandelbrot set - print((lambda Ru,Ro,Iu,Io,IM,Sx,Sy:reduce(lambda x,y:x+y,map(lambda y, + print((lambda Ru,Ro,Iu,Io,IM,Sx,Sy:reduce(lambda x,y:x+'\n'+y,map(lambda y, Iu=Iu,Io=Io,Ru=Ru,Ro=Ro,Sy=Sy,L=lambda yc,Iu=Iu,Io=Io,Ru=Ru,Ro=Ro,i=IM, Sx=Sx,Sy=Sy:reduce(lambda x,y:x+y,map(lambda x,xc=Ru,yc=yc,Ru=Ru,Ro=Ro, i=i,Sx=Sx,F=lambda xc,yc,x,y,k,f=lambda xc,yc,x,y,k,f:(k<=0)or (x*x+y*y From webhook-mailer at python.org Tue Oct 4 04:49:42 2022 From: webhook-mailer at python.org (vstinner) Date: Tue, 04 Oct 2022 08:49:42 -0000 Subject: [Python-checkins] gh-97669: Remove outdated example scripts (#97675) Message-ID: https://github.com/python/cpython/commit/6cbbc26a73879f17df8896ea4feb40c61b085775 commit: 6cbbc26a73879f17df8896ea4feb40c61b085775 branch: main author: Victor Stinner committer: vstinner date: 2022-10-04T10:49:00+02:00 summary: gh-97669: Remove outdated example scripts (#97675) Remove outdated example scripts of the Tools/scripts/ directory. A copy can be found in the old-demos project: https://github.com/gvanrossum/old-demos Removed scripts (39): * byext.py * byteyears.py * cleanfuture.py * copytime.py * crlf.py * db2pickle.py * dutree.doc * dutree.py * find-uname.py * find_recursionlimit.py * finddiv.py * findlinksto.py * findnocoding.py * fixcid.py * fixdiv.py * fixheader.py * fixnotice.py * fixps.py * get-remote-certificate.py * google.py * highlight.py * ifdef.py * import_diagnostics.py * lfcr.py * linktree.py * lll.py * mailerdaemon.py * make_ctype.py * mkreal.py * objgraph.py * pdeps.py * pickle2db.py * pindent.py * pysource.py * reindent-rst.py * rgrep.py * suff.py * texi2html.py * which.py Changes: * Remove test_fixcid, test_lll, test_pdeps and test_pindent of test.test_tools. * Remove get-remote-certificate.py changelog entry, since the script was removed. Note: there is a copy of crlf.py in Lib/test/test_lib2to3/data/. files: A Misc/NEWS.d/next/Tools-Demos/2022-09-30-14-30-12.gh-issue-97669.gvbgcg.rst D Lib/test/test_tools/test_fixcid.py D Lib/test/test_tools/test_lll.py D Lib/test/test_tools/test_pdeps.py D Lib/test/test_tools/test_pindent.py D Misc/NEWS.d/next/Security/2022-09-28-12-10-57.gh-issue-97612.y6NvOQ.rst D Tools/scripts/byext.py D Tools/scripts/byteyears.py D Tools/scripts/cleanfuture.py D Tools/scripts/copytime.py D Tools/scripts/crlf.py D Tools/scripts/db2pickle.py D Tools/scripts/dutree.doc D Tools/scripts/dutree.py D Tools/scripts/find-uname.py D Tools/scripts/find_recursionlimit.py D Tools/scripts/finddiv.py D Tools/scripts/findlinksto.py D Tools/scripts/findnocoding.py D Tools/scripts/fixcid.py D Tools/scripts/fixdiv.py D Tools/scripts/fixheader.py D Tools/scripts/fixnotice.py D Tools/scripts/fixps.py D Tools/scripts/get-remote-certificate.py D Tools/scripts/google.py D Tools/scripts/highlight.py D Tools/scripts/ifdef.py D Tools/scripts/import_diagnostics.py D Tools/scripts/lfcr.py D Tools/scripts/linktree.py D Tools/scripts/lll.py D Tools/scripts/mailerdaemon.py D Tools/scripts/make_ctype.py D Tools/scripts/mkreal.py D Tools/scripts/objgraph.py D Tools/scripts/pdeps.py D Tools/scripts/pickle2db.py D Tools/scripts/pindent.py D Tools/scripts/pysource.py D Tools/scripts/reindent-rst.py D Tools/scripts/rgrep.py D Tools/scripts/suff.py D Tools/scripts/texi2html.py D Tools/scripts/which.py M Doc/whatsnew/3.12.rst M PCbuild/lib.pyproj M Tools/scripts/README diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 1d68e84983fe..39ae2518bbdd 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -178,6 +178,11 @@ Demos and Tools `_. (Contributed by Victor Stinner in :gh:`97681`.) +* Remove outdated example scripts of the ``Tools/scripts/`` directory. + A copy can be found in the `old-demos project + `_. + (Contributed by Victor Stinner in :gh:`97669`.) + Deprecated ========== diff --git a/Lib/test/test_tools/test_fixcid.py b/Lib/test/test_tools/test_fixcid.py deleted file mode 100644 index a72f74b8b15b..000000000000 --- a/Lib/test/test_tools/test_fixcid.py +++ /dev/null @@ -1,94 +0,0 @@ -'''Test Tools/scripts/fixcid.py.''' - -from io import StringIO -import os, os.path -import runpy -import sys -from test import support -from test.support import os_helper -from test.test_tools import skip_if_missing, scriptsdir -import unittest - -skip_if_missing() - -class Test(unittest.TestCase): - def test_parse_strings(self): - old1 = 'int xx = "xx\\"xx"[xx];\n' - old2 = "int xx = 'x\\'xx' + xx;\n" - output = self.run_script(old1 + old2) - new1 = 'int yy = "xx\\"xx"[yy];\n' - new2 = "int yy = 'x\\'xx' + yy;\n" - self.assertMultiLineEqual(output, - "1\n" - "< {old1}" - "> {new1}" - "{new1}" - "2\n" - "< {old2}" - "> {new2}" - "{new2}".format(old1=old1, old2=old2, new1=new1, new2=new2) - ) - - def test_alter_comments(self): - output = self.run_script( - substfile= - "xx yy\n" - "*aa bb\n", - args=("-c", "-",), - input= - "/* xx altered */\n" - "int xx;\n" - "/* aa unaltered */\n" - "int aa;\n", - ) - self.assertMultiLineEqual(output, - "1\n" - "< /* xx altered */\n" - "> /* yy altered */\n" - "/* yy altered */\n" - "2\n" - "< int xx;\n" - "> int yy;\n" - "int yy;\n" - "/* aa unaltered */\n" - "4\n" - "< int aa;\n" - "> int bb;\n" - "int bb;\n" - ) - - def test_directory(self): - os.mkdir(os_helper.TESTFN) - self.addCleanup(os_helper.rmtree, os_helper.TESTFN) - c_filename = os.path.join(os_helper.TESTFN, "file.c") - with open(c_filename, "w", encoding="utf-8") as file: - file.write("int xx;\n") - with open(os.path.join(os_helper.TESTFN, "file.py"), "w", - encoding="utf-8") as file: - file.write("xx = 'unaltered'\n") - script = os.path.join(scriptsdir, "fixcid.py") - output = self.run_script(args=(os_helper.TESTFN,)) - self.assertMultiLineEqual(output, - "{}:\n" - "1\n" - '< int xx;\n' - '> int yy;\n'.format(c_filename) - ) - - def run_script(self, input="", *, args=("-",), substfile="xx yy\n"): - substfilename = os_helper.TESTFN + ".subst" - with open(substfilename, "w", encoding="utf-8") as file: - file.write(substfile) - self.addCleanup(os_helper.unlink, substfilename) - - argv = ["fixcid.py", "-s", substfilename] + list(args) - script = os.path.join(scriptsdir, "fixcid.py") - with support.swap_attr(sys, "argv", argv), \ - support.swap_attr(sys, "stdin", StringIO(input)), \ - support.captured_stdout() as output, \ - support.captured_stderr(): - try: - runpy.run_path(script, run_name="__main__") - except SystemExit as exit: - self.assertEqual(exit.code, 0) - return output.getvalue() diff --git a/Lib/test/test_tools/test_lll.py b/Lib/test/test_tools/test_lll.py deleted file mode 100644 index 6eeb96ed9b67..000000000000 --- a/Lib/test/test_tools/test_lll.py +++ /dev/null @@ -1,41 +0,0 @@ -"""Tests for the lll script in the Tools/script directory.""" - -import os -import tempfile -from test import support -from test.support import os_helper -from test.test_tools import skip_if_missing, import_tool -import unittest - -skip_if_missing() - - -class lllTests(unittest.TestCase): - - def setUp(self): - self.lll = import_tool('lll') - - @os_helper.skip_unless_symlink - def test_lll_multiple_dirs(self): - with tempfile.TemporaryDirectory() as dir1, \ - tempfile.TemporaryDirectory() as dir2: - fn1 = os.path.join(dir1, 'foo1') - fn2 = os.path.join(dir2, 'foo2') - for fn, dir in (fn1, dir1), (fn2, dir2): - open(fn, 'wb').close() - os.symlink(fn, os.path.join(dir, 'symlink')) - - with support.captured_stdout() as output: - self.lll.main([dir1, dir2]) - prefix = '\\\\?\\' if os.name == 'nt' else '' - self.assertEqual(output.getvalue(), - f'{dir1}:\n' - f'symlink -> {prefix}{fn1}\n' - f'\n' - f'{dir2}:\n' - f'symlink -> {prefix}{fn2}\n' - ) - - -if __name__ == '__main__': - unittest.main() diff --git a/Lib/test/test_tools/test_pdeps.py b/Lib/test/test_tools/test_pdeps.py deleted file mode 100644 index a986d10e499d..000000000000 --- a/Lib/test/test_tools/test_pdeps.py +++ /dev/null @@ -1,32 +0,0 @@ -"""Tests for the pdeps script in the Tools directory.""" - -import os -import unittest -import tempfile - -from test.test_tools import skip_if_missing, import_tool - -skip_if_missing() - - -class PdepsTests(unittest.TestCase): - - @classmethod - def setUpClass(self): - self.pdeps = import_tool('pdeps') - - def test_process_errors(self): - # Issue #14492: m_import.match(line) can be None. - with tempfile.TemporaryDirectory() as tmpdir: - fn = os.path.join(tmpdir, 'foo') - with open(fn, 'w', encoding='utf-8') as stream: - stream.write("#!/this/will/fail") - self.pdeps.process(fn, {}) - - def test_inverse_attribute_error(self): - # Issue #14492: this used to fail with an AttributeError. - self.pdeps.inverse({'a': []}) - - -if __name__ == '__main__': - unittest.main() diff --git a/Lib/test/test_tools/test_pindent.py b/Lib/test/test_tools/test_pindent.py deleted file mode 100644 index 61e97fea48cf..000000000000 --- a/Lib/test/test_tools/test_pindent.py +++ /dev/null @@ -1,339 +0,0 @@ -"""Tests for the pindent script in the Tools directory.""" - -import os -import sys -import unittest -import subprocess -import textwrap -from test.support import os_helper -from test.support.script_helper import assert_python_ok - -from test.test_tools import scriptsdir, skip_if_missing - -skip_if_missing() - - -class PindentTests(unittest.TestCase): - script = os.path.join(scriptsdir, 'pindent.py') - - def assertFileEqual(self, fn1, fn2): - with open(fn1) as f1, open(fn2) as f2: - self.assertEqual(f1.readlines(), f2.readlines()) - - def pindent(self, source, *args): - with subprocess.Popen( - (sys.executable, self.script) + args, - stdin=subprocess.PIPE, stdout=subprocess.PIPE, - universal_newlines=True) as proc: - out, err = proc.communicate(source) - self.assertIsNone(err) - return out - - def lstriplines(self, data): - return '\n'.join(line.lstrip() for line in data.splitlines()) + '\n' - - def test_selftest(self): - self.maxDiff = None - with os_helper.temp_dir() as directory: - data_path = os.path.join(directory, '_test.py') - with open(self.script, encoding='utf-8') as f: - closed = f.read() - with open(data_path, 'w', encoding='utf-8') as f: - f.write(closed) - - rc, out, err = assert_python_ok(self.script, '-d', data_path) - self.assertEqual(out, b'') - self.assertEqual(err, b'') - backup = data_path + '~' - self.assertTrue(os.path.exists(backup)) - with open(backup, encoding='utf-8') as f: - self.assertEqual(f.read(), closed) - with open(data_path, encoding='utf-8') as f: - clean = f.read() - compile(clean, '_test.py', 'exec') - self.assertEqual(self.pindent(clean, '-c'), closed) - self.assertEqual(self.pindent(closed, '-d'), clean) - - rc, out, err = assert_python_ok(self.script, '-c', data_path) - self.assertEqual(out, b'') - self.assertEqual(err, b'') - with open(backup, encoding='utf-8') as f: - self.assertEqual(f.read(), clean) - with open(data_path, encoding='utf-8') as f: - self.assertEqual(f.read(), closed) - - broken = self.lstriplines(closed) - with open(data_path, 'w', encoding='utf-8') as f: - f.write(broken) - rc, out, err = assert_python_ok(self.script, '-r', data_path) - self.assertEqual(out, b'') - self.assertEqual(err, b'') - with open(backup, encoding='utf-8') as f: - self.assertEqual(f.read(), broken) - with open(data_path, encoding='utf-8') as f: - indented = f.read() - compile(indented, '_test.py', 'exec') - self.assertEqual(self.pindent(broken, '-r'), indented) - - def pindent_test(self, clean, closed): - self.assertEqual(self.pindent(clean, '-c'), closed) - self.assertEqual(self.pindent(closed, '-d'), clean) - broken = self.lstriplines(closed) - self.assertEqual(self.pindent(broken, '-r', '-e', '-s', '4'), closed) - - def test_statements(self): - clean = textwrap.dedent("""\ - if a: - pass - - if a: - pass - else: - pass - - if a: - pass - elif: - pass - else: - pass - - while a: - break - - while a: - break - else: - pass - - for i in a: - break - - for i in a: - break - else: - pass - - try: - pass - finally: - pass - - try: - pass - except TypeError: - pass - except ValueError: - pass - else: - pass - - try: - pass - except TypeError: - pass - except ValueError: - pass - finally: - pass - - with a: - pass - - class A: - pass - - def f(): - pass - """) - - closed = textwrap.dedent("""\ - if a: - pass - # end if - - if a: - pass - else: - pass - # end if - - if a: - pass - elif: - pass - else: - pass - # end if - - while a: - break - # end while - - while a: - break - else: - pass - # end while - - for i in a: - break - # end for - - for i in a: - break - else: - pass - # end for - - try: - pass - finally: - pass - # end try - - try: - pass - except TypeError: - pass - except ValueError: - pass - else: - pass - # end try - - try: - pass - except TypeError: - pass - except ValueError: - pass - finally: - pass - # end try - - with a: - pass - # end with - - class A: - pass - # end class A - - def f(): - pass - # end def f - """) - self.pindent_test(clean, closed) - - def test_multilevel(self): - clean = textwrap.dedent("""\ - def foobar(a, b): - if a == b: - a = a+1 - elif a < b: - b = b-1 - if b > a: a = a-1 - else: - print 'oops!' - """) - closed = textwrap.dedent("""\ - def foobar(a, b): - if a == b: - a = a+1 - elif a < b: - b = b-1 - if b > a: a = a-1 - # end if - else: - print 'oops!' - # end if - # end def foobar - """) - self.pindent_test(clean, closed) - - def test_preserve_indents(self): - clean = textwrap.dedent("""\ - if a: - if b: - pass - """) - closed = textwrap.dedent("""\ - if a: - if b: - pass - # end if - # end if - """) - self.assertEqual(self.pindent(clean, '-c'), closed) - self.assertEqual(self.pindent(closed, '-d'), clean) - broken = self.lstriplines(closed) - self.assertEqual(self.pindent(broken, '-r', '-e', '-s', '9'), closed) - clean = textwrap.dedent("""\ - if a: - \tif b: - \t\tpass - """) - closed = textwrap.dedent("""\ - if a: - \tif b: - \t\tpass - \t# end if - # end if - """) - self.assertEqual(self.pindent(clean, '-c'), closed) - self.assertEqual(self.pindent(closed, '-d'), clean) - broken = self.lstriplines(closed) - self.assertEqual(self.pindent(broken, '-r'), closed) - - def test_escaped_newline(self): - clean = textwrap.dedent("""\ - class\\ - \\ - A: - def\ - \\ - f: - pass - """) - closed = textwrap.dedent("""\ - class\\ - \\ - A: - def\ - \\ - f: - pass - # end def f - # end class A - """) - self.assertEqual(self.pindent(clean, '-c'), closed) - self.assertEqual(self.pindent(closed, '-d'), clean) - - def test_empty_line(self): - clean = textwrap.dedent("""\ - if a: - - pass - """) - closed = textwrap.dedent("""\ - if a: - - pass - # end if - """) - self.pindent_test(clean, closed) - - def test_oneline(self): - clean = textwrap.dedent("""\ - if a: pass - """) - closed = textwrap.dedent("""\ - if a: pass - # end if - """) - self.pindent_test(clean, closed) - - -if __name__ == '__main__': - unittest.main() diff --git a/Misc/NEWS.d/next/Security/2022-09-28-12-10-57.gh-issue-97612.y6NvOQ.rst b/Misc/NEWS.d/next/Security/2022-09-28-12-10-57.gh-issue-97612.y6NvOQ.rst deleted file mode 100644 index 2f113492d42d..000000000000 --- a/Misc/NEWS.d/next/Security/2022-09-28-12-10-57.gh-issue-97612.y6NvOQ.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix a shell code injection vulnerability in the ``get-remote-certificate.py`` -example script. The script no longer uses a shell to run ``openssl`` commands. -Issue reported and initial fix by Caleb Shortt. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Tools-Demos/2022-09-30-14-30-12.gh-issue-97669.gvbgcg.rst b/Misc/NEWS.d/next/Tools-Demos/2022-09-30-14-30-12.gh-issue-97669.gvbgcg.rst new file mode 100644 index 000000000000..604f20290fc8 --- /dev/null +++ b/Misc/NEWS.d/next/Tools-Demos/2022-09-30-14-30-12.gh-issue-97669.gvbgcg.rst @@ -0,0 +1,3 @@ +Remove outdated example scripts of the ``Tools/scripts/`` directory. A copy can +be found in the `old-demos project `_. +Patch by Victor Stinner. diff --git a/PCbuild/lib.pyproj b/PCbuild/lib.pyproj index e8c99f6b246c..9934dc577bf3 100644 --- a/PCbuild/lib.pyproj +++ b/PCbuild/lib.pyproj @@ -1334,12 +1334,9 @@ - - - diff --git a/Tools/scripts/README b/Tools/scripts/README index c1d66731ba64..6affa67b3449 100644 --- a/Tools/scripts/README +++ b/Tools/scripts/README @@ -1,65 +1,25 @@ This directory contains a collection of executable Python scripts that are -useful while building, extending or managing Python. Some (e.g., dutree or lll) -are also generally useful UNIX tools. +useful while building, extending or managing Python. 2to3 Main script for running the 2to3 conversion tool abitype.py Converts a C file to use the PEP 384 type definition API analyze_dxp.py Analyzes the result of sys.getdxp() -byext.py Print lines/words/chars stats of files by extension -byteyears.py Print product of a file's size and age -cleanfuture.py Fix redundant Python __future__ statements combinerefs.py A helper for analyzing PYTHONDUMPREFS output -copytime.py Copy one file's atime and mtime to another -crlf.py Change CRLF line endings to LF (Windows to Unix) -db2pickle.py Dump a database file to a pickle diff.py Print file diffs in context, unified, or ndiff formats -dutree.py Format du(1) output as a tree sorted by size eptags.py Create Emacs TAGS file for Python modules -finddiv.py A grep-like tool that looks for division operators -findlinksto.py Recursively find symbolic links to a given path prefix -findnocoding.py Find source files which need an encoding declaration -find_recursionlimit.py Find the maximum recursion limit on this machine -find-uname.py Look for the given arguments in the sets of all Unicode names -fixcid.py Massive identifier substitution on C source files -fixdiv.py Tool to fix division operators. -fixheader.py Add some cpp magic to a C include file -fixnotice.py Fix the copyright notice in source files -fixps.py Fix Python scripts' first line (if #!) -ftpmirror.py FTP mirror script -get-remote-certificate.py Fetch the certificate that the server(s) are providing in PEM form -google.py Open a webbrowser with Google gprof2html.py Transform gprof(1) output into useful HTML -highlight.py Python syntax highlighting with HTML output idle3 Main program to start IDLE -ifdef.py Remove #if(n)def groups from C sources -import_diagnostics.py Miscellaneous diagnostics for the import system -lfcr.py Change LF line endings to CRLF (Unix to Windows) -linktree.py Make a copy of a tree with links to original files -lll.py Find and list symbolic links in current directory -mailerdaemon.py Parse error messages from mailer daemons (Sjoerd&Jack) -make_ctype.py Generate ctype.h replacement in stringobject.c md5sum.py Print MD5 checksums of argument files -mkreal.py Turn a symbolic link into a real file or directory ndiff.py Intelligent diff between text files (Tim Peters) nm2def.py Create a template for PC/python_nt.def (Marc Lemburg) -objgraph.py Print object graph from nm output on a library parseentities.py Utility for parsing HTML entity definitions parse_html5_entities.py Utility for parsing HTML5 entity definitions patchcheck.py Perform common checks and cleanup before committing pathfix.py Change #!/usr/local/bin/python into something else -pdeps.py Print dependencies between Python modules -pickle2db.py Load a pickle generated by db2pickle.py to a database -pindent.py Indent Python code, giving block-closing comments ptags.py Create vi tags file for Python modules pydoc3 Python documentation browser -pysource.py Find Python source files reindent.py Change .py files to use 4-space indents -reindent-rst.py Fix-up reStructuredText file whitespace -rgrep.py Reverse grep through a file (useful for big logfiles) run_tests.py Run the test suite with more sensible default options stable_abi.py Stable ABI checks and file generators. -suff.py Sort a list of files by suffix -texi2html.py Convert GNU texinfo files into HTML untabify.py Replace tabs with spaces in argument files -which.py Find a program in $PATH win_add2path.py Add Python to the search path on Windows diff --git a/Tools/scripts/byext.py b/Tools/scripts/byext.py deleted file mode 100755 index a4b2f7ff6d82..000000000000 --- a/Tools/scripts/byext.py +++ /dev/null @@ -1,132 +0,0 @@ -#! /usr/bin/env python3 - -"""Show file statistics by extension.""" - -import os -import sys - - -class Stats: - - def __init__(self): - self.stats = {} - - def statargs(self, args): - for arg in args: - if os.path.isdir(arg): - self.statdir(arg) - elif os.path.isfile(arg): - self.statfile(arg) - else: - sys.stderr.write("Can't find %s\n" % arg) - self.addstats("", "unknown", 1) - - def statdir(self, dir): - self.addstats("", "dirs", 1) - try: - names = os.listdir(dir) - except OSError as err: - sys.stderr.write("Can't list %s: %s\n" % (dir, err)) - self.addstats("", "unlistable", 1) - return - for name in sorted(names): - if name.startswith(".#"): - continue # Skip CVS temp files - if name.endswith("~"): - continue # Skip Emacs backup files - full = os.path.join(dir, name) - if os.path.islink(full): - self.addstats("", "links", 1) - elif os.path.isdir(full): - self.statdir(full) - else: - self.statfile(full) - - def statfile(self, filename): - head, ext = os.path.splitext(filename) - head, base = os.path.split(filename) - if ext == base: - ext = "" # E.g. .cvsignore is deemed not to have an extension - ext = os.path.normcase(ext) - if not ext: - ext = "" - self.addstats(ext, "files", 1) - try: - with open(filename, "rb") as f: - data = f.read() - except IOError as err: - sys.stderr.write("Can't open %s: %s\n" % (filename, err)) - self.addstats(ext, "unopenable", 1) - return - self.addstats(ext, "bytes", len(data)) - if b'\0' in data: - self.addstats(ext, "binary", 1) - return - if not data: - self.addstats(ext, "empty", 1) - # self.addstats(ext, "chars", len(data)) - lines = str(data, "latin-1").splitlines() - self.addstats(ext, "lines", len(lines)) - del lines - words = data.split() - self.addstats(ext, "words", len(words)) - - def addstats(self, ext, key, n): - d = self.stats.setdefault(ext, {}) - d[key] = d.get(key, 0) + n - - def report(self): - exts = sorted(self.stats) - # Get the column keys - columns = {} - for ext in exts: - columns.update(self.stats[ext]) - cols = sorted(columns) - colwidth = {} - colwidth["ext"] = max(map(len, exts)) - minwidth = 6 - self.stats["TOTAL"] = {} - for col in cols: - total = 0 - cw = max(minwidth, len(col)) - for ext in exts: - value = self.stats[ext].get(col) - if value is None: - w = 0 - else: - w = len("%d" % value) - total += value - cw = max(cw, w) - cw = max(cw, len(str(total))) - colwidth[col] = cw - self.stats["TOTAL"][col] = total - exts.append("TOTAL") - for ext in exts: - self.stats[ext]["ext"] = ext - cols.insert(0, "ext") - - def printheader(): - for col in cols: - print("%*s" % (colwidth[col], col), end=' ') - print() - - printheader() - for ext in exts: - for col in cols: - value = self.stats[ext].get(col, "") - print("%*s" % (colwidth[col], value), end=' ') - print() - printheader() # Another header at the bottom - - -def main(): - args = sys.argv[1:] - if not args: - args = [os.curdir] - s = Stats() - s.statargs(args) - s.report() - - -if __name__ == "__main__": - main() diff --git a/Tools/scripts/byteyears.py b/Tools/scripts/byteyears.py deleted file mode 100755 index f58c34608faa..000000000000 --- a/Tools/scripts/byteyears.py +++ /dev/null @@ -1,61 +0,0 @@ -#! /usr/bin/env python3 - -# Print the product of age and size of each file, in suitable units. -# -# Usage: byteyears [ -a | -m | -c ] file ... -# -# Options -[amc] select atime, mtime (default) or ctime as age. - -import sys, os, time -from stat import * - -def main(): - - # Use lstat() to stat files if it exists, else stat() - try: - statfunc = os.lstat - except AttributeError: - statfunc = os.stat - - # Parse options - if sys.argv[1] == '-m': - itime = ST_MTIME - del sys.argv[1] - elif sys.argv[1] == '-c': - itime = ST_CTIME - del sys.argv[1] - elif sys.argv[1] == '-a': - itime = ST_CTIME - del sys.argv[1] - else: - itime = ST_MTIME - - secs_per_year = 365.0 * 24.0 * 3600.0 # Scale factor - now = time.time() # Current time, for age computations - status = 0 # Exit status, set to 1 on errors - - # Compute max file name length - maxlen = 1 - for filename in sys.argv[1:]: - maxlen = max(maxlen, len(filename)) - - # Process each argument in turn - for filename in sys.argv[1:]: - try: - st = statfunc(filename) - except OSError as msg: - sys.stderr.write("can't stat %r: %r\n" % (filename, msg)) - status = 1 - st = () - if st: - anytime = st[itime] - size = st[ST_SIZE] - age = now - anytime - byteyears = float(size) * float(age) / secs_per_year - print(filename.ljust(maxlen), end=' ') - print(repr(int(byteyears)).rjust(8)) - - sys.exit(status) - -if __name__ == '__main__': - main() diff --git a/Tools/scripts/cleanfuture.py b/Tools/scripts/cleanfuture.py deleted file mode 100755 index 94f691263215..000000000000 --- a/Tools/scripts/cleanfuture.py +++ /dev/null @@ -1,275 +0,0 @@ -#! /usr/bin/env python3 - -"""cleanfuture [-d][-r][-v] path ... - --d Dry run. Analyze, but don't make any changes to, files. --r Recurse. Search for all .py files in subdirectories too. --v Verbose. Print informative msgs. - -Search Python (.py) files for future statements, and remove the features -from such statements that are already mandatory in the version of Python -you're using. - -Pass one or more file and/or directory paths. When a directory path, all -.py files within the directory will be examined, and, if the -r option is -given, likewise recursively for subdirectories. - -Overwrites files in place, renaming the originals with a .bak extension. If -cleanfuture finds nothing to change, the file is left alone. If cleanfuture -does change a file, the changed file is a fixed-point (i.e., running -cleanfuture on the resulting .py file won't change it again, at least not -until you try it again with a later Python release). - -Limitations: You can do these things, but this tool won't help you then: - -+ A future statement cannot be mixed with any other statement on the same - physical line (separated by semicolon). - -+ A future statement cannot contain an "as" clause. - -Example: Assuming you're using Python 2.2, if a file containing - -from __future__ import nested_scopes, generators - -is analyzed by cleanfuture, the line is rewritten to - -from __future__ import generators - -because nested_scopes is no longer optional in 2.2 but generators is. -""" - -import __future__ -import tokenize -import os -import sys - -dryrun = 0 -recurse = 0 -verbose = 0 - -def errprint(*args): - strings = map(str, args) - msg = ' '.join(strings) - if msg[-1:] != '\n': - msg += '\n' - sys.stderr.write(msg) - -def main(): - import getopt - global verbose, recurse, dryrun - try: - opts, args = getopt.getopt(sys.argv[1:], "drv") - except getopt.error as msg: - errprint(msg) - return - for o, a in opts: - if o == '-d': - dryrun += 1 - elif o == '-r': - recurse += 1 - elif o == '-v': - verbose += 1 - if not args: - errprint("Usage:", __doc__) - return - for arg in args: - check(arg) - -def check(file): - if os.path.isdir(file) and not os.path.islink(file): - if verbose: - print("listing directory", file) - names = os.listdir(file) - for name in names: - fullname = os.path.join(file, name) - if ((recurse and os.path.isdir(fullname) and - not os.path.islink(fullname)) - or name.lower().endswith(".py")): - check(fullname) - return - - if verbose: - print("checking", file, "...", end=' ') - try: - f = open(file) - except IOError as msg: - errprint("%r: I/O Error: %s" % (file, str(msg))) - return - - with f: - ff = FutureFinder(f, file) - changed = ff.run() - if changed: - ff.gettherest() - if changed: - if verbose: - print("changed.") - if dryrun: - print("But this is a dry run, so leaving it alone.") - for s, e, line in changed: - print("%r lines %d-%d" % (file, s+1, e+1)) - for i in range(s, e+1): - print(ff.lines[i], end=' ') - if line is None: - print("-- deleted") - else: - print("-- change to:") - print(line, end=' ') - if not dryrun: - bak = file + ".bak" - if os.path.exists(bak): - os.remove(bak) - os.rename(file, bak) - if verbose: - print("renamed", file, "to", bak) - with open(file, "w") as g: - ff.write(g) - if verbose: - print("wrote new", file) - else: - if verbose: - print("unchanged.") - -class FutureFinder: - - def __init__(self, f, fname): - self.f = f - self.fname = fname - self.ateof = 0 - self.lines = [] # raw file lines - - # List of (start_index, end_index, new_line) triples. - self.changed = [] - - # Line-getter for tokenize. - def getline(self): - if self.ateof: - return "" - line = self.f.readline() - if line == "": - self.ateof = 1 - else: - self.lines.append(line) - return line - - def run(self): - STRING = tokenize.STRING - NL = tokenize.NL - NEWLINE = tokenize.NEWLINE - COMMENT = tokenize.COMMENT - NAME = tokenize.NAME - OP = tokenize.OP - - changed = self.changed - get = tokenize.generate_tokens(self.getline).__next__ - type, token, (srow, scol), (erow, ecol), line = get() - - # Chew up initial comments and blank lines (if any). - while type in (COMMENT, NL, NEWLINE): - type, token, (srow, scol), (erow, ecol), line = get() - - # Chew up docstring (if any -- and it may be implicitly catenated!). - while type is STRING: - type, token, (srow, scol), (erow, ecol), line = get() - - # Analyze the future stmts. - while 1: - # Chew up comments and blank lines (if any). - while type in (COMMENT, NL, NEWLINE): - type, token, (srow, scol), (erow, ecol), line = get() - - if not (type is NAME and token == "from"): - break - startline = srow - 1 # tokenize is one-based - type, token, (srow, scol), (erow, ecol), line = get() - - if not (type is NAME and token == "__future__"): - break - type, token, (srow, scol), (erow, ecol), line = get() - - if not (type is NAME and token == "import"): - break - type, token, (srow, scol), (erow, ecol), line = get() - - # Get the list of features. - features = [] - while type is NAME: - features.append(token) - type, token, (srow, scol), (erow, ecol), line = get() - - if not (type is OP and token == ','): - break - type, token, (srow, scol), (erow, ecol), line = get() - - # A trailing comment? - comment = None - if type is COMMENT: - comment = token - type, token, (srow, scol), (erow, ecol), line = get() - - if type is not NEWLINE: - errprint("Skipping file %r; can't parse line %d:\n%s" % - (self.fname, srow, line)) - return [] - - endline = srow - 1 - - # Check for obsolete features. - okfeatures = [] - for f in features: - object = getattr(__future__, f, None) - if object is None: - # A feature we don't know about yet -- leave it in. - # They'll get a compile-time error when they compile - # this program, but that's not our job to sort out. - okfeatures.append(f) - else: - released = object.getMandatoryRelease() - if released is None or released <= sys.version_info: - # Withdrawn or obsolete. - pass - else: - okfeatures.append(f) - - # Rewrite the line if at least one future-feature is obsolete. - if len(okfeatures) < len(features): - if len(okfeatures) == 0: - line = None - else: - line = "from __future__ import " - line += ', '.join(okfeatures) - if comment is not None: - line += ' ' + comment - line += '\n' - changed.append((startline, endline, line)) - - # Loop back for more future statements. - - return changed - - def gettherest(self): - if self.ateof: - self.therest = '' - else: - self.therest = self.f.read() - - def write(self, f): - changed = self.changed - assert changed - # Prevent calling this again. - self.changed = [] - # Apply changes in reverse order. - changed.reverse() - for s, e, line in changed: - if line is None: - # pure deletion - del self.lines[s:e+1] - else: - self.lines[s:e+1] = [line] - f.writelines(self.lines) - # Copy over the remainder of the file. - if self.therest: - f.write(self.therest) - -if __name__ == '__main__': - main() diff --git a/Tools/scripts/copytime.py b/Tools/scripts/copytime.py deleted file mode 100755 index 715683f12557..000000000000 --- a/Tools/scripts/copytime.py +++ /dev/null @@ -1,26 +0,0 @@ -#! /usr/bin/env python3 - -# Copy one file's atime and mtime to another - -import sys -import os -from stat import ST_ATIME, ST_MTIME # Really constants 7 and 8 - -def main(): - if len(sys.argv) != 3: - sys.stderr.write('usage: copytime source destination\n') - sys.exit(2) - file1, file2 = sys.argv[1], sys.argv[2] - try: - stat1 = os.stat(file1) - except OSError: - sys.stderr.write(file1 + ': cannot stat\n') - sys.exit(1) - try: - os.utime(file2, (stat1[ST_ATIME], stat1[ST_MTIME])) - except OSError: - sys.stderr.write(file2 + ': cannot change time\n') - sys.exit(2) - -if __name__ == '__main__': - main() diff --git a/Tools/scripts/crlf.py b/Tools/scripts/crlf.py deleted file mode 100755 index f231d292cebe..000000000000 --- a/Tools/scripts/crlf.py +++ /dev/null @@ -1,23 +0,0 @@ -#! /usr/bin/env python3 -"Replace CRLF with LF in argument files. Print names of changed files." - -import sys, os - -def main(): - for filename in sys.argv[1:]: - if os.path.isdir(filename): - print(filename, "Directory!") - continue - with open(filename, "rb") as f: - data = f.read() - if b'\0' in data: - print(filename, "Binary!") - continue - newdata = data.replace(b"\r\n", b"\n") - if newdata != data: - print(filename) - with open(filename, "wb") as f: - f.write(newdata) - -if __name__ == '__main__': - main() diff --git a/Tools/scripts/db2pickle.py b/Tools/scripts/db2pickle.py deleted file mode 100755 index a5532a8f3a41..000000000000 --- a/Tools/scripts/db2pickle.py +++ /dev/null @@ -1,135 +0,0 @@ -#!/usr/bin/env python3 - -""" -Synopsis: %(prog)s [-h|-g|-b|-r|-a] dbfile [ picklefile ] - -Convert the database file given on the command line to a pickle -representation. The optional flags indicate the type of the database: - - -a - open using dbm (any supported format) - -b - open as bsddb btree file - -d - open as dbm file - -g - open as gdbm file - -h - open as bsddb hash file - -r - open as bsddb recno file - -The default is hash. If a pickle file is named it is opened for write -access (deleting any existing data). If no pickle file is named, the pickle -output is written to standard output. - -""" - -import getopt -try: - import bsddb -except ImportError: - bsddb = None -try: - import dbm.ndbm as dbm -except ImportError: - dbm = None -try: - import dbm.gnu as gdbm -except ImportError: - gdbm = None -try: - import dbm.ndbm as anydbm -except ImportError: - anydbm = None -import sys -try: - import pickle as pickle -except ImportError: - import pickle - -prog = sys.argv[0] - -def usage(): - sys.stderr.write(__doc__ % globals()) - -def main(args): - try: - opts, args = getopt.getopt(args, "hbrdag", - ["hash", "btree", "recno", "dbm", - "gdbm", "anydbm"]) - except getopt.error: - usage() - return 1 - - if len(args) == 0 or len(args) > 2: - usage() - return 1 - elif len(args) == 1: - dbfile = args[0] - pfile = sys.stdout - else: - dbfile = args[0] - try: - pfile = open(args[1], 'wb') - except IOError: - sys.stderr.write("Unable to open %s\n" % args[1]) - return 1 - - dbopen = None - for opt, arg in opts: - if opt in ("-h", "--hash"): - try: - dbopen = bsddb.hashopen - except AttributeError: - sys.stderr.write("bsddb module unavailable.\n") - return 1 - elif opt in ("-b", "--btree"): - try: - dbopen = bsddb.btopen - except AttributeError: - sys.stderr.write("bsddb module unavailable.\n") - return 1 - elif opt in ("-r", "--recno"): - try: - dbopen = bsddb.rnopen - except AttributeError: - sys.stderr.write("bsddb module unavailable.\n") - return 1 - elif opt in ("-a", "--anydbm"): - try: - dbopen = anydbm.open - except AttributeError: - sys.stderr.write("dbm module unavailable.\n") - return 1 - elif opt in ("-g", "--gdbm"): - try: - dbopen = gdbm.open - except AttributeError: - sys.stderr.write("dbm.gnu module unavailable.\n") - return 1 - elif opt in ("-d", "--dbm"): - try: - dbopen = dbm.open - except AttributeError: - sys.stderr.write("dbm.ndbm module unavailable.\n") - return 1 - if dbopen is None: - if bsddb is None: - sys.stderr.write("bsddb module unavailable - ") - sys.stderr.write("must specify dbtype.\n") - return 1 - else: - dbopen = bsddb.hashopen - - try: - db = dbopen(dbfile, 'r') - except bsddb.error: - sys.stderr.write("Unable to open %s. " % dbfile) - sys.stderr.write("Check for format or version mismatch.\n") - return 1 - - for k in db.keys(): - pickle.dump((k, db[k]), pfile, 1==1) - - db.close() - pfile.close() - - return 0 - -if __name__ == "__main__": - sys.exit(main(sys.argv[1:])) diff --git a/Tools/scripts/dutree.doc b/Tools/scripts/dutree.doc deleted file mode 100644 index 490126b0182d..000000000000 --- a/Tools/scripts/dutree.doc +++ /dev/null @@ -1,54 +0,0 @@ -Path: cwi.nl!sun4nl!mcsun!uunet!cs.utexas.edu!convex!usenet -From: tchrist at convex.COM (Tom Christiansen) -Newsgroups: comp.lang.perl -Subject: Re: The problems of Perl (Re: Question (silly?)) -Message-ID: <1992Jan17.053115.4220 at convex.com> -Date: 17 Jan 92 05:31:15 GMT -References: <17458 at ector.cs.purdue.edu> <1992Jan16.165347.25583 at cherokee.uswest.com> <=#Hues+4 at cs.psu.edu> -Sender: usenet at convex.com (news access account) -Reply-To: tchrist at convex.COM (Tom Christiansen) -Organization: CONVEX Realtime Development, Colorado Springs, CO -Lines: 83 -Nntp-Posting-Host: pixel.convex.com - -From the keyboard of flee at cs.psu.edu (Felix Lee): -:And Perl is definitely awkward with data types. I haven't yet found a -:pleasant way of shoving non-trivial data types into Perl's grammar. - -Yes, it's pretty awful at that, alright. Sometimes I write perl programs -that need them, and sometimes it just takes a little creativity. But -sometimes it's not worth it. I actually wrote a C program the other day -(gasp) because I didn't want to deal with a game matrix with six links per node. - -:Here's a very simple problem that's tricky to express in Perl: process -:the output of "du" to produce output that's indented to reflect the -:tree structure, and with each subtree sorted by size. Something like: -: 434 /etc -: | 344 . -: | 50 install -: | 35 uucp -: | 3 nserve -: | | 2 . -: | | 1 auth.info -: | 1 sm -: | 1 sm.bak - -At first I thought I could just keep one local list around -at once, but this seems inherently recursive. Which means -I need an real recursive data structure. Maybe you could -do it with one of the %assoc arrays Larry uses in the begat -programs, but I broke down and got dirty. I think the hardest -part was matching Felix's desired output exactly. It's not -blazingly fast: I should probably inline the &childof routine, -but it *was* faster to write than I could have written the -equivalent C program. - - ---tom - --- -"GUIs normally make it simple to accomplish simple actions and impossible -to accomplish complex actions." --Doug Gwyn (22/Jun/91 in comp.unix.wizards) - - Tom Christiansen tchrist at convex.com convex!tchrist - diff --git a/Tools/scripts/dutree.py b/Tools/scripts/dutree.py deleted file mode 100755 index d25cf72b707e..000000000000 --- a/Tools/scripts/dutree.py +++ /dev/null @@ -1,60 +0,0 @@ -#! /usr/bin/env python3 -# Format du output in a tree shape - -import os, sys, errno - -def main(): - total, d = None, {} - with os.popen('du ' + ' '.join(sys.argv[1:])) as p: - for line in p: - i = 0 - while line[i] in '0123456789': i = i+1 - size = eval(line[:i]) - while line[i] in ' \t': i = i+1 - filename = line[i:-1] - comps = filename.split('/') - if comps[0] == '': comps[0] = '/' - if comps[len(comps)-1] == '': del comps[len(comps)-1] - total, d = store(size, comps, total, d) - try: - display(total, d) - except IOError as e: - if e.errno != errno.EPIPE: - raise - -def store(size, comps, total, d): - if comps == []: - return size, d - if comps[0] not in d: - d[comps[0]] = None, {} - t1, d1 = d[comps[0]] - d[comps[0]] = store(size, comps[1:], t1, d1) - return total, d - -def display(total, d): - show(total, d, '') - -def show(total, d, prefix): - if not d: return - list = [] - sum = 0 - for key in d.keys(): - tsub, dsub = d[key] - list.append((tsub, key)) - if tsub is not None: sum = sum + tsub -## if sum < total: -## list.append((total - sum, os.curdir)) - list.sort() - list.reverse() - width = len(repr(list[0][0])) - for tsub, key in list: - if tsub is None: - psub = prefix - else: - print(prefix + repr(tsub).rjust(width) + ' ' + key) - psub = prefix + ' '*(width-1) + '|' + ' '*(len(key)+1) - if key in d: - show(tsub, d[key][1], psub) - -if __name__ == '__main__': - main() diff --git a/Tools/scripts/find-uname.py b/Tools/scripts/find-uname.py deleted file mode 100755 index b6ec1b6d7906..000000000000 --- a/Tools/scripts/find-uname.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env python3 - -""" -For each argument on the command line, look for it in the set of all Unicode -names. Arguments are treated as case-insensitive regular expressions, e.g.: - - % find-uname 'small letter a$' 'horizontal line' - *** small letter a$ matches *** - LATIN SMALL LETTER A (97) - COMBINING LATIN SMALL LETTER A (867) - CYRILLIC SMALL LETTER A (1072) - PARENTHESIZED LATIN SMALL LETTER A (9372) - CIRCLED LATIN SMALL LETTER A (9424) - FULLWIDTH LATIN SMALL LETTER A (65345) - *** horizontal line matches *** - HORIZONTAL LINE EXTENSION (9135) -""" - -import unicodedata -import sys -import re - -def main(args): - unicode_names = [] - for ix in range(sys.maxunicode+1): - try: - unicode_names.append((ix, unicodedata.name(chr(ix)))) - except ValueError: # no name for the character - pass - for arg in args: - pat = re.compile(arg, re.I) - matches = [(y,x) for (x,y) in unicode_names - if pat.search(y) is not None] - if matches: - print("***", arg, "matches", "***") - for match in matches: - print("%s (%d)" % match) - -if __name__ == "__main__": - main(sys.argv[1:]) diff --git a/Tools/scripts/find_recursionlimit.py b/Tools/scripts/find_recursionlimit.py deleted file mode 100755 index b2842a62efdb..000000000000 --- a/Tools/scripts/find_recursionlimit.py +++ /dev/null @@ -1,128 +0,0 @@ -#! /usr/bin/env python3 -"""Find the maximum recursion limit that prevents interpreter termination. - -This script finds the maximum safe recursion limit on a particular -platform. If you need to change the recursion limit on your system, -this script will tell you a safe upper bound. To use the new limit, -call sys.setrecursionlimit(). - -This module implements several ways to create infinite recursion in -Python. Different implementations end up pushing different numbers of -C stack frames, depending on how many calls through Python's abstract -C API occur. - -After each round of tests, it prints a message: -"Limit of NNNN is fine". - -The highest printed value of "NNNN" is therefore the highest potentially -safe limit for your system (which depends on the OS, architecture, but also -the compilation flags). Please note that it is practically impossible to -test all possible recursion paths in the interpreter, so the results of -this test should not be trusted blindly -- although they give a good hint -of which values are reasonable. - -NOTE: When the C stack space allocated by your system is exceeded due -to excessive recursion, exact behaviour depends on the platform, although -the interpreter will always fail in a likely brutal way: either a -segmentation fault, a MemoryError, or just a silent abort. - -NB: A program that does not use __methods__ can set a higher limit. -""" - -import sys -import itertools - -class RecursiveBlowup1: - def __init__(self): - self.__init__() - -def test_init(): - return RecursiveBlowup1() - -class RecursiveBlowup2: - def __repr__(self): - return repr(self) - -def test_repr(): - return repr(RecursiveBlowup2()) - -class RecursiveBlowup4: - def __add__(self, x): - return x + self - -def test_add(): - return RecursiveBlowup4() + RecursiveBlowup4() - -class RecursiveBlowup5: - def __getattr__(self, attr): - return getattr(self, attr) - -def test_getattr(): - return RecursiveBlowup5().attr - -class RecursiveBlowup6: - def __getitem__(self, item): - return self[item - 2] + self[item - 1] - -def test_getitem(): - return RecursiveBlowup6()[5] - -def test_recurse(): - return test_recurse() - -def test_cpickle(_cache={}): - import io - try: - import _pickle - except ImportError: - print("cannot import _pickle, skipped!") - return - k, l = None, None - for n in itertools.count(): - try: - l = _cache[n] - continue # Already tried and it works, let's save some time - except KeyError: - for i in range(100): - l = [k, l] - k = {i: l} - _pickle.Pickler(io.BytesIO(), protocol=-1).dump(l) - _cache[n] = l - -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 RecursionError even at higher recursion limits - compile("()" * (10 * sys.getrecursionlimit()), "", "single") - -def check_limit(n, test_func_name): - sys.setrecursionlimit(n) - if test_func_name.startswith("test_"): - print(test_func_name[5:]) - else: - print(test_func_name) - test_func = globals()[test_func_name] - try: - test_func() - # 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 (RecursionError, AttributeError): - pass - else: - print("Yikes!") - -if __name__ == '__main__': - - limit = 1000 - while 1: - check_limit(limit, "test_recurse") - check_limit(limit, "test_add") - check_limit(limit, "test_repr") - check_limit(limit, "test_init") - check_limit(limit, "test_getattr") - check_limit(limit, "test_getitem") - check_limit(limit, "test_cpickle") - check_limit(limit, "test_compiler_recursion") - print("Limit of %d is fine" % limit) - limit = limit + 100 diff --git a/Tools/scripts/finddiv.py b/Tools/scripts/finddiv.py deleted file mode 100755 index d21253cf1c8a..000000000000 --- a/Tools/scripts/finddiv.py +++ /dev/null @@ -1,89 +0,0 @@ -#! /usr/bin/env python3 - -"""finddiv - a grep-like tool that looks for division operators. - -Usage: finddiv [-l] file_or_directory ... - -For directory arguments, all files in the directory whose name ends in -.py are processed, and subdirectories are processed recursively. - -This actually tokenizes the files to avoid false hits in comments or -strings literals. - -By default, this prints all lines containing a / or /= operator, in -grep -n style. With the -l option specified, it prints the filename -of files that contain at least one / or /= operator. -""" - -import os -import sys -import getopt -import tokenize - -def main(): - try: - opts, args = getopt.getopt(sys.argv[1:], "lh") - except getopt.error as msg: - usage(msg) - return 2 - if not args: - usage("at least one file argument is required") - return 2 - listnames = 0 - for o, a in opts: - if o == "-h": - print(__doc__) - return - if o == "-l": - listnames = 1 - exit = None - for filename in args: - x = process(filename, listnames) - exit = exit or x - return exit - -def usage(msg): - sys.stderr.write("%s: %s\n" % (sys.argv[0], msg)) - sys.stderr.write("Usage: %s [-l] file ...\n" % sys.argv[0]) - sys.stderr.write("Try `%s -h' for more information.\n" % sys.argv[0]) - -def process(filename, listnames): - if os.path.isdir(filename): - return processdir(filename, listnames) - try: - fp = open(filename) - except IOError as msg: - sys.stderr.write("Can't open: %s\n" % msg) - return 1 - with fp: - g = tokenize.generate_tokens(fp.readline) - lastrow = None - for type, token, (row, col), end, line in g: - if token in ("/", "/="): - if listnames: - print(filename) - break - if row != lastrow: - lastrow = row - print("%s:%d:%s" % (filename, row, line), end=' ') - -def processdir(dir, listnames): - try: - names = os.listdir(dir) - except OSError as msg: - sys.stderr.write("Can't list directory: %s\n" % dir) - return 1 - files = [] - for name in names: - fn = os.path.join(dir, name) - if os.path.normcase(fn).endswith(".py") or os.path.isdir(fn): - files.append(fn) - files.sort(key=os.path.normcase) - exit = None - for fn in files: - x = process(fn, listnames) - exit = exit or x - return exit - -if __name__ == "__main__": - sys.exit(main()) diff --git a/Tools/scripts/findlinksto.py b/Tools/scripts/findlinksto.py deleted file mode 100755 index b924f27b095e..000000000000 --- a/Tools/scripts/findlinksto.py +++ /dev/null @@ -1,43 +0,0 @@ -#! /usr/bin/env python3 - -# findlinksto -# -# find symbolic links to a path matching a regular expression - -import os -import sys -import re -import getopt - -def main(): - try: - opts, args = getopt.getopt(sys.argv[1:], '') - if len(args) < 2: - raise getopt.GetoptError('not enough arguments', None) - except getopt.GetoptError as msg: - sys.stdout = sys.stderr - print(msg) - print('usage: findlinksto pattern directory ...') - sys.exit(2) - pat, dirs = args[0], args[1:] - prog = re.compile(pat) - for dirname in dirs: - os.walk(dirname, visit, prog) - -def visit(prog, dirname, names): - if os.path.islink(dirname): - names[:] = [] - return - if os.path.ismount(dirname): - print('descend into', dirname) - for name in names: - name = os.path.join(dirname, name) - try: - linkto = os.readlink(name) - if prog.search(linkto) is not None: - print(name, '->', linkto) - except OSError: - pass - -if __name__ == '__main__': - main() diff --git a/Tools/scripts/findnocoding.py b/Tools/scripts/findnocoding.py deleted file mode 100755 index 6c16b1ce1518..000000000000 --- a/Tools/scripts/findnocoding.py +++ /dev/null @@ -1,107 +0,0 @@ -#!/usr/bin/env python3 - -"""List all those Python files that require a coding directive - -Usage: findnocoding.py dir1 [dir2...] -""" - -__author__ = "Oleg Broytmann, Georg Brandl" - -import sys, os, re, getopt - -# our pysource module finds Python source files -try: - import pysource -except ImportError: - # emulate the module with a simple os.walk - class pysource: - has_python_ext = looks_like_python = can_be_compiled = None - def walk_python_files(self, paths, *args, **kwargs): - for path in paths: - if os.path.isfile(path): - yield path.endswith(".py") - elif os.path.isdir(path): - for root, dirs, files in os.walk(path): - for filename in files: - if filename.endswith(".py"): - yield os.path.join(root, filename) - pysource = pysource() - - - print("The pysource module is not available; " - "no sophisticated Python source file search will be done.", file=sys.stderr) - - -decl_re = re.compile(rb'^[ \t\f]*#.*?coding[:=][ \t]*([-\w.]+)') -blank_re = re.compile(rb'^[ \t\f]*(?:[#\r\n]|$)') - -def get_declaration(line): - match = decl_re.match(line) - if match: - return match.group(1) - return b'' - -def has_correct_encoding(text, codec): - try: - str(text, codec) - except UnicodeDecodeError: - return False - else: - return True - -def needs_declaration(fullpath): - try: - infile = open(fullpath, 'rb') - except IOError: # Oops, the file was removed - ignore it - return None - - with infile: - line1 = infile.readline() - line2 = infile.readline() - - if (get_declaration(line1) or - blank_re.match(line1) and get_declaration(line2)): - # the file does have an encoding declaration, so trust it - return False - - # check the whole file for non utf-8 characters - rest = infile.read() - - if has_correct_encoding(line1+line2+rest, "utf-8"): - return False - - return True - - -usage = """Usage: %s [-cd] paths... - -c: recognize Python source files trying to compile them - -d: debug output""" % sys.argv[0] - -if __name__ == '__main__': - - try: - opts, args = getopt.getopt(sys.argv[1:], 'cd') - except getopt.error as msg: - print(msg, file=sys.stderr) - print(usage, file=sys.stderr) - sys.exit(1) - - is_python = pysource.looks_like_python - debug = False - - for o, a in opts: - if o == '-c': - is_python = pysource.can_be_compiled - elif o == '-d': - debug = True - - if not args: - print(usage, file=sys.stderr) - sys.exit(1) - - for fullpath in pysource.walk_python_files(args, is_python): - if debug: - print("Testing for coding: %s" % fullpath) - result = needs_declaration(fullpath) - if result: - print(fullpath) diff --git a/Tools/scripts/fixcid.py b/Tools/scripts/fixcid.py deleted file mode 100755 index 8f35eaeeb4f6..000000000000 --- a/Tools/scripts/fixcid.py +++ /dev/null @@ -1,316 +0,0 @@ -#! /usr/bin/env python3 - -# Perform massive identifier substitution on C source files. -# This actually tokenizes the files (to some extent) so it can -# avoid making substitutions inside strings or comments. -# Inside strings, substitutions are never made; inside comments, -# it is a user option (off by default). -# -# The substitutions are read from one or more files whose lines, -# when not empty, after stripping comments starting with #, -# must contain exactly two words separated by whitespace: the -# old identifier and its replacement. -# -# The option -r reverses the sense of the substitutions (this may be -# useful to undo a particular substitution). -# -# If the old identifier is prefixed with a '*' (with no intervening -# whitespace), then it will not be substituted inside comments. -# -# Command line arguments are files or directories to be processed. -# Directories are searched recursively for files whose name looks -# like a C file (ends in .h or .c). The special filename '-' means -# operate in filter mode: read stdin, write stdout. -# -# Symbolic links are always ignored (except as explicit directory -# arguments). -# -# The original files are kept as back-up with a "~" suffix. -# -# Changes made are reported to stdout in a diff-like format. -# -# NB: by changing only the function fixline() you can turn this -# into a program for different changes to C source files; by -# changing the function wanted() you can make a different selection of -# files. - -import sys -import re -import os -from stat import * -import getopt - -err = sys.stderr.write -dbg = err -rep = sys.stdout.write - -def usage(): - progname = sys.argv[0] - err('Usage: ' + progname + - ' [-c] [-r] [-s file] ... file-or-directory ...\n') - err('\n') - err('-c : substitute inside comments\n') - err('-r : reverse direction for following -s options\n') - err('-s substfile : add a file of substitutions\n') - err('\n') - err('Each non-empty non-comment line in a substitution file must\n') - err('contain exactly two words: an identifier and its replacement.\n') - err('Comments start with a # character and end at end of line.\n') - err('If an identifier is preceded with a *, it is not substituted\n') - err('inside a comment even when -c is specified.\n') - -def main(): - try: - opts, args = getopt.getopt(sys.argv[1:], 'crs:') - except getopt.error as msg: - err('Options error: ' + str(msg) + '\n') - usage() - sys.exit(2) - bad = 0 - if not args: # No arguments - usage() - sys.exit(2) - for opt, arg in opts: - if opt == '-c': - setdocomments() - if opt == '-r': - setreverse() - if opt == '-s': - addsubst(arg) - for arg in args: - if os.path.isdir(arg): - if recursedown(arg): bad = 1 - elif os.path.islink(arg): - err(arg + ': will not process symbolic links\n') - bad = 1 - else: - if fix(arg): bad = 1 - sys.exit(bad) - -# Change this regular expression to select a different set of files -Wanted = r'^[a-zA-Z0-9_]+\.[ch]$' -def wanted(name): - return re.match(Wanted, name) - -def recursedown(dirname): - dbg('recursedown(%r)\n' % (dirname,)) - bad = 0 - try: - names = os.listdir(dirname) - except OSError as msg: - err(dirname + ': cannot list directory: ' + str(msg) + '\n') - return 1 - names.sort() - subdirs = [] - for name in names: - if name in (os.curdir, os.pardir): continue - fullname = os.path.join(dirname, name) - if os.path.islink(fullname): pass - elif os.path.isdir(fullname): - subdirs.append(fullname) - elif wanted(name): - if fix(fullname): bad = 1 - for fullname in subdirs: - if recursedown(fullname): bad = 1 - return bad - -def fix(filename): -## dbg('fix(%r)\n' % (filename,)) - if filename == '-': - # Filter mode - f = sys.stdin - g = sys.stdout - else: - # File replacement mode - try: - f = open(filename, 'r') - except IOError as msg: - err(filename + ': cannot open: ' + str(msg) + '\n') - return 1 - head, tail = os.path.split(filename) - tempname = os.path.join(head, '@' + tail) - g = None - # If we find a match, we rewind the file and start over but - # now copy everything to a temp file. - lineno = 0 - initfixline() - while 1: - line = f.readline() - if not line: break - lineno = lineno + 1 - while line[-2:] == '\\\n': - nextline = f.readline() - if not nextline: break - line = line + nextline - lineno = lineno + 1 - newline = fixline(line) - if newline != line: - if g is None: - try: - g = open(tempname, 'w') - except IOError as msg: - f.close() - err(tempname+': cannot create: '+ - str(msg)+'\n') - return 1 - f.seek(0) - lineno = 0 - initfixline() - rep(filename + ':\n') - continue # restart from the beginning - rep(repr(lineno) + '\n') - rep('< ' + line) - rep('> ' + newline) - if g is not None: - g.write(newline) - - # End of file - if filename == '-': return 0 # Done in filter mode - f.close() - if not g: return 0 # No changes - g.close() - - # Finishing touch -- move files - - # First copy the file's mode to the temp file - try: - statbuf = os.stat(filename) - os.chmod(tempname, statbuf[ST_MODE] & 0o7777) - except OSError as msg: - err(tempname + ': warning: chmod failed (' + str(msg) + ')\n') - # Then make a backup of the original file as filename~ - try: - os.rename(filename, filename + '~') - except OSError as msg: - err(filename + ': warning: backup failed (' + str(msg) + ')\n') - # Now move the temp file to the original file - try: - os.rename(tempname, filename) - except OSError as msg: - err(filename + ': rename failed (' + str(msg) + ')\n') - return 1 - # Return success - return 0 - -# Tokenizing ANSI C (partly) - -Identifier = '(struct )?[a-zA-Z_][a-zA-Z0-9_]+' -String = r'"([^\n\\"]|\\.)*"' -Char = r"'([^\n\\']|\\.)*'" -CommentStart = r'/\*' -CommentEnd = r'\*/' - -Hexnumber = '0[xX][0-9a-fA-F]*[uUlL]*' -Octnumber = '0[0-7]*[uUlL]*' -Decnumber = '[1-9][0-9]*[uUlL]*' -Intnumber = Hexnumber + '|' + Octnumber + '|' + Decnumber -Exponent = '[eE][-+]?[0-9]+' -Pointfloat = r'([0-9]+\.[0-9]*|\.[0-9]+)(' + Exponent + r')?' -Expfloat = '[0-9]+' + Exponent -Floatnumber = Pointfloat + '|' + Expfloat -Number = Floatnumber + '|' + Intnumber - -# Anything else is an operator -- don't list this explicitly because of '/*' - -OutsideComment = (Identifier, Number, String, Char, CommentStart) -OutsideCommentPattern = '(' + '|'.join(OutsideComment) + ')' -OutsideCommentProgram = re.compile(OutsideCommentPattern) - -InsideComment = (Identifier, Number, CommentEnd) -InsideCommentPattern = '(' + '|'.join(InsideComment) + ')' -InsideCommentProgram = re.compile(InsideCommentPattern) - -def initfixline(): - global Program - Program = OutsideCommentProgram - -def fixline(line): - global Program -## print('-->', repr(line)) - i = 0 - while i < len(line): - match = Program.search(line, i) - if match is None: break - i = match.start() - found = match.group(0) -## if Program is InsideCommentProgram: print(end='... ') -## else: print(end=' ') -## print(found) - if len(found) == 2: - if found == '/*': - Program = InsideCommentProgram - elif found == '*/': - Program = OutsideCommentProgram - n = len(found) - if found in Dict: - subst = Dict[found] - if Program is InsideCommentProgram: - if not Docomments: - print('Found in comment:', found) - i = i + n - continue - if found in NotInComment: -## print(end='Ignored in comment: ') -## print(found, '-->', subst) -## print('Line:', line, end='') - subst = found -## else: -## print(end='Substituting in comment: ') -## print(found, '-->', subst) -## print('Line:', line, end='') - line = line[:i] + subst + line[i+n:] - n = len(subst) - i = i + n - return line - -Docomments = 0 -def setdocomments(): - global Docomments - Docomments = 1 - -Reverse = 0 -def setreverse(): - global Reverse - Reverse = (not Reverse) - -Dict = {} -NotInComment = {} -def addsubst(substfile): - try: - fp = open(substfile, 'r') - except IOError as msg: - err(substfile + ': cannot read substfile: ' + str(msg) + '\n') - sys.exit(1) - with fp: - lineno = 0 - while 1: - line = fp.readline() - if not line: break - lineno = lineno + 1 - try: - i = line.index('#') - except ValueError: - i = -1 # Happens to delete trailing \n - words = line[:i].split() - if not words: continue - if len(words) == 3 and words[0] == 'struct': - words[:2] = [words[0] + ' ' + words[1]] - elif len(words) != 2: - err(substfile + '%s:%r: warning: bad line: %r' % (substfile, lineno, line)) - continue - if Reverse: - [value, key] = words - else: - [key, value] = words - if value[0] == '*': - value = value[1:] - if key[0] == '*': - key = key[1:] - NotInComment[key] = value - if key in Dict: - err('%s:%r: warning: overriding: %r %r\n' % (substfile, lineno, key, value)) - err('%s:%r: warning: previous: %r\n' % (substfile, lineno, Dict[key])) - Dict[key] = value - -if __name__ == '__main__': - main() diff --git a/Tools/scripts/fixdiv.py b/Tools/scripts/fixdiv.py deleted file mode 100755 index df7c481aa228..000000000000 --- a/Tools/scripts/fixdiv.py +++ /dev/null @@ -1,378 +0,0 @@ -#! /usr/bin/env python3 - -"""fixdiv - tool to fix division operators. - -To use this tool, first run `python -Qwarnall yourscript.py 2>warnings'. -This runs the script `yourscript.py' while writing warning messages -about all uses of the classic division operator to the file -`warnings'. The warnings look like this: - - :: DeprecationWarning: classic division - -The warnings are written to stderr, so you must use `2>' for the I/O -redirect. I know of no way to redirect stderr on Windows in a DOS -box, so you will have to modify the script to set sys.stderr to some -kind of log file if you want to do this on Windows. - -The warnings are not limited to the script; modules imported by the -script may also trigger warnings. In fact a useful technique is to -write a test script specifically intended to exercise all code in a -particular module or set of modules. - -Then run `python fixdiv.py warnings'. This first reads the warnings, -looking for classic division warnings, and sorts them by file name and -line number. Then, for each file that received at least one warning, -it parses the file and tries to match the warnings up to the division -operators found in the source code. If it is successful, it writes -its findings to stdout, preceded by a line of dashes and a line of the -form: - - Index: - -If the only findings found are suggestions to change a / operator into -a // operator, the output is acceptable input for the Unix 'patch' -program. - -Here are the possible messages on stdout (N stands for a line number): - -- A plain-diff-style change ('NcN', a line marked by '<', a line - containing '---', and a line marked by '>'): - - A / operator was found that should be changed to //. This is the - recommendation when only int and/or long arguments were seen. - -- 'True division / operator at line N' and a line marked by '=': - - A / operator was found that can remain unchanged. This is the - recommendation when only float and/or complex arguments were seen. - -- 'Ambiguous / operator (..., ...) at line N', line marked by '?': - - A / operator was found for which int or long as well as float or - complex arguments were seen. This is highly unlikely; if it occurs, - you may have to restructure the code to keep the classic semantics, - or maybe you don't care about the classic semantics. - -- 'No conclusive evidence on line N', line marked by '*': - - A / operator was found for which no warnings were seen. This could - be code that was never executed, or code that was only executed - with user-defined objects as arguments. You will have to - investigate further. Note that // can be overloaded separately from - /, using __floordiv__. True division can also be separately - overloaded, using __truediv__. Classic division should be the same - as either of those. (XXX should I add a warning for division on - user-defined objects, to disambiguate this case from code that was - never executed?) - -- 'Phantom ... warnings for line N', line marked by '*': - - A warning was seen for a line not containing a / operator. The most - likely cause is a warning about code executed by 'exec' or eval() - (see note below), or an indirect invocation of the / operator, for - example via the div() function in the operator module. It could - also be caused by a change to the file between the time the test - script was run to collect warnings and the time fixdiv was run. - -- 'More than one / operator in line N'; or - 'More than one / operator per statement in lines N-N': - - The scanner found more than one / operator on a single line, or in a - statement split across multiple lines. Because the warnings - framework doesn't (and can't) show the offset within the line, and - the code generator doesn't always give the correct line number for - operations in a multi-line statement, we can't be sure whether all - operators in the statement were executed. To be on the safe side, - by default a warning is issued about this case. In practice, these - cases are usually safe, and the -m option suppresses these warning. - -- 'Can't find the / operator in line N', line marked by '*': - - This really shouldn't happen. It means that the tokenize module - reported a '/' operator but the line it returns didn't contain a '/' - character at the indicated position. - -- 'Bad warning for line N: XYZ', line marked by '*': - - This really shouldn't happen. It means that a 'classic XYZ - division' warning was read with XYZ being something other than - 'int', 'long', 'float', or 'complex'. - -Notes: - -- The augmented assignment operator /= is handled the same way as the - / operator. - -- This tool never looks at the // operator; no warnings are ever - generated for use of this operator. - -- This tool never looks at the / operator when a future division - statement is in effect; no warnings are generated in this case, and - because the tool only looks at files for which at least one classic - division warning was seen, it will never look at files containing a - future division statement. - -- Warnings may be issued for code not read from a file, but executed - using the exec() or eval() functions. These may have - in the filename position, in which case the fixdiv script - will attempt and fail to open a file named '' and issue a - warning about this failure; or these may be reported as 'Phantom' - warnings (see above). You're on your own to deal with these. You - could make all recommended changes and add a future division - statement to all affected files, and then re-run the test script; it - should not issue any warnings. If there are any, and you have a - hard time tracking down where they are generated, you can use the - -Werror option to force an error instead of a first warning, - generating a traceback. - -- The tool should be run from the same directory as that from which - the original script was run, otherwise it won't be able to open - files given by relative pathnames. -""" - -import sys -import getopt -import re -import tokenize - -multi_ok = 0 - -def main(): - try: - opts, args = getopt.getopt(sys.argv[1:], "hm") - except getopt.error as msg: - usage(msg) - return 2 - for o, a in opts: - if o == "-h": - print(__doc__) - return - if o == "-m": - global multi_ok - multi_ok = 1 - if not args: - usage("at least one file argument is required") - return 2 - if args[1:]: - sys.stderr.write("%s: extra file arguments ignored\n", sys.argv[0]) - warnings = readwarnings(args[0]) - if warnings is None: - return 1 - files = list(warnings.keys()) - if not files: - print("No classic division warnings read from", args[0]) - return - files.sort() - exit = None - for filename in files: - x = process(filename, warnings[filename]) - exit = exit or x - return exit - -def usage(msg): - sys.stderr.write("%s: %s\n" % (sys.argv[0], msg)) - sys.stderr.write("Usage: %s [-m] warnings\n" % sys.argv[0]) - sys.stderr.write("Try `%s -h' for more information.\n" % sys.argv[0]) - -PATTERN = (r"^(.+?):(\d+): DeprecationWarning: " - r"classic (int|long|float|complex) division$") - -def readwarnings(warningsfile): - prog = re.compile(PATTERN) - warnings = {} - try: - f = open(warningsfile) - except IOError as msg: - sys.stderr.write("can't open: %s\n" % msg) - return - with f: - while 1: - line = f.readline() - if not line: - break - m = prog.match(line) - if not m: - if line.find("division") >= 0: - sys.stderr.write("Warning: ignored input " + line) - continue - filename, lineno, what = m.groups() - list = warnings.get(filename) - if list is None: - warnings[filename] = list = [] - list.append((int(lineno), sys.intern(what))) - return warnings - -def process(filename, list): - print("-"*70) - assert list # if this fails, readwarnings() is broken - try: - fp = open(filename) - except IOError as msg: - sys.stderr.write("can't open: %s\n" % msg) - return 1 - with fp: - print("Index:", filename) - f = FileContext(fp) - list.sort() - index = 0 # list[:index] has been processed, list[index:] is still to do - g = tokenize.generate_tokens(f.readline) - while 1: - startlineno, endlineno, slashes = lineinfo = scanline(g) - if startlineno is None: - break - assert startlineno <= endlineno is not None - orphans = [] - while index < len(list) and list[index][0] < startlineno: - orphans.append(list[index]) - index += 1 - if orphans: - reportphantomwarnings(orphans, f) - warnings = [] - while index < len(list) and list[index][0] <= endlineno: - warnings.append(list[index]) - index += 1 - if not slashes and not warnings: - pass - elif slashes and not warnings: - report(slashes, "No conclusive evidence") - elif warnings and not slashes: - reportphantomwarnings(warnings, f) - else: - if len(slashes) > 1: - if not multi_ok: - rows = [] - lastrow = None - for (row, col), line in slashes: - if row == lastrow: - continue - rows.append(row) - lastrow = row - assert rows - if len(rows) == 1: - print("*** More than one / operator in line", rows[0]) - else: - print("*** More than one / operator per statement", end=' ') - print("in lines %d-%d" % (rows[0], rows[-1])) - intlong = [] - floatcomplex = [] - bad = [] - for lineno, what in warnings: - if what in ("int", "long"): - intlong.append(what) - elif what in ("float", "complex"): - floatcomplex.append(what) - else: - bad.append(what) - lastrow = None - for (row, col), line in slashes: - if row == lastrow: - continue - lastrow = row - line = chop(line) - if line[col:col+1] != "/": - print("*** Can't find the / operator in line %d:" % row) - print("*", line) - continue - if bad: - print("*** Bad warning for line %d:" % row, bad) - print("*", line) - elif intlong and not floatcomplex: - print("%dc%d" % (row, row)) - print("<", line) - print("---") - print(">", line[:col] + "/" + line[col:]) - elif floatcomplex and not intlong: - print("True division / operator at line %d:" % row) - print("=", line) - elif intlong and floatcomplex: - print("*** Ambiguous / operator (%s, %s) at line %d:" % - ("|".join(intlong), "|".join(floatcomplex), row)) - print("?", line) - -def reportphantomwarnings(warnings, f): - blocks = [] - lastrow = None - lastblock = None - for row, what in warnings: - if row != lastrow: - lastblock = [row] - blocks.append(lastblock) - lastblock.append(what) - for block in blocks: - row = block[0] - whats = "/".join(block[1:]) - print("*** Phantom %s warnings for line %d:" % (whats, row)) - f.report(row, mark="*") - -def report(slashes, message): - lastrow = None - for (row, col), line in slashes: - if row != lastrow: - print("*** %s on line %d:" % (message, row)) - print("*", chop(line)) - lastrow = row - -class FileContext: - def __init__(self, fp, window=5, lineno=1): - self.fp = fp - self.window = 5 - self.lineno = 1 - self.eoflookahead = 0 - self.lookahead = [] - self.buffer = [] - def fill(self): - while len(self.lookahead) < self.window and not self.eoflookahead: - line = self.fp.readline() - if not line: - self.eoflookahead = 1 - break - self.lookahead.append(line) - def readline(self): - self.fill() - if not self.lookahead: - return "" - line = self.lookahead.pop(0) - self.buffer.append(line) - self.lineno += 1 - return line - def __getitem__(self, index): - self.fill() - bufstart = self.lineno - len(self.buffer) - lookend = self.lineno + len(self.lookahead) - if bufstart <= index < self.lineno: - return self.buffer[index - bufstart] - if self.lineno <= index < lookend: - return self.lookahead[index - self.lineno] - raise KeyError - def report(self, first, last=None, mark="*"): - if last is None: - last = first - for i in range(first, last+1): - try: - line = self[first] - except KeyError: - line = "" - print(mark, chop(line)) - -def scanline(g): - slashes = [] - startlineno = None - endlineno = None - for type, token, start, end, line in g: - endlineno = end[0] - if startlineno is None: - startlineno = endlineno - if token in ("/", "/="): - slashes.append((start, line)) - if type == tokenize.NEWLINE: - break - return startlineno, endlineno, slashes - -def chop(line): - if line.endswith("\n"): - return line[:-1] - else: - return line - -if __name__ == "__main__": - sys.exit(main()) diff --git a/Tools/scripts/fixheader.py b/Tools/scripts/fixheader.py deleted file mode 100755 index c834eec1e20e..000000000000 --- a/Tools/scripts/fixheader.py +++ /dev/null @@ -1,49 +0,0 @@ -#! /usr/bin/env python3 - -# Add some standard cpp magic to a header file - -import sys - -def main(): - args = sys.argv[1:] - for filename in args: - process(filename) - -def process(filename): - try: - f = open(filename, 'r') - except IOError as msg: - sys.stderr.write('%s: can\'t open: %s\n' % (filename, str(msg))) - return - with f: - data = f.read() - if data[:2] != '/*': - sys.stderr.write('%s does not begin with C comment\n' % filename) - return - try: - f = open(filename, 'w') - except IOError as msg: - sys.stderr.write('%s: can\'t write: %s\n' % (filename, str(msg))) - return - with f: - sys.stderr.write('Processing %s ...\n' % filename) - magic = 'Py_' - for c in filename: - if ord(c)<=0x80 and c.isalnum(): - magic = magic + c.upper() - else: magic = magic + '_' - print('#ifndef', magic, file=f) - print('#define', magic, file=f) - print('#ifdef __cplusplus', file=f) - print('extern "C" {', file=f) - print('#endif', file=f) - print(file=f) - f.write(data) - print(file=f) - print('#ifdef __cplusplus', file=f) - print('}', file=f) - print('#endif', file=f) - print('#endif /*', '!'+magic, '*/', file=f) - -if __name__ == '__main__': - main() diff --git a/Tools/scripts/fixnotice.py b/Tools/scripts/fixnotice.py deleted file mode 100755 index 317051dd82f3..000000000000 --- a/Tools/scripts/fixnotice.py +++ /dev/null @@ -1,109 +0,0 @@ -#! /usr/bin/env python3 - -"""(Ostensibly) fix copyright notices in files. - -Actually, this script will simply replace a block of text in a file from one -string to another. It will only do this once though, i.e. not globally -throughout the file. It writes a backup file and then does an os.rename() -dance for atomicity. - -Usage: fixnotices.py [options] [filenames] -Options: - -h / --help - Print this message and exit - - --oldnotice=file - Use the notice in the file as the old (to be replaced) string, instead - of the hard coded value in the script. - - --newnotice=file - Use the notice in the file as the new (replacement) string, instead of - the hard coded value in the script. - - --dry-run - Don't actually make the changes, but print out the list of files that - would change. When used with -v, a status will be printed for every - file. - - -v / --verbose - Print a message for every file looked at, indicating whether the file - is changed or not. -""" - -OLD_NOTICE = """/*********************************************************** -Copyright (c) 2000, BeOpen.com. -Copyright (c) 1995-2000, Corporation for National Research Initiatives. -Copyright (c) 1990-1995, Stichting Mathematisch Centrum. -All rights reserved. - -See the file "Misc/COPYRIGHT" for information on usage and -redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES. -******************************************************************/ -""" -import os -import sys -import getopt - -NEW_NOTICE = "" -DRYRUN = 0 -VERBOSE = 0 - - -def usage(code, msg=''): - print(__doc__ % globals()) - if msg: - print(msg) - sys.exit(code) - - -def main(): - global DRYRUN, OLD_NOTICE, NEW_NOTICE, VERBOSE - try: - opts, args = getopt.getopt(sys.argv[1:], 'hv', - ['help', 'oldnotice=', 'newnotice=', - 'dry-run', 'verbose']) - except getopt.error as msg: - usage(1, msg) - - for opt, arg in opts: - if opt in ('-h', '--help'): - usage(0) - elif opt in ('-v', '--verbose'): - VERBOSE = 1 - elif opt == '--dry-run': - DRYRUN = 1 - elif opt == '--oldnotice': - with open(arg) as fp: - OLD_NOTICE = fp.read() - elif opt == '--newnotice': - with open(arg) as fp: - NEW_NOTICE = fp.read() - - for arg in args: - process(arg) - - -def process(file): - with open(file) as f: - data = f.read() - i = data.find(OLD_NOTICE) - if i < 0: - if VERBOSE: - print('no change:', file) - return - elif DRYRUN or VERBOSE: - print(' change:', file) - if DRYRUN: - # Don't actually change the file - return - data = data[:i] + NEW_NOTICE + data[i+len(OLD_NOTICE):] - new = file + ".new" - backup = file + ".bak" - with open(new, "w") as f: - f.write(data) - os.rename(file, backup) - os.rename(new, file) - - -if __name__ == '__main__': - main() diff --git a/Tools/scripts/fixps.py b/Tools/scripts/fixps.py deleted file mode 100755 index 725300e56a27..000000000000 --- a/Tools/scripts/fixps.py +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env python3 - -# Fix Python script(s) to reference the interpreter via /usr/bin/env python. -# Warning: this overwrites the file without making a backup. - -import sys -import re - - -def main(): - for filename in sys.argv[1:]: - try: - f = open(filename, 'r') - except IOError as msg: - print(filename, ': can\'t open :', msg) - continue - with f: - line = f.readline() - if not re.match('^#! */usr/local/bin/python', line): - print(filename, ': not a /usr/local/bin/python script') - continue - rest = f.read() - line = re.sub('/usr/local/bin/python', - '/usr/bin/env python', line) - print(filename, ':', repr(line)) - with open(filename, "w") as f: - f.write(line) - f.write(rest) - -if __name__ == '__main__': - main() diff --git a/Tools/scripts/get-remote-certificate.py b/Tools/scripts/get-remote-certificate.py deleted file mode 100755 index 68272fca83fe..000000000000 --- a/Tools/scripts/get-remote-certificate.py +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env python3 -# -# fetch the certificate that the server(s) are providing in PEM form -# -# args are HOST:PORT [, HOST:PORT...] -# -# By Bill Janssen. - -import re -import os -import sys -import tempfile - - -def fetch_server_certificate (host, port): - - def subproc(cmd): - from subprocess import Popen, PIPE, STDOUT, DEVNULL - proc = Popen(cmd, stdout=PIPE, stderr=STDOUT, stdin=DEVNULL) - status = proc.wait() - output = proc.stdout.read() - return status, output - - def strip_to_x509_cert(certfile_contents, outfile=None): - m = re.search(br"^([-]+BEGIN CERTIFICATE[-]+[\r]*\n" - br".*[\r]*^[-]+END CERTIFICATE[-]+)$", - certfile_contents, re.MULTILINE | re.DOTALL) - if not m: - return None - else: - tn = tempfile.mktemp() - with open(tn, "wb") as fp: - fp.write(m.group(1) + b"\n") - try: - tn2 = (outfile or tempfile.mktemp()) - cmd = ['openssl', 'x509', '-in', tn, '-out', tn2] - status, output = subproc(cmd) - if status != 0: - raise RuntimeError('OpenSSL x509 failed with status %s and ' - 'output: %r' % (status, output)) - with open(tn2, 'rb') as fp: - data = fp.read() - os.unlink(tn2) - return data - finally: - os.unlink(tn) - - cmd = ['openssl', 's_client', '-connect', '%s:%s' % (host, port), '-showcerts'] - status, output = subproc(cmd) - - if status != 0: - raise RuntimeError('OpenSSL connect failed with status %s and ' - 'output: %r' % (status, output)) - certtext = strip_to_x509_cert(output) - if not certtext: - raise ValueError("Invalid response received from server at %s:%s" % - (host, port)) - return certtext - - -if __name__ == "__main__": - if len(sys.argv) < 2: - sys.stderr.write( - "Usage: %s HOSTNAME:PORTNUMBER [, HOSTNAME:PORTNUMBER...]\n" % - sys.argv[0]) - sys.exit(1) - for arg in sys.argv[1:]: - host, port = arg.split(":") - sys.stdout.buffer.write(fetch_server_certificate(host, int(port))) - sys.exit(0) diff --git a/Tools/scripts/google.py b/Tools/scripts/google.py deleted file mode 100755 index 82fb2871885d..000000000000 --- a/Tools/scripts/google.py +++ /dev/null @@ -1,25 +0,0 @@ -#! /usr/bin/env python3 - -"""Script to search with Google - -Usage: - python3 google.py [search terms] -""" - -import sys -import urllib.parse -import webbrowser - - -def main(args): - def quote(arg): - if ' ' in arg: - arg = '"%s"' % arg - return urllib.parse.quote_plus(arg) - - qstring = '+'.join(quote(arg) for arg in args) - url = urllib.parse.urljoin('https://www.google.com/search', '?q=' + qstring) - webbrowser.open(url) - -if __name__ == '__main__': - main(sys.argv[1:]) diff --git a/Tools/scripts/highlight.py b/Tools/scripts/highlight.py deleted file mode 100755 index 9272fee4ee3b..000000000000 --- a/Tools/scripts/highlight.py +++ /dev/null @@ -1,265 +0,0 @@ -#!/usr/bin/env python3 -'''Add syntax highlighting to Python source code''' - -__author__ = 'Raymond Hettinger' - -import builtins -import functools -import html as html_module -import keyword -import re -import tokenize - -#### Analyze Python Source ################################# - -def is_builtin(s): - 'Return True if s is the name of a builtin' - return hasattr(builtins, s) - -def combine_range(lines, start, end): - 'Join content from a range of lines between start and end' - (srow, scol), (erow, ecol) = start, end - if srow == erow: - return lines[srow-1][scol:ecol], end - rows = [lines[srow-1][scol:]] + lines[srow: erow-1] + [lines[erow-1][:ecol]] - return ''.join(rows), end - -def analyze_python(source): - '''Generate and classify chunks of Python for syntax highlighting. - Yields tuples in the form: (category, categorized_text). - ''' - lines = source.splitlines(True) - lines.append('') - readline = functools.partial(next, iter(lines), '') - kind = tok_str = '' - tok_type = tokenize.COMMENT - written = (1, 0) - for tok in tokenize.generate_tokens(readline): - prev_tok_type, prev_tok_str = tok_type, tok_str - tok_type, tok_str, (srow, scol), (erow, ecol), logical_lineno = tok - kind = '' - if tok_type == tokenize.COMMENT: - kind = 'comment' - elif tok_type == tokenize.OP and tok_str[:1] not in '{}[](),.:;@': - kind = 'operator' - elif tok_type == tokenize.STRING: - kind = 'string' - if prev_tok_type == tokenize.INDENT or scol==0: - kind = 'docstring' - elif tok_type == tokenize.NAME: - if tok_str in ('def', 'class', 'import', 'from'): - kind = 'definition' - elif prev_tok_str in ('def', 'class'): - kind = 'defname' - elif keyword.iskeyword(tok_str): - kind = 'keyword' - elif is_builtin(tok_str) and prev_tok_str != '.': - kind = 'builtin' - if kind: - text, written = combine_range(lines, written, (srow, scol)) - yield '', text - text, written = tok_str, (erow, ecol) - yield kind, text - line_upto_token, written = combine_range(lines, written, (erow, ecol)) - yield '', line_upto_token - -#### Raw Output ########################################### - -def raw_highlight(classified_text): - 'Straight text display of text classifications' - result = [] - for kind, text in classified_text: - result.append('%15s: %r\n' % (kind or 'plain', text)) - return ''.join(result) - -#### ANSI Output ########################################### - -default_ansi = { - 'comment': ('\033[0;31m', '\033[0m'), - 'string': ('\033[0;32m', '\033[0m'), - 'docstring': ('\033[0;32m', '\033[0m'), - 'keyword': ('\033[0;33m', '\033[0m'), - 'builtin': ('\033[0;35m', '\033[0m'), - 'definition': ('\033[0;33m', '\033[0m'), - 'defname': ('\033[0;34m', '\033[0m'), - 'operator': ('\033[0;33m', '\033[0m'), -} - -def ansi_highlight(classified_text, colors=default_ansi): - 'Add syntax highlighting to source code using ANSI escape sequences' - # http://en.wikipedia.org/wiki/ANSI_escape_code - result = [] - for kind, text in classified_text: - opener, closer = colors.get(kind, ('', '')) - result += [opener, text, closer] - return ''.join(result) - -#### HTML Output ########################################### - -def html_highlight(classified_text,opener='
\n', closer='
\n'): - 'Convert classified text to an HTML fragment' - result = [opener] - for kind, text in classified_text: - if kind: - result.append('' % kind) - result.append(html_module.escape(text)) - if kind: - result.append('') - result.append(closer) - return ''.join(result) - -default_css = { - '.comment': '{color: crimson;}', - '.string': '{color: forestgreen;}', - '.docstring': '{color: forestgreen; font-style:italic;}', - '.keyword': '{color: darkorange;}', - '.builtin': '{color: purple;}', - '.definition': '{color: darkorange; font-weight:bold;}', - '.defname': '{color: blue;}', - '.operator': '{color: brown;}', -} - -default_html = '''\ - - - - - {title} - - - -{body} - - -''' - -def build_html_page(classified_text, title='python', - css=default_css, html=default_html): - 'Create a complete HTML page with colorized source code' - css_str = '\n'.join(['%s %s' % item for item in css.items()]) - result = html_highlight(classified_text) - title = html_module.escape(title) - return html.format(title=title, css=css_str, body=result) - -#### LaTeX Output ########################################## - -default_latex_commands = { - 'comment': r'{\color{red}#1}', - 'string': r'{\color{ForestGreen}#1}', - 'docstring': r'{\emph{\color{ForestGreen}#1}}', - 'keyword': r'{\color{orange}#1}', - 'builtin': r'{\color{purple}#1}', - 'definition': r'{\color{orange}#1}', - 'defname': r'{\color{blue}#1}', - 'operator': r'{\color{brown}#1}', -} - -default_latex_document = r''' -\documentclass{article} -\usepackage{alltt} -\usepackage{upquote} -\usepackage{color} -\usepackage[usenames,dvipsnames]{xcolor} -\usepackage[cm]{fullpage} -%(macros)s -\begin{document} -\center{\LARGE{%(title)s}} -\begin{alltt} -%(body)s -\end{alltt} -\end{document} -''' - -def alltt_escape(s): - 'Replace backslash and braces with their escaped equivalents' - xlat = {'{': r'\{', '}': r'\}', '\\': r'\textbackslash{}'} - return re.sub(r'[\\{}]', lambda mo: xlat[mo.group()], s) - -def latex_highlight(classified_text, title = 'python', - commands = default_latex_commands, - document = default_latex_document): - 'Create a complete LaTeX document with colorized source code' - macros = '\n'.join(r'\newcommand{\py%s}[1]{%s}' % c for c in commands.items()) - result = [] - for kind, text in classified_text: - if kind: - result.append(r'\py%s{' % kind) - result.append(alltt_escape(text)) - if kind: - result.append('}') - return default_latex_document % dict(title=title, macros=macros, body=''.join(result)) - - -if __name__ == '__main__': - import argparse - import os.path - import sys - import textwrap - import webbrowser - - parser = argparse.ArgumentParser( - description = 'Add syntax highlighting to Python source code', - formatter_class=argparse.RawDescriptionHelpFormatter, - epilog = textwrap.dedent(''' - examples: - - # Show syntax highlighted code in the terminal window - $ ./highlight.py myfile.py - - # Colorize myfile.py and display in a browser - $ ./highlight.py -b myfile.py - - # Create an HTML section to embed in an existing webpage - ./highlight.py -s myfile.py - - # Create a complete HTML file - $ ./highlight.py -c myfile.py > myfile.html - - # Create a PDF using LaTeX - $ ./highlight.py -l myfile.py | pdflatex - - ''')) - parser.add_argument('sourcefile', metavar = 'SOURCEFILE', - help = 'file containing Python sourcecode') - parser.add_argument('-b', '--browser', action = 'store_true', - help = 'launch a browser to show results') - parser.add_argument('-c', '--complete', action = 'store_true', - help = 'build a complete html webpage') - parser.add_argument('-l', '--latex', action = 'store_true', - help = 'build a LaTeX document') - parser.add_argument('-r', '--raw', action = 'store_true', - help = 'raw parse of categorized text') - parser.add_argument('-s', '--section', action = 'store_true', - help = 'show an HTML section rather than a complete webpage') - args = parser.parse_args() - - if args.section and (args.browser or args.complete): - parser.error('The -s/--section option is incompatible with ' - 'the -b/--browser or -c/--complete options') - - sourcefile = args.sourcefile - with open(sourcefile) as f: - source = f.read() - classified_text = analyze_python(source) - - if args.raw: - encoded = raw_highlight(classified_text) - elif args.complete or args.browser: - encoded = build_html_page(classified_text, title=sourcefile) - elif args.section: - encoded = html_highlight(classified_text) - elif args.latex: - encoded = latex_highlight(classified_text, title=sourcefile) - else: - encoded = ansi_highlight(classified_text) - - if args.browser: - htmlfile = os.path.splitext(os.path.basename(sourcefile))[0] + '.html' - with open(htmlfile, 'w') as f: - f.write(encoded) - webbrowser.open('file://' + os.path.abspath(htmlfile)) - else: - sys.stdout.write(encoded) diff --git a/Tools/scripts/ifdef.py b/Tools/scripts/ifdef.py deleted file mode 100755 index 22249b2d0af5..000000000000 --- a/Tools/scripts/ifdef.py +++ /dev/null @@ -1,111 +0,0 @@ -#! /usr/bin/env python3 - -# Selectively preprocess #ifdef / #ifndef statements. -# Usage: -# ifdef [-Dname] ... [-Uname] ... [file] ... -# -# This scans the file(s), looking for #ifdef and #ifndef preprocessor -# commands that test for one of the names mentioned in the -D and -U -# options. On standard output it writes a copy of the input file(s) -# minus those code sections that are suppressed by the selected -# combination of defined/undefined symbols. The #if(n)def/#else/#else -# lines themselves (if the #if(n)def tests for one of the mentioned -# names) are removed as well. - -# Features: Arbitrary nesting of recognized and unrecognized -# preprocessor statements works correctly. Unrecognized #if* commands -# are left in place, so it will never remove too much, only too -# little. It does accept whitespace around the '#' character. - -# Restrictions: There should be no comments or other symbols on the -# #if(n)def lines. The effect of #define/#undef commands in the input -# file or in included files is not taken into account. Tests using -# #if and the defined() pseudo function are not recognized. The #elif -# command is not recognized. Improperly nesting is not detected. -# Lines that look like preprocessor commands but which are actually -# part of comments or string literals will be mistaken for -# preprocessor commands. - -import sys -import getopt - -defs = [] -undefs = [] - -def main(): - opts, args = getopt.getopt(sys.argv[1:], 'D:U:') - for o, a in opts: - if o == '-D': - defs.append(a) - if o == '-U': - undefs.append(a) - if not args: - args = ['-'] - for filename in args: - if filename == '-': - process(sys.stdin, sys.stdout) - else: - with open(filename) as f: - process(f, sys.stdout) - -def process(fpi, fpo): - keywords = ('if', 'ifdef', 'ifndef', 'else', 'endif') - ok = 1 - stack = [] - while 1: - line = fpi.readline() - if not line: break - while line[-2:] == '\\\n': - nextline = fpi.readline() - if not nextline: break - line = line + nextline - tmp = line.strip() - if tmp[:1] != '#': - if ok: fpo.write(line) - continue - tmp = tmp[1:].strip() - words = tmp.split() - keyword = words[0] - if keyword not in keywords: - if ok: fpo.write(line) - continue - if keyword in ('ifdef', 'ifndef') and len(words) == 2: - if keyword == 'ifdef': - ko = 1 - else: - ko = 0 - word = words[1] - if word in defs: - stack.append((ok, ko, word)) - if not ko: ok = 0 - elif word in undefs: - stack.append((ok, not ko, word)) - if ko: ok = 0 - else: - stack.append((ok, -1, word)) - if ok: fpo.write(line) - elif keyword == 'if': - stack.append((ok, -1, '')) - if ok: fpo.write(line) - elif keyword == 'else' and stack: - s_ok, s_ko, s_word = stack[-1] - if s_ko < 0: - if ok: fpo.write(line) - else: - s_ko = not s_ko - ok = s_ok - if not s_ko: ok = 0 - stack[-1] = s_ok, s_ko, s_word - elif keyword == 'endif' and stack: - s_ok, s_ko, s_word = stack[-1] - if s_ko < 0: - if ok: fpo.write(line) - del stack[-1] - ok = s_ok - else: - sys.stderr.write('Unknown keyword %s\n' % keyword) - if stack: - sys.stderr.write('stack: %s\n' % stack) - -if __name__ == '__main__': - main() diff --git a/Tools/scripts/import_diagnostics.py b/Tools/scripts/import_diagnostics.py deleted file mode 100755 index c907221d049c..000000000000 --- a/Tools/scripts/import_diagnostics.py +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env python3 -"""Miscellaneous diagnostics for the import system""" - -import sys -import argparse -from pprint import pprint - -def _dump_state(args): - print(sys.version) - for name in args.attributes: - print("sys.{}:".format(name)) - pprint(getattr(sys, name)) - -def _add_dump_args(cmd): - cmd.add_argument("attributes", metavar="ATTR", nargs="+", - help="sys module attribute to display") - -COMMANDS = ( - ("dump", "Dump import state", _dump_state, _add_dump_args), -) - -def _make_parser(): - parser = argparse.ArgumentParser() - sub = parser.add_subparsers(title="Commands") - for name, description, implementation, add_args in COMMANDS: - cmd = sub.add_parser(name, help=description) - cmd.set_defaults(command=implementation) - add_args(cmd) - return parser - -def main(args): - parser = _make_parser() - args = parser.parse_args(args) - return args.command(args) - -if __name__ == "__main__": - sys.exit(main(sys.argv[1:])) diff --git a/Tools/scripts/lfcr.py b/Tools/scripts/lfcr.py deleted file mode 100755 index bf8fe1c245ef..000000000000 --- a/Tools/scripts/lfcr.py +++ /dev/null @@ -1,24 +0,0 @@ -#! /usr/bin/env python3 - -"Replace LF with CRLF in argument files. Print names of changed files." - -import sys, re, os - -def main(): - for filename in sys.argv[1:]: - if os.path.isdir(filename): - print(filename, "Directory!") - continue - with open(filename, "rb") as f: - data = f.read() - if b'\0' in data: - print(filename, "Binary!") - continue - newdata = re.sub(b"\r?\n", b"\r\n", data) - if newdata != data: - print(filename) - with open(filename, "wb") as f: - f.write(newdata) - -if __name__ == '__main__': - main() diff --git a/Tools/scripts/linktree.py b/Tools/scripts/linktree.py deleted file mode 100755 index e83f198593ad..000000000000 --- a/Tools/scripts/linktree.py +++ /dev/null @@ -1,80 +0,0 @@ -#! /usr/bin/env python3 - -# linktree -# -# Make a copy of a directory tree with symbolic links to all files in the -# original tree. -# All symbolic links go to a special symbolic link at the top, so you -# can easily fix things if the original source tree moves. -# See also "mkreal". -# -# usage: mklinks oldtree newtree - -import sys, os - -LINK = '.LINK' # Name of special symlink at the top. - -debug = 0 - -def main(): - if not 3 <= len(sys.argv) <= 4: - print('usage:', sys.argv[0], 'oldtree newtree [linkto]') - return 2 - oldtree, newtree = sys.argv[1], sys.argv[2] - if len(sys.argv) > 3: - link = sys.argv[3] - link_may_fail = 1 - else: - link = LINK - link_may_fail = 0 - if not os.path.isdir(oldtree): - print(oldtree + ': not a directory') - return 1 - try: - os.mkdir(newtree, 0o777) - except OSError as msg: - print(newtree + ': cannot mkdir:', msg) - return 1 - linkname = os.path.join(newtree, link) - try: - os.symlink(os.path.join(os.pardir, oldtree), linkname) - except OSError as msg: - if not link_may_fail: - print(linkname + ': cannot symlink:', msg) - return 1 - else: - print(linkname + ': warning: cannot symlink:', msg) - linknames(oldtree, newtree, link) - return 0 - -def linknames(old, new, link): - if debug: print('linknames', (old, new, link)) - try: - names = os.listdir(old) - except OSError as msg: - print(old + ': warning: cannot listdir:', msg) - return - for name in names: - if name not in (os.curdir, os.pardir): - oldname = os.path.join(old, name) - linkname = os.path.join(link, name) - newname = os.path.join(new, name) - if debug > 1: print(oldname, newname, linkname) - if os.path.isdir(oldname) and \ - not os.path.islink(oldname): - try: - os.mkdir(newname, 0o777) - ok = 1 - except: - print(newname + \ - ': warning: cannot mkdir:', msg) - ok = 0 - if ok: - linkname = os.path.join(os.pardir, - linkname) - linknames(oldname, newname, linkname) - else: - os.symlink(linkname, newname) - -if __name__ == '__main__': - sys.exit(main()) diff --git a/Tools/scripts/lll.py b/Tools/scripts/lll.py deleted file mode 100755 index 1b48eac8aad8..000000000000 --- a/Tools/scripts/lll.py +++ /dev/null @@ -1,27 +0,0 @@ -#! /usr/bin/env python3 - -# Find symbolic links and show where they point to. -# Arguments are directories to search; default is current directory. -# No recursion. -# (This is a totally different program from "findsymlinks.py"!) - -import sys, os - -def lll(dirname): - for name in os.listdir(dirname): - if name not in (os.curdir, os.pardir): - full = os.path.join(dirname, name) - if os.path.islink(full): - print(name, '->', os.readlink(full)) -def main(args): - if not args: args = [os.curdir] - first = 1 - for arg in args: - if len(args) > 1: - if not first: print() - first = 0 - print(arg + ':') - lll(arg) - -if __name__ == '__main__': - main(sys.argv[1:]) diff --git a/Tools/scripts/mailerdaemon.py b/Tools/scripts/mailerdaemon.py deleted file mode 100755 index 9595ee4a0153..000000000000 --- a/Tools/scripts/mailerdaemon.py +++ /dev/null @@ -1,246 +0,0 @@ -#!/usr/bin/env python3 -"""Classes to parse mailer-daemon messages.""" - -import calendar -import email.message -import re -import os -import sys - - -class Unparseable(Exception): - pass - - -class ErrorMessage(email.message.Message): - def __init__(self): - email.message.Message.__init__(self) - self.sub = '' - - def is_warning(self): - sub = self.get('Subject') - if not sub: - return 0 - sub = sub.lower() - if sub.startswith('waiting mail'): - return 1 - if 'warning' in sub: - return 1 - self.sub = sub - return 0 - - def get_errors(self): - for p in EMPARSERS: - self.rewindbody() - try: - return p(self.fp, self.sub) - except Unparseable: - pass - raise Unparseable - -# List of re's or tuples of re's. -# If a re, it should contain at least a group (?P...) which -# should refer to the email address. The re can also contain a group -# (?P...) which should refer to the reason (error message). -# If no reason is present, the emparse_list_reason list is used to -# find a reason. -# If a tuple, the tuple should contain 2 re's. The first re finds a -# location, the second re is repeated one or more times to find -# multiple email addresses. The second re is matched (not searched) -# where the previous match ended. -# The re's are compiled using the re module. -emparse_list_list = [ - 'error: (?Punresolvable): (?P.+)', - ('----- The following addresses had permanent fatal errors -----\n', - '(?P[^ \n].*)\n( .*\n)?'), - 'remote execution.*\n.*rmail (?P.+)', - ('The following recipients did not receive your message:\n\n', - ' +(?P.*)\n(The following recipients did not receive your message:\n\n)?'), - '------- Failure Reasons --------\n\n(?P.*)\n(?P.*)', - '^<(?P.*)>:\n(?P.*)', - '^(?PUser mailbox exceeds allowed size): (?P.+)', - '^5\\d{2} <(?P[^\n>]+)>\\.\\.\\. (?P.+)', - '^Original-Recipient: rfc822;(?P.*)', - '^did not reach the following recipient\\(s\\):\n\n(?P.*) on .*\n +(?P.*)', - '^ <(?P[^\n>]+)> \\.\\.\\. (?P.*)', - '^Report on your message to: (?P.*)\nReason: (?P.*)', - '^Your message was not delivered to +(?P.*)\n +for the following reason:\n +(?P.*)', - '^ was not +(?P[^ \n].*?) *\n.*\n.*\n.*\n because:.*\n +(?P[^ \n].*?) *\n', - ] -# compile the re's in the list and store them in-place. -for i in range(len(emparse_list_list)): - x = emparse_list_list[i] - if isinstance(x, str): - x = re.compile(x, re.MULTILINE) - else: - xl = [] - for x in x: - xl.append(re.compile(x, re.MULTILINE)) - x = tuple(xl) - del xl - emparse_list_list[i] = x - del x -del i - -# list of re's used to find reasons (error messages). -# if a string, "<>" is replaced by a copy of the email address. -# The expressions are searched for in order. After the first match, -# no more expressions are searched for. So, order is important. -emparse_list_reason = [ - r'^5\d{2} <>\.\.\. (?P.*)', - r'<>\.\.\. (?P.*)', - re.compile(r'^<<< 5\d{2} (?P.*)', re.MULTILINE), - re.compile('===== stderr was =====\nrmail: (?P.*)'), - re.compile('^Diagnostic-Code: (?P.*)', re.MULTILINE), - ] -emparse_list_from = re.compile('^From:', re.IGNORECASE|re.MULTILINE) -def emparse_list(fp, sub): - data = fp.read() - res = emparse_list_from.search(data) - if res is None: - from_index = len(data) - else: - from_index = res.start(0) - errors = [] - emails = [] - reason = None - for regexp in emparse_list_list: - if isinstance(regexp, tuple): - res = regexp[0].search(data, 0, from_index) - if res is not None: - try: - reason = res.group('reason') - except IndexError: - pass - while 1: - res = regexp[1].match(data, res.end(0), from_index) - if res is None: - break - emails.append(res.group('email')) - break - else: - res = regexp.search(data, 0, from_index) - if res is not None: - emails.append(res.group('email')) - try: - reason = res.group('reason') - except IndexError: - pass - break - if not emails: - raise Unparseable - if not reason: - reason = sub - if reason[:15] == 'returned mail: ': - reason = reason[15:] - for regexp in emparse_list_reason: - if isinstance(regexp, str): - for i in range(len(emails)-1,-1,-1): - email = emails[i] - exp = re.compile(re.escape(email).join(regexp.split('<>')), re.MULTILINE) - res = exp.search(data) - if res is not None: - errors.append(' '.join((email.strip()+': '+res.group('reason')).split())) - del emails[i] - continue - res = regexp.search(data) - if res is not None: - reason = res.group('reason') - break - for email in emails: - errors.append(' '.join((email.strip()+': '+reason).split())) - return errors - -EMPARSERS = [emparse_list] - -def sort_numeric(a, b): - a = int(a) - b = int(b) - if a < b: - return -1 - elif a > b: - return 1 - else: - return 0 - -def parsedir(dir, modify): - os.chdir(dir) - pat = re.compile('^[0-9]*$') - errordict = {} - errorfirst = {} - errorlast = {} - nok = nwarn = nbad = 0 - - # find all numeric file names and sort them - files = list(filter(lambda fn, pat=pat: pat.match(fn) is not None, os.listdir('.'))) - files.sort(sort_numeric) - - for fn in files: - # Lets try to parse the file. - fp = open(fn) - m = email.message_from_file(fp, _class=ErrorMessage) - sender = m.getaddr('From') - print('%s\t%-40s\t'%(fn, sender[1]), end=' ') - - if m.is_warning(): - fp.close() - print('warning only') - nwarn = nwarn + 1 - if modify: - os.rename(fn, ','+fn) -## os.unlink(fn) - continue - - try: - errors = m.get_errors() - except Unparseable: - print('** Not parseable') - nbad = nbad + 1 - fp.close() - continue - print(len(errors), 'errors') - - # Remember them - for e in errors: - try: - mm, dd = m.getdate('date')[1:1+2] - date = '%s %02d' % (calendar.month_abbr[mm], dd) - except: - date = '??????' - if e not in errordict: - errordict[e] = 1 - errorfirst[e] = '%s (%s)' % (fn, date) - else: - errordict[e] = errordict[e] + 1 - errorlast[e] = '%s (%s)' % (fn, date) - - fp.close() - nok = nok + 1 - if modify: - os.rename(fn, ','+fn) -## os.unlink(fn) - - print('--------------') - print(nok, 'files parsed,',nwarn,'files warning-only,', end=' ') - print(nbad,'files unparseable') - print('--------------') - list = [] - for e in errordict.keys(): - list.append((errordict[e], errorfirst[e], errorlast[e], e)) - list.sort() - for num, first, last, e in list: - print('%d %s - %s\t%s' % (num, first, last, e)) - -def main(): - modify = 0 - if len(sys.argv) > 1 and sys.argv[1] == '-d': - modify = 1 - del sys.argv[1] - if len(sys.argv) > 1: - for folder in sys.argv[1:]: - parsedir(folder, modify) - else: - parsedir('/ufs/jack/Mail/errorsinbox', modify) - -if __name__ == '__main__' or sys.argv[0] == __name__: - main() diff --git a/Tools/scripts/make_ctype.py b/Tools/scripts/make_ctype.py deleted file mode 100755 index afee1c583330..000000000000 --- a/Tools/scripts/make_ctype.py +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env python3 -"""Script that generates the ctype.h-replacement in stringobject.c.""" - -NAMES = ("LOWER", "UPPER", "ALPHA", "DIGIT", "XDIGIT", "ALNUM", "SPACE") - -print(""" -#define FLAG_LOWER 0x01 -#define FLAG_UPPER 0x02 -#define FLAG_ALPHA (FLAG_LOWER|FLAG_UPPER) -#define FLAG_DIGIT 0x04 -#define FLAG_ALNUM (FLAG_ALPHA|FLAG_DIGIT) -#define FLAG_SPACE 0x08 -#define FLAG_XDIGIT 0x10 - -static unsigned int ctype_table[256] = {""") - -for i in range(128): - c = chr(i) - flags = [] - for name in NAMES: - if name in ("ALPHA", "ALNUM"): - continue - if name == "XDIGIT": - method = lambda: c.isdigit() or c.upper() in "ABCDEF" - else: - method = getattr(c, "is" + name.lower()) - if method(): - flags.append("FLAG_" + name) - rc = repr(c) - if c == '\v': - rc = "'\\v'" - elif c == '\f': - rc = "'\\f'" - if not flags: - print(" 0, /* 0x%x %s */" % (i, rc)) - else: - print(" %s, /* 0x%x %s */" % ("|".join(flags), i, rc)) - -for i in range(128, 256, 16): - print(" %s," % ", ".join(16*["0"])) - -print("};") -print("") - -for name in NAMES: - print("#define IS%s(c) (ctype_table[Py_CHARMASK(c)] & FLAG_%s)" % - (name, name)) - -print("") - -for name in NAMES: - name = "is" + name.lower() - print("#undef %s" % name) - print("#define %s(c) undefined_%s(c)" % (name, name)) - -print(""" -static unsigned char ctype_tolower[256] = {""") - -for i in range(0, 256, 8): - values = [] - for i in range(i, i+8): - if i < 128: - c = chr(i) - if c.isupper(): - i = ord(c.lower()) - values.append("0x%02x" % i) - print(" %s," % ", ".join(values)) - -print("};") - -print(""" -static unsigned char ctype_toupper[256] = {""") - -for i in range(0, 256, 8): - values = [] - for i in range(i, i+8): - if i < 128: - c = chr(i) - if c.islower(): - i = ord(c.upper()) - values.append("0x%02x" % i) - print(" %s," % ", ".join(values)) - -print("};") - -print(""" -#define TOLOWER(c) (ctype_tolower[Py_CHARMASK(c)]) -#define TOUPPER(c) (ctype_toupper[Py_CHARMASK(c)]) - -#undef tolower -#define tolower(c) undefined_tolower(c) -#undef toupper -#define toupper(c) undefined_toupper(c) -""") diff --git a/Tools/scripts/mkreal.py b/Tools/scripts/mkreal.py deleted file mode 100755 index f169da43fe11..000000000000 --- a/Tools/scripts/mkreal.py +++ /dev/null @@ -1,65 +0,0 @@ -#! /usr/bin/env python3 - -# mkreal -# -# turn a symlink to a directory into a real directory - -import sys -import os -from stat import * - -join = os.path.join - -error = 'mkreal error' - -BUFSIZE = 32*1024 - -def mkrealfile(name): - st = os.stat(name) # Get the mode - mode = S_IMODE(st[ST_MODE]) - linkto = os.readlink(name) # Make sure again it's a symlink - with open(name, 'rb') as f_in: # This ensures it's a file - os.unlink(name) - with open(name, 'wb') as f_out: - while 1: - buf = f_in.read(BUFSIZE) - if not buf: break - f_out.write(buf) - os.chmod(name, mode) - -def mkrealdir(name): - st = os.stat(name) # Get the mode - mode = S_IMODE(st[ST_MODE]) - linkto = os.readlink(name) - files = os.listdir(name) - os.unlink(name) - os.mkdir(name, mode) - os.chmod(name, mode) - linkto = join(os.pardir, linkto) - # - for filename in files: - if filename not in (os.curdir, os.pardir): - os.symlink(join(linkto, filename), join(name, filename)) - -def main(): - sys.stdout = sys.stderr - progname = os.path.basename(sys.argv[0]) - if progname == '-c': progname = 'mkreal' - args = sys.argv[1:] - if not args: - print('usage:', progname, 'path ...') - sys.exit(2) - status = 0 - for name in args: - if not os.path.islink(name): - print(progname+':', name+':', 'not a symlink') - status = 1 - else: - if os.path.isdir(name): - mkrealdir(name) - else: - mkrealfile(name) - sys.exit(status) - -if __name__ == '__main__': - main() diff --git a/Tools/scripts/objgraph.py b/Tools/scripts/objgraph.py deleted file mode 100755 index add41e692c03..000000000000 --- a/Tools/scripts/objgraph.py +++ /dev/null @@ -1,211 +0,0 @@ -#! /usr/bin/env python3 - -# objgraph -# -# Read "nm -o" input of a set of libraries or modules and print various -# interesting listings, such as: -# -# - which names are used but not defined in the set (and used where), -# - which names are defined in the set (and where), -# - which modules use which other modules, -# - which modules are used by which other modules. -# -# Usage: objgraph [-cdu] [file] ... -# -c: print callers per objectfile -# -d: print callees per objectfile -# -u: print usage of undefined symbols -# If none of -cdu is specified, all are assumed. -# Use "nm -o" to generate the input -# e.g.: nm -o /lib/libc.a | objgraph - - -import sys -import os -import getopt -import re - -# Types of symbols. -# -definitions = 'TRGDSBAEC' -externals = 'UV' -ignore = 'Nntrgdsbavuc' - -# Regular expression to parse "nm -o" output. -# -matcher = re.compile('(.*):\t?........ (.) (.*)$') - -# Store "item" in "dict" under "key". -# The dictionary maps keys to lists of items. -# If there is no list for the key yet, it is created. -# -def store(dict, key, item): - if key in dict: - dict[key].append(item) - else: - dict[key] = [item] - -# Return a flattened version of a list of strings: the concatenation -# of its elements with intervening spaces. -# -def flat(list): - s = '' - for item in list: - s = s + ' ' + item - return s[1:] - -# Global variables mapping defined/undefined names to files and back. -# -file2undef = {} -def2file = {} -file2def = {} -undef2file = {} - -# Read one input file and merge the data into the tables. -# Argument is an open file. -# -def readinput(fp): - while 1: - s = fp.readline() - if not s: - break - # If you get any output from this line, - # it is probably caused by an unexpected input line: - if matcher.search(s) < 0: s; continue # Shouldn't happen - (ra, rb), (r1a, r1b), (r2a, r2b), (r3a, r3b) = matcher.regs[:4] - fn, name, type = s[r1a:r1b], s[r3a:r3b], s[r2a:r2b] - if type in definitions: - store(def2file, name, fn) - store(file2def, fn, name) - elif type in externals: - store(file2undef, fn, name) - store(undef2file, name, fn) - elif not type in ignore: - print(fn + ':' + name + ': unknown type ' + type) - -# Print all names that were undefined in some module and where they are -# defined. -# -def printcallee(): - flist = sorted(file2undef.keys()) - for filename in flist: - print(filename + ':') - elist = file2undef[filename] - elist.sort() - for ext in elist: - if len(ext) >= 8: - tabs = '\t' - else: - tabs = '\t\t' - if ext not in def2file: - print('\t' + ext + tabs + ' *undefined') - else: - print('\t' + ext + tabs + flat(def2file[ext])) - -# Print for each module the names of the other modules that use it. -# -def printcaller(): - files = sorted(file2def.keys()) - for filename in files: - callers = [] - for label in file2def[filename]: - if label in undef2file: - callers = callers + undef2file[label] - if callers: - callers.sort() - print(filename + ':') - lastfn = '' - for fn in callers: - if fn != lastfn: - print('\t' + fn) - lastfn = fn - else: - print(filename + ': unused') - -# Print undefined names and where they are used. -# -def printundef(): - undefs = {} - for filename in list(file2undef.keys()): - for ext in file2undef[filename]: - if ext not in def2file: - store(undefs, ext, filename) - elist = sorted(undefs.keys()) - for ext in elist: - print(ext + ':') - flist = sorted(undefs[ext]) - for filename in flist: - print('\t' + filename) - -# Print warning messages about names defined in more than one file. -# -def warndups(): - savestdout = sys.stdout - sys.stdout = sys.stderr - names = sorted(def2file.keys()) - for name in names: - if len(def2file[name]) > 1: - print('warning:', name, 'multiply defined:', end=' ') - print(flat(def2file[name])) - sys.stdout = savestdout - -# Main program -# -def main(): - try: - optlist, args = getopt.getopt(sys.argv[1:], 'cdu') - except getopt.error: - sys.stdout = sys.stderr - print('Usage:', os.path.basename(sys.argv[0]), end=' ') - print('[-cdu] [file] ...') - print('-c: print callers per objectfile') - print('-d: print callees per objectfile') - print('-u: print usage of undefined symbols') - print('If none of -cdu is specified, all are assumed.') - print('Use "nm -o" to generate the input') - print('e.g.: nm -o /lib/libc.a | objgraph') - return 1 - optu = optc = optd = 0 - for opt, void in optlist: - if opt == '-u': - optu = 1 - elif opt == '-c': - optc = 1 - elif opt == '-d': - optd = 1 - if optu == optc == optd == 0: - optu = optc = optd = 1 - if not args: - args = ['-'] - for filename in args: - if filename == '-': - readinput(sys.stdin) - else: - with open(filename) as f: - readinput(f) - # - warndups() - # - more = (optu + optc + optd > 1) - if optd: - if more: - print('---------------All callees------------------') - printcallee() - if optu: - if more: - print('---------------Undefined callees------------') - printundef() - if optc: - if more: - print('---------------All Callers------------------') - printcaller() - return 0 - -# Call the main program. -# Use its return value as exit status. -# Catch interrupts to avoid stack trace. -# -if __name__ == '__main__': - try: - sys.exit(main()) - except KeyboardInterrupt: - sys.exit(1) diff --git a/Tools/scripts/pdeps.py b/Tools/scripts/pdeps.py deleted file mode 100755 index ab0040f48e2e..000000000000 --- a/Tools/scripts/pdeps.py +++ /dev/null @@ -1,164 +0,0 @@ -#! /usr/bin/env python3 - -# pdeps -# -# Find dependencies between a bunch of Python modules. -# -# Usage: -# pdeps file1.py file2.py ... -# -# Output: -# Four tables separated by lines like '--- Closure ---': -# 1) Direct dependencies, listing which module imports which other modules -# 2) The inverse of (1) -# 3) Indirect dependencies, or the closure of the above -# 4) The inverse of (3) -# -# To do: -# - command line options to select output type -# - option to automatically scan the Python library for referenced modules -# - option to limit output to particular modules - - -import sys -import re -import os - - -# Main program -# -def main(): - args = sys.argv[1:] - if not args: - print('usage: pdeps file.py file.py ...') - return 2 - # - table = {} - for arg in args: - process(arg, table) - # - print('--- Uses ---') - printresults(table) - # - print('--- Used By ---') - inv = inverse(table) - printresults(inv) - # - print('--- Closure of Uses ---') - reach = closure(table) - printresults(reach) - # - print('--- Closure of Used By ---') - invreach = inverse(reach) - printresults(invreach) - # - return 0 - - -# Compiled regular expressions to search for import statements -# -m_import = re.compile('^[ \t]*from[ \t]+([^ \t]+)[ \t]+') -m_from = re.compile('^[ \t]*import[ \t]+([^#]+)') - - -# Collect data from one file -# -def process(filename, table): - with open(filename, encoding='utf-8') as fp: - mod = os.path.basename(filename) - if mod[-3:] == '.py': - mod = mod[:-3] - table[mod] = list = [] - while 1: - line = fp.readline() - if not line: break - while line[-1:] == '\\': - nextline = fp.readline() - if not nextline: break - line = line[:-1] + nextline - m_found = m_import.match(line) or m_from.match(line) - if m_found: - (a, b), (a1, b1) = m_found.regs[:2] - else: continue - words = line[a1:b1].split(',') - # print '#', line, words - for word in words: - word = word.strip() - if word not in list: - list.append(word) - - -# Compute closure (this is in fact totally general) -# -def closure(table): - modules = list(table.keys()) - # - # Initialize reach with a copy of table - # - reach = {} - for mod in modules: - reach[mod] = table[mod][:] - # - # Iterate until no more change - # - change = 1 - while change: - change = 0 - for mod in modules: - for mo in reach[mod]: - if mo in modules: - for m in reach[mo]: - if m not in reach[mod]: - reach[mod].append(m) - change = 1 - # - return reach - - -# Invert a table (this is again totally general). -# All keys of the original table are made keys of the inverse, -# so there may be empty lists in the inverse. -# -def inverse(table): - inv = {} - for key in table.keys(): - if key not in inv: - inv[key] = [] - for item in table[key]: - store(inv, item, key) - return inv - - -# Store "item" in "dict" under "key". -# The dictionary maps keys to lists of items. -# If there is no list for the key yet, it is created. -# -def store(dict, key, item): - if key in dict: - dict[key].append(item) - else: - dict[key] = [item] - - -# Tabulate results neatly -# -def printresults(table): - modules = sorted(table.keys()) - maxlen = 0 - for mod in modules: maxlen = max(maxlen, len(mod)) - for mod in modules: - list = sorted(table[mod]) - print(mod.ljust(maxlen), ':', end=' ') - if mod in list: - print('(*)', end=' ') - for ref in list: - print(ref, end=' ') - print() - - -# Call main and honor exit status -if __name__ == '__main__': - try: - sys.exit(main()) - except KeyboardInterrupt: - sys.exit(1) diff --git a/Tools/scripts/pickle2db.py b/Tools/scripts/pickle2db.py deleted file mode 100755 index b5b657186328..000000000000 --- a/Tools/scripts/pickle2db.py +++ /dev/null @@ -1,147 +0,0 @@ -#!/usr/bin/env python3 - -""" -Synopsis: %(prog)s [-h|-b|-g|-r|-a|-d] [ picklefile ] dbfile - -Read the given picklefile as a series of key/value pairs and write to a new -database. If the database already exists, any contents are deleted. The -optional flags indicate the type of the output database: - - -a - open using dbm (open any supported format) - -b - open as bsddb btree file - -d - open as dbm.ndbm file - -g - open as dbm.gnu file - -h - open as bsddb hash file - -r - open as bsddb recno file - -The default is hash. If a pickle file is named it is opened for read -access. If no pickle file is named, the pickle input is read from standard -input. - -Note that recno databases can only contain integer keys, so you can't dump a -hash or btree database using db2pickle.py and reconstitute it to a recno -database with %(prog)s unless your keys are integers. - -""" - -import getopt -try: - import bsddb -except ImportError: - bsddb = None -try: - import dbm.ndbm as dbm -except ImportError: - dbm = None -try: - import dbm.gnu as gdbm -except ImportError: - gdbm = None -try: - import dbm.ndbm as anydbm -except ImportError: - anydbm = None -import sys -try: - import pickle as pickle -except ImportError: - import pickle - -prog = sys.argv[0] - -def usage(): - sys.stderr.write(__doc__ % globals()) - -def main(args): - try: - opts, args = getopt.getopt(args, "hbrdag", - ["hash", "btree", "recno", "dbm", "anydbm", - "gdbm"]) - except getopt.error: - usage() - return 1 - - if len(args) == 0 or len(args) > 2: - usage() - return 1 - elif len(args) == 1: - pfile = sys.stdin - dbfile = args[0] - else: - try: - pfile = open(args[0], 'rb') - except IOError: - sys.stderr.write("Unable to open %s\n" % args[0]) - return 1 - dbfile = args[1] - - dbopen = None - for opt, arg in opts: - if opt in ("-h", "--hash"): - try: - dbopen = bsddb.hashopen - except AttributeError: - sys.stderr.write("bsddb module unavailable.\n") - return 1 - elif opt in ("-b", "--btree"): - try: - dbopen = bsddb.btopen - except AttributeError: - sys.stderr.write("bsddb module unavailable.\n") - return 1 - elif opt in ("-r", "--recno"): - try: - dbopen = bsddb.rnopen - except AttributeError: - sys.stderr.write("bsddb module unavailable.\n") - return 1 - elif opt in ("-a", "--anydbm"): - try: - dbopen = anydbm.open - except AttributeError: - sys.stderr.write("dbm module unavailable.\n") - return 1 - elif opt in ("-g", "--gdbm"): - try: - dbopen = gdbm.open - except AttributeError: - sys.stderr.write("dbm.gnu module unavailable.\n") - return 1 - elif opt in ("-d", "--dbm"): - try: - dbopen = dbm.open - except AttributeError: - sys.stderr.write("dbm.ndbm module unavailable.\n") - return 1 - if dbopen is None: - if bsddb is None: - sys.stderr.write("bsddb module unavailable - ") - sys.stderr.write("must specify dbtype.\n") - return 1 - else: - dbopen = bsddb.hashopen - - try: - db = dbopen(dbfile, 'c') - except bsddb.error: - sys.stderr.write("Unable to open %s. " % dbfile) - sys.stderr.write("Check for format or version mismatch.\n") - return 1 - else: - for k in list(db.keys()): - del db[k] - - while 1: - try: - (key, val) = pickle.load(pfile) - except EOFError: - break - db[key] = val - - db.close() - pfile.close() - - return 0 - -if __name__ == "__main__": - sys.exit(main(sys.argv[1:])) diff --git a/Tools/scripts/pindent.py b/Tools/scripts/pindent.py deleted file mode 100755 index 33334204a4d4..000000000000 --- a/Tools/scripts/pindent.py +++ /dev/null @@ -1,506 +0,0 @@ -#! /usr/bin/env python3 - -# This file contains a class and a main program that perform three -# related (though complimentary) formatting operations on Python -# programs. When called as "pindent -c", it takes a valid Python -# program as input and outputs a version augmented with block-closing -# comments. When called as "pindent -d", it assumes its input is a -# Python program with block-closing comments and outputs a commentless -# version. When called as "pindent -r" it assumes its input is a -# Python program with block-closing comments but with its indentation -# messed up, and outputs a properly indented version. - -# A "block-closing comment" is a comment of the form '# end ' -# where is the keyword that opened the block. If the -# opening keyword is 'def' or 'class', the function or class name may -# be repeated in the block-closing comment as well. Here is an -# example of a program fully augmented with block-closing comments: - -# def foobar(a, b): -# if a == b: -# a = a+1 -# elif a < b: -# b = b-1 -# if b > a: a = a-1 -# # end if -# else: -# print 'oops!' -# # end if -# # end def foobar - -# Note that only the last part of an if...elif...else... block needs a -# block-closing comment; the same is true for other compound -# statements (e.g. try...except). Also note that "short-form" blocks -# like the second 'if' in the example must be closed as well; -# otherwise the 'else' in the example would be ambiguous (remember -# that indentation is not significant when interpreting block-closing -# comments). - -# The operations are idempotent (i.e. applied to their own output -# they yield an identical result). Running first "pindent -c" and -# then "pindent -r" on a valid Python program produces a program that -# is semantically identical to the input (though its indentation may -# be different). Running "pindent -e" on that output produces a -# program that only differs from the original in indentation. - -# Other options: -# -s stepsize: set the indentation step size (default 8) -# -t tabsize : set the number of spaces a tab character is worth (default 8) -# -e : expand TABs into spaces -# file ... : input file(s) (default standard input) -# The results always go to standard output - -# Caveats: -# - comments ending in a backslash will be mistaken for continued lines -# - continuations using backslash are always left unchanged -# - continuations inside parentheses are not extra indented by -r -# but must be indented for -c to work correctly (this breaks -# idempotency!) -# - continued lines inside triple-quoted strings are totally garbled - -# Secret feature: -# - On input, a block may also be closed with an "end statement" -- -# this is a block-closing comment without the '#' sign. - -# Possible improvements: -# - check syntax based on transitions in 'next' table -# - better error reporting -# - better error recovery -# - check identifier after class/def - -# The following wishes need a more complete tokenization of the source: -# - Don't get fooled by comments ending in backslash -# - reindent continuation lines indicated by backslash -# - handle continuation lines inside parentheses/braces/brackets -# - handle triple quoted strings spanning lines -# - realign comments -# - optionally do much more thorough reformatting, a la C indent - -# Defaults -STEPSIZE = 8 -TABSIZE = 8 -EXPANDTABS = False - -import io -import re -import sys - -next = {} -next['if'] = next['elif'] = 'elif', 'else', 'end' -next['while'] = next['for'] = 'else', 'end' -next['try'] = 'except', 'finally' -next['except'] = 'except', 'else', 'finally', 'end' -next['else'] = next['finally'] = next['with'] = \ - next['def'] = next['class'] = 'end' -next['end'] = () -start = 'if', 'while', 'for', 'try', 'with', 'def', 'class' - -class PythonIndenter: - - def __init__(self, fpi = sys.stdin, fpo = sys.stdout, - indentsize = STEPSIZE, tabsize = TABSIZE, expandtabs = EXPANDTABS): - self.fpi = fpi - self.fpo = fpo - self.indentsize = indentsize - self.tabsize = tabsize - self.lineno = 0 - self.expandtabs = expandtabs - self._write = fpo.write - self.kwprog = re.compile( - r'^(?:\s|\\\n)*(?P[a-z]+)' - r'((?:\s|\\\n)+(?P[a-zA-Z_]\w*))?' - r'[^\w]') - self.endprog = re.compile( - r'^(?:\s|\\\n)*#?\s*end\s+(?P[a-z]+)' - r'(\s+(?P[a-zA-Z_]\w*))?' - r'[^\w]') - self.wsprog = re.compile(r'^[ \t]*') - # end def __init__ - - def write(self, line): - if self.expandtabs: - self._write(line.expandtabs(self.tabsize)) - else: - self._write(line) - # end if - # end def write - - def readline(self): - line = self.fpi.readline() - if line: self.lineno += 1 - # end if - return line - # end def readline - - def error(self, fmt, *args): - if args: fmt = fmt % args - # end if - sys.stderr.write('Error at line %d: %s\n' % (self.lineno, fmt)) - self.write('### %s ###\n' % fmt) - # end def error - - def getline(self): - line = self.readline() - while line[-2:] == '\\\n': - line2 = self.readline() - if not line2: break - # end if - line += line2 - # end while - return line - # end def getline - - def putline(self, line, indent): - tabs, spaces = divmod(indent*self.indentsize, self.tabsize) - i = self.wsprog.match(line).end() - line = line[i:] - if line[:1] not in ('\n', '\r', ''): - line = '\t'*tabs + ' '*spaces + line - # end if - self.write(line) - # end def putline - - def reformat(self): - stack = [] - while True: - line = self.getline() - if not line: break # EOF - # end if - m = self.endprog.match(line) - if m: - kw = 'end' - kw2 = m.group('kw') - if not stack: - self.error('unexpected end') - elif stack.pop()[0] != kw2: - self.error('unmatched end') - # end if - self.putline(line, len(stack)) - continue - # end if - m = self.kwprog.match(line) - if m: - kw = m.group('kw') - if kw in start: - self.putline(line, len(stack)) - stack.append((kw, kw)) - continue - # end if - if kw in next and stack: - self.putline(line, len(stack)-1) - kwa, kwb = stack[-1] - stack[-1] = kwa, kw - continue - # end if - # end if - self.putline(line, len(stack)) - # end while - if stack: - self.error('unterminated keywords') - for kwa, kwb in stack: - self.write('\t%s\n' % kwa) - # end for - # end if - # end def reformat - - def delete(self): - begin_counter = 0 - end_counter = 0 - while True: - line = self.getline() - if not line: break # EOF - # end if - m = self.endprog.match(line) - if m: - end_counter += 1 - continue - # end if - m = self.kwprog.match(line) - if m: - kw = m.group('kw') - if kw in start: - begin_counter += 1 - # end if - # end if - self.write(line) - # end while - if begin_counter - end_counter < 0: - sys.stderr.write('Warning: input contained more end tags than expected\n') - elif begin_counter - end_counter > 0: - sys.stderr.write('Warning: input contained less end tags than expected\n') - # end if - # end def delete - - def complete(self): - stack = [] - todo = [] - currentws = thisid = firstkw = lastkw = topid = '' - while True: - line = self.getline() - i = self.wsprog.match(line).end() - m = self.endprog.match(line) - if m: - thiskw = 'end' - endkw = m.group('kw') - thisid = m.group('id') - else: - m = self.kwprog.match(line) - if m: - thiskw = m.group('kw') - if thiskw not in next: - thiskw = '' - # end if - if thiskw in ('def', 'class'): - thisid = m.group('id') - else: - thisid = '' - # end if - elif line[i:i+1] in ('\n', '#'): - todo.append(line) - continue - else: - thiskw = '' - # end if - # end if - indentws = line[:i] - indent = len(indentws.expandtabs(self.tabsize)) - current = len(currentws.expandtabs(self.tabsize)) - while indent < current: - if firstkw: - if topid: - s = '# end %s %s\n' % ( - firstkw, topid) - else: - s = '# end %s\n' % firstkw - # end if - self.write(currentws + s) - firstkw = lastkw = '' - # end if - currentws, firstkw, lastkw, topid = stack.pop() - current = len(currentws.expandtabs(self.tabsize)) - # end while - if indent == current and firstkw: - if thiskw == 'end': - if endkw != firstkw: - self.error('mismatched end') - # end if - firstkw = lastkw = '' - elif not thiskw or thiskw in start: - if topid: - s = '# end %s %s\n' % ( - firstkw, topid) - else: - s = '# end %s\n' % firstkw - # end if - self.write(currentws + s) - firstkw = lastkw = topid = '' - # end if - # end if - if indent > current: - stack.append((currentws, firstkw, lastkw, topid)) - if thiskw and thiskw not in start: - # error - thiskw = '' - # end if - currentws, firstkw, lastkw, topid = \ - indentws, thiskw, thiskw, thisid - # end if - if thiskw: - if thiskw in start: - firstkw = lastkw = thiskw - topid = thisid - else: - lastkw = thiskw - # end if - # end if - for l in todo: self.write(l) - # end for - todo = [] - if not line: break - # end if - self.write(line) - # end while - # end def complete -# end class PythonIndenter - -# Simplified user interface -# - xxx_filter(input, output): read and write file objects -# - xxx_string(s): take and return string object -# - xxx_file(filename): process file in place, return true iff changed - -def complete_filter(input = sys.stdin, output = sys.stdout, - stepsize = STEPSIZE, tabsize = TABSIZE, expandtabs = EXPANDTABS): - pi = PythonIndenter(input, output, stepsize, tabsize, expandtabs) - pi.complete() -# end def complete_filter - -def delete_filter(input= sys.stdin, output = sys.stdout, - stepsize = STEPSIZE, tabsize = TABSIZE, expandtabs = EXPANDTABS): - pi = PythonIndenter(input, output, stepsize, tabsize, expandtabs) - pi.delete() -# end def delete_filter - -def reformat_filter(input = sys.stdin, output = sys.stdout, - stepsize = STEPSIZE, tabsize = TABSIZE, expandtabs = EXPANDTABS): - pi = PythonIndenter(input, output, stepsize, tabsize, expandtabs) - pi.reformat() -# end def reformat_filter - -def complete_string(source, stepsize = STEPSIZE, tabsize = TABSIZE, expandtabs = EXPANDTABS): - input = io.StringIO(source) - output = io.StringIO() - pi = PythonIndenter(input, output, stepsize, tabsize, expandtabs) - pi.complete() - return output.getvalue() -# end def complete_string - -def delete_string(source, stepsize = STEPSIZE, tabsize = TABSIZE, expandtabs = EXPANDTABS): - input = io.StringIO(source) - output = io.StringIO() - pi = PythonIndenter(input, output, stepsize, tabsize, expandtabs) - pi.delete() - return output.getvalue() -# end def delete_string - -def reformat_string(source, stepsize = STEPSIZE, tabsize = TABSIZE, expandtabs = EXPANDTABS): - input = io.StringIO(source) - output = io.StringIO() - pi = PythonIndenter(input, output, stepsize, tabsize, expandtabs) - pi.reformat() - return output.getvalue() -# end def reformat_string - -def make_backup(filename): - import os, os.path - backup = filename + '~' - if os.path.lexists(backup): - try: - os.remove(backup) - except OSError: - print("Can't remove backup %r" % (backup,), file=sys.stderr) - # end try - # end if - try: - os.rename(filename, backup) - except OSError: - print("Can't rename %r to %r" % (filename, backup), file=sys.stderr) - # end try -# end def make_backup - -def complete_file(filename, stepsize = STEPSIZE, tabsize = TABSIZE, expandtabs = EXPANDTABS): - with open(filename, 'r') as f: - source = f.read() - # end with - result = complete_string(source, stepsize, tabsize, expandtabs) - if source == result: return 0 - # end if - make_backup(filename) - with open(filename, 'w') as f: - f.write(result) - # end with - return 1 -# end def complete_file - -def delete_file(filename, stepsize = STEPSIZE, tabsize = TABSIZE, expandtabs = EXPANDTABS): - with open(filename, 'r') as f: - source = f.read() - # end with - result = delete_string(source, stepsize, tabsize, expandtabs) - if source == result: return 0 - # end if - make_backup(filename) - with open(filename, 'w') as f: - f.write(result) - # end with - return 1 -# end def delete_file - -def reformat_file(filename, stepsize = STEPSIZE, tabsize = TABSIZE, expandtabs = EXPANDTABS): - with open(filename, 'r') as f: - source = f.read() - # end with - result = reformat_string(source, stepsize, tabsize, expandtabs) - if source == result: return 0 - # end if - make_backup(filename) - with open(filename, 'w') as f: - f.write(result) - # end with - return 1 -# end def reformat_file - -# Test program when called as a script - -usage = """ -usage: pindent (-c|-d|-r) [-s stepsize] [-t tabsize] [-e] [file] ... --c : complete a correctly indented program (add #end directives) --d : delete #end directives --r : reformat a completed program (use #end directives) --s stepsize: indentation step (default %(STEPSIZE)d) --t tabsize : the worth in spaces of a tab (default %(TABSIZE)d) --e : expand TABs into spaces (default OFF) -[file] ... : files are changed in place, with backups in file~ -If no files are specified or a single - is given, -the program acts as a filter (reads stdin, writes stdout). -""" % vars() - -def error_both(op1, op2): - sys.stderr.write('Error: You can not specify both '+op1+' and -'+op2[0]+' at the same time\n') - sys.stderr.write(usage) - sys.exit(2) -# end def error_both - -def test(): - import getopt - try: - opts, args = getopt.getopt(sys.argv[1:], 'cdrs:t:e') - except getopt.error as msg: - sys.stderr.write('Error: %s\n' % msg) - sys.stderr.write(usage) - sys.exit(2) - # end try - action = None - stepsize = STEPSIZE - tabsize = TABSIZE - expandtabs = EXPANDTABS - for o, a in opts: - if o == '-c': - if action: error_both(o, action) - # end if - action = 'complete' - elif o == '-d': - if action: error_both(o, action) - # end if - action = 'delete' - elif o == '-r': - if action: error_both(o, action) - # end if - action = 'reformat' - elif o == '-s': - stepsize = int(a) - elif o == '-t': - tabsize = int(a) - elif o == '-e': - expandtabs = True - # end if - # end for - if not action: - sys.stderr.write( - 'You must specify -c(omplete), -d(elete) or -r(eformat)\n') - sys.stderr.write(usage) - sys.exit(2) - # end if - if not args or args == ['-']: - action = eval(action + '_filter') - action(sys.stdin, sys.stdout, stepsize, tabsize, expandtabs) - else: - action = eval(action + '_file') - for filename in args: - action(filename, stepsize, tabsize, expandtabs) - # end for - # end if -# end def test - -if __name__ == '__main__': - test() -# end if diff --git a/Tools/scripts/pysource.py b/Tools/scripts/pysource.py deleted file mode 100755 index 69e8e0df4ff0..000000000000 --- a/Tools/scripts/pysource.py +++ /dev/null @@ -1,130 +0,0 @@ -#!/usr/bin/env python3 - -"""\ -List python source files. - -There are three functions to check whether a file is a Python source, listed -here with increasing complexity: - -- has_python_ext() checks whether a file name ends in '.py[w]'. -- look_like_python() checks whether the file is not binary and either has - the '.py[w]' extension or the first line contains the word 'python'. -- can_be_compiled() checks whether the file can be compiled by compile(). - -The file also must be of appropriate size - not bigger than a megabyte. - -walk_python_files() recursively lists all Python files under the given directories. -""" -__author__ = "Oleg Broytmann, Georg Brandl" - -__all__ = ["has_python_ext", "looks_like_python", "can_be_compiled", "walk_python_files"] - - -import os, re - -binary_re = re.compile(br'[\x00-\x08\x0E-\x1F\x7F]') - -debug = False - -def print_debug(msg): - if debug: print(msg) - - -def _open(fullpath): - try: - size = os.stat(fullpath).st_size - except OSError as err: # Permission denied - ignore the file - print_debug("%s: permission denied: %s" % (fullpath, err)) - return None - - if size > 1024*1024: # too big - print_debug("%s: the file is too big: %d bytes" % (fullpath, size)) - return None - - try: - return open(fullpath, "rb") - except IOError as err: # Access denied, or a special file - ignore it - print_debug("%s: access denied: %s" % (fullpath, err)) - return None - -def has_python_ext(fullpath): - return fullpath.endswith(".py") or fullpath.endswith(".pyw") - -def looks_like_python(fullpath): - infile = _open(fullpath) - if infile is None: - return False - - with infile: - line = infile.readline() - - if binary_re.search(line): - # file appears to be binary - print_debug("%s: appears to be binary" % fullpath) - return False - - if fullpath.endswith(".py") or fullpath.endswith(".pyw"): - return True - elif b"python" in line: - # disguised Python script (e.g. CGI) - return True - - return False - -def can_be_compiled(fullpath): - infile = _open(fullpath) - if infile is None: - return False - - with infile: - code = infile.read() - - try: - compile(code, fullpath, "exec") - except Exception as err: - print_debug("%s: cannot compile: %s" % (fullpath, err)) - return False - - return True - - -def walk_python_files(paths, is_python=looks_like_python, exclude_dirs=None): - """\ - Recursively yield all Python source files below the given paths. - - paths: a list of files and/or directories to be checked. - is_python: a function that takes a file name and checks whether it is a - Python source file - exclude_dirs: a list of directory base names that should be excluded in - the search - """ - if exclude_dirs is None: - exclude_dirs=[] - - for path in paths: - print_debug("testing: %s" % path) - if os.path.isfile(path): - if is_python(path): - yield path - elif os.path.isdir(path): - print_debug(" it is a directory") - for dirpath, dirnames, filenames in os.walk(path): - for exclude in exclude_dirs: - if exclude in dirnames: - dirnames.remove(exclude) - for filename in filenames: - fullpath = os.path.join(dirpath, filename) - print_debug("testing: %s" % fullpath) - if is_python(fullpath): - yield fullpath - else: - print_debug(" unknown type") - - -if __name__ == "__main__": - # Two simple examples/tests - for fullpath in walk_python_files(['.']): - print(fullpath) - print("----------") - for fullpath in walk_python_files(['.'], is_python=can_be_compiled): - print(fullpath) diff --git a/Tools/scripts/reindent-rst.py b/Tools/scripts/reindent-rst.py deleted file mode 100755 index 25608af66ac2..000000000000 --- a/Tools/scripts/reindent-rst.py +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env python3 - -# Make a reST file compliant to our pre-commit hook. -# Currently just remove trailing whitespace. - -import sys - -import patchcheck - -def main(argv=sys.argv): - patchcheck.normalize_docs_whitespace(argv[1:]) - -if __name__ == '__main__': - sys.exit(main()) diff --git a/Tools/scripts/rgrep.py b/Tools/scripts/rgrep.py deleted file mode 100755 index c39bf93aad3b..000000000000 --- a/Tools/scripts/rgrep.py +++ /dev/null @@ -1,67 +0,0 @@ -#! /usr/bin/env python3 - -"""Reverse grep. - -Usage: rgrep [-i] pattern file -""" - -import sys -import re -import getopt - - -def main(): - bufsize = 64 * 1024 - reflags = 0 - opts, args = getopt.getopt(sys.argv[1:], "i") - for o, a in opts: - if o == '-i': - reflags = reflags | re.IGNORECASE - if len(args) < 2: - usage("not enough arguments") - if len(args) > 2: - usage("exactly one file argument required") - pattern, filename = args - try: - prog = re.compile(pattern, reflags) - except re.error as msg: - usage("error in regular expression: %s" % msg) - try: - f = open(filename) - except IOError as msg: - usage("can't open %r: %s" % (filename, msg), 1) - with f: - f.seek(0, 2) - pos = f.tell() - leftover = None - while pos > 0: - size = min(pos, bufsize) - pos = pos - size - f.seek(pos) - buffer = f.read(size) - lines = buffer.split("\n") - del buffer - if leftover is None: - if not lines[-1]: - del lines[-1] - else: - lines[-1] = lines[-1] + leftover - if pos > 0: - leftover = lines[0] - del lines[0] - else: - leftover = None - for line in reversed(lines): - if prog.search(line): - print(line) - - -def usage(msg, code=2): - sys.stdout = sys.stderr - print(msg) - print(__doc__) - sys.exit(code) - - -if __name__ == '__main__': - main() diff --git a/Tools/scripts/suff.py b/Tools/scripts/suff.py deleted file mode 100755 index 0eea0d754861..000000000000 --- a/Tools/scripts/suff.py +++ /dev/null @@ -1,26 +0,0 @@ -#! /usr/bin/env python3 - -# suff -# -# show different suffixes amongst arguments - -import sys - - -def main(): - files = sys.argv[1:] - suffixes = {} - for filename in files: - suff = getsuffix(filename) - suffixes.setdefault(suff, []).append(filename) - for suff, filenames in sorted(suffixes.items()): - print(repr(suff), len(filenames)) - - -def getsuffix(filename): - name, sep, suff = filename.rpartition('.') - return sep + suff if sep else '' - - -if __name__ == '__main__': - main() diff --git a/Tools/scripts/texi2html.py b/Tools/scripts/texi2html.py deleted file mode 100755 index c06d812ab3fb..000000000000 --- a/Tools/scripts/texi2html.py +++ /dev/null @@ -1,2071 +0,0 @@ -#! /usr/bin/env python3 - -# Convert GNU texinfo files into HTML, one file per node. -# Based on Texinfo 2.14. -# Usage: texi2html [-d] [-d] [-c] inputfile outputdirectory -# The input file must be a complete texinfo file, e.g. emacs.texi. -# This creates many files (one per info node) in the output directory, -# overwriting existing files of the same name. All files created have -# ".html" as their extension. - - -# XXX To do: -# - handle @comment*** correctly -# - handle @xref {some words} correctly -# - handle @ftable correctly (items aren't indexed?) -# - handle @itemx properly -# - handle @exdent properly -# - add links directly to the proper line from indices -# - check against the definitive list of @-cmds; we still miss (among others): -# - @defindex (hard) -# - @c(omment) in the middle of a line (rarely used) -# - @this* (not really needed, only used in headers anyway) -# - @today{} (ever used outside title page?) - -# More consistent handling of chapters/sections/etc. -# Lots of documentation -# Many more options: -# -top designate top node -# -links customize which types of links are included -# -split split at chapters or sections instead of nodes -# -name Allow different types of filename handling. Non unix systems -# will have problems with long node names -# ... -# Support the most recent texinfo version and take a good look at HTML 3.0 -# More debugging output (customizable) and more flexible error handling -# How about icons ? - -# rpyron 2002-05-07 -# Robert Pyron -# 1. BUGFIX: In function makefile(), strip blanks from the nodename. -# This is necessary to match the behavior of parser.makeref() and -# parser.do_node(). -# 2. BUGFIX fixed KeyError in end_ifset (well, I may have just made -# it go away, rather than fix it) -# 3. BUGFIX allow @menu and menu items inside @ifset or @ifclear -# 4. Support added for: -# @uref URL reference -# @image image file reference (see note below) -# @multitable output an HTML table -# @vtable -# 5. Partial support for accents, to match MAKEINFO output -# 6. I added a new command-line option, '-H basename', to specify -# HTML Help output. This will cause three files to be created -# in the current directory: -# `basename`.hhp HTML Help Workshop project file -# `basename`.hhc Contents file for the project -# `basename`.hhk Index file for the project -# When fed into HTML Help Workshop, the resulting file will be -# named `basename`.chm. -# 7. A new class, HTMLHelp, to accomplish item 6. -# 8. Various calls to HTMLHelp functions. -# A NOTE ON IMAGES: Just as 'outputdirectory' must exist before -# running this program, all referenced images must already exist -# in outputdirectory. - -import os -import sys -import string -import re - -MAGIC = '\\input texinfo' - -cmprog = re.compile('^@([a-z]+)([ \t]|$)') # Command (line-oriented) -blprog = re.compile('^[ \t]*$') # Blank line -kwprog = re.compile('@[a-z]+') # Keyword (embedded, usually - # with {} args) -spprog = re.compile('[\n@{}&<>]') # Special characters in - # running text - # - # menu item (Yuck!) -miprog = re.compile(r'^\* ([^:]*):(:|[ \t]*([^\t,\n.]+)([^ \t\n]*))[ \t\n]*') -# 0 1 1 2 3 34 42 0 -# ----- ---------- --------- -# -|----------------------------- -# ----------------------------------------------------- - - - - -class HTMLNode: - """Some of the parser's functionality is separated into this class. - - A Node accumulates its contents, takes care of links to other Nodes - and saves itself when it is finished and all links are resolved. - """ - - DOCTYPE = '' - - type = 0 - cont = '' - epilogue = '\n' - - def __init__(self, dir, name, topname, title, next, prev, up): - self.dirname = dir - self.name = name - if topname: - self.topname = topname - else: - self.topname = name - self.title = title - self.next = next - self.prev = prev - self.up = up - self.lines = [] - - def write(self, *lines): - for line in lines: - self.lines.append(line) - - def flush(self): - with open(self.dirname + '/' + makefile(self.name), 'w') as fp: - fp.write(self.prologue) - fp.write(self.text) - fp.write(self.epilogue) - - def link(self, label, nodename, rel=None, rev=None): - if nodename: - if nodename.lower() == '(dir)': - addr = '../dir.html' - title = '' - else: - addr = makefile(nodename) - title = ' TITLE="%s"' % nodename - self.write(label, ': ', nodename, ' \n') - - def finalize(self): - length = len(self.lines) - self.text = ''.join(self.lines) - self.lines = [] - self.open_links() - self.output_links() - self.close_links() - links = ''.join(self.lines) - self.lines = [] - self.prologue = ( - self.DOCTYPE + - '\n\n' - ' \n' - ' ' + self.title + '\n' - ' \n' - ' \n' - ' \n' - '\n' + - links) - if length > 20: - self.epilogue = '

\n%s\n' % links - - def open_links(self): - self.write('


\n') - - def close_links(self): - self.write('
\n') - - def output_links(self): - if self.cont != self.next: - self.link(' Cont', self.cont) - self.link(' Next', self.next, rel='Next') - self.link(' Prev', self.prev, rel='Previous') - self.link(' Up', self.up, rel='Up') - if self.name != self.topname: - self.link(' Top', self.topname) - - -class HTML3Node(HTMLNode): - - DOCTYPE = '' - - def open_links(self): - self.write('\n') - - -class TexinfoParser: - - COPYRIGHT_SYMBOL = "©" - FN_ID_PATTERN = "(%(id)s)" - FN_SOURCE_PATTERN = '' \ - + FN_ID_PATTERN + '' - FN_TARGET_PATTERN = '' \ - + FN_ID_PATTERN + '\n%(text)s

\n' - FN_HEADER = '\n

\n


\n' \ - 'Footnotes\n

' - - - Node = HTMLNode - - # Initialize an instance - def __init__(self): - self.unknown = {} # statistics about unknown @-commands - self.filenames = {} # Check for identical filenames - self.debugging = 0 # larger values produce more output - self.print_headers = 0 # always print headers? - self.nodefp = None # open file we're writing to - self.nodelineno = 0 # Linenumber relative to node - self.links = None # Links from current node - self.savetext = None # If not None, save text head instead - self.savestack = [] # If not None, save text head instead - self.htmlhelp = None # html help data - self.dirname = 'tmp' # directory where files are created - self.includedir = '.' # directory to search @include files - self.nodename = '' # name of current node - self.topname = '' # name of top node (first node seen) - self.title = '' # title of this whole Texinfo tree - self.resetindex() # Reset all indices - self.contents = [] # Reset table of contents - self.numbering = [] # Reset section numbering counters - self.nofill = 0 # Normal operation: fill paragraphs - self.values={'html': 1} # Names that should be parsed in ifset - self.stackinfo={} # Keep track of state in the stack - # XXX The following should be reset per node?! - self.footnotes = [] # Reset list of footnotes - self.itemarg = None # Reset command used by @item - self.itemnumber = None # Reset number for @item in @enumerate - self.itemindex = None # Reset item index name - self.node = None - self.nodestack = [] - self.cont = 0 - self.includedepth = 0 - - # Set htmlhelp helper class - def sethtmlhelp(self, htmlhelp): - self.htmlhelp = htmlhelp - - # Set (output) directory name - def setdirname(self, dirname): - self.dirname = dirname - - # Set include directory name - def setincludedir(self, includedir): - self.includedir = includedir - - # Parse the contents of an entire file - def parse(self, fp): - line = fp.readline() - lineno = 1 - while line and (line[0] == '%' or blprog.match(line)): - line = fp.readline() - lineno = lineno + 1 - if line[:len(MAGIC)] != MAGIC: - raise SyntaxError('file does not begin with %r' % (MAGIC,)) - self.parserest(fp, lineno) - - # Parse the contents of a file, not expecting a MAGIC header - def parserest(self, fp, initial_lineno): - lineno = initial_lineno - self.done = 0 - self.skip = 0 - self.stack = [] - accu = [] - while not self.done: - line = fp.readline() - self.nodelineno = self.nodelineno + 1 - if not line: - if accu: - if not self.skip: self.process(accu) - accu = [] - if initial_lineno > 0: - print('*** EOF before @bye') - break - lineno = lineno + 1 - mo = cmprog.match(line) - if mo: - a, b = mo.span(1) - cmd = line[a:b] - if cmd in ('noindent', 'refill'): - accu.append(line) - else: - if accu: - if not self.skip: - self.process(accu) - accu = [] - self.command(line, mo) - elif blprog.match(line) and \ - 'format' not in self.stack and \ - 'example' not in self.stack: - if accu: - if not self.skip: - self.process(accu) - if self.nofill: - self.write('\n') - else: - self.write('

\n') - accu = [] - else: - # Append the line including trailing \n! - accu.append(line) - # - if self.skip: - print('*** Still skipping at the end') - if self.stack: - print('*** Stack not empty at the end') - print('***', self.stack) - if self.includedepth == 0: - while self.nodestack: - self.nodestack[-1].finalize() - self.nodestack[-1].flush() - del self.nodestack[-1] - - # Start saving text in a buffer instead of writing it to a file - def startsaving(self): - if self.savetext is not None: - self.savestack.append(self.savetext) - # print '*** Recursively saving text, expect trouble' - self.savetext = '' - - # Return the text saved so far and start writing to file again - def collectsavings(self): - savetext = self.savetext - if len(self.savestack) > 0: - self.savetext = self.savestack[-1] - del self.savestack[-1] - else: - self.savetext = None - return savetext or '' - - # Write text to file, or save it in a buffer, or ignore it - def write(self, *args): - try: - text = ''.join(args) - except: - print(args) - raise TypeError - if self.savetext is not None: - self.savetext = self.savetext + text - elif self.nodefp: - self.nodefp.write(text) - elif self.node: - self.node.write(text) - - # Complete the current node -- write footnotes and close file - def endnode(self): - if self.savetext is not None: - print('*** Still saving text at end of node') - dummy = self.collectsavings() - if self.footnotes: - self.writefootnotes() - if self.nodefp: - if self.nodelineno > 20: - self.write('


\n') - [name, next, prev, up] = self.nodelinks[:4] - self.link('Next', next) - self.link('Prev', prev) - self.link('Up', up) - if self.nodename != self.topname: - self.link('Top', self.topname) - self.write('
\n') - self.write('\n') - self.nodefp.close() - self.nodefp = None - elif self.node: - if not self.cont and \ - (not self.node.type or \ - (self.node.next and self.node.prev and self.node.up)): - self.node.finalize() - self.node.flush() - else: - self.nodestack.append(self.node) - self.node = None - self.nodename = '' - - # Process a list of lines, expanding embedded @-commands - # This mostly distinguishes between menus and normal text - def process(self, accu): - if self.debugging > 1: - print('!'*self.debugging, 'process:', self.skip, self.stack, end=' ') - if accu: print(accu[0][:30], end=' ') - if accu[0][30:] or accu[1:]: print('...', end=' ') - print() - if self.inmenu(): - # XXX should be done differently - for line in accu: - mo = miprog.match(line) - if not mo: - line = line.strip() + '\n' - self.expand(line) - continue - bgn, end = mo.span(0) - a, b = mo.span(1) - c, d = mo.span(2) - e, f = mo.span(3) - g, h = mo.span(4) - label = line[a:b] - nodename = line[c:d] - if nodename[0] == ':': nodename = label - else: nodename = line[e:f] - punct = line[g:h] - self.write('
  • ', nodename, - '', punct, '\n') - self.htmlhelp.menuitem(nodename) - self.expand(line[end:]) - else: - text = ''.join(accu) - self.expand(text) - - # find 'menu' (we might be inside 'ifset' or 'ifclear') - def inmenu(self): - #if 'menu' in self.stack: - # print 'inmenu :', self.skip, self.stack, self.stackinfo - stack = self.stack - while stack and stack[-1] in ('ifset','ifclear'): - try: - if self.stackinfo[len(stack)]: - return 0 - except KeyError: - pass - stack = stack[:-1] - return (stack and stack[-1] == 'menu') - - # Write a string, expanding embedded @-commands - def expand(self, text): - stack = [] - i = 0 - n = len(text) - while i < n: - start = i - mo = spprog.search(text, i) - if mo: - i = mo.start() - else: - self.write(text[start:]) - break - self.write(text[start:i]) - c = text[i] - i = i+1 - if c == '\n': - self.write('\n') - continue - if c == '<': - self.write('<') - continue - if c == '>': - self.write('>') - continue - if c == '&': - self.write('&') - continue - if c == '{': - stack.append('') - continue - if c == '}': - if not stack: - print('*** Unmatched }') - self.write('}') - continue - cmd = stack[-1] - del stack[-1] - try: - method = getattr(self, 'close_' + cmd) - except AttributeError: - self.unknown_close(cmd) - continue - method() - continue - if c != '@': - # Cannot happen unless spprog is changed - raise RuntimeError('unexpected funny %r' % c) - start = i - while i < n and text[i] in string.ascii_letters: i = i+1 - if i == start: - # @ plus non-letter: literal next character - i = i+1 - c = text[start:i] - if c == ':': - # `@:' means no extra space after - # preceding `.', `?', `!' or `:' - pass - else: - # `@.' means a sentence-ending period; - # `@@', `@{', `@}' quote `@', `{', `}' - self.write(c) - continue - cmd = text[start:i] - if i < n and text[i] == '{': - i = i+1 - stack.append(cmd) - try: - method = getattr(self, 'open_' + cmd) - except AttributeError: - self.unknown_open(cmd) - continue - method() - continue - try: - method = getattr(self, 'handle_' + cmd) - except AttributeError: - self.unknown_handle(cmd) - continue - method() - if stack: - print('*** Stack not empty at para:', stack) - - # --- Handle unknown embedded @-commands --- - - def unknown_open(self, cmd): - print('*** No open func for @' + cmd + '{...}') - cmd = cmd + '{' - self.write('@', cmd) - if cmd not in self.unknown: - self.unknown[cmd] = 1 - else: - self.unknown[cmd] = self.unknown[cmd] + 1 - - def unknown_close(self, cmd): - print('*** No close func for @' + cmd + '{...}') - cmd = '}' + cmd - self.write('}') - if cmd not in self.unknown: - self.unknown[cmd] = 1 - else: - self.unknown[cmd] = self.unknown[cmd] + 1 - - def unknown_handle(self, cmd): - print('*** No handler for @' + cmd) - self.write('@', cmd) - if cmd not in self.unknown: - self.unknown[cmd] = 1 - else: - self.unknown[cmd] = self.unknown[cmd] + 1 - - # XXX The following sections should be ordered as the texinfo docs - - # --- Embedded @-commands without {} argument list -- - - def handle_noindent(self): pass - - def handle_refill(self): pass - - # --- Include file handling --- - - def do_include(self, args): - file = args - file = os.path.join(self.includedir, file) - try: - fp = open(file, 'r') - except IOError as msg: - print('*** Can\'t open include file', repr(file)) - return - with fp: - print('!'*self.debugging, '--> file', repr(file)) - save_done = self.done - save_skip = self.skip - save_stack = self.stack - self.includedepth = self.includedepth + 1 - self.parserest(fp, 0) - self.includedepth = self.includedepth - 1 - self.done = save_done - self.skip = save_skip - self.stack = save_stack - print('!'*self.debugging, '<-- file', repr(file)) - - # --- Special Insertions --- - - def open_dmn(self): pass - def close_dmn(self): pass - - def open_dots(self): self.write('...') - def close_dots(self): pass - - def open_bullet(self): pass - def close_bullet(self): pass - - def open_TeX(self): self.write('TeX') - def close_TeX(self): pass - - def handle_copyright(self): self.write(self.COPYRIGHT_SYMBOL) - def open_copyright(self): self.write(self.COPYRIGHT_SYMBOL) - def close_copyright(self): pass - - def open_minus(self): self.write('-') - def close_minus(self): pass - - # --- Accents --- - - # rpyron 2002-05-07 - # I would like to do at least as well as makeinfo when - # it is producing HTML output: - # - # input output - # @"o @"o umlaut accent - # @'o 'o acute accent - # @,{c} @,{c} cedilla accent - # @=o @=o macron/overbar accent - # @^o @^o circumflex accent - # @`o `o grave accent - # @~o @~o tilde accent - # @dotaccent{o} @dotaccent{o} overdot accent - # @H{o} @H{o} long Hungarian umlaut - # @ringaccent{o} @ringaccent{o} ring accent - # @tieaccent{oo} @tieaccent{oo} tie-after accent - # @u{o} @u{o} breve accent - # @ubaraccent{o} @ubaraccent{o} underbar accent - # @udotaccent{o} @udotaccent{o} underdot accent - # @v{o} @v{o} hacek or check accent - # @exclamdown{} ¡ upside-down ! - # @questiondown{} ¿ upside-down ? - # @aa{}, at AA{} å,Å a,A with circle - # @ae{}, at AE{} æ,Æ ae,AE ligatures - # @dotless{i} @dotless{i} dotless i - # @dotless{j} @dotless{j} dotless j - # @l{}, at L{} l/,L/ suppressed-L,l - # @o{}, at O{} ø,Ø O,o with slash - # @oe{}, at OE{} oe,OE oe,OE ligatures - # @ss{} ß es-zet or sharp S - # - # The following character codes and approximations have been - # copied from makeinfo's HTML output. - - def open_exclamdown(self): self.write('¡') # upside-down ! - def close_exclamdown(self): pass - def open_questiondown(self): self.write('¿') # upside-down ? - def close_questiondown(self): pass - def open_aa(self): self.write('å') # a with circle - def close_aa(self): pass - def open_AA(self): self.write('Å') # A with circle - def close_AA(self): pass - def open_ae(self): self.write('æ') # ae ligatures - def close_ae(self): pass - def open_AE(self): self.write('Æ') # AE ligatures - def close_AE(self): pass - def open_o(self): self.write('ø') # o with slash - def close_o(self): pass - def open_O(self): self.write('Ø') # O with slash - def close_O(self): pass - def open_ss(self): self.write('ß') # es-zet or sharp S - def close_ss(self): pass - def open_oe(self): self.write('oe') # oe ligatures - def close_oe(self): pass - def open_OE(self): self.write('OE') # OE ligatures - def close_OE(self): pass - def open_l(self): self.write('l/') # suppressed-l - def close_l(self): pass - def open_L(self): self.write('L/') # suppressed-L - def close_L(self): pass - - # --- Special Glyphs for Examples --- - - def open_result(self): self.write('=>') - def close_result(self): pass - - def open_expansion(self): self.write('==>') - def close_expansion(self): pass - - def open_print(self): self.write('-|') - def close_print(self): pass - - def open_error(self): self.write('error-->') - def close_error(self): pass - - def open_equiv(self): self.write('==') - def close_equiv(self): pass - - def open_point(self): self.write('-!-') - def close_point(self): pass - - # --- Cross References --- - - def open_pxref(self): - self.write('see ') - self.startsaving() - def close_pxref(self): - self.makeref() - - def open_xref(self): - self.write('See ') - self.startsaving() - def close_xref(self): - self.makeref() - - def open_ref(self): - self.startsaving() - def close_ref(self): - self.makeref() - - def open_inforef(self): - self.write('See info file ') - self.startsaving() - def close_inforef(self): - text = self.collectsavings() - args = [s.strip() for s in text.split(',')] - while len(args) < 3: args.append('') - node = args[0] - file = args[2] - self.write('`', file, '\', node `', node, '\'') - - def makeref(self): - text = self.collectsavings() - args = [s.strip() for s in text.split(',')] - while len(args) < 5: args.append('') - nodename = label = args[0] - if args[2]: label = args[2] - file = args[3] - title = args[4] - href = makefile(nodename) - if file: - href = '../' + file + '/' + href - self.write('', label, '') - - # rpyron 2002-05-07 uref support - def open_uref(self): - self.startsaving() - def close_uref(self): - text = self.collectsavings() - args = [s.strip() for s in text.split(',')] - while len(args) < 2: args.append('') - href = args[0] - label = args[1] - if not label: label = href - self.write('', label, '') - - # rpyron 2002-05-07 image support - # GNU makeinfo producing HTML output tries `filename.png'; if - # that does not exist, it tries `filename.jpg'. If that does - # not exist either, it complains. GNU makeinfo does not handle - # GIF files; however, I include GIF support here because - # MySQL documentation uses GIF files. - - def open_image(self): - self.startsaving() - def close_image(self): - self.makeimage() - def makeimage(self): - text = self.collectsavings() - args = [s.strip() for s in text.split(',')] - while len(args) < 5: args.append('') - filename = args[0] - width = args[1] - height = args[2] - alt = args[3] - ext = args[4] - - # The HTML output will have a reference to the image - # that is relative to the HTML output directory, - # which is what 'filename' gives us. However, we need - # to find it relative to our own current directory, - # so we construct 'imagename'. - imagelocation = self.dirname + '/' + filename - - if os.path.exists(imagelocation+'.png'): - filename += '.png' - elif os.path.exists(imagelocation+'.jpg'): - filename += '.jpg' - elif os.path.exists(imagelocation+'.gif'): # MySQL uses GIF files - filename += '.gif' - else: - print("*** Cannot find image " + imagelocation) - #TODO: what is 'ext'? - self.write('' ) - self.htmlhelp.addimage(imagelocation) - - - # --- Marking Words and Phrases --- - - # --- Other @xxx{...} commands --- - - def open_(self): pass # Used by {text enclosed in braces} - def close_(self): pass - - open_asis = open_ - close_asis = close_ - - def open_cite(self): self.write('') - def close_cite(self): self.write('') - - def open_code(self): self.write('') - def close_code(self): self.write('') - - def open_t(self): self.write('') - def close_t(self): self.write('') - - def open_dfn(self): self.write('') - def close_dfn(self): self.write('') - - def open_emph(self): self.write('') - def close_emph(self): self.write('') - - def open_i(self): self.write('') - def close_i(self): self.write('') - - def open_footnote(self): - # if self.savetext is not None: - # print '*** Recursive footnote -- expect weirdness' - id = len(self.footnotes) + 1 - self.write(self.FN_SOURCE_PATTERN % {'id': repr(id)}) - self.startsaving() - - def close_footnote(self): - id = len(self.footnotes) + 1 - self.footnotes.append((id, self.collectsavings())) - - def writefootnotes(self): - self.write(self.FN_HEADER) - for id, text in self.footnotes: - self.write(self.FN_TARGET_PATTERN - % {'id': repr(id), 'text': text}) - self.footnotes = [] - - def open_file(self): self.write('') - def close_file(self): self.write('') - - def open_kbd(self): self.write('') - def close_kbd(self): self.write('') - - def open_key(self): self.write('') - def close_key(self): self.write('') - - def open_r(self): self.write('') - def close_r(self): self.write('') - - def open_samp(self): self.write('`') - def close_samp(self): self.write('\'') - - def open_sc(self): self.write('') - def close_sc(self): self.write('') - - def open_strong(self): self.write('') - def close_strong(self): self.write('') - - def open_b(self): self.write('') - def close_b(self): self.write('') - - def open_var(self): self.write('') - def close_var(self): self.write('') - - def open_w(self): self.write('') - def close_w(self): self.write('') - - def open_url(self): self.startsaving() - def close_url(self): - text = self.collectsavings() - self.write('', text, '') - - def open_email(self): self.startsaving() - def close_email(self): - text = self.collectsavings() - self.write('', text, '') - - open_titlefont = open_ - close_titlefont = close_ - - def open_small(self): pass - def close_small(self): pass - - def command(self, line, mo): - a, b = mo.span(1) - cmd = line[a:b] - args = line[b:].strip() - if self.debugging > 1: - print('!'*self.debugging, 'command:', self.skip, self.stack, \ - '@' + cmd, args) - try: - func = getattr(self, 'do_' + cmd) - except AttributeError: - try: - func = getattr(self, 'bgn_' + cmd) - except AttributeError: - # don't complain if we are skipping anyway - if not self.skip: - self.unknown_cmd(cmd, args) - return - self.stack.append(cmd) - func(args) - return - if not self.skip or cmd == 'end': - func(args) - - def unknown_cmd(self, cmd, args): - print('*** unknown', '@' + cmd, args) - if cmd not in self.unknown: - self.unknown[cmd] = 1 - else: - self.unknown[cmd] = self.unknown[cmd] + 1 - - def do_end(self, args): - words = args.split() - if not words: - print('*** @end w/o args') - else: - cmd = words[0] - if not self.stack or self.stack[-1] != cmd: - print('*** @end', cmd, 'unexpected') - else: - del self.stack[-1] - try: - func = getattr(self, 'end_' + cmd) - except AttributeError: - self.unknown_end(cmd) - return - func() - - def unknown_end(self, cmd): - cmd = 'end ' + cmd - print('*** unknown', '@' + cmd) - if cmd not in self.unknown: - self.unknown[cmd] = 1 - else: - self.unknown[cmd] = self.unknown[cmd] + 1 - - # --- Comments --- - - def do_comment(self, args): pass - do_c = do_comment - - # --- Conditional processing --- - - def bgn_ifinfo(self, args): pass - def end_ifinfo(self): pass - - def bgn_iftex(self, args): self.skip = self.skip + 1 - def end_iftex(self): self.skip = self.skip - 1 - - def bgn_ignore(self, args): self.skip = self.skip + 1 - def end_ignore(self): self.skip = self.skip - 1 - - def bgn_tex(self, args): self.skip = self.skip + 1 - def end_tex(self): self.skip = self.skip - 1 - - def do_set(self, args): - fields = args.split(' ') - key = fields[0] - if len(fields) == 1: - value = 1 - else: - value = ' '.join(fields[1:]) - self.values[key] = value - - def do_clear(self, args): - self.values[args] = None - - def bgn_ifset(self, args): - if args not in self.values or self.values[args] is None: - self.skip = self.skip + 1 - self.stackinfo[len(self.stack)] = 1 - else: - self.stackinfo[len(self.stack)] = 0 - def end_ifset(self): - try: - if self.stackinfo[len(self.stack) + 1]: - self.skip = self.skip - 1 - del self.stackinfo[len(self.stack) + 1] - except KeyError: - print('*** end_ifset: KeyError :', len(self.stack) + 1) - - def bgn_ifclear(self, args): - if args in self.values and self.values[args] is not None: - self.skip = self.skip + 1 - self.stackinfo[len(self.stack)] = 1 - else: - self.stackinfo[len(self.stack)] = 0 - def end_ifclear(self): - try: - if self.stackinfo[len(self.stack) + 1]: - self.skip = self.skip - 1 - del self.stackinfo[len(self.stack) + 1] - except KeyError: - print('*** end_ifclear: KeyError :', len(self.stack) + 1) - - def open_value(self): - self.startsaving() - - def close_value(self): - key = self.collectsavings() - if key in self.values: - self.write(self.values[key]) - else: - print('*** Undefined value: ', key) - - # --- Beginning a file --- - - do_finalout = do_comment - do_setchapternewpage = do_comment - do_setfilename = do_comment - - def do_settitle(self, args): - self.startsaving() - self.expand(args) - self.title = self.collectsavings() - def do_parskip(self, args): pass - - # --- Ending a file --- - - def do_bye(self, args): - self.endnode() - self.done = 1 - - # --- Title page --- - - def bgn_titlepage(self, args): self.skip = self.skip + 1 - def end_titlepage(self): self.skip = self.skip - 1 - def do_shorttitlepage(self, args): pass - - def do_center(self, args): - # Actually not used outside title page... - self.write('

    ') - self.expand(args) - self.write('

    \n') - do_title = do_center - do_subtitle = do_center - do_author = do_center - - do_vskip = do_comment - do_vfill = do_comment - do_smallbook = do_comment - - do_paragraphindent = do_comment - do_setchapternewpage = do_comment - do_headings = do_comment - do_footnotestyle = do_comment - - do_evenheading = do_comment - do_evenfooting = do_comment - do_oddheading = do_comment - do_oddfooting = do_comment - do_everyheading = do_comment - do_everyfooting = do_comment - - # --- Nodes --- - - def do_node(self, args): - self.endnode() - self.nodelineno = 0 - parts = [s.strip() for s in args.split(',')] - while len(parts) < 4: parts.append('') - self.nodelinks = parts - [name, next, prev, up] = parts[:4] - file = self.dirname + '/' + makefile(name) - if file in self.filenames: - print('*** Filename already in use: ', file) - else: - if self.debugging: print('!'*self.debugging, '--- writing', file) - self.filenames[file] = 1 - # self.nodefp = open(file, 'w') - self.nodename = name - if self.cont and self.nodestack: - self.nodestack[-1].cont = self.nodename - if not self.topname: self.topname = name - title = name - if self.title: title = title + ' -- ' + self.title - self.node = self.Node(self.dirname, self.nodename, self.topname, - title, next, prev, up) - self.htmlhelp.addnode(self.nodename,next,prev,up,file) - - def link(self, label, nodename): - if nodename: - if nodename.lower() == '(dir)': - addr = '../dir.html' - else: - addr = makefile(nodename) - self.write(label, ': ', nodename, ' \n') - - # --- Sectioning commands --- - - def popstack(self, type): - if (self.node): - self.node.type = type - while self.nodestack: - if self.nodestack[-1].type > type: - self.nodestack[-1].finalize() - self.nodestack[-1].flush() - del self.nodestack[-1] - elif self.nodestack[-1].type == type: - if not self.nodestack[-1].next: - self.nodestack[-1].next = self.node.name - if not self.node.prev: - self.node.prev = self.nodestack[-1].name - self.nodestack[-1].finalize() - self.nodestack[-1].flush() - del self.nodestack[-1] - else: - if type > 1 and not self.node.up: - self.node.up = self.nodestack[-1].name - break - - def do_chapter(self, args): - self.heading('H1', args, 0) - self.popstack(1) - - def do_unnumbered(self, args): - self.heading('H1', args, -1) - self.popstack(1) - def do_appendix(self, args): - self.heading('H1', args, -1) - self.popstack(1) - def do_top(self, args): - self.heading('H1', args, -1) - def do_chapheading(self, args): - self.heading('H1', args, -1) - def do_majorheading(self, args): - self.heading('H1', args, -1) - - def do_section(self, args): - self.heading('H1', args, 1) - self.popstack(2) - - def do_unnumberedsec(self, args): - self.heading('H1', args, -1) - self.popstack(2) - def do_appendixsec(self, args): - self.heading('H1', args, -1) - self.popstack(2) - do_appendixsection = do_appendixsec - def do_heading(self, args): - self.heading('H1', args, -1) - - def do_subsection(self, args): - self.heading('H2', args, 2) - self.popstack(3) - def do_unnumberedsubsec(self, args): - self.heading('H2', args, -1) - self.popstack(3) - def do_appendixsubsec(self, args): - self.heading('H2', args, -1) - self.popstack(3) - def do_subheading(self, args): - self.heading('H2', args, -1) - - def do_subsubsection(self, args): - self.heading('H3', args, 3) - self.popstack(4) - def do_unnumberedsubsubsec(self, args): - self.heading('H3', args, -1) - self.popstack(4) - def do_appendixsubsubsec(self, args): - self.heading('H3', args, -1) - self.popstack(4) - def do_subsubheading(self, args): - self.heading('H3', args, -1) - - def heading(self, type, args, level): - if level >= 0: - while len(self.numbering) <= level: - self.numbering.append(0) - del self.numbering[level+1:] - self.numbering[level] = self.numbering[level] + 1 - x = '' - for i in self.numbering: - x = x + repr(i) + '.' - args = x + ' ' + args - self.contents.append((level, args, self.nodename)) - self.write('<', type, '>') - self.expand(args) - self.write('\n') - if self.debugging or self.print_headers: - print('---', args) - - def do_contents(self, args): - # pass - self.listcontents('Table of Contents', 999) - - def do_shortcontents(self, args): - pass - # self.listcontents('Short Contents', 0) - do_summarycontents = do_shortcontents - - def listcontents(self, title, maxlevel): - self.write('

    ', title, '

    \n
      \n') - prevlevels = [0] - for level, title, node in self.contents: - if level > maxlevel: - continue - if level > prevlevels[-1]: - # can only advance one level at a time - self.write(' '*prevlevels[-1], '
        \n') - prevlevels.append(level) - elif level < prevlevels[-1]: - # might drop back multiple levels - while level < prevlevels[-1]: - del prevlevels[-1] - self.write(' '*prevlevels[-1], - '
      \n') - self.write(' '*level, '
    • ') - self.expand(title) - self.write('\n') - self.write('
    \n' * len(prevlevels)) - - # --- Page lay-out --- - - # These commands are only meaningful in printed text - - def do_page(self, args): pass - - def do_need(self, args): pass - - def bgn_group(self, args): pass - def end_group(self): pass - - # --- Line lay-out --- - - def do_sp(self, args): - if self.nofill: - self.write('\n') - else: - self.write('

    \n') - - def do_hline(self, args): - self.write('


    ') - - # --- Function and variable definitions --- - - def bgn_deffn(self, args): - self.write('
    ') - self.do_deffnx(args) - - def end_deffn(self): - self.write('
    \n') - - def do_deffnx(self, args): - self.write('
    ') - words = splitwords(args, 2) - [category, name], rest = words[:2], words[2:] - self.expand('@b{%s}' % name) - for word in rest: self.expand(' ' + makevar(word)) - #self.expand(' -- ' + category) - self.write('\n
    ') - self.index('fn', name) - - def bgn_defun(self, args): self.bgn_deffn('Function ' + args) - end_defun = end_deffn - def do_defunx(self, args): self.do_deffnx('Function ' + args) - - def bgn_defmac(self, args): self.bgn_deffn('Macro ' + args) - end_defmac = end_deffn - def do_defmacx(self, args): self.do_deffnx('Macro ' + args) - - def bgn_defspec(self, args): self.bgn_deffn('{Special Form} ' + args) - end_defspec = end_deffn - def do_defspecx(self, args): self.do_deffnx('{Special Form} ' + args) - - def bgn_defvr(self, args): - self.write('
    ') - self.do_defvrx(args) - - end_defvr = end_deffn - - def do_defvrx(self, args): - self.write('
    ') - words = splitwords(args, 2) - [category, name], rest = words[:2], words[2:] - self.expand('@code{%s}' % name) - # If there are too many arguments, show them - for word in rest: self.expand(' ' + word) - #self.expand(' -- ' + category) - self.write('\n
    ') - self.index('vr', name) - - def bgn_defvar(self, args): self.bgn_defvr('Variable ' + args) - end_defvar = end_defvr - def do_defvarx(self, args): self.do_defvrx('Variable ' + args) - - def bgn_defopt(self, args): self.bgn_defvr('{User Option} ' + args) - end_defopt = end_defvr - def do_defoptx(self, args): self.do_defvrx('{User Option} ' + args) - - # --- Ditto for typed languages --- - - def bgn_deftypefn(self, args): - self.write('
    ') - self.do_deftypefnx(args) - - end_deftypefn = end_deffn - - def do_deftypefnx(self, args): - self.write('
    ') - words = splitwords(args, 3) - [category, datatype, name], rest = words[:3], words[3:] - self.expand('@code{%s} @b{%s}' % (datatype, name)) - for word in rest: self.expand(' ' + makevar(word)) - #self.expand(' -- ' + category) - self.write('\n
    ') - self.index('fn', name) - - - def bgn_deftypefun(self, args): self.bgn_deftypefn('Function ' + args) - end_deftypefun = end_deftypefn - def do_deftypefunx(self, args): self.do_deftypefnx('Function ' + args) - - def bgn_deftypevr(self, args): - self.write('
    ') - self.do_deftypevrx(args) - - end_deftypevr = end_deftypefn - - def do_deftypevrx(self, args): - self.write('
    ') - words = splitwords(args, 3) - [category, datatype, name], rest = words[:3], words[3:] - self.expand('@code{%s} @b{%s}' % (datatype, name)) - # If there are too many arguments, show them - for word in rest: self.expand(' ' + word) - #self.expand(' -- ' + category) - self.write('\n
    ') - self.index('fn', name) - - def bgn_deftypevar(self, args): - self.bgn_deftypevr('Variable ' + args) - end_deftypevar = end_deftypevr - def do_deftypevarx(self, args): - self.do_deftypevrx('Variable ' + args) - - # --- Ditto for object-oriented languages --- - - def bgn_defcv(self, args): - self.write('
    ') - self.do_defcvx(args) - - end_defcv = end_deftypevr - - def do_defcvx(self, args): - self.write('
    ') - words = splitwords(args, 3) - [category, classname, name], rest = words[:3], words[3:] - self.expand('@b{%s}' % name) - # If there are too many arguments, show them - for word in rest: self.expand(' ' + word) - #self.expand(' -- %s of @code{%s}' % (category, classname)) - self.write('\n
    ') - self.index('vr', '%s @r{on %s}' % (name, classname)) - - def bgn_defivar(self, args): - self.bgn_defcv('{Instance Variable} ' + args) - end_defivar = end_defcv - def do_defivarx(self, args): - self.do_defcvx('{Instance Variable} ' + args) - - def bgn_defop(self, args): - self.write('
    ') - self.do_defopx(args) - - end_defop = end_defcv - - def do_defopx(self, args): - self.write('
    ') - words = splitwords(args, 3) - [category, classname, name], rest = words[:3], words[3:] - self.expand('@b{%s}' % name) - for word in rest: self.expand(' ' + makevar(word)) - #self.expand(' -- %s of @code{%s}' % (category, classname)) - self.write('\n
    ') - self.index('fn', '%s @r{on %s}' % (name, classname)) - - def bgn_defmethod(self, args): - self.bgn_defop('Method ' + args) - end_defmethod = end_defop - def do_defmethodx(self, args): - self.do_defopx('Method ' + args) - - # --- Ditto for data types --- - - def bgn_deftp(self, args): - self.write('
    ') - self.do_deftpx(args) - - end_deftp = end_defcv - - def do_deftpx(self, args): - self.write('
    ') - words = splitwords(args, 2) - [category, name], rest = words[:2], words[2:] - self.expand('@b{%s}' % name) - for word in rest: self.expand(' ' + word) - #self.expand(' -- ' + category) - self.write('\n
    ') - self.index('tp', name) - - # --- Making Lists and Tables - - def bgn_enumerate(self, args): - if not args: - self.write('
      \n') - self.stackinfo[len(self.stack)] = '
    \n' - else: - self.itemnumber = args - self.write('
      \n') - self.stackinfo[len(self.stack)] = '
    \n' - def end_enumerate(self): - self.itemnumber = None - self.write(self.stackinfo[len(self.stack) + 1]) - del self.stackinfo[len(self.stack) + 1] - - def bgn_itemize(self, args): - self.itemarg = args - self.write('
      \n') - def end_itemize(self): - self.itemarg = None - self.write('
    \n') - - def bgn_table(self, args): - self.itemarg = args - self.write('
    \n') - def end_table(self): - self.itemarg = None - self.write('
    \n') - - def bgn_ftable(self, args): - self.itemindex = 'fn' - self.bgn_table(args) - def end_ftable(self): - self.itemindex = None - self.end_table() - - def bgn_vtable(self, args): - self.itemindex = 'vr' - self.bgn_table(args) - def end_vtable(self): - self.itemindex = None - self.end_table() - - def do_item(self, args): - if self.itemindex: self.index(self.itemindex, args) - if self.itemarg: - if self.itemarg[0] == '@' and self.itemarg[1] and \ - self.itemarg[1] in string.ascii_letters: - args = self.itemarg + '{' + args + '}' - else: - # some other character, e.g. '-' - args = self.itemarg + ' ' + args - if self.itemnumber is not None: - args = self.itemnumber + '. ' + args - self.itemnumber = increment(self.itemnumber) - if self.stack and self.stack[-1] == 'table': - self.write('
    ') - self.expand(args) - self.write('\n
    ') - elif self.stack and self.stack[-1] == 'multitable': - self.write('') - self.expand(args) - self.write('\n\n') - else: - self.write('
  • ') - self.expand(args) - self.write(' ') - do_itemx = do_item # XXX Should suppress leading blank line - - # rpyron 2002-05-07 multitable support - def bgn_multitable(self, args): - self.itemarg = None # should be handled by columnfractions - self.write('\n') - def end_multitable(self): - self.itemarg = None - self.write('
    \n
    \n') - def handle_columnfractions(self): - # It would be better to handle this, but for now it's in the way... - self.itemarg = None - def handle_tab(self): - self.write('\n ') - - # --- Enumerations, displays, quotations --- - # XXX Most of these should increase the indentation somehow - - def bgn_quotation(self, args): self.write('
    ') - def end_quotation(self): self.write('
    \n') - - def bgn_example(self, args): - self.nofill = self.nofill + 1 - self.write('
    ')
    -    def end_example(self):
    -        self.write('
    \n') - self.nofill = self.nofill - 1 - - bgn_lisp = bgn_example # Synonym when contents are executable lisp code - end_lisp = end_example - - bgn_smallexample = bgn_example # XXX Should use smaller font - end_smallexample = end_example - - bgn_smalllisp = bgn_lisp # Ditto - end_smalllisp = end_lisp - - bgn_display = bgn_example - end_display = end_example - - bgn_format = bgn_display - end_format = end_display - - def do_exdent(self, args): self.expand(args + '\n') - # XXX Should really mess with indentation - - def bgn_flushleft(self, args): - self.nofill = self.nofill + 1 - self.write('
    \n')
    -    def end_flushleft(self):
    -        self.write('
    \n') - self.nofill = self.nofill - 1 - - def bgn_flushright(self, args): - self.nofill = self.nofill + 1 - self.write('
    \n') - def end_flushright(self): - self.write('
    \n') - self.nofill = self.nofill - 1 - - def bgn_menu(self, args): - self.write('\n') - self.write(' Menu

    \n') - self.htmlhelp.beginmenu() - def end_menu(self): - self.write('

    \n') - self.htmlhelp.endmenu() - - def bgn_cartouche(self, args): pass - def end_cartouche(self): pass - - # --- Indices --- - - def resetindex(self): - self.noncodeindices = ['cp'] - self.indextitle = {} - self.indextitle['cp'] = 'Concept' - self.indextitle['fn'] = 'Function' - self.indextitle['ky'] = 'Keyword' - self.indextitle['pg'] = 'Program' - self.indextitle['tp'] = 'Type' - self.indextitle['vr'] = 'Variable' - # - self.whichindex = {} - for name in self.indextitle: - self.whichindex[name] = [] - - def user_index(self, name, args): - if name in self.whichindex: - self.index(name, args) - else: - print('*** No index named', repr(name)) - - def do_cindex(self, args): self.index('cp', args) - def do_findex(self, args): self.index('fn', args) - def do_kindex(self, args): self.index('ky', args) - def do_pindex(self, args): self.index('pg', args) - def do_tindex(self, args): self.index('tp', args) - def do_vindex(self, args): self.index('vr', args) - - def index(self, name, args): - self.whichindex[name].append((args, self.nodename)) - self.htmlhelp.index(args, self.nodename) - - def do_synindex(self, args): - words = args.split() - if len(words) != 2: - print('*** bad @synindex', args) - return - [old, new] = words - if old not in self.whichindex or \ - new not in self.whichindex: - print('*** bad key(s) in @synindex', args) - return - if old != new and \ - self.whichindex[old] is not self.whichindex[new]: - inew = self.whichindex[new] - inew[len(inew):] = self.whichindex[old] - self.whichindex[old] = inew - do_syncodeindex = do_synindex # XXX Should use code font - - def do_printindex(self, args): - words = args.split() - for name in words: - if name in self.whichindex: - self.prindex(name) - else: - print('*** No index named', repr(name)) - - def prindex(self, name): - iscodeindex = (name not in self.noncodeindices) - index = self.whichindex[name] - if not index: return - if self.debugging: - print('!'*self.debugging, '--- Generating', \ - self.indextitle[name], 'index') - # The node already provides a title - index1 = [] - junkprog = re.compile('^(@[a-z]+)?{') - for key, node in index: - sortkey = key.lower() - # Remove leading `@cmd{' from sort key - # -- don't bother about the matching `}' - oldsortkey = sortkey - while 1: - mo = junkprog.match(sortkey) - if not mo: - break - i = mo.end() - sortkey = sortkey[i:] - index1.append((sortkey, key, node)) - del index[:] - index1.sort() - self.write('
    \n') - prevkey = prevnode = None - for sortkey, key, node in index1: - if (key, node) == (prevkey, prevnode): - continue - if self.debugging > 1: print('!'*self.debugging, key, ':', node) - self.write('
    ') - if iscodeindex: key = '@code{' + key + '}' - if key != prevkey: - self.expand(key) - self.write('\n
    %s\n' % (makefile(node), node)) - prevkey, prevnode = key, node - self.write('
    \n') - - # --- Final error reports --- - - def report(self): - if self.unknown: - print('--- Unrecognized commands ---') - cmds = sorted(self.unknown.keys()) - for cmd in cmds: - print(cmd.ljust(20), self.unknown[cmd]) - - -class TexinfoParserHTML3(TexinfoParser): - - COPYRIGHT_SYMBOL = "©" - FN_ID_PATTERN = "[%(id)s]" - FN_SOURCE_PATTERN = '' + FN_ID_PATTERN + '' - FN_TARGET_PATTERN = '\n' \ - '

    ' + FN_ID_PATTERN \ - + '\n%(text)s

    \n' - FN_HEADER = '
    \n
    \n' \ - ' Footnotes\n

    \n' - - Node = HTML3Node - - def bgn_quotation(self, args): self.write('') - def end_quotation(self): self.write('\n') - - def bgn_example(self, args): - # this use of would not be legal in HTML 2.0, - # but is in more recent DTDs. - self.nofill = self.nofill + 1 - self.write('

    ')
    -    def end_example(self):
    -        self.write("
    \n") - self.nofill = self.nofill - 1 - - def bgn_flushleft(self, args): - self.nofill = self.nofill + 1 - self.write('
    \n')
    -
    -    def bgn_flushright(self, args):
    -        self.nofill = self.nofill + 1
    -        self.write('
    \n') - def end_flushright(self): - self.write('
    \n') - self.nofill = self.nofill - 1 - - def bgn_menu(self, args): - self.write('\n') - - -# rpyron 2002-05-07 -class HTMLHelp: - """ - This class encapsulates support for HTML Help. Node names, - file names, menu items, index items, and image file names are - accumulated until a call to finalize(). At that time, three - output files are created in the current directory: - - `helpbase`.hhp is a HTML Help Workshop project file. - It contains various information, some of - which I do not understand; I just copied - the default project info from a fresh - installation. - `helpbase`.hhc is the Contents file for the project. - `helpbase`.hhk is the Index file for the project. - - When these files are used as input to HTML Help Workshop, - the resulting file will be named: - - `helpbase`.chm - - If none of the defaults in `helpbase`.hhp are changed, - the .CHM file will have Contents, Index, Search, and - Favorites tabs. - """ - - codeprog = re.compile('@code{(.*?)}') - - def __init__(self,helpbase,dirname): - self.helpbase = helpbase - self.dirname = dirname - self.projectfile = None - self.contentfile = None - self.indexfile = None - self.nodelist = [] - self.nodenames = {} # nodename : index - self.nodeindex = {} - self.filenames = {} # filename : filename - self.indexlist = [] # (args,nodename) == (key,location) - self.current = '' - self.menudict = {} - self.dumped = {} - - - def addnode(self,name,next,prev,up,filename): - node = (name,next,prev,up,filename) - # add this file to dict - # retrieve list with self.filenames.values() - self.filenames[filename] = filename - # add this node to nodelist - self.nodeindex[name] = len(self.nodelist) - self.nodelist.append(node) - # set 'current' for menu items - self.current = name - self.menudict[self.current] = [] - - def menuitem(self,nodename): - menu = self.menudict[self.current] - menu.append(nodename) - - - def addimage(self,imagename): - self.filenames[imagename] = imagename - - def index(self, args, nodename): - self.indexlist.append((args,nodename)) - - def beginmenu(self): - pass - - def endmenu(self): - pass - - def finalize(self): - if not self.helpbase: - return - - # generate interesting filenames - resultfile = self.helpbase + '.chm' - projectfile = self.helpbase + '.hhp' - contentfile = self.helpbase + '.hhc' - indexfile = self.helpbase + '.hhk' - - # generate a reasonable title - title = self.helpbase - - # get the default topic file - (topname,topnext,topprev,topup,topfile) = self.nodelist[0] - defaulttopic = topfile - - # PROJECT FILE - try: - with open(projectfile, 'w') as fp: - print('[OPTIONS]', file=fp) - print('Auto Index=Yes', file=fp) - print('Binary TOC=No', file=fp) - print('Binary Index=Yes', file=fp) - print('Compatibility=1.1', file=fp) - print('Compiled file=' + resultfile + '', file=fp) - print('Contents file=' + contentfile + '', file=fp) - print('Default topic=' + defaulttopic + '', file=fp) - print('Error log file=ErrorLog.log', file=fp) - print('Index file=' + indexfile + '', file=fp) - print('Title=' + title + '', file=fp) - print('Display compile progress=Yes', file=fp) - print('Full-text search=Yes', file=fp) - print('Default window=main', file=fp) - print('', file=fp) - print('[WINDOWS]', file=fp) - print('main=,"' + contentfile + '","' + indexfile - + '","","",,,,,0x23520,222,0x1046,[10,10,780,560],' - '0xB0000,,,,,,0', file=fp) - print('', file=fp) - print('[FILES]', file=fp) - print('', file=fp) - self.dumpfiles(fp) - except IOError as msg: - print(projectfile, ':', msg) - sys.exit(1) - - # CONTENT FILE - try: - with open(contentfile, 'w') as fp: - print('', file=fp) - print('', file=fp) - print('', file=fp) - print('', file=fp) - print('', file=fp) - print('', file=fp) - print('', file=fp) - print('', file=fp) - print(' ', file=fp) - print(' ', file=fp) - print(' ', file=fp) - print(' ', file=fp) - print(' ', file=fp) - self.dumpnodes(fp) - print('', file=fp) - print('', file=fp) - except IOError as msg: - print(contentfile, ':', msg) - sys.exit(1) - - # INDEX FILE - try: - with open(indexfile, 'w') as fp: - print('', file=fp) - print('', file=fp) - print('', file=fp) - print('', file=fp) - print('', file=fp) - print('', file=fp) - print('', file=fp) - print('', file=fp) - print('', file=fp) - print('', file=fp) - self.dumpindex(fp) - print('', file=fp) - print('', file=fp) - except IOError as msg: - print(indexfile , ':', msg) - sys.exit(1) - - def dumpfiles(self, outfile=sys.stdout): - filelist = sorted(self.filenames.values()) - for filename in filelist: - print(filename, file=outfile) - - def dumpnodes(self, outfile=sys.stdout): - self.dumped = {} - if self.nodelist: - nodename, dummy, dummy, dummy, dummy = self.nodelist[0] - self.topnode = nodename - - print('
      ', file=outfile) - for node in self.nodelist: - self.dumpnode(node,0,outfile) - print('
    ', file=outfile) - - def dumpnode(self, node, indent=0, outfile=sys.stdout): - if node: - # Retrieve info for this node - (nodename,next,prev,up,filename) = node - self.current = nodename - - # Have we been dumped already? - if nodename in self.dumped: - return - self.dumped[nodename] = 1 - - # Print info for this node - print(' '*indent, end=' ', file=outfile) - print('
  • ', end=' ', file=outfile) - print('', end=' ', file=outfile) - print('', end=' ', file=outfile) - print('', file=outfile) - - # Does this node have menu items? - try: - menu = self.menudict[nodename] - self.dumpmenu(menu,indent+2,outfile) - except KeyError: - pass - - def dumpmenu(self, menu, indent=0, outfile=sys.stdout): - if menu: - currentnode = self.current - if currentnode != self.topnode: # XXX this is a hack - print(' '*indent + '
      ', file=outfile) - indent += 2 - for item in menu: - menunode = self.getnode(item) - self.dumpnode(menunode,indent,outfile) - if currentnode != self.topnode: # XXX this is a hack - print(' '*indent + '
    ', file=outfile) - indent -= 2 - - def getnode(self, nodename): - try: - index = self.nodeindex[nodename] - return self.nodelist[index] - except KeyError: - return None - except IndexError: - return None - - # (args,nodename) == (key,location) - def dumpindex(self, outfile=sys.stdout): - print('
      ', file=outfile) - for (key,location) in self.indexlist: - key = self.codeexpand(key) - location = makefile(location) - location = self.dirname + '/' + location - print('
    • ', end=' ', file=outfile) - print('', end=' ', file=outfile) - print('', end=' ', file=outfile) - print('', file=outfile) - print('
    ', file=outfile) - - def codeexpand(self, line): - co = self.codeprog.match(line) - if not co: - return line - bgn, end = co.span(0) - a, b = co.span(1) - line = line[:bgn] + line[a:b] + line[end:] - return line - - -# Put @var{} around alphabetic substrings -def makevar(str): - return '@var{'+str+'}' - - -# Split a string in "words" according to findwordend -def splitwords(str, minlength): - words = [] - i = 0 - n = len(str) - while i < n: - while i < n and str[i] in ' \t\n': i = i+1 - if i >= n: break - start = i - i = findwordend(str, i, n) - words.append(str[start:i]) - while len(words) < minlength: words.append('') - return words - - -# Find the end of a "word", matching braces and interpreting @@ @{ @} -fwprog = re.compile('[@{} ]') -def findwordend(str, i, n): - level = 0 - while i < n: - mo = fwprog.search(str, i) - if not mo: - break - i = mo.start() - c = str[i]; i = i+1 - if c == '@': i = i+1 # Next character is not special - elif c == '{': level = level+1 - elif c == '}': level = level-1 - elif c == ' ' and level <= 0: return i-1 - return n - - -# Convert a node name into a file name -def makefile(nodename): - nodename = nodename.strip() - return fixfunnychars(nodename) + '.html' - - -# Characters that are perfectly safe in filenames and hyperlinks -goodchars = string.ascii_letters + string.digits + '!@-=+.' - -# Replace characters that aren't perfectly safe by dashes -# Underscores are bad since Cern HTTPD treats them as delimiters for -# encoding times, so you get mismatches if you compress your files: -# a.html.gz will map to a_b.html.gz -def fixfunnychars(addr): - i = 0 - while i < len(addr): - c = addr[i] - if c not in goodchars: - c = '-' - addr = addr[:i] + c + addr[i+1:] - i = i + len(c) - return addr - - -# Increment a string used as an enumeration -def increment(s): - if not s: - return '1' - for sequence in string.digits, string.ascii_lowercase, string.ascii_uppercase: - lastc = s[-1] - if lastc in sequence: - i = sequence.index(lastc) + 1 - if i >= len(sequence): - if len(s) == 1: - s = sequence[0]*2 - if s == '00': - s = '10' - else: - s = increment(s[:-1]) + sequence[0] - else: - s = s[:-1] + sequence[i] - return s - return s # Don't increment - - -def test(): - import sys - debugging = 0 - print_headers = 0 - cont = 0 - html3 = 0 - htmlhelp = '' - - while sys.argv[1] == ['-d']: - debugging = debugging + 1 - del sys.argv[1] - if sys.argv[1] == '-p': - print_headers = 1 - del sys.argv[1] - if sys.argv[1] == '-c': - cont = 1 - del sys.argv[1] - if sys.argv[1] == '-3': - html3 = 1 - del sys.argv[1] - if sys.argv[1] == '-H': - helpbase = sys.argv[2] - del sys.argv[1:3] - if len(sys.argv) != 3: - print('usage: texi2hh [-d [-d]] [-p] [-c] [-3] [-H htmlhelp]', \ - 'inputfile outputdirectory') - sys.exit(2) - - if html3: - parser = TexinfoParserHTML3() - else: - parser = TexinfoParser() - parser.cont = cont - parser.debugging = debugging - parser.print_headers = print_headers - - file = sys.argv[1] - dirname = sys.argv[2] - parser.setdirname(dirname) - parser.setincludedir(os.path.dirname(file)) - - htmlhelp = HTMLHelp(helpbase, dirname) - parser.sethtmlhelp(htmlhelp) - - try: - fp = open(file, 'r') - except IOError as msg: - print(file, ':', msg) - sys.exit(1) - - with fp: - parser.parse(fp) - parser.report() - - htmlhelp.finalize() - - -if __name__ == "__main__": - test() diff --git a/Tools/scripts/which.py b/Tools/scripts/which.py deleted file mode 100755 index b42e07c74eca..000000000000 --- a/Tools/scripts/which.py +++ /dev/null @@ -1,61 +0,0 @@ -#! /usr/bin/env python3 - -# Variant of "which". -# On stderr, near and total misses are reported. -# '-l' argument adds ls -l of each file found. - -import sys -if sys.path[0] in (".", ""): del sys.path[0] - -import sys, os -from stat import * - -def msg(str): - sys.stderr.write(str + '\n') - -def main(): - pathlist = os.environ['PATH'].split(os.pathsep) - - sts = 0 - longlist = '' - - if sys.argv[1:] and sys.argv[1][:2] == '-l': - longlist = sys.argv[1] - del sys.argv[1] - - for prog in sys.argv[1:]: - ident = () - for dir in pathlist: - filename = os.path.join(dir, prog) - try: - st = os.stat(filename) - except OSError: - continue - if not S_ISREG(st[ST_MODE]): - msg(filename + ': not a disk file') - else: - mode = S_IMODE(st[ST_MODE]) - if mode & 0o111: - if not ident: - print(filename) - ident = st[:3] - else: - if st[:3] == ident: - s = 'same as: ' - else: - s = 'also: ' - msg(s + filename) - else: - msg(filename + ': not executable') - if longlist: - sts = os.system('ls ' + longlist + ' ' + filename) - sts = os.waitstatus_to_exitcode(sts) - if sts: msg('"ls -l" exit status: ' + repr(sts)) - if not ident: - msg(prog + ': not found') - sts = 1 - - sys.exit(sts) - -if __name__ == '__main__': - main() From webhook-mailer at python.org Tue Oct 4 09:06:10 2022 From: webhook-mailer at python.org (miss-islington) Date: Tue, 04 Oct 2022 13:06:10 -0000 Subject: [Python-checkins] Adjust stable ABI internal documentation (GH-96896) Message-ID: https://github.com/python/cpython/commit/6e533088290b909df324615df24286489603989f commit: 6e533088290b909df324615df24286489603989f branch: main author: William Woodruff committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-04T06:05:53-07:00 summary: Adjust stable ABI internal documentation (GH-96896) I was perusing this file, and noticed that this part of the documentation is slightly out of date: the `struct` items in this TOML file currently contain `struct_abi_kind` members, which distinguish between the different types of ABI compatibility described in the comment. I've updated the comment to reflect this. files: M Misc/stable_abi.toml diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml index 4da002a05862..a8920d999e81 100644 --- a/Misc/stable_abi.toml +++ b/Misc/stable_abi.toml @@ -13,13 +13,8 @@ # The current format is TOML. # There are these kinds of top-level "items": -# - struct: A C struct. Currently this file does not distinguish between: -# - opaque structs, which the Limited API only handles via pointers -# (so these can change at any time) -# - structs where only certain members are part of the stable ABI (e.g. -# PyObject) -# - structs which must not be changed at all (e.g. PyType_Slot, which is -# fully defined and used in arrays) +# - struct: A C struct. See `struct_abi_kind` for how much of the struct is +# exposed. # - function: A function that must be kept available (and exported, i.e. not # converted to a macro). # - const: A simple value, defined with `#define`. @@ -42,6 +37,18 @@ # of the stable ABI. # - a combination of the above (functions that were called by macros that # were public in the past) +# - struct_abi_kind: for `struct`, defines how much of the struct is exposed: +# - 'full-abi': All of the struct is part of the ABI, including the size +# (users may define arrays of these structs). +# Typically used for initalization, rather than at runtime. +# - 'opaque': No members are part of the ABI, nor is the size. The Limited +# API only handles these via pointers. The C definition should be +# incomplete (opaque). +# - 'members': Only specific members are part of the stable ABI. +# The struct's size may change, so it can't be used in arrays. +# Do not add new structs of this kind without an extremely good reason. +# - members: For `struct` with struct_abi_kind = 'members', a list of the +# exposed members. # - doc: for `feature_macro`, the blurb added in documentation # - windows: for `feature_macro`, this macro is defined on Windows. # (This info is used to generate the DLL manifest and needs to be available From webhook-mailer at python.org Tue Oct 4 09:15:52 2022 From: webhook-mailer at python.org (miss-islington) Date: Tue, 04 Oct 2022 13:15:52 -0000 Subject: [Python-checkins] Adjust stable ABI internal documentation (GH-96896) Message-ID: https://github.com/python/cpython/commit/bbecca523a55d7fde99e22f2d96236c5d016846a commit: bbecca523a55d7fde99e22f2d96236c5d016846a branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-04T06:15:46-07:00 summary: Adjust stable ABI internal documentation (GH-96896) I was perusing this file, and noticed that this part of the documentation is slightly out of date: the `struct` items in this TOML file currently contain `struct_abi_kind` members, which distinguish between the different types of ABI compatibility described in the comment. I've updated the comment to reflect this. (cherry picked from commit 6e533088290b909df324615df24286489603989f) Co-authored-by: William Woodruff files: M Misc/stable_abi.toml diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml index e34bfcd0b617..50dbb0c7bcff 100644 --- a/Misc/stable_abi.toml +++ b/Misc/stable_abi.toml @@ -13,13 +13,8 @@ # The current format is TOML. # There are these kinds of top-level "items": -# - struct: A C struct. Currently this file does not distinguish between: -# - opaque structs, which the Limited API only handles via pointers -# (so these can change at any time) -# - structs where only certain members are part of the stable ABI (e.g. -# PyObject) -# - structs which must not be changed at all (e.g. PyType_Slot, which is -# fully defined and used in arrays) +# - struct: A C struct. See `struct_abi_kind` for how much of the struct is +# exposed. # - function: A function that must be kept available (and exported, i.e. not # converted to a macro). # - const: A simple value, defined with `#define`. @@ -42,6 +37,18 @@ # of the stable ABI. # - a combination of the above (functions that were called by macros that # were public in the past) +# - struct_abi_kind: for `struct`, defines how much of the struct is exposed: +# - 'full-abi': All of the struct is part of the ABI, including the size +# (users may define arrays of these structs). +# Typically used for initalization, rather than at runtime. +# - 'opaque': No members are part of the ABI, nor is the size. The Limited +# API only handles these via pointers. The C definition should be +# incomplete (opaque). +# - 'members': Only specific members are part of the stable ABI. +# The struct's size may change, so it can't be used in arrays. +# Do not add new structs of this kind without an extremely good reason. +# - members: For `struct` with struct_abi_kind = 'members', a list of the +# exposed members. # - doc: for `feature_macro`, the blurb added in documentation # - windows: for `feature_macro`, this macro is defined on Windows. # (This info is used to generate the DLL manifest and needs to be available From webhook-mailer at python.org Tue Oct 4 09:29:31 2022 From: webhook-mailer at python.org (vstinner) Date: Tue, 04 Oct 2022 13:29:31 -0000 Subject: [Python-checkins] gh-97670: Remove sys.getdxp() and analyze_dxp.py script (#97671) Message-ID: https://github.com/python/cpython/commit/116fa62c6ee18e2b2ccf3697802034c0d13a16e8 commit: 116fa62c6ee18e2b2ccf3697802034c0d13a16e8 branch: main author: Victor Stinner committer: vstinner date: 2022-10-04T15:28:57+02:00 summary: gh-97670: Remove sys.getdxp() and analyze_dxp.py script (#97671) Remove the sys.getdxp() function and the Tools/scripts/analyze_dxp.py script. DXP stands for "dynamic execution pairs". They were related to DYNAMIC_EXECUTION_PROFILE and DXPAIRS macros which have been removed in Python 3.11. Python can now be built with "./configure --enable-pystats" to gather statistics on Python opcodes. files: A Misc/NEWS.d/next/Core and Builtins/2022-09-30-13-26-58.gh-issue-97670.n61vMR.rst D Tools/scripts/analyze_dxp.py M Lib/test/test_tools/test_sundry.py M Python/ceval.c M Python/sysmodule.c M Tools/scripts/README diff --git a/Lib/test/test_tools/test_sundry.py b/Lib/test/test_tools/test_sundry.py index 52369ec09a77..ed03c2f75a3a 100644 --- a/Lib/test/test_tools/test_sundry.py +++ b/Lib/test/test_tools/test_sundry.py @@ -25,7 +25,7 @@ class TestSundryScripts(unittest.TestCase): # scripts that use windows-only modules windows_only = ['win_add2path'] # denylisted for other reasons - other = ['analyze_dxp', '2to3'] + other = ['2to3'] skiplist = denylist + allowlist + windows_only + other @@ -50,13 +50,6 @@ def test_sundry_windows(self): for name in self.windows_only: import_tool(name) - def test_analyze_dxp_import(self): - if hasattr(sys, 'getdxp'): - import_tool('analyze_dxp') - else: - with self.assertRaises(RuntimeError): - import_tool('analyze_dxp') - if __name__ == '__main__': unittest.main() diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-30-13-26-58.gh-issue-97670.n61vMR.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-30-13-26-58.gh-issue-97670.n61vMR.rst new file mode 100644 index 000000000000..50b47871a5fd --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-09-30-13-26-58.gh-issue-97670.n61vMR.rst @@ -0,0 +1,6 @@ +Remove the :func:`sys.getdxp` function and the ``Tools/scripts/analyze_dxp.py`` +script. DXP stands for "dynamic execution pairs". They were related to +``DYNAMIC_EXECUTION_PROFILE`` and ``DXPAIRS`` macros which have been removed in +Python 3.11. Python can now be built with :option:`./configure --enable-pystats +<--enable-pystats>` to gather statistics on Python opcodes. Patch by Victor +Stinner. diff --git a/Python/ceval.c b/Python/ceval.c index 945377044170..82b5422c188e 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -7207,61 +7207,6 @@ format_awaitable_error(PyThreadState *tstate, PyTypeObject *type, int oparg) } } -#ifdef Py_STATS - -static PyObject * -getarray(uint64_t a[256]) -{ - int i; - PyObject *l = PyList_New(256); - if (l == NULL) return NULL; - for (i = 0; i < 256; i++) { - PyObject *x = PyLong_FromUnsignedLongLong(a[i]); - if (x == NULL) { - Py_DECREF(l); - return NULL; - } - PyList_SET_ITEM(l, i, x); - } - for (i = 0; i < 256; i++) - a[i] = 0; - return l; -} - -PyObject * -_Py_GetDXProfile(PyObject *self, PyObject *args) -{ - int i; - PyObject *l = PyList_New(257); - if (l == NULL) return NULL; - for (i = 0; i < 256; i++) { - PyObject *x = getarray(_py_stats_struct.opcode_stats[i].pair_count); - if (x == NULL) { - Py_DECREF(l); - return NULL; - } - PyList_SET_ITEM(l, i, x); - } - PyObject *counts = PyList_New(256); - if (counts == NULL) { - Py_DECREF(l); - return NULL; - } - for (i = 0; i < 256; i++) { - PyObject *x = PyLong_FromUnsignedLongLong( - _py_stats_struct.opcode_stats[i].execution_count); - if (x == NULL) { - Py_DECREF(counts); - Py_DECREF(l); - return NULL; - } - PyList_SET_ITEM(counts, i, x); - } - PyList_SET_ITEM(l, 256, counts); - return l; -} - -#endif Py_ssize_t _PyEval_RequestCodeExtraIndex(freefunc free) diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 584a8be7094b..1ecf6a2dd39f 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -2014,11 +2014,6 @@ sys__debugmallocstats_impl(PyObject *module) extern PyObject *_Py_GetObjects(PyObject *, PyObject *); #endif -#ifdef Py_STATS -/* Defined in ceval.c because it uses static globals in that file */ -extern PyObject *_Py_GetDXProfile(PyObject *, PyObject *); -#endif - #ifdef __cplusplus } #endif @@ -2217,9 +2212,6 @@ static PyMethodDef sys_methods[] = { SYS_GETDEFAULTENCODING_METHODDEF SYS_GETDLOPENFLAGS_METHODDEF SYS_GETALLOCATEDBLOCKS_METHODDEF -#ifdef Py_STATS - {"getdxp", _Py_GetDXProfile, METH_VARARGS}, -#endif SYS_GETFILESYSTEMENCODING_METHODDEF SYS_GETFILESYSTEMENCODEERRORS_METHODDEF SYS__GETQUICKENEDCOUNT_METHODDEF diff --git a/Tools/scripts/README b/Tools/scripts/README index 6affa67b3449..b53b0f21d7c2 100644 --- a/Tools/scripts/README +++ b/Tools/scripts/README @@ -3,7 +3,6 @@ useful while building, extending or managing Python. 2to3 Main script for running the 2to3 conversion tool abitype.py Converts a C file to use the PEP 384 type definition API -analyze_dxp.py Analyzes the result of sys.getdxp() combinerefs.py A helper for analyzing PYTHONDUMPREFS output diff.py Print file diffs in context, unified, or ndiff formats eptags.py Create Emacs TAGS file for Python modules diff --git a/Tools/scripts/analyze_dxp.py b/Tools/scripts/analyze_dxp.py deleted file mode 100644 index bde931e75033..000000000000 --- a/Tools/scripts/analyze_dxp.py +++ /dev/null @@ -1,129 +0,0 @@ -""" -Some helper functions to analyze the output of sys.getdxp() (which is -only available if Python was built with -DDYNAMIC_EXECUTION_PROFILE). -These will tell you which opcodes have been executed most frequently -in the current process, and, if Python was also built with -DDXPAIRS, -will tell you which instruction _pairs_ were executed most frequently, -which may help in choosing new instructions. - -If Python was built without -DDYNAMIC_EXECUTION_PROFILE, importing -this module will raise a RuntimeError. - -If you're running a script you want to profile, a simple way to get -the common pairs is: - -$ PYTHONPATH=$PYTHONPATH:/Tools/scripts \ -./python -i -O the_script.py --args -... -> from analyze_dxp import * -> s = render_common_pairs() -> open('/tmp/some_file', 'w').write(s) -""" - -import copy -import opcode -import operator -import sys -import threading - -if not hasattr(sys, "getdxp"): - raise RuntimeError("Can't import analyze_dxp: Python built without" - " -DDYNAMIC_EXECUTION_PROFILE.") - - -_profile_lock = threading.RLock() -_cumulative_profile = sys.getdxp() - -# If Python was built with -DDXPAIRS, sys.getdxp() returns a list of -# lists of ints. Otherwise it returns just a list of ints. -def has_pairs(profile): - """Returns True if the Python that produced the argument profile - was built with -DDXPAIRS.""" - - return len(profile) > 0 and isinstance(profile[0], list) - - -def reset_profile(): - """Forgets any execution profile that has been gathered so far.""" - with _profile_lock: - sys.getdxp() # Resets the internal profile - global _cumulative_profile - _cumulative_profile = sys.getdxp() # 0s out our copy. - - -def merge_profile(): - """Reads sys.getdxp() and merges it into this module's cached copy. - - We need this because sys.getdxp() 0s itself every time it's called.""" - - with _profile_lock: - new_profile = sys.getdxp() - if has_pairs(new_profile): - for first_inst in range(len(_cumulative_profile)): - for second_inst in range(len(_cumulative_profile[first_inst])): - _cumulative_profile[first_inst][second_inst] += ( - new_profile[first_inst][second_inst]) - else: - for inst in range(len(_cumulative_profile)): - _cumulative_profile[inst] += new_profile[inst] - - -def snapshot_profile(): - """Returns the cumulative execution profile until this call.""" - with _profile_lock: - merge_profile() - return copy.deepcopy(_cumulative_profile) - - -def common_instructions(profile): - """Returns the most common opcodes in order of descending frequency. - - The result is a list of tuples of the form - (opcode, opname, # of occurrences) - - """ - if has_pairs(profile) and profile: - inst_list = profile[-1] - else: - inst_list = profile - result = [(op, opcode.opname[op], count) - for op, count in enumerate(inst_list) - if count > 0] - result.sort(key=operator.itemgetter(2), reverse=True) - return result - - -def common_pairs(profile): - """Returns the most common opcode pairs in order of descending frequency. - - The result is a list of tuples of the form - ((1st opcode, 2nd opcode), - (1st opname, 2nd opname), - # of occurrences of the pair) - - """ - if not has_pairs(profile): - return [] - result = [((op1, op2), (opcode.opname[op1], opcode.opname[op2]), count) - # Drop the row of single-op profiles with [:-1] - for op1, op1profile in enumerate(profile[:-1]) - for op2, count in enumerate(op1profile) - if count > 0] - result.sort(key=operator.itemgetter(2), reverse=True) - return result - - -def render_common_pairs(profile=None): - """Renders the most common opcode pairs to a string in order of - descending frequency. - - The result is a series of lines of the form: - # of occurrences: ('1st opname', '2nd opname') - - """ - if profile is None: - profile = snapshot_profile() - def seq(): - for _, ops, count in common_pairs(profile): - yield "%s: %s\n" % (count, ops) - return ''.join(seq()) From webhook-mailer at python.org Tue Oct 4 10:39:02 2022 From: webhook-mailer at python.org (orsenthil) Date: Tue, 04 Oct 2022 14:39:02 -0000 Subject: [Python-checkins] gh-97731: fix distclean target to clean docs (#97732) Message-ID: https://github.com/python/cpython/commit/46eecc3b33b960d7e692547dd61792533d213e01 commit: 46eecc3b33b960d7e692547dd61792533d213e01 branch: main author: Skip Montanaro committer: orsenthil date: 2022-10-04T07:38:19-07:00 summary: gh-97731: fix distclean target to clean docs (#97732) fix distclean target to clean docs files: M Makefile.pre.in diff --git a/Makefile.pre.in b/Makefile.pre.in index 5201abb5ee5b..01578306bd5f 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1863,7 +1863,7 @@ altbininstall: $(BUILDPYTHON) @FRAMEWORKPYTHONW@ $(DSYMUTIL_PATH) $(DESTDIR)$(PYTHONFRAMEWORKPREFIX)/$(INSTSONAME); \ fi \ fi - + bininstall: altbininstall if test ! -d $(DESTDIR)$(LIBPC); then \ @@ -2432,8 +2432,7 @@ rmtestturds: -rm -f gb-18030-2000.xml docclean: - -rm -rf Doc/build - -rm -rf Doc/tools/sphinx Doc/tools/pygments Doc/tools/docutils + $(MAKE) -C Doc clean # like the 'clean' target but retain the profile guided optimization (PGO) # data. The PGO data is only valid if source code remains unchanged. @@ -2485,7 +2484,7 @@ clobber: clean # Make things extra clean, before making a distribution: # remove all generated files, even Makefile[.pre] # Keep configure and Python-ast.[ch], it's possible they can't be generated -distclean: clobber +distclean: clobber docclean for file in $(srcdir)/Lib/test/data/* ; do \ if test "$$file" != "$(srcdir)/Lib/test/data/README"; then rm "$$file"; fi; \ done From webhook-mailer at python.org Tue Oct 4 12:05:23 2022 From: webhook-mailer at python.org (zooba) Date: Tue, 04 Oct 2022 16:05:23 -0000 Subject: [Python-checkins] gh-97754: Update doc for default location of per-user installs on Windows (GH-97756) Message-ID: https://github.com/python/cpython/commit/a120b9f25d037a1c794df731f8cc6a2898a9165e commit: a120b9f25d037a1c794df731f8cc6a2898a9165e branch: main author: Ben Faulhaber <111227622+faulhaberben at users.noreply.github.com> committer: zooba date: 2022-10-04T17:04:41+01:00 summary: gh-97754: Update doc for default location of per-user installs on Windows (GH-97756) files: M Doc/using/windows.rst diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst index d409e81627ef..9c339521c311 100644 --- a/Doc/using/windows.rst +++ b/Doc/using/windows.rst @@ -163,11 +163,14 @@ of available options is shown below. | | | Python X.Y` | +---------------------------+--------------------------------------+--------------------------+ | DefaultJustForMeTargetDir | The default install directory for | :file:`%LocalAppData%\\\ | -| | just-for-me installs | Programs\\PythonXY` or | +| | just-for-me installs | Programs\\Python\\\ | +| | | PythonXY` or | | | | :file:`%LocalAppData%\\\ | -| | | Programs\\PythonXY-32` or| +| | | Programs\\Python\\\ | +| | | PythonXY-32` or | | | | :file:`%LocalAppData%\\\ | -| | | Programs\\PythonXY-64` | +| | | Programs\\Python\\\ | +| | | PythonXY-64` | +---------------------------+--------------------------------------+--------------------------+ | DefaultCustomTargetDir | The default custom install directory | (empty) | | | displayed in the UI | | From webhook-mailer at python.org Tue Oct 4 12:13:44 2022 From: webhook-mailer at python.org (miss-islington) Date: Tue, 04 Oct 2022 16:13:44 -0000 Subject: [Python-checkins] gh-97754: Update doc for default location of per-user installs on Windows (GH-97756) Message-ID: https://github.com/python/cpython/commit/3263aaf83feb287578f37ea41f5e3aba6e0de064 commit: 3263aaf83feb287578f37ea41f5e3aba6e0de064 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-04T09:13:37-07:00 summary: gh-97754: Update doc for default location of per-user installs on Windows (GH-97756) (cherry picked from commit a120b9f25d037a1c794df731f8cc6a2898a9165e) Co-authored-by: Ben Faulhaber <111227622+faulhaberben at users.noreply.github.com> files: M Doc/using/windows.rst diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst index 1808cbc340cb..e338b11e1aa0 100644 --- a/Doc/using/windows.rst +++ b/Doc/using/windows.rst @@ -150,11 +150,14 @@ of available options is shown below. | | | Python X.Y` | +---------------------------+--------------------------------------+--------------------------+ | DefaultJustForMeTargetDir | The default install directory for | :file:`%LocalAppData%\\\ | -| | just-for-me installs | Programs\\PythonXY` or | +| | just-for-me installs | Programs\\Python\\\ | +| | | PythonXY` or | | | | :file:`%LocalAppData%\\\ | -| | | Programs\\PythonXY-32` or| +| | | Programs\\Python\\\ | +| | | PythonXY-32` or | | | | :file:`%LocalAppData%\\\ | -| | | Programs\\PythonXY-64` | +| | | Programs\\Python\\\ | +| | | PythonXY-64` | +---------------------------+--------------------------------------+--------------------------+ | DefaultCustomTargetDir | The default custom install directory | (empty) | | | displayed in the UI | | From webhook-mailer at python.org Tue Oct 4 12:14:47 2022 From: webhook-mailer at python.org (miss-islington) Date: Tue, 04 Oct 2022 16:14:47 -0000 Subject: [Python-checkins] gh-97754: Update doc for default location of per-user installs on Windows (GH-97756) Message-ID: https://github.com/python/cpython/commit/2911521026d94fa2435c36dcaa4426303ffb5686 commit: 2911521026d94fa2435c36dcaa4426303ffb5686 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-04T09:14:42-07:00 summary: gh-97754: Update doc for default location of per-user installs on Windows (GH-97756) (cherry picked from commit a120b9f25d037a1c794df731f8cc6a2898a9165e) Co-authored-by: Ben Faulhaber <111227622+faulhaberben at users.noreply.github.com> files: M Doc/using/windows.rst diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst index 4a8655bc6130..35e26eb2b20c 100644 --- a/Doc/using/windows.rst +++ b/Doc/using/windows.rst @@ -150,11 +150,14 @@ of available options is shown below. | | | Python X.Y` | +---------------------------+--------------------------------------+--------------------------+ | DefaultJustForMeTargetDir | The default install directory for | :file:`%LocalAppData%\\\ | -| | just-for-me installs | Programs\\PythonXY` or | +| | just-for-me installs | Programs\\Python\\\ | +| | | PythonXY` or | | | | :file:`%LocalAppData%\\\ | -| | | Programs\\PythonXY-32` or| +| | | Programs\\Python\\\ | +| | | PythonXY-32` or | | | | :file:`%LocalAppData%\\\ | -| | | Programs\\PythonXY-64` | +| | | Programs\\Python\\\ | +| | | PythonXY-64` | +---------------------------+--------------------------------------+--------------------------+ | DefaultCustomTargetDir | The default custom install directory | (empty) | | | displayed in the UI | | From webhook-mailer at python.org Tue Oct 4 12:45:46 2022 From: webhook-mailer at python.org (gvanrossum) Date: Tue, 04 Oct 2022 16:45:46 -0000 Subject: [Python-checkins] GH-82604: fix docs about configuring selector (#97755) Message-ID: https://github.com/python/cpython/commit/53503ff60e9a4727af0d9a1096418675e72a0fae commit: 53503ff60e9a4727af0d9a1096418675e72a0fae branch: main author: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> committer: gvanrossum date: 2022-10-04T09:45:37-07:00 summary: GH-82604: fix docs about configuring selector (#97755) files: M Doc/library/asyncio-eventloop.rst diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index 0a960ab38b49..c51990eff8de 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -1632,9 +1632,12 @@ on Unix and :class:`ProactorEventLoop` on Windows. import asyncio import selectors - selector = selectors.SelectSelector() - loop = asyncio.SelectorEventLoop(selector) - asyncio.set_event_loop(loop) + class MyPolicy(asyncio.DefaultEventLoopPolicy): + def new_event_loop(self): + selector = selectors.SelectSelector() + return asyncio.SelectorEventLoop(selector) + + asyncio.set_event_loop_policy(MyPolicy()) .. availability:: Unix, Windows. From webhook-mailer at python.org Tue Oct 4 12:52:33 2022 From: webhook-mailer at python.org (miss-islington) Date: Tue, 04 Oct 2022 16:52:33 -0000 Subject: [Python-checkins] GH-82604: fix docs about configuring selector (GH-97755) Message-ID: https://github.com/python/cpython/commit/0dcfe0f47e471192c87d730c7d2ff3a2579e999f commit: 0dcfe0f47e471192c87d730c7d2ff3a2579e999f branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-04T09:52:28-07:00 summary: GH-82604: fix docs about configuring selector (GH-97755) (cherry picked from commit 53503ff60e9a4727af0d9a1096418675e72a0fae) Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> files: M Doc/library/asyncio-eventloop.rst diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index 5e951652f537..b83e6ace5589 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -1611,9 +1611,12 @@ on Unix and :class:`ProactorEventLoop` on Windows. import asyncio import selectors - selector = selectors.SelectSelector() - loop = asyncio.SelectorEventLoop(selector) - asyncio.set_event_loop(loop) + class MyPolicy(asyncio.DefaultEventLoopPolicy): + def new_event_loop(self): + selector = selectors.SelectSelector() + return asyncio.SelectorEventLoop(selector) + + asyncio.set_event_loop_policy(MyPolicy()) .. availability:: Unix, Windows. From webhook-mailer at python.org Tue Oct 4 12:52:40 2022 From: webhook-mailer at python.org (miss-islington) Date: Tue, 04 Oct 2022 16:52:40 -0000 Subject: [Python-checkins] GH-82604: fix docs about configuring selector (GH-97755) Message-ID: https://github.com/python/cpython/commit/f4e2686b78517852871092c84e643b9d9d81ab41 commit: f4e2686b78517852871092c84e643b9d9d81ab41 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-04T09:52:35-07:00 summary: GH-82604: fix docs about configuring selector (GH-97755) (cherry picked from commit 53503ff60e9a4727af0d9a1096418675e72a0fae) Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> files: M Doc/library/asyncio-eventloop.rst diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index a6250be6be55..d2f786990802 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -1523,9 +1523,12 @@ on Unix and :class:`ProactorEventLoop` on Windows. import asyncio import selectors - selector = selectors.SelectSelector() - loop = asyncio.SelectorEventLoop(selector) - asyncio.set_event_loop(loop) + class MyPolicy(asyncio.DefaultEventLoopPolicy): + def new_event_loop(self): + selector = selectors.SelectSelector() + return asyncio.SelectorEventLoop(selector) + + asyncio.set_event_loop_policy(MyPolicy()) .. availability:: Unix, Windows. From webhook-mailer at python.org Tue Oct 4 12:53:37 2022 From: webhook-mailer at python.org (ericvsmith) Date: Tue, 04 Oct 2022 16:53:37 -0000 Subject: [Python-checkins] gh-96142: add missing params to `dataclass._DataclassParams` (gh-96382) Message-ID: https://github.com/python/cpython/commit/4f380db1a539bf7ae157d1e0791b5ac3fecfcf01 commit: 4f380db1a539bf7ae157d1e0791b5ac3fecfcf01 branch: main author: Nikita Sobolev committer: ericvsmith date: 2022-10-04T09:53:28-07:00 summary: gh-96142: add missing params to `dataclass._DataclassParams` (gh-96382) files: A Misc/NEWS.d/next/Library/2022-08-29-12-49-30.gh-issue-96142.PdCMez.rst M Lib/dataclasses.py M Lib/test/test_dataclasses.py diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index efd83467bfa9..65fb8f251861 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -320,15 +320,25 @@ class _DataclassParams: 'order', 'unsafe_hash', 'frozen', + 'match_args', + 'kw_only', + 'slots', + 'weakref_slot', ) - def __init__(self, init, repr, eq, order, unsafe_hash, frozen): + def __init__(self, + init, repr, eq, order, unsafe_hash, frozen, + match_args, kw_only, slots, weakref_slot): self.init = init self.repr = repr self.eq = eq self.order = order self.unsafe_hash = unsafe_hash self.frozen = frozen + self.match_args = match_args + self.kw_only = kw_only + self.slots = slots + self.weakref_slot = weakref_slot def __repr__(self): return ('_DataclassParams(' @@ -337,7 +347,11 @@ def __repr__(self): f'eq={self.eq!r},' f'order={self.order!r},' f'unsafe_hash={self.unsafe_hash!r},' - f'frozen={self.frozen!r}' + f'frozen={self.frozen!r},' + f'match_args={self.match_args!r},' + f'kw_only={self.kw_only!r},' + f'slots={self.slots!r},' + f'weakref_slot={self.weakref_slot!r}' ')') @@ -905,7 +919,9 @@ def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen, globals = {} setattr(cls, _PARAMS, _DataclassParams(init, repr, eq, order, - unsafe_hash, frozen)) + unsafe_hash, frozen, + match_args, kw_only, + slots, weakref_slot)) # Find our base classes in reverse MRO order, and exclude # ourselves. In reversed order so that more derived classes diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py index e2eab695789d..328dcdcb0bce 100644 --- a/Lib/test/test_dataclasses.py +++ b/Lib/test/test_dataclasses.py @@ -68,6 +68,32 @@ def test_field_repr(self): self.assertEqual(repr_output, expected_output) + def test_dataclass_params_repr(self): + # Even though this is testing an internal implementation detail, + # it's testing a feature we want to make sure is correctly implemented + # for the sake of dataclasses itself + @dataclass(slots=True, frozen=True) + class Some: pass + + repr_output = repr(Some.__dataclass_params__) + expected_output = "_DataclassParams(init=True,repr=True," \ + "eq=True,order=False,unsafe_hash=False,frozen=True," \ + "match_args=True,kw_only=False," \ + "slots=True,weakref_slot=False)" + self.assertEqual(repr_output, expected_output) + + def test_dataclass_params_signature(self): + # Even though this is testing an internal implementation detail, + # it's testing a feature we want to make sure is correctly implemented + # for the sake of dataclasses itself + @dataclass + class Some: pass + + for param in inspect.signature(dataclass).parameters: + if param == 'cls': + continue + self.assertTrue(hasattr(Some.__dataclass_params__, param), msg=param) + def test_named_init_params(self): @dataclass class C: diff --git a/Misc/NEWS.d/next/Library/2022-08-29-12-49-30.gh-issue-96142.PdCMez.rst b/Misc/NEWS.d/next/Library/2022-08-29-12-49-30.gh-issue-96142.PdCMez.rst new file mode 100644 index 000000000000..43d1c3de9922 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-08-29-12-49-30.gh-issue-96142.PdCMez.rst @@ -0,0 +1,2 @@ +Add ``match_args``, ``kw_only``, ``slots``, and ``weakref_slot`` to +``_DataclassParams``. From webhook-mailer at python.org Tue Oct 4 12:58:40 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 04 Oct 2022 16:58:40 -0000 Subject: [Python-checkins] [3.9] gh-96845: Fix docs around importlib.abc.Traversable (GH-97515) (GH-97761) Message-ID: https://github.com/python/cpython/commit/71edddea86c53a91a56ebebdb18e9d616f4675c2 commit: 71edddea86c53a91a56ebebdb18e9d616f4675c2 branch: 3.9 author: Jason R. Coombs committer: ambv date: 2022-10-04T09:58:34-07:00 summary: [3.9] gh-96845: Fix docs around importlib.abc.Traversable (GH-97515) (GH-97761) Co-authored-by: Jason R. Coombs files: M Doc/library/importlib.rst diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst index c7fbcb21274a..975648153101 100644 --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -845,6 +845,8 @@ ABC hierarchy:: Read contents of self as text. + Note: In Python 3.11 and later, this class is found in ``importlib.resources.abc``. + .. class:: TraversableResources @@ -856,6 +858,8 @@ ABC hierarchy:: .. versionadded:: 3.9 + Note: In Python 3.11 and later, this class is found in ``importlib.resources.abc``. + :mod:`importlib.resources` -- Resources --------------------------------------- @@ -918,7 +922,7 @@ The following functions are available. .. function:: files(package) - Returns an :class:`importlib.resources.abc.Traversable` object + Returns an :class:`importlib.abc.Traversable` object representing the resource container for the package (think directory) and its resources (think files). A Traversable may contain other containers (think subdirectories). @@ -930,7 +934,7 @@ The following functions are available. .. function:: as_file(traversable) - Given a :class:`importlib.resources.abc.Traversable` object representing + Given a :class:`importlib.abc.Traversable` object representing a file, typically from :func:`importlib.resources.files`, return a context manager for use in a :keyword:`with` statement. The context manager provides a :class:`pathlib.Path` object. From webhook-mailer at python.org Tue Oct 4 12:59:13 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 04 Oct 2022 16:59:13 -0000 Subject: [Python-checkins] [3.9] gh-87597: Document TimeoutExpired.stdout & .stderr types (GH-97685) (GH-97688) Message-ID: https://github.com/python/cpython/commit/94dbdbbd403950857913049c7445534d7ec86d39 commit: 94dbdbbd403950857913049c7445534d7ec86d39 branch: 3.9 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-04T09:59:07-07:00 summary: [3.9] gh-87597: Document TimeoutExpired.stdout & .stderr types (GH-97685) (GH-97688) This documents the behavior that has always been the case since timeout support was introduced in Python 3.3. (cherry picked from commit b05dd796492160c37c9e15e3882f699f411b3461) Co-authored-by: Gregory P. Smith files: M Doc/library/subprocess.rst diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst index 45eff7ffcc35..10e40635e248 100644 --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -195,7 +195,10 @@ compatibility with older versions, see the :ref:`call-function-trio` section. .. attribute:: output Output of the child process if it was captured by :func:`run` or - :func:`check_output`. Otherwise, ``None``. + :func:`check_output`. Otherwise, ``None``. This is always + :class:`bytes` when any output was captured regardless of the + ``text=True`` setting. It may remain ``None`` instead of ``b''`` + when no output was observed. .. attribute:: stdout @@ -204,7 +207,9 @@ compatibility with older versions, see the :ref:`call-function-trio` section. .. attribute:: stderr Stderr output of the child process if it was captured by :func:`run`. - Otherwise, ``None``. + Otherwise, ``None``. This is always :class:`bytes` when stderr output + was captured regardless of the ``text=True`` setting. It may remain + ``None`` instead of ``b''`` when no stderr output was observed. .. versionadded:: 3.3 From webhook-mailer at python.org Tue Oct 4 13:00:22 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 04 Oct 2022 17:00:22 -0000 Subject: [Python-checkins] [3.9] gh-97612: Fix shell injection in get-remote-certificate.py (GH-97613) (GH-97632) Message-ID: https://github.com/python/cpython/commit/d6ef6805b2e60a50a83e73bd2f40fc3a03715b32 commit: d6ef6805b2e60a50a83e73bd2f40fc3a03715b32 branch: 3.9 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-04T10:00:16-07:00 summary: [3.9] gh-97612: Fix shell injection in get-remote-certificate.py (GH-97613) (GH-97632) gh-97612: Fix shell injection in get-remote-certificate.py (GH-97613) Fix a shell code injection vulnerability in the get-remote-certificate.py example script. The script no longer uses a shell to run "openssl" commands. Issue reported and initial fix by Caleb Shortt. Remove the Windows code path to send "quit" on stdin to the "openssl s_client" command: use DEVNULL on all platforms instead. Co-authored-by: Caleb Shortt (cherry picked from commit 83a0f44ffd8b398673ae56c310cf5768d359c341) Co-authored-by: Victor Stinner files: A Misc/NEWS.d/next/Security/2022-09-28-12-10-57.gh-issue-97612.y6NvOQ.rst M Tools/scripts/get-remote-certificate.py diff --git a/Misc/NEWS.d/next/Security/2022-09-28-12-10-57.gh-issue-97612.y6NvOQ.rst b/Misc/NEWS.d/next/Security/2022-09-28-12-10-57.gh-issue-97612.y6NvOQ.rst new file mode 100644 index 000000000000..2f113492d42d --- /dev/null +++ b/Misc/NEWS.d/next/Security/2022-09-28-12-10-57.gh-issue-97612.y6NvOQ.rst @@ -0,0 +1,3 @@ +Fix a shell code injection vulnerability in the ``get-remote-certificate.py`` +example script. The script no longer uses a shell to run ``openssl`` commands. +Issue reported and initial fix by Caleb Shortt. Patch by Victor Stinner. diff --git a/Tools/scripts/get-remote-certificate.py b/Tools/scripts/get-remote-certificate.py index 38901286e19a..68272fca83fe 100755 --- a/Tools/scripts/get-remote-certificate.py +++ b/Tools/scripts/get-remote-certificate.py @@ -15,8 +15,8 @@ def fetch_server_certificate (host, port): def subproc(cmd): - from subprocess import Popen, PIPE, STDOUT - proc = Popen(cmd, stdout=PIPE, stderr=STDOUT, shell=True) + from subprocess import Popen, PIPE, STDOUT, DEVNULL + proc = Popen(cmd, stdout=PIPE, stderr=STDOUT, stdin=DEVNULL) status = proc.wait() output = proc.stdout.read() return status, output @@ -33,8 +33,8 @@ def strip_to_x509_cert(certfile_contents, outfile=None): fp.write(m.group(1) + b"\n") try: tn2 = (outfile or tempfile.mktemp()) - status, output = subproc(r'openssl x509 -in "%s" -out "%s"' % - (tn, tn2)) + cmd = ['openssl', 'x509', '-in', tn, '-out', tn2] + status, output = subproc(cmd) if status != 0: raise RuntimeError('OpenSSL x509 failed with status %s and ' 'output: %r' % (status, output)) @@ -45,20 +45,9 @@ def strip_to_x509_cert(certfile_contents, outfile=None): finally: os.unlink(tn) - if sys.platform.startswith("win"): - tfile = tempfile.mktemp() - with open(tfile, "w") as fp: - fp.write("quit\n") - try: - status, output = subproc( - 'openssl s_client -connect "%s:%s" -showcerts < "%s"' % - (host, port, tfile)) - finally: - os.unlink(tfile) - else: - status, output = subproc( - 'openssl s_client -connect "%s:%s" -showcerts < /dev/null' % - (host, port)) + cmd = ['openssl', 's_client', '-connect', '%s:%s' % (host, port), '-showcerts'] + status, output = subproc(cmd) + if status != 0: raise RuntimeError('OpenSSL connect failed with status %s and ' 'output: %r' % (status, output)) From webhook-mailer at python.org Tue Oct 4 13:01:15 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 04 Oct 2022 17:01:15 -0000 Subject: [Python-checkins] [3.9] gh-97616: list_resize() checks for integer overflow (GH-97617) (GH-97627) Message-ID: https://github.com/python/cpython/commit/f65f3a9daf8e7d0c6c90a86f0c5bbb10ae9191bc commit: f65f3a9daf8e7d0c6c90a86f0c5bbb10ae9191bc branch: 3.9 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-04T10:01:10-07:00 summary: [3.9] gh-97616: list_resize() checks for integer overflow (GH-97617) (GH-97627) gh-97616: list_resize() checks for integer overflow (GH-97617) Fix multiplying a list by an integer (list *= int): detect the integer overflow when the new allocated length is close to the maximum size. Issue reported by Jordan Limor. list_resize() now checks for integer overflow before multiplying the new allocated length by the list item size (sizeof(PyObject*)). (cherry picked from commit a5f092f3c469b674b8d9ccbd4e4377230c9ac7cf) Co-authored-by: Victor Stinner files: A Misc/NEWS.d/next/Security/2022-09-28-17-09-37.gh-issue-97616.K1e3Xs.rst M Lib/test/test_list.py M Objects/listobject.c diff --git a/Lib/test/test_list.py b/Lib/test/test_list.py index 3c8d82958fd7..85bbf51e3f99 100644 --- a/Lib/test/test_list.py +++ b/Lib/test/test_list.py @@ -68,6 +68,19 @@ def imul(a, b): a *= b self.assertRaises((MemoryError, OverflowError), mul, lst, n) self.assertRaises((MemoryError, OverflowError), imul, lst, n) + def test_list_resize_overflow(self): + # gh-97616: test new_allocated * sizeof(PyObject*) overflow + # check in list_resize() + lst = [0] * 65 + del lst[1:] + self.assertEqual(len(lst), 1) + + size = ((2 ** (tuple.__itemsize__ * 8) - 1) // 2) + with self.assertRaises((MemoryError, OverflowError)): + lst * size + with self.assertRaises((MemoryError, OverflowError)): + lst *= size + def test_repr_large(self): # Check the repr of large list objects def check(n): diff --git a/Misc/NEWS.d/next/Security/2022-09-28-17-09-37.gh-issue-97616.K1e3Xs.rst b/Misc/NEWS.d/next/Security/2022-09-28-17-09-37.gh-issue-97616.K1e3Xs.rst new file mode 100644 index 000000000000..721427fe6465 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2022-09-28-17-09-37.gh-issue-97616.K1e3Xs.rst @@ -0,0 +1,3 @@ +Fix multiplying a list by an integer (``list *= int``): detect the integer +overflow when the new allocated length is close to the maximum size. Issue +reported by Jordan Limor. Patch by Victor Stinner. diff --git a/Objects/listobject.c b/Objects/listobject.c index 1e868b43c098..c12c02cbbf6b 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -68,8 +68,14 @@ list_resize(PyListObject *self, Py_ssize_t newsize) if (newsize == 0) new_allocated = 0; - num_allocated_bytes = new_allocated * sizeof(PyObject *); - items = (PyObject **)PyMem_Realloc(self->ob_item, num_allocated_bytes); + if (new_allocated <= (size_t)PY_SSIZE_T_MAX / sizeof(PyObject *)) { + num_allocated_bytes = new_allocated * sizeof(PyObject *); + items = (PyObject **)PyMem_Realloc(self->ob_item, num_allocated_bytes); + } + else { + // integer overflow + items = NULL; + } if (items == NULL) { PyErr_NoMemory(); return -1; From webhook-mailer at python.org Tue Oct 4 13:04:42 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 04 Oct 2022 17:04:42 -0000 Subject: [Python-checkins] [3.9] gh-97005: Update libexpat from 2.4.7 to 2.4.9 (gh-97006) (gh-97012) Message-ID: https://github.com/python/cpython/commit/9b409e418ac2bfac62a4ee7f6514e093a14bf26e commit: 9b409e418ac2bfac62a4ee7f6514e093a14bf26e branch: 3.9 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-04T10:04:33-07:00 summary: [3.9] gh-97005: Update libexpat from 2.4.7 to 2.4.9 (gh-97006) (gh-97012) gh-97005: Update libexpat from 2.4.7 to 2.4.9 (gh-97006) Co-authored-by: Gregory P. Smith [Google] (cherry picked from commit 10e3d398c31cc1695752fc52bc6ca2ce9ef6237e) Co-authored-by: Dong-hee Na Co-authored-by: Ned Deily files: A Misc/NEWS.d/next/Library/2022-09-22-14-35-02.gh-issue-97005.yf21Q7.rst M Modules/expat/COPYING M Modules/expat/expat.h M Modules/expat/internal.h M Modules/expat/siphash.h M Modules/expat/xmlparse.c M Modules/expat/xmltok.c M Modules/expat/xmltok_impl.c diff --git a/Misc/NEWS.d/next/Library/2022-09-22-14-35-02.gh-issue-97005.yf21Q7.rst b/Misc/NEWS.d/next/Library/2022-09-22-14-35-02.gh-issue-97005.yf21Q7.rst new file mode 100644 index 000000000000..d57999aa29b7 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-09-22-14-35-02.gh-issue-97005.yf21Q7.rst @@ -0,0 +1 @@ +Update bundled libexpat to 2.4.9 diff --git a/Modules/expat/COPYING b/Modules/expat/COPYING index 3c0142e71c8d..ce9e5939291e 100644 --- a/Modules/expat/COPYING +++ b/Modules/expat/COPYING @@ -1,5 +1,5 @@ Copyright (c) 1998-2000 Thai Open Source Software Center Ltd and Clark Cooper -Copyright (c) 2001-2019 Expat maintainers +Copyright (c) 2001-2022 Expat maintainers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/Modules/expat/expat.h b/Modules/expat/expat.h index c9214f64070a..2b47ce2a8d3a 100644 --- a/Modules/expat/expat.h +++ b/Modules/expat/expat.h @@ -1055,7 +1055,7 @@ XML_SetBillionLaughsAttackProtectionActivationThreshold( */ #define XML_MAJOR_VERSION 2 #define XML_MINOR_VERSION 4 -#define XML_MICRO_VERSION 7 +#define XML_MICRO_VERSION 9 #ifdef __cplusplus } diff --git a/Modules/expat/internal.h b/Modules/expat/internal.h index 444eba0fb031..e09f533b23c9 100644 --- a/Modules/expat/internal.h +++ b/Modules/expat/internal.h @@ -28,7 +28,7 @@ Copyright (c) 2002-2003 Fred L. Drake, Jr. Copyright (c) 2002-2006 Karl Waclawek Copyright (c) 2003 Greg Stein - Copyright (c) 2016-2021 Sebastian Pipping + Copyright (c) 2016-2022 Sebastian Pipping Copyright (c) 2018 Yury Gribov Copyright (c) 2019 David Loffredo Licensed under the MIT license: @@ -107,7 +107,9 @@ #include // ULONG_MAX -#if defined(_WIN32) && ! defined(__USE_MINGW_ANSI_STDIO) +#if defined(_WIN32) \ + && (! defined(__USE_MINGW_ANSI_STDIO) \ + || (1 - __USE_MINGW_ANSI_STDIO - 1 == 0)) # define EXPAT_FMT_ULL(midpart) "%" midpart "I64u" # if defined(_WIN64) // Note: modifiers "td" and "zu" do not work for MinGW # define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "I64d" diff --git a/Modules/expat/siphash.h b/Modules/expat/siphash.h index e5406d7ee9eb..303283ad2de9 100644 --- a/Modules/expat/siphash.h +++ b/Modules/expat/siphash.h @@ -106,7 +106,7 @@ * if this code is included and compiled as C++; related GCC warning is: * warning: use of C++11 long long integer constant [-Wlong-long] */ -#define _SIP_ULL(high, low) (((uint64_t)high << 32) | low) +#define _SIP_ULL(high, low) ((((uint64_t)high) << 32) | (low)) #define SIP_ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b)))) diff --git a/Modules/expat/xmlparse.c b/Modules/expat/xmlparse.c index 05216d997b07..c0bece51d700 100644 --- a/Modules/expat/xmlparse.c +++ b/Modules/expat/xmlparse.c @@ -1,4 +1,4 @@ -/* fcb1a62fefa945567301146eb98e3ad3413e823a41c4378e84e8b6b6f308d824 (2.4.7+) +/* 90815a2b2c80c03b2b889fe1d427bb2b9e3282aa065e42784e001db4f23de324 (2.4.9+) __ __ _ ___\ \/ /_ __ __ _| |_ / _ \\ /| '_ \ / _` | __| @@ -19,7 +19,7 @@ Copyright (c) 2016 Gustavo Grieco Copyright (c) 2016 Pascal Cuoq Copyright (c) 2016 Ed Schouten - Copyright (c) 2017-2018 Rhodri James + Copyright (c) 2017-2022 Rhodri James Copyright (c) 2017 V?clav Slav?k Copyright (c) 2017 Viktor Szakats Copyright (c) 2017 Chanho Park @@ -4271,7 +4271,7 @@ processXmlDecl(XML_Parser parser, int isGeneralTextEntity, const char *s, const XML_Char *storedEncName = NULL; const ENCODING *newEncoding = NULL; const char *version = NULL; - const char *versionend; + const char *versionend = NULL; const XML_Char *storedversion = NULL; int standalone = -1; @@ -5826,10 +5826,15 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end, { parser->m_processor = contentProcessor; /* see externalEntityContentProcessor vs contentProcessor */ - return doContent(parser, parser->m_parentParser ? 1 : 0, parser->m_encoding, - s, end, nextPtr, - (XML_Bool)! parser->m_parsingStatus.finalBuffer, - XML_ACCOUNT_DIRECT); + result = doContent(parser, parser->m_parentParser ? 1 : 0, + parser->m_encoding, s, end, nextPtr, + (XML_Bool)! parser->m_parsingStatus.finalBuffer, + XML_ACCOUNT_DIRECT); + if (result == XML_ERROR_NONE) { + if (! storeRawNames(parser)) + return XML_ERROR_NO_MEMORY; + } + return result; } } diff --git a/Modules/expat/xmltok.c b/Modules/expat/xmltok.c index c659983b4008..2b7012a58be4 100644 --- a/Modules/expat/xmltok.c +++ b/Modules/expat/xmltok.c @@ -21,6 +21,7 @@ Copyright (c) 2017 Jos? Guti?rrez de la Concha Copyright (c) 2019 David Loffredo Copyright (c) 2021 Dong-hee Na + Copyright (c) 2022 Martin Ettl Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -296,7 +297,7 @@ sb_charMatches(const ENCODING *enc, const char *p, int c) { } #else /* c is an ASCII character */ -# define CHAR_MATCHES(enc, p, c) (*(p) == c) +# define CHAR_MATCHES(enc, p, c) (*(p) == (c)) #endif #define PREFIX(ident) normal_##ident @@ -740,7 +741,7 @@ DEFINE_UTF16_TO_UTF16(big2_) ((p)[1] == 0 ? ((struct normal_encoding *)(enc))->type[(unsigned char)*(p)] \ : unicode_byte_type((p)[1], (p)[0])) #define LITTLE2_BYTE_TO_ASCII(p) ((p)[1] == 0 ? (p)[0] : -1) -#define LITTLE2_CHAR_MATCHES(p, c) ((p)[1] == 0 && (p)[0] == c) +#define LITTLE2_CHAR_MATCHES(p, c) ((p)[1] == 0 && (p)[0] == (c)) #define LITTLE2_IS_NAME_CHAR_MINBPC(p) \ UCS2_GET_NAMING(namePages, (unsigned char)p[1], (unsigned char)p[0]) #define LITTLE2_IS_NMSTRT_CHAR_MINBPC(p) \ @@ -875,7 +876,7 @@ static const struct normal_encoding internal_little2_encoding ? ((struct normal_encoding *)(enc))->type[(unsigned char)(p)[1]] \ : unicode_byte_type((p)[0], (p)[1])) #define BIG2_BYTE_TO_ASCII(p) ((p)[0] == 0 ? (p)[1] : -1) -#define BIG2_CHAR_MATCHES(p, c) ((p)[0] == 0 && (p)[1] == c) +#define BIG2_CHAR_MATCHES(p, c) ((p)[0] == 0 && (p)[1] == (c)) #define BIG2_IS_NAME_CHAR_MINBPC(p) \ UCS2_GET_NAMING(namePages, (unsigned char)p[0], (unsigned char)p[1]) #define BIG2_IS_NMSTRT_CHAR_MINBPC(p) \ diff --git a/Modules/expat/xmltok_impl.c b/Modules/expat/xmltok_impl.c index 4072b06497d1..1971d74bf8c9 100644 --- a/Modules/expat/xmltok_impl.c +++ b/Modules/expat/xmltok_impl.c @@ -16,6 +16,7 @@ Copyright (c) 2018 Anton Maklakov Copyright (c) 2019 David Loffredo Copyright (c) 2020 Boris Kolpackov + Copyright (c) 2022 Martin Ettl Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -96,7 +97,7 @@ # define CHECK_NMSTRT_CASE(n, enc, ptr, end, nextTokPtr) \ case BT_LEAD##n: \ - if (end - ptr < n) \ + if ((end) - (ptr) < (n)) \ return XML_TOK_PARTIAL_CHAR; \ if (IS_INVALID_CHAR(enc, ptr, n) || ! IS_NMSTRT_CHAR(enc, ptr, n)) { \ *nextTokPtr = ptr; \ @@ -124,7 +125,8 @@ # define PREFIX(ident) ident # endif -# define HAS_CHARS(enc, ptr, end, count) (end - ptr >= count * MINBPC(enc)) +# define HAS_CHARS(enc, ptr, end, count) \ + ((end) - (ptr) >= ((count)*MINBPC(enc))) # define HAS_CHAR(enc, ptr, end) HAS_CHARS(enc, ptr, end, 1) From webhook-mailer at python.org Tue Oct 4 13:05:50 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 04 Oct 2022 17:05:50 -0000 Subject: [Python-checkins] [3.9] gh-95778: Mention sys.set_int_max_str_digits() in error message (#96874) (#96877) Message-ID: https://github.com/python/cpython/commit/41188134bd2120f0cedd681ed88743c11c7f3742 commit: 41188134bd2120f0cedd681ed88743c11c7f3742 branch: 3.9 author: Victor Stinner committer: ambv date: 2022-10-04T10:05:45-07:00 summary: [3.9] gh-95778: Mention sys.set_int_max_str_digits() in error message (#96874) (#96877) When ValueError is raised if an integer is larger than the limit, mention sys.set_int_max_str_digits() in the error message. (cherry picked from commit e841ffc915e82e5ea6e3b473205417d63494808d) Co-authored-by: Ned Deily files: A Misc/NEWS.d/next/Core and Builtins/2022-09-16-19-02-40.gh-issue-95778.cJmnst.rst M Doc/library/stdtypes.rst M Objects/longobject.c diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 6eef56455edb..d6b270d144a7 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -5277,7 +5277,7 @@ When an operation would exceed the limit, a :exc:`ValueError` is raised: >>> _ = int('2' * 5432) Traceback (most recent call last): ... - ValueError: Exceeds the limit (4300) for integer string conversion: value has 5432 digits. + ValueError: Exceeds the limit (4300) for integer string conversion: value has 5432 digits; use sys.set_int_max_str_digits() to increase the limit. >>> i = int('2' * 4300) >>> len(str(i)) 4300 @@ -5285,7 +5285,7 @@ When an operation would exceed the limit, a :exc:`ValueError` is raised: >>> len(str(i_squared)) Traceback (most recent call last): ... - ValueError: Exceeds the limit (4300) for integer string conversion: value has 8599 digits. + ValueError: Exceeds the limit (4300) for integer string conversion: value has 8599 digits; use sys.set_int_max_str_digits() to increase the limit. >>> len(hex(i_squared)) 7144 >>> assert int(hex(i_squared), base=16) == i*i # Hexadecimal is unlimited. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-16-19-02-40.gh-issue-95778.cJmnst.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-16-19-02-40.gh-issue-95778.cJmnst.rst new file mode 100644 index 000000000000..ebf63778a605 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-09-16-19-02-40.gh-issue-95778.cJmnst.rst @@ -0,0 +1,3 @@ +When :exc:`ValueError` is raised if an integer is larger than the limit, +mention the :func:`sys.set_int_max_str_digits` function in the error message. +Patch by Victor Stinner. diff --git a/Objects/longobject.c b/Objects/longobject.c index ec18ec32b8a8..2a9178a05015 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -38,8 +38,8 @@ PyObject *_PyLong_One = NULL; #define IS_SMALL_INT(ival) (-NSMALLNEGINTS <= (ival) && (ival) < NSMALLPOSINTS) #define IS_SMALL_UINT(ival) ((ival) < NSMALLPOSINTS) -#define _MAX_STR_DIGITS_ERROR_FMT_TO_INT "Exceeds the limit (%d) for integer string conversion: value has %zd digits" -#define _MAX_STR_DIGITS_ERROR_FMT_TO_STR "Exceeds the limit (%d) for integer string conversion" +#define _MAX_STR_DIGITS_ERROR_FMT_TO_INT "Exceeds the limit (%d) for integer string conversion: value has %zd digits; use sys.set_int_max_str_digits() to increase the limit" +#define _MAX_STR_DIGITS_ERROR_FMT_TO_STR "Exceeds the limit (%d) for integer string conversion; use sys.set_int_max_str_digits() to increase the limit" static PyObject * get_small_int(sdigit ival) From webhook-mailer at python.org Tue Oct 4 13:06:22 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 04 Oct 2022 17:06:22 -0000 Subject: [Python-checkins] [3.9] gh-96577: Fixes buffer overrun in _msi module (GH-96633) (GH-96657) Message-ID: https://github.com/python/cpython/commit/938223e8d1eabdd6a73531a8dd52407ef23f6375 commit: 938223e8d1eabdd6a73531a8dd52407ef23f6375 branch: 3.9 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-04T10:06:17-07:00 summary: [3.9] gh-96577: Fixes buffer overrun in _msi module (GH-96633) (GH-96657) gh-96577: Fixes buffer overrun in _msi module (GH-96633) (cherry picked from commit 4114bcc9ef7595a07196bcecf9c7d6d39f57f64d) Co-authored-by: Steve Dower files: A Misc/NEWS.d/next/Windows/2022-09-07-00-11-33.gh-issue-96577.kV4K_1.rst M PC/_msi.c diff --git a/Misc/NEWS.d/next/Windows/2022-09-07-00-11-33.gh-issue-96577.kV4K_1.rst b/Misc/NEWS.d/next/Windows/2022-09-07-00-11-33.gh-issue-96577.kV4K_1.rst new file mode 100644 index 000000000000..6025e5ce4130 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2022-09-07-00-11-33.gh-issue-96577.kV4K_1.rst @@ -0,0 +1 @@ +Fixes a potential buffer overrun in :mod:`msilib`. diff --git a/PC/_msi.c b/PC/_msi.c index 913d3b85abb5..fd68e1df07f7 100644 --- a/PC/_msi.c +++ b/PC/_msi.c @@ -292,7 +292,7 @@ msierror(int status) int code; char buf[2000]; char *res = buf; - DWORD size = sizeof(buf); + DWORD size = Py_ARRAY_LENGTH(buf); MSIHANDLE err = MsiGetLastErrorRecord(); if (err == 0) { @@ -386,7 +386,7 @@ record_getstring(msiobj* record, PyObject* args) unsigned int status; WCHAR buf[2000]; WCHAR *res = buf; - DWORD size = sizeof(buf); + DWORD size = Py_ARRAY_LENGTH(buf); PyObject* string; if (!PyArg_ParseTuple(args, "I:GetString", &field)) From webhook-mailer at python.org Tue Oct 4 13:08:00 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 04 Oct 2022 17:08:00 -0000 Subject: [Python-checkins] [3.8] gh-97612: Fix shell injection in get-remote-certificate.py (GH-97613) (GH-97633) Message-ID: https://github.com/python/cpython/commit/90620490c04b6894d5a3f4214ecf5a10b41d25ec commit: 90620490c04b6894d5a3f4214ecf5a10b41d25ec branch: 3.8 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-04T10:07:55-07:00 summary: [3.8] gh-97612: Fix shell injection in get-remote-certificate.py (GH-97613) (GH-97633) Fix a shell code injection vulnerability in the get-remote-certificate.py example script. The script no longer uses a shell to run "openssl" commands. Issue reported and initial fix by Caleb Shortt. Remove the Windows code path to send "quit" on stdin to the "openssl s_client" command: use DEVNULL on all platforms instead. Co-authored-by: Caleb Shortt (cherry picked from commit 83a0f44ffd8b398673ae56c310cf5768d359c341) Co-authored-by: Victor Stinner files: A Misc/NEWS.d/next/Security/2022-09-28-12-10-57.gh-issue-97612.y6NvOQ.rst M Tools/scripts/get-remote-certificate.py diff --git a/Misc/NEWS.d/next/Security/2022-09-28-12-10-57.gh-issue-97612.y6NvOQ.rst b/Misc/NEWS.d/next/Security/2022-09-28-12-10-57.gh-issue-97612.y6NvOQ.rst new file mode 100644 index 000000000000..2f113492d42d --- /dev/null +++ b/Misc/NEWS.d/next/Security/2022-09-28-12-10-57.gh-issue-97612.y6NvOQ.rst @@ -0,0 +1,3 @@ +Fix a shell code injection vulnerability in the ``get-remote-certificate.py`` +example script. The script no longer uses a shell to run ``openssl`` commands. +Issue reported and initial fix by Caleb Shortt. Patch by Victor Stinner. diff --git a/Tools/scripts/get-remote-certificate.py b/Tools/scripts/get-remote-certificate.py index 38901286e19a..68272fca83fe 100755 --- a/Tools/scripts/get-remote-certificate.py +++ b/Tools/scripts/get-remote-certificate.py @@ -15,8 +15,8 @@ def fetch_server_certificate (host, port): def subproc(cmd): - from subprocess import Popen, PIPE, STDOUT - proc = Popen(cmd, stdout=PIPE, stderr=STDOUT, shell=True) + from subprocess import Popen, PIPE, STDOUT, DEVNULL + proc = Popen(cmd, stdout=PIPE, stderr=STDOUT, stdin=DEVNULL) status = proc.wait() output = proc.stdout.read() return status, output @@ -33,8 +33,8 @@ def strip_to_x509_cert(certfile_contents, outfile=None): fp.write(m.group(1) + b"\n") try: tn2 = (outfile or tempfile.mktemp()) - status, output = subproc(r'openssl x509 -in "%s" -out "%s"' % - (tn, tn2)) + cmd = ['openssl', 'x509', '-in', tn, '-out', tn2] + status, output = subproc(cmd) if status != 0: raise RuntimeError('OpenSSL x509 failed with status %s and ' 'output: %r' % (status, output)) @@ -45,20 +45,9 @@ def strip_to_x509_cert(certfile_contents, outfile=None): finally: os.unlink(tn) - if sys.platform.startswith("win"): - tfile = tempfile.mktemp() - with open(tfile, "w") as fp: - fp.write("quit\n") - try: - status, output = subproc( - 'openssl s_client -connect "%s:%s" -showcerts < "%s"' % - (host, port, tfile)) - finally: - os.unlink(tfile) - else: - status, output = subproc( - 'openssl s_client -connect "%s:%s" -showcerts < /dev/null' % - (host, port)) + cmd = ['openssl', 's_client', '-connect', '%s:%s' % (host, port), '-showcerts'] + status, output = subproc(cmd) + if status != 0: raise RuntimeError('OpenSSL connect failed with status %s and ' 'output: %r' % (status, output)) From webhook-mailer at python.org Tue Oct 4 13:08:29 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 04 Oct 2022 17:08:29 -0000 Subject: [Python-checkins] [3.8] gh-97616: list_resize() checks for integer overflow (GH-97617) (GH-97628) Message-ID: https://github.com/python/cpython/commit/f9ce9d4684cc293f40171af8fde253e4762baf9d commit: f9ce9d4684cc293f40171af8fde253e4762baf9d branch: 3.8 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-04T10:08:24-07:00 summary: [3.8] gh-97616: list_resize() checks for integer overflow (GH-97617) (GH-97628) gh-97616: list_resize() checks for integer overflow (GH-97617) Fix multiplying a list by an integer (list *= int): detect the integer overflow when the new allocated length is close to the maximum size. Issue reported by Jordan Limor. list_resize() now checks for integer overflow before multiplying the new allocated length by the list item size (sizeof(PyObject*)). (cherry picked from commit a5f092f3c469b674b8d9ccbd4e4377230c9ac7cf) Co-authored-by: Victor Stinner files: A Misc/NEWS.d/next/Security/2022-09-28-17-09-37.gh-issue-97616.K1e3Xs.rst M Lib/test/test_list.py M Objects/listobject.c diff --git a/Lib/test/test_list.py b/Lib/test/test_list.py index 105ef650eee9..75ecc70b0b0d 100644 --- a/Lib/test/test_list.py +++ b/Lib/test/test_list.py @@ -68,6 +68,19 @@ def imul(a, b): a *= b self.assertRaises((MemoryError, OverflowError), mul, lst, n) self.assertRaises((MemoryError, OverflowError), imul, lst, n) + def test_list_resize_overflow(self): + # gh-97616: test new_allocated * sizeof(PyObject*) overflow + # check in list_resize() + lst = [0] * 65 + del lst[1:] + self.assertEqual(len(lst), 1) + + size = ((2 ** (tuple.__itemsize__ * 8) - 1) // 2) + with self.assertRaises((MemoryError, OverflowError)): + lst * size + with self.assertRaises((MemoryError, OverflowError)): + lst *= size + def test_repr_large(self): # Check the repr of large list objects def check(n): diff --git a/Misc/NEWS.d/next/Security/2022-09-28-17-09-37.gh-issue-97616.K1e3Xs.rst b/Misc/NEWS.d/next/Security/2022-09-28-17-09-37.gh-issue-97616.K1e3Xs.rst new file mode 100644 index 000000000000..721427fe6465 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2022-09-28-17-09-37.gh-issue-97616.K1e3Xs.rst @@ -0,0 +1,3 @@ +Fix multiplying a list by an integer (``list *= int``): detect the integer +overflow when the new allocated length is close to the maximum size. Issue +reported by Jordan Limor. Patch by Victor Stinner. diff --git a/Objects/listobject.c b/Objects/listobject.c index 30444089ffaf..473de9d2dda5 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -66,8 +66,14 @@ list_resize(PyListObject *self, Py_ssize_t newsize) if (newsize == 0) new_allocated = 0; - num_allocated_bytes = new_allocated * sizeof(PyObject *); - items = (PyObject **)PyMem_Realloc(self->ob_item, num_allocated_bytes); + if (new_allocated <= (size_t)PY_SSIZE_T_MAX / sizeof(PyObject *)) { + num_allocated_bytes = new_allocated * sizeof(PyObject *); + items = (PyObject **)PyMem_Realloc(self->ob_item, num_allocated_bytes); + } + else { + // integer overflow + items = NULL; + } if (items == NULL) { PyErr_NoMemory(); return -1; From webhook-mailer at python.org Tue Oct 4 13:56:56 2022 From: webhook-mailer at python.org (gvanrossum) Date: Tue, 04 Oct 2022 17:56:56 -0000 Subject: [Python-checkins] gh-93357: Start porting asyncio server test cases to IsolatedAsyncioTestCase (#93369) Message-ID: https://github.com/python/cpython/commit/ce8fc186ac81bce1727bf4192205148daabf5c2e commit: ce8fc186ac81bce1727bf4192205148daabf5c2e branch: main author: Oleg Iarygin committer: gvanrossum date: 2022-10-04T10:56:47-07:00 summary: gh-93357: Start porting asyncio server test cases to IsolatedAsyncioTestCase (#93369) Lay the foundation for further work in `asyncio.test_streams`. files: M Lib/test/test_asyncio/test_streams.py diff --git a/Lib/test/test_asyncio/test_streams.py b/Lib/test/test_asyncio/test_streams.py index 0c49099bc499..d1f8aef4bb9c 100644 --- a/Lib/test/test_asyncio/test_streams.py +++ b/Lib/test/test_asyncio/test_streams.py @@ -566,46 +566,10 @@ def test_exception_cancel(self): test_utils.run_briefly(self.loop) self.assertIs(stream._waiter, None) - def test_start_server(self): - - class MyServer: - - def __init__(self, loop): - self.server = None - self.loop = loop - - async def handle_client(self, client_reader, client_writer): - data = await client_reader.readline() - client_writer.write(data) - await client_writer.drain() - client_writer.close() - await client_writer.wait_closed() - - def start(self): - sock = socket.create_server(('127.0.0.1', 0)) - self.server = self.loop.run_until_complete( - asyncio.start_server(self.handle_client, - sock=sock)) - return sock.getsockname() - - def handle_client_callback(self, client_reader, client_writer): - self.loop.create_task(self.handle_client(client_reader, - client_writer)) - - def start_callback(self): - sock = socket.create_server(('127.0.0.1', 0)) - addr = sock.getsockname() - sock.close() - self.server = self.loop.run_until_complete( - asyncio.start_server(self.handle_client_callback, - host=addr[0], port=addr[1])) - return addr - - def stop(self): - if self.server is not None: - self.server.close() - self.loop.run_until_complete(self.server.wait_closed()) - self.server = None + +class NewStreamTests(unittest.IsolatedAsyncioTestCase): + + async def test_start_server(self): async def client(addr): reader, writer = await asyncio.open_connection(*addr) @@ -617,61 +581,43 @@ async def client(addr): await writer.wait_closed() return msgback - messages = [] - self.loop.set_exception_handler(lambda loop, ctx: messages.append(ctx)) - - # test the server variant with a coroutine as client handler - server = MyServer(self.loop) - addr = server.start() - msg = self.loop.run_until_complete(self.loop.create_task(client(addr))) - server.stop() - self.assertEqual(msg, b"hello world!\n") + async def handle_client(client_reader, client_writer): + data = await client_reader.readline() + client_writer.write(data) + await client_writer.drain() + client_writer.close() + await client_writer.wait_closed() + + with self.subTest(msg="coroutine"): + server = await asyncio.start_server( + handle_client, + host=socket_helper.HOSTv4 + ) + addr = server.sockets[0].getsockname() + msg = await client(addr) + server.close() + await server.wait_closed() + self.assertEqual(msg, b"hello world!\n") - # test the server variant with a callback as client handler - server = MyServer(self.loop) - addr = server.start_callback() - msg = self.loop.run_until_complete(self.loop.create_task(client(addr))) - server.stop() - self.assertEqual(msg, b"hello world!\n") + with self.subTest(msg="callback"): + async def handle_client_callback(client_reader, client_writer): + asyncio.get_running_loop().create_task( + handle_client(client_reader, client_writer) + ) - self.assertEqual(messages, []) + server = await asyncio.start_server( + handle_client_callback, + host=socket_helper.HOSTv4 + ) + addr = server.sockets[0].getsockname() + reader, writer = await asyncio.open_connection(*addr) + msg = await client(addr) + server.close() + await server.wait_closed() + self.assertEqual(msg, b"hello world!\n") @socket_helper.skip_unless_bind_unix_socket - def test_start_unix_server(self): - - class MyServer: - - def __init__(self, loop, path): - self.server = None - self.loop = loop - self.path = path - - async def handle_client(self, client_reader, client_writer): - data = await client_reader.readline() - client_writer.write(data) - await client_writer.drain() - client_writer.close() - await client_writer.wait_closed() - - def start(self): - self.server = self.loop.run_until_complete( - asyncio.start_unix_server(self.handle_client, - path=self.path)) - - def handle_client_callback(self, client_reader, client_writer): - self.loop.create_task(self.handle_client(client_reader, - client_writer)) - - def start_callback(self): - start = asyncio.start_unix_server(self.handle_client_callback, - path=self.path) - self.server = self.loop.run_until_complete(start) - - def stop(self): - if self.server is not None: - self.server.close() - self.loop.run_until_complete(self.server.wait_closed()) - self.server = None + async def test_start_unix_server(self): async def client(path): reader, writer = await asyncio.open_unix_connection(path) @@ -683,64 +629,42 @@ async def client(path): await writer.wait_closed() return msgback - messages = [] - self.loop.set_exception_handler(lambda loop, ctx: messages.append(ctx)) - - # test the server variant with a coroutine as client handler - with test_utils.unix_socket_path() as path: - server = MyServer(self.loop, path) - server.start() - msg = self.loop.run_until_complete( - self.loop.create_task(client(path))) - server.stop() - self.assertEqual(msg, b"hello world!\n") - - # test the server variant with a callback as client handler - with test_utils.unix_socket_path() as path: - server = MyServer(self.loop, path) - server.start_callback() - msg = self.loop.run_until_complete( - self.loop.create_task(client(path))) - server.stop() - self.assertEqual(msg, b"hello world!\n") - - self.assertEqual(messages, []) + async def handle_client(client_reader, client_writer): + data = await client_reader.readline() + client_writer.write(data) + await client_writer.drain() + client_writer.close() + await client_writer.wait_closed() + + with self.subTest(msg="coroutine"): + with test_utils.unix_socket_path() as path: + server = await asyncio.start_unix_server( + handle_client, + path=path + ) + msg = await client(path) + server.close() + await server.wait_closed() + self.assertEqual(msg, b"hello world!\n") + + with self.subTest(msg="callback"): + async def handle_client_callback(client_reader, client_writer): + asyncio.get_running_loop().create_task( + handle_client(client_reader, client_writer) + ) + + with test_utils.unix_socket_path() as path: + server = await asyncio.start_unix_server( + handle_client_callback, + path=path + ) + msg = await client(path) + server.close() + await server.wait_closed() + self.assertEqual(msg, b"hello world!\n") @unittest.skipIf(ssl is None, 'No ssl module') - def test_start_tls(self): - - class MyServer: - - def __init__(self, loop): - self.server = None - self.loop = loop - - async def handle_client(self, client_reader, client_writer): - data1 = await client_reader.readline() - client_writer.write(data1) - await client_writer.drain() - assert client_writer.get_extra_info('sslcontext') is None - await client_writer.start_tls( - test_utils.simple_server_sslcontext()) - assert client_writer.get_extra_info('sslcontext') is not None - data2 = await client_reader.readline() - client_writer.write(data2) - await client_writer.drain() - client_writer.close() - await client_writer.wait_closed() - - def start(self): - sock = socket.create_server(('127.0.0.1', 0)) - self.server = self.loop.run_until_complete( - asyncio.start_server(self.handle_client, - sock=sock)) - return sock.getsockname() - - def stop(self): - if self.server is not None: - self.server.close() - self.loop.run_until_complete(self.server.wait_closed()) - self.server = None + async def test_start_tls(self): async def client(addr): reader, writer = await asyncio.open_connection(*addr) @@ -757,18 +681,49 @@ async def client(addr): await writer.wait_closed() return msgback1, msgback2 - messages = [] - self.loop.set_exception_handler(lambda loop, ctx: messages.append(ctx)) - - server = MyServer(self.loop) - addr = server.start() - msg1, msg2 = self.loop.run_until_complete(client(addr)) - server.stop() - - self.assertEqual(messages, []) + async def handle_client(client_reader, client_writer): + data1 = await client_reader.readline() + client_writer.write(data1) + await client_writer.drain() + assert client_writer.get_extra_info('sslcontext') is None + await client_writer.start_tls( + test_utils.simple_server_sslcontext()) + assert client_writer.get_extra_info('sslcontext') is not None + + data2 = await client_reader.readline() + client_writer.write(data2) + await client_writer.drain() + client_writer.close() + await client_writer.wait_closed() + + server = await asyncio.start_server( + handle_client, + host=socket_helper.HOSTv4 + ) + addr = server.sockets[0].getsockname() + + msg1, msg2 = await client(addr) + server.close() + await server.wait_closed() self.assertEqual(msg1, b"hello world 1!\n") self.assertEqual(msg2, b"hello world 2!\n") + +class StreamTests2(test_utils.TestCase): + + def setUp(self): + super().setUp() + self.loop = asyncio.new_event_loop() + self.set_event_loop(self.loop) + + def tearDown(self): + # just in case if we have transport close callbacks + test_utils.run_briefly(self.loop) + + self.loop.close() + gc.collect() + super().tearDown() + @unittest.skipIf(sys.platform == 'win32', "Don't have pipes") def test_read_all_from_pipe_reader(self): # See asyncio issue 168. This test is derived from the example @@ -986,22 +941,20 @@ def test_LimitOverrunError_pickleable(self): self.assertEqual(str(e), str(e2)) self.assertEqual(e.consumed, e2.consumed) - def test_wait_closed_on_close(self): - with test_utils.run_test_server() as httpd: + async def test_wait_closed_on_close(self): + async with test_utils.run_test_server() as httpd: rd, wr = self.loop.run_until_complete( asyncio.open_connection(*httpd.address)) wr.write(b'GET / HTTP/1.0\r\n\r\n') - f = rd.readline() - data = self.loop.run_until_complete(f) + data = await rd.readline() self.assertEqual(data, b'HTTP/1.0 200 OK\r\n') - f = rd.read() - data = self.loop.run_until_complete(f) + await rd.read() self.assertTrue(data.endswith(b'\r\n\r\nTest message')) self.assertFalse(wr.is_closing()) wr.close() self.assertTrue(wr.is_closing()) - self.loop.run_until_complete(wr.wait_closed()) + await wr.wait_closed() def test_wait_closed_on_close_with_unread_data(self): with test_utils.run_test_server() as httpd: @@ -1057,15 +1010,10 @@ async def inner(httpd): self.assertEqual(messages, []) - def test_eof_feed_when_closing_writer(self): + async def test_eof_feed_when_closing_writer(self): # See http://bugs.python.org/issue35065 - messages = [] - self.loop.set_exception_handler(lambda loop, ctx: messages.append(ctx)) - - with test_utils.run_test_server() as httpd: - rd, wr = self.loop.run_until_complete( - asyncio.open_connection(*httpd.address)) - + async with test_utils.run_test_server() as httpd: + rd, wr = await asyncio.open_connection(*httpd.address) wr.close() f = wr.wait_closed() self.loop.run_until_complete(f) @@ -1074,8 +1022,6 @@ def test_eof_feed_when_closing_writer(self): data = self.loop.run_until_complete(f) self.assertEqual(data, b'') - self.assertEqual(messages, []) - if __name__ == '__main__': unittest.main() From webhook-mailer at python.org Tue Oct 4 14:06:31 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 04 Oct 2022 18:06:31 -0000 Subject: [Python-checkins] [3.8] gh-97005: Update libexpat from 2.4.7 to 2.4.9 (gh-97006) (gh-97013) Message-ID: https://github.com/python/cpython/commit/069b7186be6025c0c03937b748dfc5fd6a57c9f2 commit: 069b7186be6025c0c03937b748dfc5fd6a57c9f2 branch: 3.8 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-04T11:06:26-07:00 summary: [3.8] gh-97005: Update libexpat from 2.4.7 to 2.4.9 (gh-97006) (gh-97013) gh-97005: Update libexpat from 2.4.7 to 2.4.9 (gh-97006) Co-authored-by: Gregory P. Smith [Google] (cherry picked from commit 10e3d398c31cc1695752fc52bc6ca2ce9ef6237e) Co-authored-by: Dong-hee Na files: A Misc/NEWS.d/next/Library/2022-09-22-14-35-02.gh-issue-97005.yf21Q7.rst M Modules/expat/COPYING M Modules/expat/expat.h M Modules/expat/internal.h M Modules/expat/siphash.h M Modules/expat/xmlparse.c M Modules/expat/xmltok.c M Modules/expat/xmltok_impl.c diff --git a/Misc/NEWS.d/next/Library/2022-09-22-14-35-02.gh-issue-97005.yf21Q7.rst b/Misc/NEWS.d/next/Library/2022-09-22-14-35-02.gh-issue-97005.yf21Q7.rst new file mode 100644 index 000000000000..d57999aa29b7 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-09-22-14-35-02.gh-issue-97005.yf21Q7.rst @@ -0,0 +1 @@ +Update bundled libexpat to 2.4.9 diff --git a/Modules/expat/COPYING b/Modules/expat/COPYING index 3c0142e71c8d..ce9e5939291e 100644 --- a/Modules/expat/COPYING +++ b/Modules/expat/COPYING @@ -1,5 +1,5 @@ Copyright (c) 1998-2000 Thai Open Source Software Center Ltd and Clark Cooper -Copyright (c) 2001-2019 Expat maintainers +Copyright (c) 2001-2022 Expat maintainers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/Modules/expat/expat.h b/Modules/expat/expat.h index c9214f64070a..2b47ce2a8d3a 100644 --- a/Modules/expat/expat.h +++ b/Modules/expat/expat.h @@ -1055,7 +1055,7 @@ XML_SetBillionLaughsAttackProtectionActivationThreshold( */ #define XML_MAJOR_VERSION 2 #define XML_MINOR_VERSION 4 -#define XML_MICRO_VERSION 7 +#define XML_MICRO_VERSION 9 #ifdef __cplusplus } diff --git a/Modules/expat/internal.h b/Modules/expat/internal.h index 444eba0fb031..e09f533b23c9 100644 --- a/Modules/expat/internal.h +++ b/Modules/expat/internal.h @@ -28,7 +28,7 @@ Copyright (c) 2002-2003 Fred L. Drake, Jr. Copyright (c) 2002-2006 Karl Waclawek Copyright (c) 2003 Greg Stein - Copyright (c) 2016-2021 Sebastian Pipping + Copyright (c) 2016-2022 Sebastian Pipping Copyright (c) 2018 Yury Gribov Copyright (c) 2019 David Loffredo Licensed under the MIT license: @@ -107,7 +107,9 @@ #include // ULONG_MAX -#if defined(_WIN32) && ! defined(__USE_MINGW_ANSI_STDIO) +#if defined(_WIN32) \ + && (! defined(__USE_MINGW_ANSI_STDIO) \ + || (1 - __USE_MINGW_ANSI_STDIO - 1 == 0)) # define EXPAT_FMT_ULL(midpart) "%" midpart "I64u" # if defined(_WIN64) // Note: modifiers "td" and "zu" do not work for MinGW # define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "I64d" diff --git a/Modules/expat/siphash.h b/Modules/expat/siphash.h index e5406d7ee9eb..303283ad2de9 100644 --- a/Modules/expat/siphash.h +++ b/Modules/expat/siphash.h @@ -106,7 +106,7 @@ * if this code is included and compiled as C++; related GCC warning is: * warning: use of C++11 long long integer constant [-Wlong-long] */ -#define _SIP_ULL(high, low) (((uint64_t)high << 32) | low) +#define _SIP_ULL(high, low) ((((uint64_t)high) << 32) | (low)) #define SIP_ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b)))) diff --git a/Modules/expat/xmlparse.c b/Modules/expat/xmlparse.c index 05216d997b07..c0bece51d700 100644 --- a/Modules/expat/xmlparse.c +++ b/Modules/expat/xmlparse.c @@ -1,4 +1,4 @@ -/* fcb1a62fefa945567301146eb98e3ad3413e823a41c4378e84e8b6b6f308d824 (2.4.7+) +/* 90815a2b2c80c03b2b889fe1d427bb2b9e3282aa065e42784e001db4f23de324 (2.4.9+) __ __ _ ___\ \/ /_ __ __ _| |_ / _ \\ /| '_ \ / _` | __| @@ -19,7 +19,7 @@ Copyright (c) 2016 Gustavo Grieco Copyright (c) 2016 Pascal Cuoq Copyright (c) 2016 Ed Schouten - Copyright (c) 2017-2018 Rhodri James + Copyright (c) 2017-2022 Rhodri James Copyright (c) 2017 V?clav Slav?k Copyright (c) 2017 Viktor Szakats Copyright (c) 2017 Chanho Park @@ -4271,7 +4271,7 @@ processXmlDecl(XML_Parser parser, int isGeneralTextEntity, const char *s, const XML_Char *storedEncName = NULL; const ENCODING *newEncoding = NULL; const char *version = NULL; - const char *versionend; + const char *versionend = NULL; const XML_Char *storedversion = NULL; int standalone = -1; @@ -5826,10 +5826,15 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end, { parser->m_processor = contentProcessor; /* see externalEntityContentProcessor vs contentProcessor */ - return doContent(parser, parser->m_parentParser ? 1 : 0, parser->m_encoding, - s, end, nextPtr, - (XML_Bool)! parser->m_parsingStatus.finalBuffer, - XML_ACCOUNT_DIRECT); + result = doContent(parser, parser->m_parentParser ? 1 : 0, + parser->m_encoding, s, end, nextPtr, + (XML_Bool)! parser->m_parsingStatus.finalBuffer, + XML_ACCOUNT_DIRECT); + if (result == XML_ERROR_NONE) { + if (! storeRawNames(parser)) + return XML_ERROR_NO_MEMORY; + } + return result; } } diff --git a/Modules/expat/xmltok.c b/Modules/expat/xmltok.c index c659983b4008..2b7012a58be4 100644 --- a/Modules/expat/xmltok.c +++ b/Modules/expat/xmltok.c @@ -21,6 +21,7 @@ Copyright (c) 2017 Jos? Guti?rrez de la Concha Copyright (c) 2019 David Loffredo Copyright (c) 2021 Dong-hee Na + Copyright (c) 2022 Martin Ettl Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -296,7 +297,7 @@ sb_charMatches(const ENCODING *enc, const char *p, int c) { } #else /* c is an ASCII character */ -# define CHAR_MATCHES(enc, p, c) (*(p) == c) +# define CHAR_MATCHES(enc, p, c) (*(p) == (c)) #endif #define PREFIX(ident) normal_##ident @@ -740,7 +741,7 @@ DEFINE_UTF16_TO_UTF16(big2_) ((p)[1] == 0 ? ((struct normal_encoding *)(enc))->type[(unsigned char)*(p)] \ : unicode_byte_type((p)[1], (p)[0])) #define LITTLE2_BYTE_TO_ASCII(p) ((p)[1] == 0 ? (p)[0] : -1) -#define LITTLE2_CHAR_MATCHES(p, c) ((p)[1] == 0 && (p)[0] == c) +#define LITTLE2_CHAR_MATCHES(p, c) ((p)[1] == 0 && (p)[0] == (c)) #define LITTLE2_IS_NAME_CHAR_MINBPC(p) \ UCS2_GET_NAMING(namePages, (unsigned char)p[1], (unsigned char)p[0]) #define LITTLE2_IS_NMSTRT_CHAR_MINBPC(p) \ @@ -875,7 +876,7 @@ static const struct normal_encoding internal_little2_encoding ? ((struct normal_encoding *)(enc))->type[(unsigned char)(p)[1]] \ : unicode_byte_type((p)[0], (p)[1])) #define BIG2_BYTE_TO_ASCII(p) ((p)[0] == 0 ? (p)[1] : -1) -#define BIG2_CHAR_MATCHES(p, c) ((p)[0] == 0 && (p)[1] == c) +#define BIG2_CHAR_MATCHES(p, c) ((p)[0] == 0 && (p)[1] == (c)) #define BIG2_IS_NAME_CHAR_MINBPC(p) \ UCS2_GET_NAMING(namePages, (unsigned char)p[0], (unsigned char)p[1]) #define BIG2_IS_NMSTRT_CHAR_MINBPC(p) \ diff --git a/Modules/expat/xmltok_impl.c b/Modules/expat/xmltok_impl.c index 4072b06497d1..1971d74bf8c9 100644 --- a/Modules/expat/xmltok_impl.c +++ b/Modules/expat/xmltok_impl.c @@ -16,6 +16,7 @@ Copyright (c) 2018 Anton Maklakov Copyright (c) 2019 David Loffredo Copyright (c) 2020 Boris Kolpackov + Copyright (c) 2022 Martin Ettl Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -96,7 +97,7 @@ # define CHECK_NMSTRT_CASE(n, enc, ptr, end, nextTokPtr) \ case BT_LEAD##n: \ - if (end - ptr < n) \ + if ((end) - (ptr) < (n)) \ return XML_TOK_PARTIAL_CHAR; \ if (IS_INVALID_CHAR(enc, ptr, n) || ! IS_NMSTRT_CHAR(enc, ptr, n)) { \ *nextTokPtr = ptr; \ @@ -124,7 +125,8 @@ # define PREFIX(ident) ident # endif -# define HAS_CHARS(enc, ptr, end, count) (end - ptr >= count * MINBPC(enc)) +# define HAS_CHARS(enc, ptr, end, count) \ + ((end) - (ptr) >= ((count)*MINBPC(enc))) # define HAS_CHAR(enc, ptr, end) HAS_CHARS(enc, ptr, end, 1) From webhook-mailer at python.org Tue Oct 4 14:07:14 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 04 Oct 2022 18:07:14 -0000 Subject: [Python-checkins] [3.8] gh-96577: Fixes buffer overrun in _msi module (GH-96633) (GH-96658) Message-ID: https://github.com/python/cpython/commit/12c72d684d43bf87e8457fd0190343daf01db23d commit: 12c72d684d43bf87e8457fd0190343daf01db23d branch: 3.8 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-04T11:07:09-07:00 summary: [3.8] gh-96577: Fixes buffer overrun in _msi module (GH-96633) (GH-96658) gh-96577: Fixes buffer overrun in _msi module (GH-96633) (cherry picked from commit 4114bcc9ef7595a07196bcecf9c7d6d39f57f64d) Co-authored-by: Steve Dower files: A Misc/NEWS.d/next/Windows/2022-09-07-00-11-33.gh-issue-96577.kV4K_1.rst M PC/_msi.c diff --git a/Misc/NEWS.d/next/Windows/2022-09-07-00-11-33.gh-issue-96577.kV4K_1.rst b/Misc/NEWS.d/next/Windows/2022-09-07-00-11-33.gh-issue-96577.kV4K_1.rst new file mode 100644 index 000000000000..6025e5ce4130 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2022-09-07-00-11-33.gh-issue-96577.kV4K_1.rst @@ -0,0 +1 @@ +Fixes a potential buffer overrun in :mod:`msilib`. diff --git a/PC/_msi.c b/PC/_msi.c index 5079a524646f..0b92712233c9 100644 --- a/PC/_msi.c +++ b/PC/_msi.c @@ -292,7 +292,7 @@ msierror(int status) int code; char buf[2000]; char *res = buf; - DWORD size = sizeof(buf); + DWORD size = Py_ARRAY_LENGTH(buf); MSIHANDLE err = MsiGetLastErrorRecord(); if (err == 0) { @@ -386,7 +386,7 @@ record_getstring(msiobj* record, PyObject* args) unsigned int status; WCHAR buf[2000]; WCHAR *res = buf; - DWORD size = sizeof(buf); + DWORD size = Py_ARRAY_LENGTH(buf); PyObject* string; if (!PyArg_ParseTuple(args, "I:GetString", &field)) From webhook-mailer at python.org Tue Oct 4 14:37:13 2022 From: webhook-mailer at python.org (gvanrossum) Date: Tue, 04 Oct 2022 18:37:13 -0000 Subject: [Python-checkins] GH-95913: Update what's new in 3.11 for asyncio (#97806) Message-ID: https://github.com/python/cpython/commit/9fbfa42ece3e0256657ce2594c7c3eb8b3ac8ff3 commit: 9fbfa42ece3e0256657ce2594c7c3eb8b3ac8ff3 branch: main author: Guido van Rossum committer: gvanrossum date: 2022-10-04T11:36:20-07:00 summary: GH-95913: Update what's new in 3.11 for asyncio (#97806) Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> Co-authored-by: C.A.M. Gerlach Co-authored-by: Jelle Zijlstra files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 19821e1b6029..0d38abfc0005 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -529,27 +529,51 @@ New Modules Improved Modules ================ +.. _whatsnew311-asyncio: + asyncio ------- -* Add raw datagram socket functions to the event loop: - :meth:`~asyncio.AbstractEventLoop.sock_sendto`, - :meth:`~asyncio.AbstractEventLoop.sock_recvfrom` and - :meth:`~asyncio.AbstractEventLoop.sock_recvfrom_into`. - (Contributed by Alex Gr?nholm in :issue:`46805`.) - -* Add :meth:`~asyncio.streams.StreamWriter.start_tls` method for upgrading - existing stream-based connections to TLS. (Contributed by Ian Good in - :issue:`34975`.) - -* Add :class:`~asyncio.Barrier` class to the synchronization primitives of - the asyncio library. (Contributed by Yves Duprat and Andrew Svetlov in - :gh:`87518`.) - -* Add :class:`~asyncio.TaskGroup` class, +* Added the :class:`~asyncio.TaskGroup` class, an :ref:`asynchronous context manager ` holding a group of tasks that will wait for all of them upon exit. - (Contributed by Yury Seliganov and others.) + For new code this is recommended over using + :func:`~asyncio.create_task` and :func:`~asyncio.gather` directly. + (Contributed by Yury Selivanov and others in :gh:`90908`.) + +* Added :func:`~asyncio.timeout`, an asynchronous context manager for + setting a timeout on asynchronous operations. For new code this is + recommended over using :func:`~asyncio.wait_for` directly. + (Contributed by Andrew Svetlov in :gh:`90927`.) + +* Added the :class:`~asyncio.Runner` class, which exposes the machinery + used by :func:`~asyncio.run`. + (Contributed by Andrew Svetlov in :gh:`91218`.) + +* Added the :class:`~asyncio.Barrier` class to the synchronization + primitives in the asyncio library, and the related + :exc:`~asyncio.BrokenBarrierError` exception. + (Contributed by Yves Duprat and Andrew Svetlov in :gh:`87518`.) + +* Added keyword argument *all_errors* to :meth:`asyncio.loop.create_connection` + so that multiple connection errors can be raised as an :exc:`ExceptionGroup`. + +* Added the :meth:`asyncio.StreamWriter.start_tls` method for + upgrading existing stream-based connections to TLS. + (Contributed by Ian Good in :issue:`34975`.) + +* Added raw datagram socket functions to the event loop: + :meth:`~asyncio.loop.sock_sendto`, + :meth:`~asyncio.loop.sock_recvfrom` and + :meth:`~asyncio.loop.sock_recvfrom_into`. + These have implementations in :class:`~asyncio.SelectorEventLoop` and + :class:`~asyncio.ProactorEventLoop`. + (Contributed by Alex Gr?nholm in :issue:`46805`.) + +* Added :meth:`~asyncio.Task.cancelling` and + :meth:`~asyncio.Task.uncancel` methods to :class:`~asyncio.Task`. + These are primarily intended for internal use, + notably by :class:`~asyncio.TaskGroup`. contextlib ---------- From webhook-mailer at python.org Tue Oct 4 14:45:44 2022 From: webhook-mailer at python.org (miss-islington) Date: Tue, 04 Oct 2022 18:45:44 -0000 Subject: [Python-checkins] GH-95913: Update what's new in 3.11 for asyncio (GH-97806) Message-ID: https://github.com/python/cpython/commit/dcec9b70c96fac8b9ebf54d05459c15f0606b3c6 commit: dcec9b70c96fac8b9ebf54d05459c15f0606b3c6 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-04T11:45:02-07:00 summary: GH-95913: Update what's new in 3.11 for asyncio (GH-97806) Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> Co-authored-by: C.A.M. Gerlach Co-authored-by: Jelle Zijlstra (cherry picked from commit 9fbfa42ece3e0256657ce2594c7c3eb8b3ac8ff3) Co-authored-by: Guido van Rossum files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 60e2d794e6c1..fe36f99f5382 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -540,27 +540,51 @@ New Modules Improved Modules ================ +.. _whatsnew311-asyncio: + asyncio ------- -* Add raw datagram socket functions to the event loop: - :meth:`~asyncio.AbstractEventLoop.sock_sendto`, - :meth:`~asyncio.AbstractEventLoop.sock_recvfrom` and - :meth:`~asyncio.AbstractEventLoop.sock_recvfrom_into`. - (Contributed by Alex Gr?nholm in :issue:`46805`.) - -* Add :meth:`~asyncio.streams.StreamWriter.start_tls` method for upgrading - existing stream-based connections to TLS. (Contributed by Ian Good in - :issue:`34975`.) - -* Add :class:`~asyncio.Barrier` class to the synchronization primitives of - the asyncio library. (Contributed by Yves Duprat and Andrew Svetlov in - :gh:`87518`.) - -* Add :class:`~asyncio.TaskGroup` class, +* Added the :class:`~asyncio.TaskGroup` class, an :ref:`asynchronous context manager ` holding a group of tasks that will wait for all of them upon exit. - (Contributed by Yury Seliganov and others.) + For new code this is recommended over using + :func:`~asyncio.create_task` and :func:`~asyncio.gather` directly. + (Contributed by Yury Selivanov and others in :gh:`90908`.) + +* Added :func:`~asyncio.timeout`, an asynchronous context manager for + setting a timeout on asynchronous operations. For new code this is + recommended over using :func:`~asyncio.wait_for` directly. + (Contributed by Andrew Svetlov in :gh:`90927`.) + +* Added the :class:`~asyncio.Runner` class, which exposes the machinery + used by :func:`~asyncio.run`. + (Contributed by Andrew Svetlov in :gh:`91218`.) + +* Added the :class:`~asyncio.Barrier` class to the synchronization + primitives in the asyncio library, and the related + :exc:`~asyncio.BrokenBarrierError` exception. + (Contributed by Yves Duprat and Andrew Svetlov in :gh:`87518`.) + +* Added keyword argument *all_errors* to :meth:`asyncio.loop.create_connection` + so that multiple connection errors can be raised as an :exc:`ExceptionGroup`. + +* Added the :meth:`asyncio.StreamWriter.start_tls` method for + upgrading existing stream-based connections to TLS. + (Contributed by Ian Good in :issue:`34975`.) + +* Added raw datagram socket functions to the event loop: + :meth:`~asyncio.loop.sock_sendto`, + :meth:`~asyncio.loop.sock_recvfrom` and + :meth:`~asyncio.loop.sock_recvfrom_into`. + These have implementations in :class:`~asyncio.SelectorEventLoop` and + :class:`~asyncio.ProactorEventLoop`. + (Contributed by Alex Gr?nholm in :issue:`46805`.) + +* Added :meth:`~asyncio.Task.cancelling` and + :meth:`~asyncio.Task.uncancel` methods to :class:`~asyncio.Task`. + These are primarily intended for internal use, + notably by :class:`~asyncio.TaskGroup`. contextlib ---------- From webhook-mailer at python.org Tue Oct 4 14:57:11 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 04 Oct 2022 18:57:11 -0000 Subject: [Python-checkins] [3.8] gh-96848: Fix -X int_max_str_digits option parsing (GH-96988) (GH-97575) Message-ID: https://github.com/python/cpython/commit/18a0cdb2dc86452d8d75aac7e9bb610270979411 commit: 18a0cdb2dc86452d8d75aac7e9bb610270979411 branch: 3.8 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-04T11:57:06-07:00 summary: [3.8] gh-96848: Fix -X int_max_str_digits option parsing (GH-96988) (GH-97575) Fix command line parsing: reject "-X int_max_str_digits" option with no value (invalid) when the PYTHONINTMAXSTRDIGITS environment variable is set to a valid limit. (cherry picked from commit 41351662bcd21672d8ccfa62fe44d72027e6bcf8) Co-authored-by: Victor Stinner files: A Misc/NEWS.d/next/Core and Builtins/2022-09-21-14-38-31.gh-issue-96848.WuoLzU.rst M Lib/test/test_cmd_line.py M Python/initconfig.c diff --git a/Lib/test/test_cmd_line.py b/Lib/test/test_cmd_line.py index 9f09a5017622..3e2f12a9d5f2 100644 --- a/Lib/test/test_cmd_line.py +++ b/Lib/test/test_cmd_line.py @@ -794,6 +794,8 @@ def test_int_max_str_digits(self): assert_python_failure('-X', 'int_max_str_digits', '-c', code) assert_python_failure('-X', 'int_max_str_digits=foo', '-c', code) assert_python_failure('-X', 'int_max_str_digits=100', '-c', code) + assert_python_failure('-X', 'int_max_str_digits', '-c', code, + PYTHONINTMAXSTRDIGITS='4000') assert_python_failure('-c', code, PYTHONINTMAXSTRDIGITS='foo') assert_python_failure('-c', code, PYTHONINTMAXSTRDIGITS='100') diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-21-14-38-31.gh-issue-96848.WuoLzU.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-21-14-38-31.gh-issue-96848.WuoLzU.rst new file mode 100644 index 000000000000..a9b04ce87d4d --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-09-21-14-38-31.gh-issue-96848.WuoLzU.rst @@ -0,0 +1,3 @@ +Fix command line parsing: reject :option:`-X int_max_str_digits <-X>` option +with no value (invalid) when the :envvar:`PYTHONINTMAXSTRDIGITS` environment +variable is set to a valid limit. Patch by Victor Stinner. diff --git a/Python/initconfig.c b/Python/initconfig.c index c2203c82367e..003ac76c6e8b 100644 --- a/Python/initconfig.c +++ b/Python/initconfig.c @@ -1403,10 +1403,10 @@ static PyStatus config_init_int_max_str_digits(PyConfig *config) { int maxdigits; - int valid = 0; const char *env = config_get_env(config, "PYTHONINTMAXSTRDIGITS"); if (env) { + int valid = 0; if (!_Py_str_to_int(env, &maxdigits)) { valid = ((maxdigits == 0) || (maxdigits >= _PY_LONG_MAX_STR_DIGITS_THRESHOLD)); } @@ -1424,6 +1424,7 @@ config_init_int_max_str_digits(PyConfig *config) const wchar_t *xoption = config_get_xoption(config, L"int_max_str_digits"); if (xoption) { const wchar_t *sep = wcschr(xoption, L'='); + int valid = 0; if (sep) { if (!config_wstr_to_int(sep + 1, &maxdigits)) { valid = ((maxdigits == 0) || (maxdigits >= _PY_LONG_MAX_STR_DIGITS_THRESHOLD)); From webhook-mailer at python.org Tue Oct 4 14:57:39 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 04 Oct 2022 18:57:39 -0000 Subject: [Python-checkins] [3.9] gh-96848: Fix -X int_max_str_digits option parsing (GH-96988) (GH-97574) Message-ID: https://github.com/python/cpython/commit/358b7a4454daf22b0c3b958da6172bf7f3090be3 commit: 358b7a4454daf22b0c3b958da6172bf7f3090be3 branch: 3.9 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-04T11:57:34-07:00 summary: [3.9] gh-96848: Fix -X int_max_str_digits option parsing (GH-96988) (GH-97574) gh-96848: Fix -X int_max_str_digits option parsing (GH-96988) Fix command line parsing: reject "-X int_max_str_digits" option with no value (invalid) when the PYTHONINTMAXSTRDIGITS environment variable is set to a valid limit. (cherry picked from commit 41351662bcd21672d8ccfa62fe44d72027e6bcf8) Co-authored-by: Victor Stinner files: A Misc/NEWS.d/next/Core and Builtins/2022-09-21-14-38-31.gh-issue-96848.WuoLzU.rst M Lib/test/test_cmd_line.py M Python/initconfig.c diff --git a/Lib/test/test_cmd_line.py b/Lib/test/test_cmd_line.py index e38fc698c52d..9fb48c5bac86 100644 --- a/Lib/test/test_cmd_line.py +++ b/Lib/test/test_cmd_line.py @@ -821,6 +821,8 @@ def test_int_max_str_digits(self): assert_python_failure('-X', 'int_max_str_digits', '-c', code) assert_python_failure('-X', 'int_max_str_digits=foo', '-c', code) assert_python_failure('-X', 'int_max_str_digits=100', '-c', code) + assert_python_failure('-X', 'int_max_str_digits', '-c', code, + PYTHONINTMAXSTRDIGITS='4000') assert_python_failure('-c', code, PYTHONINTMAXSTRDIGITS='foo') assert_python_failure('-c', code, PYTHONINTMAXSTRDIGITS='100') diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-21-14-38-31.gh-issue-96848.WuoLzU.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-21-14-38-31.gh-issue-96848.WuoLzU.rst new file mode 100644 index 000000000000..a9b04ce87d4d --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-09-21-14-38-31.gh-issue-96848.WuoLzU.rst @@ -0,0 +1,3 @@ +Fix command line parsing: reject :option:`-X int_max_str_digits <-X>` option +with no value (invalid) when the :envvar:`PYTHONINTMAXSTRDIGITS` environment +variable is set to a valid limit. Patch by Victor Stinner. diff --git a/Python/initconfig.c b/Python/initconfig.c index a2c435f34474..7ab52fb934c9 100644 --- a/Python/initconfig.c +++ b/Python/initconfig.c @@ -1426,10 +1426,10 @@ static PyStatus config_init_int_max_str_digits(PyConfig *config) { int maxdigits; - int valid = 0; const char *env = config_get_env(config, "PYTHONINTMAXSTRDIGITS"); if (env) { + int valid = 0; if (!_Py_str_to_int(env, &maxdigits)) { valid = ((maxdigits == 0) || (maxdigits >= _PY_LONG_MAX_STR_DIGITS_THRESHOLD)); } @@ -1447,6 +1447,7 @@ config_init_int_max_str_digits(PyConfig *config) const wchar_t *xoption = config_get_xoption(config, L"int_max_str_digits"); if (xoption) { const wchar_t *sep = wcschr(xoption, L'='); + int valid = 0; if (sep) { if (!config_wstr_to_int(sep + 1, &maxdigits)) { valid = ((maxdigits == 0) || (maxdigits >= _PY_LONG_MAX_STR_DIGITS_THRESHOLD)); From webhook-mailer at python.org Tue Oct 4 14:58:15 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 04 Oct 2022 18:58:15 -0000 Subject: [Python-checkins] [3.8] gh-95778: Mention sys.set_int_max_str_digits() in error message (GH-96874) (GH-96877) (GH-97835) Message-ID: https://github.com/python/cpython/commit/dca2fd28235bca84935701d468996fd1b3adbb12 commit: dca2fd28235bca84935701d468996fd1b3adbb12 branch: 3.8 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-04T11:58:10-07:00 summary: [3.8] gh-95778: Mention sys.set_int_max_str_digits() in error message (GH-96874) (GH-96877) (GH-97835) [3.9] gh-95778: Mention sys.set_int_max_str_digits() in error message (GH-96874) (GH-96877) When ValueError is raised if an integer is larger than the limit, mention sys.set_int_max_str_digits() in the error message. (cherry picked from commit e841ffc915e82e5ea6e3b473205417d63494808d) Co-authored-by: Ned Deily (cherry picked from commit 41188134bd2120f0cedd681ed88743c11c7f3742) Co-authored-by: Victor Stinner files: A Misc/NEWS.d/next/Core and Builtins/2022-09-16-19-02-40.gh-issue-95778.cJmnst.rst M Doc/library/stdtypes.rst M Objects/longobject.c diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 14d48e6b07c0..45d648bca0c5 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -4903,7 +4903,7 @@ When an operation would exceed the limit, a :exc:`ValueError` is raised: >>> _ = int('2' * 5432) Traceback (most recent call last): ... - ValueError: Exceeds the limit (4300) for integer string conversion: value has 5432 digits. + ValueError: Exceeds the limit (4300) for integer string conversion: value has 5432 digits; use sys.set_int_max_str_digits() to increase the limit. >>> i = int('2' * 4300) >>> len(str(i)) 4300 @@ -4911,7 +4911,7 @@ When an operation would exceed the limit, a :exc:`ValueError` is raised: >>> len(str(i_squared)) Traceback (most recent call last): ... - ValueError: Exceeds the limit (4300) for integer string conversion: value has 8599 digits. + ValueError: Exceeds the limit (4300) for integer string conversion: value has 8599 digits; use sys.set_int_max_str_digits() to increase the limit. >>> len(hex(i_squared)) 7144 >>> assert int(hex(i_squared), base=16) == i*i # Hexadecimal is unlimited. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-16-19-02-40.gh-issue-95778.cJmnst.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-16-19-02-40.gh-issue-95778.cJmnst.rst new file mode 100644 index 000000000000..ebf63778a605 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-09-16-19-02-40.gh-issue-95778.cJmnst.rst @@ -0,0 +1,3 @@ +When :exc:`ValueError` is raised if an integer is larger than the limit, +mention the :func:`sys.set_int_max_str_digits` function in the error message. +Patch by Victor Stinner. diff --git a/Objects/longobject.c b/Objects/longobject.c index a58a2e1e78b1..268505197672 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -48,8 +48,8 @@ static PyLongObject small_ints[NSMALLNEGINTS + NSMALLPOSINTS]; Py_ssize_t _Py_quick_int_allocs, _Py_quick_neg_int_allocs; #endif -#define _MAX_STR_DIGITS_ERROR_FMT_TO_INT "Exceeds the limit (%d) for integer string conversion: value has %zd digits" -#define _MAX_STR_DIGITS_ERROR_FMT_TO_STR "Exceeds the limit (%d) for integer string conversion" +#define _MAX_STR_DIGITS_ERROR_FMT_TO_INT "Exceeds the limit (%d) for integer string conversion: value has %zd digits; use sys.set_int_max_str_digits() to increase the limit" +#define _MAX_STR_DIGITS_ERROR_FMT_TO_STR "Exceeds the limit (%d) for integer string conversion; use sys.set_int_max_str_digits() to increase the limit" static PyObject * get_small_int(sdigit ival) From webhook-mailer at python.org Tue Oct 4 14:59:49 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 04 Oct 2022 18:59:49 -0000 Subject: [Python-checkins] [3.7] gh-95778: Mention sys.set_int_max_str_digits() in error message (GH-96874) (GH-96877) (GH-97836) Message-ID: https://github.com/python/cpython/commit/7fcfa94a856afecd20f7f66b6c248f776724bf7c commit: 7fcfa94a856afecd20f7f66b6c248f776724bf7c branch: 3.7 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-04T11:59:43-07:00 summary: [3.7] gh-95778: Mention sys.set_int_max_str_digits() in error message (GH-96874) (GH-96877) (GH-97836) [3.9] gh-95778: Mention sys.set_int_max_str_digits() in error message (GH-96874) (GH-96877) When ValueError is raised if an integer is larger than the limit, mention sys.set_int_max_str_digits() in the error message. (cherry picked from commit e841ffc915e82e5ea6e3b473205417d63494808d) Co-authored-by: Ned Deily (cherry picked from commit 41188134bd2120f0cedd681ed88743c11c7f3742) Co-authored-by: Victor Stinner files: A Misc/NEWS.d/next/Core and Builtins/2022-09-16-19-02-40.gh-issue-95778.cJmnst.rst M Doc/library/stdtypes.rst M Objects/longobject.c diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 36e0bed90d44..99dc1b2be3d4 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -4774,7 +4774,7 @@ When an operation would exceed the limit, a :exc:`ValueError` is raised: >>> _ = int('2' * 5432) Traceback (most recent call last): ... - ValueError: Exceeds the limit (4300) for integer string conversion: value has 5432 digits. + ValueError: Exceeds the limit (4300) for integer string conversion: value has 5432 digits; use sys.set_int_max_str_digits() to increase the limit. >>> i = int('2' * 4300) >>> len(str(i)) 4300 @@ -4782,7 +4782,7 @@ When an operation would exceed the limit, a :exc:`ValueError` is raised: >>> len(str(i_squared)) Traceback (most recent call last): ... - ValueError: Exceeds the limit (4300) for integer string conversion: value has 8599 digits. + ValueError: Exceeds the limit (4300) for integer string conversion: value has 8599 digits; use sys.set_int_max_str_digits() to increase the limit. >>> len(hex(i_squared)) 7144 >>> assert int(hex(i_squared), base=16) == i*i # Hexadecimal is unlimited. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-16-19-02-40.gh-issue-95778.cJmnst.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-16-19-02-40.gh-issue-95778.cJmnst.rst new file mode 100644 index 000000000000..ebf63778a605 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-09-16-19-02-40.gh-issue-95778.cJmnst.rst @@ -0,0 +1,3 @@ +When :exc:`ValueError` is raised if an integer is larger than the limit, +mention the :func:`sys.set_int_max_str_digits` function in the error message. +Patch by Victor Stinner. diff --git a/Objects/longobject.c b/Objects/longobject.c index a481a16eb01c..13db94b3d4ad 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -47,8 +47,8 @@ static PyLongObject small_ints[NSMALLNEGINTS + NSMALLPOSINTS]; Py_ssize_t quick_int_allocs, quick_neg_int_allocs; #endif -#define _MAX_STR_DIGITS_ERROR_FMT_TO_INT "Exceeds the limit (%d) for integer string conversion: value has %zd digits" -#define _MAX_STR_DIGITS_ERROR_FMT_TO_STR "Exceeds the limit (%d) for integer string conversion" +#define _MAX_STR_DIGITS_ERROR_FMT_TO_INT "Exceeds the limit (%d) for integer string conversion: value has %zd digits; use sys.set_int_max_str_digits() to increase the limit" +#define _MAX_STR_DIGITS_ERROR_FMT_TO_STR "Exceeds the limit (%d) for integer string conversion; use sys.set_int_max_str_digits() to increase the limit" static PyObject * get_small_int(sdigit ival) From webhook-mailer at python.org Tue Oct 4 15:01:13 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Tue, 04 Oct 2022 19:01:13 -0000 Subject: [Python-checkins] [3.10] gh-97709: Included newline separator in Mandelbrot set (GH-97737) (#97823) Message-ID: https://github.com/python/cpython/commit/19ed29ed3c96e21998afc35af13845c7868509b6 commit: 19ed29ed3c96e21998afc35af13845c7868509b6 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: JelleZijlstra date: 2022-10-04T12:01:07-07:00 summary: [3.10] gh-97709: Included newline separator in Mandelbrot set (GH-97737) (#97823) Included newline separator in Mandelbrot set Now the Mandelbrot set one-liner example on separates the lines with a '\n' character. (cherry picked from commit 49802605f8e47c5c7ddc8a6cecdf4afe44765586) Co-authored-by: matheusja files: M Doc/faq/programming.rst M Doc/tools/susp-ignored.csv diff --git a/Doc/faq/programming.rst b/Doc/faq/programming.rst index a93fe53c6703..a33774ac9c05 100644 --- a/Doc/faq/programming.rst +++ b/Doc/faq/programming.rst @@ -735,7 +735,7 @@ Is it possible to write obfuscated one-liners in Python? -------------------------------------------------------- Yes. Usually this is done by nesting :keyword:`lambda` within -:keyword:`!lambda`. See the following three examples, due to Ulf Bartelt:: +:keyword:`!lambda`. See the following three examples, slightly adapted from Ulf Bartelt:: from functools import reduce @@ -748,7 +748,7 @@ Yes. Usually this is done by nesting :keyword:`lambda` within f(x,f), range(10)))) # Mandelbrot set - print((lambda Ru,Ro,Iu,Io,IM,Sx,Sy:reduce(lambda x,y:x+y,map(lambda y, + print((lambda Ru,Ro,Iu,Io,IM,Sx,Sy:reduce(lambda x,y:x+'\n'+y,map(lambda y, Iu=Iu,Io=Io,Ru=Ru,Ro=Ro,Sy=Sy,L=lambda yc,Iu=Iu,Io=Io,Ru=Ru,Ro=Ro,i=IM, Sx=Sx,Sy=Sy:reduce(lambda x,y:x+y,map(lambda x,xc=Ru,yc=yc,Ru=Ru,Ro=Ro, i=i,Sx=Sx,F=lambda xc,yc,x,y,k,f=lambda xc,yc,x,y,k,f:(k<=0)or (x*x+y*y diff --git a/Doc/tools/susp-ignored.csv b/Doc/tools/susp-ignored.csv index 75049783e19c..c1b27246ca12 100644 --- a/Doc/tools/susp-ignored.csv +++ b/Doc/tools/susp-ignored.csv @@ -12,7 +12,7 @@ extending/extending,,:myfunction,"PyArg_ParseTuple(args, ""D:myfunction"", &c);" extending/extending,,:set,"if (PyArg_ParseTuple(args, ""O:set_callback"", &temp)) {" extending/newtypes,,:call,"if (!PyArg_ParseTuple(args, ""sss:call"", &arg1, &arg2, &arg3)) {" faq/programming,,:chr,">=4.0) or 1+f(xc,yc,x*x-y*y+xc,2.0*x*y+yc,k-1,f):f(xc,yc,x,y,k,f):chr(" -faq/programming,,:reduce,"print((lambda Ru,Ro,Iu,Io,IM,Sx,Sy:reduce(lambda x,y:x+y,map(lambda y," +faq/programming,,:reduce,"print((lambda Ru,Ro,Iu,Io,IM,Sx,Sy:reduce(lambda x,y:x+'\n'+y,map(lambda y," faq/programming,,:reduce,"Sx=Sx,Sy=Sy:reduce(lambda x,y:x+y,map(lambda x,xc=Ru,yc=yc,Ru=Ru,Ro=Ro," faq/windows,,:d48eceb,"Python 3.6.4 (v3.6.4:d48eceb, Dec 19 2017, 06:04:45) [MSC v.1900 32 bit (Intel)] on win32" howto/curses,,:black,"colors when it activates color mode. They are: 0:black, 1:red," From webhook-mailer at python.org Tue Oct 4 17:56:51 2022 From: webhook-mailer at python.org (orsenthil) Date: Tue, 04 Oct 2022 21:56:51 -0000 Subject: [Python-checkins] [3.11] gh-97731: fix distclean target to clean docs GH-97732 (#97844) Message-ID: https://github.com/python/cpython/commit/87a9e0f815071d79be166864f25b9eee79ae5d11 commit: 87a9e0f815071d79be166864f25b9eee79ae5d11 branch: 3.11 author: Senthil Kumaran committer: orsenthil date: 2022-10-04T14:56:46-07:00 summary: [3.11] gh-97731: fix distclean target to clean docs GH-97732 (#97844) Backport gh-97731: fix distclean target to clean docs #97732 to 3.11 files: M Makefile.pre.in diff --git a/Makefile.pre.in b/Makefile.pre.in index 3efc6c2456c4..d23976ff80fb 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -2388,8 +2388,7 @@ rmtestturds: -rm -f gb-18030-2000.xml docclean: - -rm -rf Doc/build - -rm -rf Doc/tools/sphinx Doc/tools/pygments Doc/tools/docutils + $(MAKE) -C Doc clean # like the 'clean' target but retain the profile guided optimization (PGO) # data. The PGO data is only valid if source code remains unchanged. @@ -2440,7 +2439,7 @@ clobber: clean # Make things extra clean, before making a distribution: # remove all generated files, even Makefile[.pre] # Keep configure and Python-ast.[ch], it's possible they can't be generated -distclean: clobber +distclean: clobber docclean for file in $(srcdir)/Lib/test/data/* ; do \ if test "$$file" != "$(srcdir)/Lib/test/data/README"; then rm "$$file"; fi; \ done From webhook-mailer at python.org Tue Oct 4 17:57:00 2022 From: webhook-mailer at python.org (orsenthil) Date: Tue, 04 Oct 2022 21:57:00 -0000 Subject: [Python-checkins] [3.10] gh-97731: fix distclean target to clean docs GH-97732 (#97846) Message-ID: https://github.com/python/cpython/commit/989bdbcfae265e6e7f5b8ef1551443a6f19a58d9 commit: 989bdbcfae265e6e7f5b8ef1551443a6f19a58d9 branch: 3.10 author: Senthil Kumaran committer: orsenthil date: 2022-10-04T14:56:55-07:00 summary: [3.10] gh-97731: fix distclean target to clean docs GH-97732 (#97846) Backport gh-97731: fix distclean target to clean docs #97732 to 3.10 files: M Makefile.pre.in diff --git a/Makefile.pre.in b/Makefile.pre.in index ee85f35b10da..95f0d870a38a 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1897,8 +1897,7 @@ rmtestturds: -rm -f gb-18030-2000.xml docclean: - -rm -rf Doc/build - -rm -rf Doc/tools/sphinx Doc/tools/pygments Doc/tools/docutils + $(MAKE) -C Doc clean # like the 'clean' target but retain the profile guided optimization (PGO) # data. The PGO data is only valid if source code remains unchanged. @@ -1942,7 +1941,7 @@ clobber: clean # Make things extra clean, before making a distribution: # remove all generated files, even Makefile[.pre] # Keep configure and Python-ast.[ch], it's possible they can't be generated -distclean: clobber +distclean: clobber docclean for file in $(srcdir)/Lib/test/data/* ; do \ if test "$$file" != "$(srcdir)/Lib/test/data/README"; then rm "$$file"; fi; \ done From webhook-mailer at python.org Tue Oct 4 18:04:54 2022 From: webhook-mailer at python.org (orsenthil) Date: Tue, 04 Oct 2022 22:04:54 -0000 Subject: [Python-checkins] gh-90301: Doc: Add references to PEP 686 (#96816) Message-ID: https://github.com/python/cpython/commit/87679a6e607eec1134d77222a3a92d0d11f768ad commit: 87679a6e607eec1134d77222a3a92d0d11f768ad branch: main author: Inada Naoki committer: orsenthil date: 2022-10-04T15:04:44-07:00 summary: gh-90301: Doc: Add references to PEP 686 (#96816) Doc: Add references to PEP 686. files: M Doc/library/io.rst M Doc/library/os.rst diff --git a/Doc/library/io.rst b/Doc/library/io.rst index 97a70646a93c..7ec990c3212a 100644 --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -123,17 +123,19 @@ encoding is not UTF-8 for most Windows users. For example:: with open("README.md") as f: long_description = f.read() -Additionally, while there is no concrete plan as of yet, Python may change -the default text file encoding to UTF-8 in the future. - Accordingly, it is highly recommended that you specify the encoding explicitly when opening text files. If you want to use UTF-8, pass ``encoding="utf-8"``. To use the current locale encoding, -``encoding="locale"`` is supported in Python 3.10. +``encoding="locale"`` is supported since Python 3.10. + +.. seealso:: + + :ref:`utf8-mode` + Python UTF-8 Mode can be used to change the default encoding to + UTF-8 from locale-specific encoding. -When you need to run existing code on Windows that attempts to open -UTF-8 files using the default locale encoding, you can enable the UTF-8 -mode. See :ref:`UTF-8 mode on Windows `. + :pep:`686` + Python 3.15 will make :ref:`utf8-mode` default. .. _io-encoding-warning: diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 1436b324c2d8..cb06dc690b4d 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -159,6 +159,11 @@ can be read from :data:`sys.flags.utf8_mode `. See also the :ref:`UTF-8 mode on Windows ` and the :term:`filesystem encoding and error handler`. +.. seealso:: + + :pep:`686` + Python 3.15 will make :ref:`utf8-mode` default. + .. _os-procinfo: From webhook-mailer at python.org Tue Oct 4 18:14:58 2022 From: webhook-mailer at python.org (miss-islington) Date: Tue, 04 Oct 2022 22:14:58 -0000 Subject: [Python-checkins] gh-90301: Doc: Add references to PEP 686 (GH-96816) Message-ID: https://github.com/python/cpython/commit/cad4dca7bfd5f32d07d0af598ecc3ac295c59d19 commit: cad4dca7bfd5f32d07d0af598ecc3ac295c59d19 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-04T15:14:52-07:00 summary: gh-90301: Doc: Add references to PEP 686 (GH-96816) Doc: Add references to PEP 686. (cherry picked from commit 87679a6e607eec1134d77222a3a92d0d11f768ad) Co-authored-by: Inada Naoki files: M Doc/library/io.rst M Doc/library/os.rst diff --git a/Doc/library/io.rst b/Doc/library/io.rst index 97a70646a93c..7ec990c3212a 100644 --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -123,17 +123,19 @@ encoding is not UTF-8 for most Windows users. For example:: with open("README.md") as f: long_description = f.read() -Additionally, while there is no concrete plan as of yet, Python may change -the default text file encoding to UTF-8 in the future. - Accordingly, it is highly recommended that you specify the encoding explicitly when opening text files. If you want to use UTF-8, pass ``encoding="utf-8"``. To use the current locale encoding, -``encoding="locale"`` is supported in Python 3.10. +``encoding="locale"`` is supported since Python 3.10. + +.. seealso:: + + :ref:`utf8-mode` + Python UTF-8 Mode can be used to change the default encoding to + UTF-8 from locale-specific encoding. -When you need to run existing code on Windows that attempts to open -UTF-8 files using the default locale encoding, you can enable the UTF-8 -mode. See :ref:`UTF-8 mode on Windows `. + :pep:`686` + Python 3.15 will make :ref:`utf8-mode` default. .. _io-encoding-warning: diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 4784110fb103..fbfeeb2d7e1f 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -159,6 +159,11 @@ can be read from :data:`sys.flags.utf8_mode `. See also the :ref:`UTF-8 mode on Windows ` and the :term:`filesystem encoding and error handler`. +.. seealso:: + + :pep:`686` + Python 3.15 will make :ref:`utf8-mode` default. + .. _os-procinfo: From webhook-mailer at python.org Tue Oct 4 18:18:13 2022 From: webhook-mailer at python.org (orsenthil) Date: Tue, 04 Oct 2022 22:18:13 -0000 Subject: [Python-checkins] gh-96448: fix documentation for _thread.lock.acquire (#96449) Message-ID: https://github.com/python/cpython/commit/7acb93f0d44c6fb971fdb09b86f68896e3b1e2f8 commit: 7acb93f0d44c6fb971fdb09b86f68896e3b1e2f8 branch: main author: Daniel Giger committer: orsenthil date: 2022-10-04T15:18:04-07:00 summary: gh-96448: fix documentation for _thread.lock.acquire (#96449) * fix documentation for _thread.lock.acquire * update formatting of _thread.lock.acquire() doc files: M Doc/library/_thread.rst diff --git a/Doc/library/_thread.rst b/Doc/library/_thread.rst index d61ce9039349..9df9e7914e09 100644 --- a/Doc/library/_thread.rst +++ b/Doc/library/_thread.rst @@ -157,21 +157,21 @@ This module defines the following constants and functions: Lock objects have the following methods: -.. method:: lock.acquire(waitflag=1, timeout=-1) +.. method:: lock.acquire(blocking=True, timeout=-1) Without any optional argument, this method acquires the lock unconditionally, if necessary waiting until it is released by another thread (only one thread at a time can acquire a lock --- that's their reason for existence). - If the integer *waitflag* argument is present, the action depends on its - value: if it is zero, the lock is only acquired if it can be acquired - immediately without waiting, while if it is nonzero, the lock is acquired + If the *blocking* argument is present, the action depends on its + value: if it is False, the lock is only acquired if it can be acquired + immediately without waiting, while if it is True, the lock is acquired unconditionally as above. If the floating-point *timeout* argument is present and positive, it specifies the maximum wait time in seconds before returning. A negative *timeout* argument specifies an unbounded wait. You cannot specify - a *timeout* if *waitflag* is zero. + a *timeout* if *blocking* is False. The return value is ``True`` if the lock is acquired successfully, ``False`` if not. From webhook-mailer at python.org Tue Oct 4 18:21:33 2022 From: webhook-mailer at python.org (orsenthil) Date: Tue, 04 Oct 2022 22:21:33 -0000 Subject: [Python-checkins] [3.11] gh-96448: fix documentation for _thread.lock.acquire (GH-96449) (#97851) Message-ID: https://github.com/python/cpython/commit/d45698269e2c36ac078a91b12f2cef5b5d077de0 commit: d45698269e2c36ac078a91b12f2cef5b5d077de0 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: orsenthil date: 2022-10-04T15:21:28-07:00 summary: [3.11] gh-96448: fix documentation for _thread.lock.acquire (GH-96449) (#97851) gh-96448: fix documentation for _thread.lock.acquire (GH-96449) * fix documentation for _thread.lock.acquire * update formatting of _thread.lock.acquire() doc (cherry picked from commit 7acb93f0d44c6fb971fdb09b86f68896e3b1e2f8) Co-authored-by: Daniel Giger Co-authored-by: Daniel Giger files: M Doc/library/_thread.rst diff --git a/Doc/library/_thread.rst b/Doc/library/_thread.rst index ea4aa304bec0..ecd7a68e627f 100644 --- a/Doc/library/_thread.rst +++ b/Doc/library/_thread.rst @@ -157,21 +157,21 @@ This module defines the following constants and functions: Lock objects have the following methods: -.. method:: lock.acquire(waitflag=1, timeout=-1) +.. method:: lock.acquire(blocking=True, timeout=-1) Without any optional argument, this method acquires the lock unconditionally, if necessary waiting until it is released by another thread (only one thread at a time can acquire a lock --- that's their reason for existence). - If the integer *waitflag* argument is present, the action depends on its - value: if it is zero, the lock is only acquired if it can be acquired - immediately without waiting, while if it is nonzero, the lock is acquired + If the *blocking* argument is present, the action depends on its + value: if it is False, the lock is only acquired if it can be acquired + immediately without waiting, while if it is True, the lock is acquired unconditionally as above. If the floating-point *timeout* argument is present and positive, it specifies the maximum wait time in seconds before returning. A negative *timeout* argument specifies an unbounded wait. You cannot specify - a *timeout* if *waitflag* is zero. + a *timeout* if *blocking* is False. The return value is ``True`` if the lock is acquired successfully, ``False`` if not. From webhook-mailer at python.org Tue Oct 4 18:21:43 2022 From: webhook-mailer at python.org (orsenthil) Date: Tue, 04 Oct 2022 22:21:43 -0000 Subject: [Python-checkins] [3.10] gh-96448: fix documentation for _thread.lock.acquire (GH-96449) (#97852) Message-ID: https://github.com/python/cpython/commit/f9b49b6bfa710c653b72f10b5b92ac791f51c229 commit: f9b49b6bfa710c653b72f10b5b92ac791f51c229 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: orsenthil date: 2022-10-04T15:21:38-07:00 summary: [3.10] gh-96448: fix documentation for _thread.lock.acquire (GH-96449) (#97852) gh-96448: fix documentation for _thread.lock.acquire (GH-96449) * fix documentation for _thread.lock.acquire * update formatting of _thread.lock.acquire() doc (cherry picked from commit 7acb93f0d44c6fb971fdb09b86f68896e3b1e2f8) Co-authored-by: Daniel Giger Co-authored-by: Daniel Giger files: M Doc/library/_thread.rst diff --git a/Doc/library/_thread.rst b/Doc/library/_thread.rst index 1e6452b7b826..927245647090 100644 --- a/Doc/library/_thread.rst +++ b/Doc/library/_thread.rst @@ -155,21 +155,21 @@ This module defines the following constants and functions: Lock objects have the following methods: -.. method:: lock.acquire(waitflag=1, timeout=-1) +.. method:: lock.acquire(blocking=True, timeout=-1) Without any optional argument, this method acquires the lock unconditionally, if necessary waiting until it is released by another thread (only one thread at a time can acquire a lock --- that's their reason for existence). - If the integer *waitflag* argument is present, the action depends on its - value: if it is zero, the lock is only acquired if it can be acquired - immediately without waiting, while if it is nonzero, the lock is acquired + If the *blocking* argument is present, the action depends on its + value: if it is False, the lock is only acquired if it can be acquired + immediately without waiting, while if it is True, the lock is acquired unconditionally as above. If the floating-point *timeout* argument is present and positive, it specifies the maximum wait time in seconds before returning. A negative *timeout* argument specifies an unbounded wait. You cannot specify - a *timeout* if *waitflag* is zero. + a *timeout* if *blocking* is False. The return value is ``True`` if the lock is acquired successfully, ``False`` if not. From webhook-mailer at python.org Tue Oct 4 18:31:26 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 04 Oct 2022 22:31:26 -0000 Subject: [Python-checkins] gh-97008: Add a Python implementation of AttributeError and NameError suggestions (#97022) Message-ID: https://github.com/python/cpython/commit/bbc7cd649a6ef56eb09278f3e746ca89b9d592c9 commit: bbc7cd649a6ef56eb09278f3e746ca89b9d592c9 branch: main author: ?ukasz Langa committer: ambv date: 2022-10-04T15:31:16-07:00 summary: gh-97008: Add a Python implementation of AttributeError and NameError suggestions (#97022) Relevant tests moved from test_exceptions to test_traceback to be able to compare both implementations. Co-authored-by: Carl Friedrich Bolz-Tereick files: A Lib/test/levenshtein_examples.json A Misc/NEWS.d/next/Library/2022-10-04-00-43-43.gh-issue-97008.3rjtt6.rst A Tools/scripts/generate_levenshtein_examples.py M .gitattributes M Lib/test/test_exceptions.py M Lib/test/test_traceback.py M Lib/traceback.py M Makefile.pre.in diff --git a/.gitattributes b/.gitattributes index 79f7b712aa45..d7e0ab2f36f5 100644 --- a/.gitattributes +++ b/.gitattributes @@ -73,6 +73,7 @@ Include/internal/pycore_runtime_init_generated.h generated Include/opcode.h generated Include/token.h generated Lib/keyword.py generated +Lib/test/levenshtein_examples.json generated Lib/test/test_stable_abi_ctypes.py generated Lib/token.py generated Objects/typeslots.inc generated diff --git a/Lib/test/levenshtein_examples.json b/Lib/test/levenshtein_examples.json new file mode 100644 index 000000000000..a32672cfdba8 --- /dev/null +++ b/Lib/test/levenshtein_examples.json @@ -0,0 +1,50002 @@ +[ + [ + "", + "", + 0 + ], + [ + "", + "AabBbb", + 12 + ], + [ + "", + "AbaC", + 8 + ], + [ + "", + "B", + 2 + ], + [ + "", + "Ba", + 4 + ], + [ + "", + "CBaACCCa", + 16 + ], + [ + "", + "CCbBC", + 10 + ], + [ + "", + "CcbCbaaAB", + 18 + ], + [ + "", + "bAa", + 6 + ], + [ + "", + "bAaCABb", + 14 + ], + [ + "A", + "A", + 0 + ], + [ + "A", + "AA", + 2 + ], + [ + "A", + "AABCAabcC", + 16 + ], + [ + "A", + "AACB", + 6 + ], + [ + "A", + "AACC", + 6 + ], + [ + "A", + "ABAaBbc", + 12 + ], + [ + "A", + "ABCcC", + 8 + ], + [ + "A", + "ABa", + 4 + ], + [ + "A", + "ABbBabcaa", + 16 + ], + [ + "A", + "ABbbCBcA", + 14 + ], + [ + "A", + "ACCBcBbBb", + 16 + ], + [ + "A", + "ACa", + 4 + ], + [ + "A", + "ACb", + 4 + ], + [ + "A", + "ACcbbaAB", + 14 + ], + [ + "A", + "AaAaccAb", + 14 + ], + [ + "A", + "AaabbCC", + 12 + ], + [ + "A", + "AabB", + 6 + ], + [ + "A", + "AbBa", + 6 + ], + [ + "A", + "AbBaA", + 8 + ], + [ + "A", + "AbCBBCaC", + 14 + ], + [ + "A", + "AbCb", + 6 + ], + [ + "A", + "AbcB", + 6 + ], + [ + "A", + "B", + 2 + ], + [ + "A", + "BA", + 2 + ], + [ + "A", + "BABbCc", + 10 + ], + [ + "A", + "BABca", + 8 + ], + [ + "A", + "BB", + 4 + ], + [ + "A", + "BBaBBaa", + 13 + ], + [ + "A", + "BBbbaAA", + 12 + ], + [ + "A", + "BCCAAc", + 10 + ], + [ + "A", + "BCa", + 5 + ], + [ + "A", + "BCcaC", + 9 + ], + [ + "A", + "BCccaa", + 11 + ], + [ + "A", + "BaacCbC", + 13 + ], + [ + "A", + "BabCC", + 9 + ], + [ + "A", + "Bac", + 5 + ], + [ + "A", + "BbCbb", + 10 + ], + [ + "A", + "BbaBAC", + 10 + ], + [ + "A", + "Bbc", + 6 + ], + [ + "A", + "BcB", + 6 + ], + [ + "A", + "BcCAbCBA", + 14 + ], + [ + "A", + "BcaaCbCB", + 15 + ], + [ + "A", + "C", + 2 + ], + [ + "A", + "CA", + 2 + ], + [ + "A", + "CABAacB", + 12 + ], + [ + "A", + "CABBABBc", + 14 + ], + [ + "A", + "CAaaBc", + 10 + ], + [ + "A", + "CBAA", + 6 + ], + [ + "A", + "CBCcBaBAB", + 16 + ], + [ + "A", + "CBcbc", + 10 + ], + [ + "A", + "CC", + 4 + ], + [ + "A", + "CCA", + 4 + ], + [ + "A", + "CCB", + 6 + ], + [ + "A", + "CCBaACcC", + 14 + ], + [ + "A", + "CCBcAAacb", + 16 + ], + [ + "A", + "CaCCaA", + 10 + ], + [ + "A", + "CbAB", + 6 + ], + [ + "A", + "CbBaAACC", + 14 + ], + [ + "A", + "CbCCbB", + 12 + ], + [ + "A", + "CbacBb", + 11 + ], + [ + "A", + "CbbABc", + 10 + ], + [ + "A", + "CcC", + 6 + ], + [ + "A", + "CcCacAAAC", + 16 + ], + [ + "A", + "CccCbaCcb", + 17 + ], + [ + "A", + "a", + 1 + ], + [ + "A", + "aABABBa", + 12 + ], + [ + "A", + "aABBA", + 8 + ], + [ + "A", + "aABCaBCa", + 14 + ], + [ + "A", + "aACBabAC", + 14 + ], + [ + "A", + "aBCb", + 7 + ], + [ + "A", + "aBaB", + 7 + ], + [ + "A", + "aBbBb", + 9 + ], + [ + "A", + "aC", + 3 + ], + [ + "A", + "aCA", + 4 + ], + [ + "A", + "aaBBb", + 9 + ], + [ + "A", + "aaC", + 5 + ], + [ + "A", + "aaCb", + 7 + ], + [ + "A", + "aaCbABbb", + 14 + ], + [ + "A", + "aaCcbb", + 11 + ], + [ + "A", + "aaaaCcAB", + 14 + ], + [ + "A", + "aaabb", + 9 + ], + [ + "A", + "aaacCabCC", + 17 + ], + [ + "A", + "aacBccCAC", + 16 + ], + [ + "A", + "aacC", + 7 + ], + [ + "A", + "abCAb", + 8 + ], + [ + "A", + "abbBcaccc", + 17 + ], + [ + "A", + "acCAB", + 8 + ], + [ + "A", + "acacBcAA", + 14 + ], + [ + "A", + "b", + 2 + ], + [ + "A", + "bABACaB", + 12 + ], + [ + "A", + "bAbA", + 6 + ], + [ + "A", + "bAbaBc", + 10 + ], + [ + "A", + "bBAa", + 6 + ], + [ + "A", + "bBa", + 5 + ], + [ + "A", + "bBaCAab", + 12 + ], + [ + "A", + "bBaCaCBbB", + 17 + ], + [ + "A", + "bBbAbaBa", + 14 + ], + [ + "A", + "bBbacabAb", + 16 + ], + [ + "A", + "bCCbA", + 8 + ], + [ + "A", + "bCCbB", + 10 + ], + [ + "A", + "bCbbACc", + 12 + ], + [ + "A", + "bCbbc", + 10 + ], + [ + "A", + "baACBCB", + 12 + ], + [ + "A", + "babABb", + 10 + ], + [ + "A", + "bacB", + 7 + ], + [ + "A", + "bacacA", + 10 + ], + [ + "A", + "bb", + 4 + ], + [ + "A", + "bbCa", + 7 + ], + [ + "A", + "bbCbaa", + 11 + ], + [ + "A", + "bbbAcb", + 10 + ], + [ + "A", + "bc", + 4 + ], + [ + "A", + "bcAAcCAb", + 14 + ], + [ + "A", + "bcC", + 6 + ], + [ + "A", + "bcbbaab", + 13 + ], + [ + "A", + "c", + 2 + ], + [ + "A", + "cAB", + 4 + ], + [ + "A", + "cACAc", + 8 + ], + [ + "A", + "cAaBccaC", + 14 + ], + [ + "A", + "cAcAaCAc", + 14 + ], + [ + "A", + "cBAaC", + 8 + ], + [ + "A", + "cBAac", + 8 + ], + [ + "A", + "cBCAABbc", + 14 + ], + [ + "A", + "cBaCbab", + 13 + ], + [ + "A", + "cBacA", + 8 + ], + [ + "A", + "cBb", + 6 + ], + [ + "A", + "cC", + 4 + ], + [ + "A", + "cCBABaC", + 12 + ], + [ + "A", + "cCCCa", + 9 + ], + [ + "A", + "cCa", + 5 + ], + [ + "A", + "cCaAaCaCB", + 16 + ], + [ + "A", + "cCabbbCa", + 15 + ], + [ + "A", + "caacCacAb", + 16 + ], + [ + "A", + "cabbC", + 9 + ], + [ + "A", + "cb", + 4 + ], + [ + "A", + "cbC", + 6 + ], + [ + "A", + "cbCAaAaAB", + 16 + ], + [ + "A", + "cbbaaAbbB", + 16 + ], + [ + "A", + "cc", + 4 + ], + [ + "A", + "ccCcCBaB", + 15 + ], + [ + "A", + "ccabbC", + 11 + ], + [ + "AA", + "AA", + 0 + ], + [ + "AA", + "ACAA", + 4 + ], + [ + "AA", + "BAc", + 4 + ], + [ + "AA", + "BC", + 4 + ], + [ + "AA", + "BaccaAA", + 10 + ], + [ + "AA", + "Bba", + 5 + ], + [ + "AA", + "BbcbcccAB", + 16 + ], + [ + "AA", + "CAb", + 4 + ], + [ + "AA", + "Cc", + 4 + ], + [ + "AA", + "CcBACCa", + 11 + ], + [ + "AA", + "aCBa", + 6 + ], + [ + "AA", + "aaBA", + 5 + ], + [ + "AA", + "aaBac", + 8 + ], + [ + "AA", + "bAAabBA", + 10 + ], + [ + "AA", + "bABbacbb", + 13 + ], + [ + "AA", + "bBbBbc", + 12 + ], + [ + "AA", + "bC", + 4 + ], + [ + "AA", + "bCabb", + 9 + ], + [ + "AA", + "baAB", + 5 + ], + [ + "AA", + "bbBaBcCBB", + 17 + ], + [ + "AA", + "bbBbAaaB", + 13 + ], + [ + "AA", + "c", + 4 + ], + [ + "AA", + "cACaCbab", + 13 + ], + [ + "AA", + "cBbCbBcA", + 14 + ], + [ + "AA", + "cBba", + 7 + ], + [ + "AA", + "cCbBBCca", + 15 + ], + [ + "AA", + "cacaca", + 10 + ], + [ + "AA", + "ccbccAa", + 11 + ], + [ + "AAA", + "B", + 6 + ], + [ + "AAA", + "C", + 6 + ], + [ + "AAA", + "aBBbcAaBa", + 14 + ], + [ + "AAA", + "aacbbBbbc", + 16 + ], + [ + "AAA", + "abAb", + 5 + ], + [ + "AAA", + "cccaAbBcB", + 15 + ], + [ + "AAAAABA", + "CaBcAaa", + 10 + ], + [ + "AAABACbC", + "BBBC", + 11 + ], + [ + "AAABAbaaA", + "CBbbacb", + 12 + ], + [ + "AAABa", + "AA", + 6 + ], + [ + "AAABc", + "cbBabcaBA", + 14 + ], + [ + "AAAC", + "acBcCCcC", + 13 + ], + [ + "AAACAbAaa", + "BCc", + 16 + ], + [ + "AAACBACc", + "CaCabAc", + 10 + ], + [ + "AAACCbbcA", + "bc", + 14 + ], + [ + "AAACa", + "A", + 8 + ], + [ + "AAACbCaa", + "acABAAa", + 9 + ], + [ + "AAACbaaa", + "BBa", + 13 + ], + [ + "AAAa", + "bBaaCc", + 9 + ], + [ + "AAAaAB", + "BCB", + 10 + ], + [ + "AAAaAcC", + "CAbBcBBC", + 12 + ], + [ + "AAAaCAAb", + "aBbAbaaA", + 12 + ], + [ + "AAAaCaA", + "cBcABaAb", + 11 + ], + [ + "AAAaaaaA", + "ABBBcaA", + 10 + ], + [ + "AAAb", + "AcC", + 6 + ], + [ + "AAAb", + "B", + 7 + ], + [ + "AAAbAB", + "cCBaAbcc", + 11 + ], + [ + "AAAbBcbc", + "C", + 15 + ], + [ + "AAAbaAABb", + "cCcAaca", + 15 + ], + [ + "AAAbbaA", + "Cbcc", + 12 + ], + [ + "AAAbbc", + "ABcaCCbca", + 11 + ], + [ + "AAAbcAcBA", + "bBaACAC", + 13 + ], + [ + "AAAbcbCa", + "cabCCbCba", + 10 + ], + [ + "AAAcAcCC", + "cbBCAAB", + 13 + ], + [ + "AAAcBAbCB", + "cbbABC", + 12 + ], + [ + "AAB", + "CB", + 4 + ], + [ + "AAB", + "accAC", + 7 + ], + [ + "AAB", + "bCCbaBbAc", + 15 + ], + [ + "AAB", + "bbb", + 5 + ], + [ + "AAB", + "bcCBcC", + 10 + ], + [ + "AABA", + "AAc", + 4 + ], + [ + "AABA", + "cBCAbA", + 7 + ], + [ + "AABABCcCc", + "abAC", + 12 + ], + [ + "AABAaB", + "BAB", + 6 + ], + [ + "AABAbAa", + "BcaB", + 11 + ], + [ + "AABAcb", + "cca", + 10 + ], + [ + "AABBA", + "AbAaCBb", + 8 + ], + [ + "AABBAACcC", + "A", + 16 + ], + [ + "AABBBcb", + "B", + 12 + ], + [ + "AABBCaB", + "bAbBA", + 8 + ], + [ + "AABBCabC", + "BCC", + 10 + ], + [ + "AABBCcB", + "cABBBAACc", + 10 + ], + [ + "AABBabAA", + "A", + 14 + ], + [ + "AABBac", + "BACCCB", + 10 + ], + [ + "AABBc", + "CAaBaA", + 7 + ], + [ + "AABCb", + "CcaCab", + 8 + ], + [ + "AABCbccb", + "B", + 14 + ], + [ + "AABCcA", + "BabC", + 8 + ], + [ + "AABCcB", + "BAB", + 8 + ], + [ + "AABCca", + "AbBBC", + 7 + ], + [ + "AABCcbBB", + "Bab", + 12 + ], + [ + "AABa", + "ACCcBA", + 7 + ], + [ + "AABa", + "BCcbaAa", + 11 + ], + [ + "AABa", + "C", + 8 + ], + [ + "AABaAc", + "Ccaa", + 9 + ], + [ + "AABaC", + "aA", + 7 + ], + [ + "AABaCccb", + "AABaAAbc", + 8 + ], + [ + "AABabcc", + "ccaABC", + 11 + ], + [ + "AABacB", + "cCbaa", + 9 + ], + [ + "AABacBac", + "AcAa", + 10 + ], + [ + "AABaccb", + "CcbBbbc", + 12 + ], + [ + "AABbBa", + "bBAcbaaB", + 10 + ], + [ + "AABbCc", + "AccbaB", + 8 + ], + [ + "AABba", + "cBbAc", + 7 + ], + [ + "AABbaBa", + "BBaAbb", + 10 + ], + [ + "AABc", + "BccAAA", + 10 + ], + [ + "AABcABaaA", + "cbB", + 14 + ], + [ + "AABcAC", + "acabAC", + 7 + ], + [ + "AABcBbcb", + "baAACAbAB", + 11 + ], + [ + "AABcCB", + "ca", + 10 + ], + [ + "AABcaBC", + "AaAaab", + 8 + ], + [ + "AAC", + "CBabAaB", + 11 + ], + [ + "AAC", + "aBA", + 5 + ], + [ + "AAC", + "aCBCBbac", + 13 + ], + [ + "AAC", + "aCa", + 5 + ], + [ + "AAC", + "baaBAba", + 11 + ], + [ + "AAC", + "bbAbc", + 7 + ], + [ + "AACA", + "aaCB", + 4 + ], + [ + "AACA", + "ab", + 7 + ], + [ + "AACA", + "cc", + 7 + ], + [ + "AACAba", + "CBAAaAB", + 9 + ], + [ + "AACAba", + "b", + 10 + ], + [ + "AACAbbc", + "AbaCABCcB", + 8 + ], + [ + "AACBACbcB", + "b", + 16 + ], + [ + "AACBC", + "Abbc", + 6 + ], + [ + "AACBC", + "aaCcAb", + 8 + ], + [ + "AACBCA", + "A", + 10 + ], + [ + "AACBCcbaa", + "cbBca", + 12 + ], + [ + "AACBaB", + "AAcABBA", + 7 + ], + [ + "AACBc", + "aABCaACA", + 10 + ], + [ + "AACC", + "bB", + 8 + ], + [ + "AACCA", + "b", + 10 + ], + [ + "AACCAC", + "Ccab", + 8 + ], + [ + "AACCBBAac", + "abbabb", + 14 + ], + [ + "AACCCCbc", + "BBCCaB", + 11 + ], + [ + "AACCCc", + "bcCbaBACA", + 14 + ], + [ + "AACCaBcA", + "BaC", + 13 + ], + [ + "AACCaca", + "ccbaBBaB", + 13 + ], + [ + "AACCc", + "b", + 10 + ], + [ + "AACa", + "BAC", + 4 + ], + [ + "AACaAaBA", + "AbcbB", + 11 + ], + [ + "AACaac", + "C", + 10 + ], + [ + "AACacB", + "CcbCBaBb", + 11 + ], + [ + "AACb", + "AC", + 4 + ], + [ + "AACb", + "ac", + 6 + ], + [ + "AACbAC", + "BBCCBCa", + 10 + ], + [ + "AACbC", + "bb", + 8 + ], + [ + "AACbbcaa", + "bbaaBCBb", + 14 + ], + [ + "AACbc", + "AbcbbBcCB", + 11 + ], + [ + "AACbc", + "aCCB", + 6 + ], + [ + "AACbcAaAb", + "BABcaBBAA", + 12 + ], + [ + "AACbcb", + "cabBc", + 8 + ], + [ + "AACc", + "BbCC", + 5 + ], + [ + "AACc", + "bbb", + 8 + ], + [ + "AACcAABAC", + "CBAcBaABa", + 11 + ], + [ + "AACcAb", + "CBCbCACcb", + 11 + ], + [ + "AACcCAAc", + "AbAACbCC", + 11 + ], + [ + "AACcabbC", + "cAAccbAB", + 9 + ], + [ + "AACcbA", + "BCCCcaCc", + 12 + ], + [ + "AAa", + "ACCC", + 6 + ], + [ + "AAa", + "BcAC", + 6 + ], + [ + "AAa", + "CACcaAAAb", + 13 + ], + [ + "AAa", + "CAaCA", + 6 + ], + [ + "AAa", + "aCcBACb", + 11 + ], + [ + "AAa", + "abACAA", + 7 + ], + [ + "AAa", + "b", + 6 + ], + [ + "AAa", + "cAAaBA", + 6 + ], + [ + "AAa", + "cBaB", + 6 + ], + [ + "AAaA", + "ca", + 6 + ], + [ + "AAaACcb", + "ABCcb", + 6 + ], + [ + "AAaB", + "aCAC", + 6 + ], + [ + "AAaB", + "cbAb", + 6 + ], + [ + "AAaBA", + "bBAc", + 8 + ], + [ + "AAaBB", + "ABCCaCBb", + 9 + ], + [ + "AAaBa", + "AcB", + 6 + ], + [ + "AAaBaB", + "aCcb", + 9 + ], + [ + "AAaBacBaC", + "CacABc", + 12 + ], + [ + "AAaBbAb", + "cC", + 14 + ], + [ + "AAaBbcaa", + "caB", + 12 + ], + [ + "AAaC", + "aCbBcBCB", + 13 + ], + [ + "AAaCACAB", + "cBa", + 14 + ], + [ + "AAaCCaCaA", + "baACABCCA", + 10 + ], + [ + "AAaCCcbb", + "aa", + 13 + ], + [ + "AAaCaccb", + "AAA", + 11 + ], + [ + "AAaCbAAAc", + "babcbBccb", + 14 + ], + [ + "AAaCcB", + "aA", + 9 + ], + [ + "AAaa", + "Abcbb", + 8 + ], + [ + "AAaaA", + "ACaCAcaa", + 9 + ], + [ + "AAaaB", + "cAaaAB", + 4 + ], + [ + "AAaaBbaC", + "bbCaCBc", + 12 + ], + [ + "AAaaCBabC", + "bBb", + 14 + ], + [ + "AAaacacca", + "C", + 17 + ], + [ + "AAaaccbA", + "CB", + 14 + ], + [ + "AAabAbac", + "cbABacbbc", + 11 + ], + [ + "AAabBBaA", + "caCcAAB", + 13 + ], + [ + "AAabCA", + "CbACAA", + 9 + ], + [ + "AAabCbCA", + "ACb", + 10 + ], + [ + "AAabb", + "B", + 9 + ], + [ + "AAabc", + "cBc", + 7 + ], + [ + "AAacA", + "CBBcB", + 8 + ], + [ + "AAacA", + "Cc", + 8 + ], + [ + "AAacCBCBc", + "bAaacCc", + 9 + ], + [ + "AAacCaBa", + "a", + 14 + ], + [ + "AAacCbCCC", + "BaB", + 15 + ], + [ + "AAaccABAA", + "bBCb", + 16 + ], + [ + "AAb", + "AbB", + 3 + ], + [ + "AAb", + "B", + 5 + ], + [ + "AAb", + "aCBbBBa", + 11 + ], + [ + "AAb", + "bAAc", + 4 + ], + [ + "AAb", + "bABA", + 5 + ], + [ + "AAb", + "bBCbBbaCA", + 16 + ], + [ + "AAb", + "bbBBaB", + 10 + ], + [ + "AAb", + "bbCcAb", + 8 + ], + [ + "AAbA", + "Bbb", + 6 + ], + [ + "AAbAAaBCC", + "b", + 16 + ], + [ + "AAbABB", + "Ca", + 11 + ], + [ + "AAbAaBBcB", + "BABaCB", + 10 + ], + [ + "AAbBBb", + "a", + 11 + ], + [ + "AAbBCCb", + "bA", + 12 + ], + [ + "AAbBbBcC", + "C", + 14 + ], + [ + "AAbBbbBcc", + "aCA", + 16 + ], + [ + "AAbC", + "cBbBCBBb", + 12 + ], + [ + "AAbCbBcC", + "BaABcCaCc", + 11 + ], + [ + "AAbCcCbC", + "a", + 15 + ], + [ + "AAba", + "cBCabCC", + 11 + ], + [ + "AAba", + "cBcBCcaBc", + 15 + ], + [ + "AAbaCabC", + "Aa", + 12 + ], + [ + "AAbabb", + "cbBAca", + 10 + ], + [ + "AAbb", + "AcbaaAB", + 9 + ], + [ + "AAbb", + "bccb", + 6 + ], + [ + "AAbbAcAB", + "cbacaBBBA", + 14 + ], + [ + "AAbbBAaAC", + "bcbaabc", + 11 + ], + [ + "AAbbbB", + "bCa", + 10 + ], + [ + "AAbcBbA", + "aaccCbB", + 8 + ], + [ + "AAbcaBBBA", + "ABb", + 13 + ], + [ + "AAbcacaB", + "cAAAbBb", + 12 + ], + [ + "AAbcbacC", + "abbbAaCCa", + 10 + ], + [ + "AAc", + "ACAc", + 2 + ], + [ + "AAc", + "AbB", + 4 + ], + [ + "AAc", + "BAabA", + 7 + ], + [ + "AAc", + "aAbc", + 3 + ], + [ + "AAc", + "aaaaacAA", + 12 + ], + [ + "AAc", + "aab", + 4 + ], + [ + "AAc", + "c", + 4 + ], + [ + "AAcA", + "AAbAAA", + 6 + ], + [ + "AAcABCA", + "bBBAbab", + 11 + ], + [ + "AAcAC", + "cCAAa", + 8 + ], + [ + "AAcAac", + "cAcA", + 6 + ], + [ + "AAcAbBcB", + "AAAAB", + 8 + ], + [ + "AAcAccAb", + "Ccac", + 11 + ], + [ + "AAcBBBcCB", + "A", + 16 + ], + [ + "AAcBbA", + "Aa", + 9 + ], + [ + "AAcC", + "bCbcaCCa", + 12 + ], + [ + "AAcCabaB", + "cACAC", + 11 + ], + [ + "AAcaACCBA", + "abcBCca", + 11 + ], + [ + "AAcaCBAcB", + "cCaBCcC", + 11 + ], + [ + "AAcab", + "A", + 8 + ], + [ + "AAcab", + "AcaabCccc", + 12 + ], + [ + "AAcb", + "aCBCcCBcC", + 14 + ], + [ + "AAcbAccc", + "CcccbA", + 12 + ], + [ + "AAcbCCAcB", + "BbbCaACc", + 11 + ], + [ + "AAcbCca", + "a", + 12 + ], + [ + "AAcbc", + "caCcb", + 7 + ], + [ + "AAcc", + "CcaBbcC", + 10 + ], + [ + "AAccB", + "cCca", + 7 + ], + [ + "AAccb", + "aA", + 7 + ], + [ + "AAccccbAA", + "caAaa", + 14 + ], + [ + "AB", + "A", + 2 + ], + [ + "AB", + "AACca", + 8 + ], + [ + "AB", + "ABcAc", + 6 + ], + [ + "AB", + "ACCACCbC", + 13 + ], + [ + "AB", + "BAA", + 4 + ], + [ + "AB", + "BAbac", + 7 + ], + [ + "AB", + "BC", + 4 + ], + [ + "AB", + "BbaCAc", + 10 + ], + [ + "AB", + "Bbac", + 7 + ], + [ + "AB", + "BcA", + 6 + ], + [ + "AB", + "CAAacB", + 8 + ], + [ + "AB", + "CC", + 4 + ], + [ + "AB", + "CCaabBcb", + 13 + ], + [ + "AB", + "CCcB", + 6 + ], + [ + "AB", + "CbA", + 5 + ], + [ + "AB", + "aCAC", + 6 + ], + [ + "AB", + "bBA", + 4 + ], + [ + "AB", + "bCbB", + 6 + ], + [ + "AB", + "bCccbbb", + 13 + ], + [ + "AB", + "bbb", + 5 + ], + [ + "AB", + "bcAbAAA", + 11 + ], + [ + "AB", + "bcbC", + 7 + ], + [ + "AB", + "c", + 4 + ], + [ + "AB", + "cCabccbCB", + 15 + ], + [ + "AB", + "caCBB", + 7 + ], + [ + "AB", + "caaac", + 9 + ], + [ + "AB", + "cababCa", + 12 + ], + [ + "ABA", + "A", + 4 + ], + [ + "ABA", + "ACBcBa", + 7 + ], + [ + "ABA", + "AcAb", + 4 + ], + [ + "ABA", + "abbBaaC", + 10 + ], + [ + "ABA", + "c", + 6 + ], + [ + "ABA", + "caAaCCbc", + 13 + ], + [ + "ABAAB", + "cbB", + 7 + ], + [ + "ABAABacbC", + "Ba", + 14 + ], + [ + "ABAAaCAa", + "cABb", + 14 + ], + [ + "ABAAaaBb", + "BCACaB", + 8 + ], + [ + "ABAAabb", + "bAcABc", + 9 + ], + [ + "ABAAabbCC", + "cbcBc", + 15 + ], + [ + "ABAAbBCb", + "aCACb", + 9 + ], + [ + "ABAAc", + "AbCc", + 5 + ], + [ + "ABAAcC", + "A", + 10 + ], + [ + "ABABBCaBb", + "aAcBcc", + 12 + ], + [ + "ABABCAB", + "cbBBCaA", + 8 + ], + [ + "ABABaaCc", + "BBBBBAB", + 11 + ], + [ + "ABABbCCab", + "aAC", + 13 + ], + [ + "ABAC", + "abaAC", + 4 + ], + [ + "ABACAccCC", + "BBCBcbCAc", + 11 + ], + [ + "ABACCAACA", + "aAacA", + 11 + ], + [ + "ABACaa", + "BA", + 8 + ], + [ + "ABACb", + "b", + 8 + ], + [ + "ABACbaCcC", + "cCBBbCbC", + 12 + ], + [ + "ABAa", + "A", + 6 + ], + [ + "ABAaAbbc", + "ccaCBA", + 13 + ], + [ + "ABAaB", + "bb", + 8 + ], + [ + "ABAaCCAB", + "acba", + 12 + ], + [ + "ABAaaBCBB", + "BaCC", + 12 + ], + [ + "ABAacbAbA", + "ABAb", + 10 + ], + [ + "ABAb", + "AcA", + 4 + ], + [ + "ABAb", + "cCab", + 5 + ], + [ + "ABAbACCB", + "cBCB", + 10 + ], + [ + "ABAbBC", + "BBAacabC", + 9 + ], + [ + "ABAbCCb", + "BAA", + 10 + ], + [ + "ABAbaCBB", + "aaCbbbBB", + 9 + ], + [ + "ABAbaCcC", + "bac", + 10 + ], + [ + "ABAc", + "CBACCbBA", + 11 + ], + [ + "ABAcAcB", + "Ac", + 10 + ], + [ + "ABAca", + "aCcCaAbC", + 12 + ], + [ + "ABAcaBc", + "bCaabABAb", + 14 + ], + [ + "ABAcaac", + "BcA", + 9 + ], + [ + "ABAcabA", + "aa", + 11 + ], + [ + "ABAcb", + "cCa", + 9 + ], + [ + "ABB", + "acaccCcA", + 15 + ], + [ + "ABB", + "bAaAAC", + 10 + ], + [ + "ABB", + "bBbAA", + 7 + ], + [ + "ABB", + "bac", + 6 + ], + [ + "ABBAAaCc", + "CaCaCAaCc", + 9 + ], + [ + "ABBAAbb", + "acBbCba", + 9 + ], + [ + "ABBAAc", + "bBccabAcB", + 11 + ], + [ + "ABBAbbAA", + "abAaaa", + 10 + ], + [ + "ABBAcBaa", + "Ab", + 13 + ], + [ + "ABBAcbAc", + "abBccbA", + 6 + ], + [ + "ABBBAa", + "ccBbcBa", + 9 + ], + [ + "ABBBAbAcc", + "abCaCAbcc", + 10 + ], + [ + "ABBBB", + "cAaCBCbCb", + 12 + ], + [ + "ABBBCaB", + "BaAbBabBa", + 12 + ], + [ + "ABBCC", + "aBBbaBAab", + 13 + ], + [ + "ABBCCc", + "aAcAbB", + 11 + ], + [ + "ABBCCcab", + "AcBcbcbAc", + 10 + ], + [ + "ABBa", + "bA", + 6 + ], + [ + "ABBaACA", + "cbBcAB", + 9 + ], + [ + "ABBaACCcb", + "bbCCcCb", + 10 + ], + [ + "ABBaa", + "bcabCCC", + 12 + ], + [ + "ABBabAbAC", + "AbcbbAcCc", + 10 + ], + [ + "ABBaba", + "BCcbAaBCA", + 13 + ], + [ + "ABBacb", + "CAbcBAbBa", + 11 + ], + [ + "ABBb", + "Aabc", + 5 + ], + [ + "ABBb", + "aAcAb", + 6 + ], + [ + "ABBbBAbCA", + "CCBACAAb", + 14 + ], + [ + "ABBbCbb", + "bccbcAc", + 11 + ], + [ + "ABBbb", + "aAabbCbCC", + 11 + ], + [ + "ABBcBBC", + "bCaB", + 10 + ], + [ + "ABBcCCC", + "bABbaCCC", + 5 + ], + [ + "ABBcb", + "aCc", + 7 + ], + [ + "ABBcbcC", + "AACBbAC", + 8 + ], + [ + "ABBccBcAa", + "ABa", + 12 + ], + [ + "ABBccCBA", + "CCCACa", + 12 + ], + [ + "ABBccc", + "B", + 10 + ], + [ + "ABC", + "BAaACA", + 8 + ], + [ + "ABC", + "BCc", + 4 + ], + [ + "ABC", + "CAa", + 6 + ], + [ + "ABC", + "CBca", + 5 + ], + [ + "ABC", + "CbCbbCB", + 11 + ], + [ + "ABC", + "bacacB", + 10 + ], + [ + "ABC", + "c", + 5 + ], + [ + "ABCAB", + "bAaAc", + 8 + ], + [ + "ABCAC", + "BaCBaC", + 7 + ], + [ + "ABCAa", + "aABbb", + 8 + ], + [ + "ABCAbAacA", + "cbCAa", + 11 + ], + [ + "ABCBC", + "AB", + 6 + ], + [ + "ABCBa", + "CcAACBC", + 8 + ], + [ + "ABCBa", + "caBbccC", + 10 + ], + [ + "ABCCAa", + "A", + 10 + ], + [ + "ABCCC", + "CC", + 6 + ], + [ + "ABCCbcBc", + "AbCBcBB", + 6 + ], + [ + "ABCCcCBB", + "bbccAbBBc", + 11 + ], + [ + "ABCCccaB", + "aCcACCCa", + 10 + ], + [ + "ABCaBa", + "BBb", + 8 + ], + [ + "ABCaBa", + "bbAcAA", + 10 + ], + [ + "ABCaC", + "bcCcab", + 8 + ], + [ + "ABCaa", + "AbCcaAb", + 6 + ], + [ + "ABCab", + "b", + 8 + ], + [ + "ABCabB", + "AAc", + 9 + ], + [ + "ABCb", + "CBBBC", + 7 + ], + [ + "ABCb", + "aABCcBC", + 7 + ], + [ + "ABCbAA", + "Ba", + 9 + ], + [ + "ABCbBBbc", + "cabbbCbcB", + 11 + ], + [ + "ABCbC", + "cc", + 8 + ], + [ + "ABCbCaCCc", + "aABB", + 15 + ], + [ + "ABCbaaCbb", + "CBbBBABBB", + 12 + ], + [ + "ABCbaaac", + "aaCaCCCca", + 13 + ], + [ + "ABCbbA", + "BCaAa", + 7 + ], + [ + "ABCbcC", + "ccbBBa", + 11 + ], + [ + "ABCc", + "Aa", + 6 + ], + [ + "ABCcAabbB", + "cCCaBBc", + 11 + ], + [ + "ABCcBcbC", + "Bcbcc", + 8 + ], + [ + "ABCcb", + "CacBAb", + 9 + ], + [ + "ABCccaAcC", + "BaAcBbC", + 12 + ], + [ + "ABa", + "AaabCa", + 7 + ], + [ + "ABa", + "CaA", + 5 + ], + [ + "ABaABc", + "caC", + 9 + ], + [ + "ABaAC", + "Caca", + 8 + ], + [ + "ABaAb", + "bAaC", + 7 + ], + [ + "ABaB", + "c", + 8 + ], + [ + "ABaBa", + "aacCAc", + 10 + ], + [ + "ABaBb", + "acbaBCcb", + 8 + ], + [ + "ABaBccB", + "BacbBBBcb", + 11 + ], + [ + "ABaCAb", + "aba", + 8 + ], + [ + "ABaCCC", + "aCAaacbc", + 10 + ], + [ + "ABaCc", + "bB", + 8 + ], + [ + "ABaa", + "CCcCC", + 10 + ], + [ + "ABabAbb", + "BCAcB", + 9 + ], + [ + "ABabBC", + "acc", + 9 + ], + [ + "ABabBaAc", + "AbBCbaBBB", + 12 + ], + [ + "ABababAC", + "aabaaBAA", + 8 + ], + [ + "ABabb", + "bBb", + 6 + ], + [ + "ABabcBacC", + "aC", + 14 + ], + [ + "ABabcBcc", + "BAcB", + 9 + ], + [ + "ABacCac", + "bbaCBcbcB", + 11 + ], + [ + "ABacbAAab", + "bC", + 16 + ], + [ + "ABacbbaCC", + "CbCbcbBAA", + 13 + ], + [ + "ABb", + "AaAcB", + 7 + ], + [ + "ABb", + "B", + 4 + ], + [ + "ABb", + "BB", + 3 + ], + [ + "ABb", + "BBaCCAAA", + 14 + ], + [ + "ABb", + "bBBaA", + 7 + ], + [ + "ABb", + "baCaaBaa", + 13 + ], + [ + "ABbA", + "CaACAABa", + 12 + ], + [ + "ABbACAC", + "BAcBBaB", + 12 + ], + [ + "ABbACAaAa", + "Cca", + 14 + ], + [ + "ABbAaa", + "cbacaa", + 7 + ], + [ + "ABbAaaB", + "BBc", + 11 + ], + [ + "ABbAacbAC", + "bAbAaacaa", + 11 + ], + [ + "ABbAbA", + "aaAaB", + 9 + ], + [ + "ABbBAb", + "a", + 11 + ], + [ + "ABbBcCbcA", + "acaAacBAB", + 15 + ], + [ + "ABbCC", + "caACcc", + 9 + ], + [ + "ABbCaAbb", + "b", + 14 + ], + [ + "ABbCb", + "aABCBBca", + 10 + ], + [ + "ABbCbA", + "A", + 10 + ], + [ + "ABbCbA", + "AbCbB", + 4 + ], + [ + "ABbCbbBa", + "B", + 14 + ], + [ + "ABbCcB", + "AaCccab", + 8 + ], + [ + "ABbaACBCc", + "baBCbCbcB", + 11 + ], + [ + "ABbaabcCC", + "aaaacAAAA", + 15 + ], + [ + "ABbacAAA", + "CAAccb", + 13 + ], + [ + "ABbb", + "cAaC", + 8 + ], + [ + "ABbbA", + "BCcbb", + 8 + ], + [ + "ABbbC", + "ABBc", + 4 + ], + [ + "ABbbbB", + "BCabaCc", + 12 + ], + [ + "ABbc", + "bBcAAac", + 10 + ], + [ + "ABbcc", + "AbBABaaa", + 11 + ], + [ + "ABbccBA", + "cACaCcCC", + 11 + ], + [ + "ABc", + "a", + 5 + ], + [ + "ABc", + "aA", + 5 + ], + [ + "ABc", + "b", + 5 + ], + [ + "ABcA", + "CB", + 6 + ], + [ + "ABcAa", + "BcbAC", + 6 + ], + [ + "ABcAaB", + "ab", + 9 + ], + [ + "ABcAbAa", + "AcAABbb", + 9 + ], + [ + "ABcAc", + "c", + 8 + ], + [ + "ABcAcCAc", + "cAcBcCaC", + 8 + ], + [ + "ABcBBcCCB", + "BaAcBbC", + 12 + ], + [ + "ABcBbAb", + "aAbACcAca", + 13 + ], + [ + "ABcBcCCbB", + "cbAC", + 13 + ], + [ + "ABcC", + "Cabc", + 6 + ], + [ + "ABcC", + "c", + 6 + ], + [ + "ABcCAaCc", + "C", + 14 + ], + [ + "ABcCAbCba", + "CcBa", + 12 + ], + [ + "ABcCBb", + "CAb", + 8 + ], + [ + "ABcCCa", + "bCaca", + 7 + ], + [ + "ABcCCcBa", + "Cbc", + 12 + ], + [ + "ABcCbbBbC", + "b", + 16 + ], + [ + "ABcaBC", + "Bcc", + 7 + ], + [ + "ABcaBb", + "CB", + 9 + ], + [ + "ABcb", + "a", + 7 + ], + [ + "ABcbAcc", + "AbBa", + 9 + ], + [ + "ABcbBC", + "cCcAa", + 10 + ], + [ + "ABcbCacCb", + "ba", + 14 + ], + [ + "ABcc", + "bAAcbCa", + 9 + ], + [ + "ABccA", + "CA", + 7 + ], + [ + "ABcccb", + "CB", + 10 + ], + [ + "AC", + "A", + 2 + ], + [ + "AC", + "AAb", + 4 + ], + [ + "AC", + "AB", + 2 + ], + [ + "AC", + "ABBc", + 5 + ], + [ + "AC", + "ABaaaBc", + 11 + ], + [ + "AC", + "ACBaAbb", + 10 + ], + [ + "AC", + "AaBcBC", + 8 + ], + [ + "AC", + "AaCCCB", + 8 + ], + [ + "AC", + "AabB", + 6 + ], + [ + "AC", + "AacAaBc", + 11 + ], + [ + "AC", + "AbBCacbA", + 12 + ], + [ + "AC", + "AbbbcbACb", + 14 + ], + [ + "AC", + "B", + 4 + ], + [ + "AC", + "BBbA", + 8 + ], + [ + "AC", + "BCaa", + 6 + ], + [ + "AC", + "BbCaaA", + 10 + ], + [ + "AC", + "BcAab", + 8 + ], + [ + "AC", + "C", + 2 + ], + [ + "AC", + "CAcb", + 5 + ], + [ + "AC", + "Ca", + 4 + ], + [ + "AC", + "CabAB", + 8 + ], + [ + "AC", + "aABaABAB", + 14 + ], + [ + "AC", + "aAacbbcAC", + 14 + ], + [ + "AC", + "aBCaCBba", + 13 + ], + [ + "AC", + "aa", + 3 + ], + [ + "AC", + "aaaBBabAb", + 16 + ], + [ + "AC", + "baccAbcB", + 13 + ], + [ + "AC", + "c", + 3 + ], + [ + "AC", + "cACCaBA", + 10 + ], + [ + "AC", + "cCaaAacaA", + 15 + ], + [ + "AC", + "cbcbbcC", + 12 + ], + [ + "ACA", + "Aa", + 3 + ], + [ + "ACA", + "C", + 4 + ], + [ + "ACA", + "CbaaBc", + 11 + ], + [ + "ACA", + "aAABAAcb", + 12 + ], + [ + "ACA", + "cACCbaAaC", + 12 + ], + [ + "ACAA", + "AcaAAb", + 5 + ], + [ + "ACAABBaC", + "A", + 14 + ], + [ + "ACAABcA", + "bCBACacC", + 10 + ], + [ + "ACAAC", + "bB", + 10 + ], + [ + "ACAAC", + "cBaaCabaC", + 11 + ], + [ + "ACAAa", + "CAa", + 4 + ], + [ + "ACAAaCaA", + "AAacb", + 9 + ], + [ + "ACAAbcaAa", + "bba", + 14 + ], + [ + "ACABA", + "bAB", + 6 + ], + [ + "ACABA", + "c", + 9 + ], + [ + "ACABABA", + "CcC", + 12 + ], + [ + "ACABACaB", + "bcBAaAB", + 8 + ], + [ + "ACABbCaBc", + "cA", + 15 + ], + [ + "ACAC", + "aaBAA", + 7 + ], + [ + "ACACB", + "aaCcbaBC", + 11 + ], + [ + "ACACBB", + "cCb", + 8 + ], + [ + "ACACBbccA", + "BABbAc", + 10 + ], + [ + "ACACC", + "BaAA", + 8 + ], + [ + "ACACa", + "Bccc", + 8 + ], + [ + "ACACbB", + "aCaacAaC", + 11 + ], + [ + "ACACbab", + "cC", + 11 + ], + [ + "ACAaA", + "Aaabbc", + 9 + ], + [ + "ACAaB", + "caBBcB", + 9 + ], + [ + "ACAaBA", + "CAbCC", + 8 + ], + [ + "ACAaCBccb", + "c", + 16 + ], + [ + "ACAabbCAc", + "BB", + 16 + ], + [ + "ACAb", + "AaaCC", + 7 + ], + [ + "ACAbBCaCA", + "A", + 16 + ], + [ + "ACAbbaaBA", + "aacacABbc", + 15 + ], + [ + "ACAbcB", + "bcBCB", + 7 + ], + [ + "ACAc", + "CCbcaabA", + 12 + ], + [ + "ACAcBCc", + "AcaAbcb", + 8 + ], + [ + "ACAcaabA", + "CACbBC", + 10 + ], + [ + "ACB", + "ACbbaBb", + 8 + ], + [ + "ACB", + "aCbbc", + 6 + ], + [ + "ACB", + "baBacBAB", + 12 + ], + [ + "ACB", + "cabbCcBA", + 11 + ], + [ + "ACBA", + "CbCCCaCAc", + 14 + ], + [ + "ACBAC", + "CaABbbcBA", + 13 + ], + [ + "ACBACBB", + "cAABCbBC", + 9 + ], + [ + "ACBACCba", + "ACBCcCb", + 5 + ], + [ + "ACBAbCBc", + "bC", + 12 + ], + [ + "ACBAba", + "aAaCaC", + 10 + ], + [ + "ACBAcb", + "aCACc", + 6 + ], + [ + "ACBB", + "bAbb", + 6 + ], + [ + "ACBBAB", + "BbBCb", + 8 + ], + [ + "ACBBABBa", + "bbabA", + 11 + ], + [ + "ACBBBaA", + "bccbA", + 10 + ], + [ + "ACBBBaCA", + "bCCCB", + 12 + ], + [ + "ACBBcAccc", + "ab", + 16 + ], + [ + "ACBCCC", + "a", + 11 + ], + [ + "ACBCbaa", + "ACCAbCCb", + 10 + ], + [ + "ACBaA", + "BcBcBcA", + 9 + ], + [ + "ACBaBa", + "AaAa", + 6 + ], + [ + "ACBabaa", + "abcAbbb", + 10 + ], + [ + "ACBabbab", + "CAa", + 11 + ], + [ + "ACBac", + "BcbcCb", + 9 + ], + [ + "ACBb", + "bcCAca", + 10 + ], + [ + "ACBbCaaBB", + "Cc", + 15 + ], + [ + "ACBba", + "CcaAbbc", + 10 + ], + [ + "ACBbaAbAC", + "aCabbAC", + 7 + ], + [ + "ACBbcAcB", + "cb", + 13 + ], + [ + "ACBcAB", + "cb", + 9 + ], + [ + "ACBcaaAAb", + "ACBA", + 10 + ], + [ + "ACC", + "BcccCaAba", + 15 + ], + [ + "ACC", + "Ccb", + 5 + ], + [ + "ACC", + "aB", + 5 + ], + [ + "ACC", + "bBcABBbAC", + 14 + ], + [ + "ACC", + "cABA", + 6 + ], + [ + "ACC", + "caACC", + 4 + ], + [ + "ACCA", + "BaaBc", + 9 + ], + [ + "ACCA", + "BacAabAAa", + 14 + ], + [ + "ACCACABB", + "ABAAbBaBa", + 11 + ], + [ + "ACCAbB", + "CcbAacC", + 11 + ], + [ + "ACCAccAB", + "ACbCC", + 10 + ], + [ + "ACCBAAC", + "Ac", + 11 + ], + [ + "ACCBAaBC", + "a", + 14 + ], + [ + "ACCBB", + "BcCccabbA", + 13 + ], + [ + "ACCBBcac", + "CCB", + 10 + ], + [ + "ACCBCBC", + "AcaaCacba", + 11 + ], + [ + "ACCBac", + "aCACaCc", + 7 + ], + [ + "ACCBb", + "BaCac", + 8 + ], + [ + "ACCBbcbAC", + "AAaCaCBCC", + 12 + ], + [ + "ACCBcCBB", + "aBBABb", + 10 + ], + [ + "ACCBcaaCa", + "CBb", + 14 + ], + [ + "ACCBcc", + "bbAa", + 11 + ], + [ + "ACCCAaCcC", + "CBAc", + 12 + ], + [ + "ACCCBac", + "CcCBACBB", + 9 + ], + [ + "ACCCC", + "CACCACc", + 5 + ], + [ + "ACCCb", + "CbBaCcb", + 9 + ], + [ + "ACCCbaCAc", + "abACCC", + 11 + ], + [ + "ACCaAACa", + "C", + 14 + ], + [ + "ACCaACAa", + "a", + 14 + ], + [ + "ACCaB", + "A", + 8 + ], + [ + "ACCaCA", + "a", + 10 + ], + [ + "ACCaaAc", + "A", + 12 + ], + [ + "ACCac", + "a", + 8 + ], + [ + "ACCbA", + "aCCBa", + 3 + ], + [ + "ACCbB", + "BaAa", + 10 + ], + [ + "ACCbC", + "CcbaCC", + 7 + ], + [ + "ACCbCba", + "a", + 12 + ], + [ + "ACCbaBbb", + "aA", + 14 + ], + [ + "ACCbba", + "aaCBCbccB", + 11 + ], + [ + "ACCbbbC", + "BCbABAbaA", + 13 + ], + [ + "ACCbcBa", + "aCBaBcbC", + 9 + ], + [ + "ACCbcbccB", + "caAAbaCcb", + 13 + ], + [ + "ACCcAccCc", + "AccAb", + 11 + ], + [ + "ACCcBcB", + "AcBcAAca", + 9 + ], + [ + "ACCcC", + "a", + 9 + ], + [ + "ACCcaC", + "cCA", + 8 + ], + [ + "ACCcacC", + "BBaaAcAab", + 14 + ], + [ + "ACa", + "AcbCAbaB", + 10 + ], + [ + "ACa", + "Bca", + 3 + ], + [ + "ACa", + "ba", + 4 + ], + [ + "ACa", + "baAAaba", + 10 + ], + [ + "ACaA", + "A", + 6 + ], + [ + "ACaA", + "ABCAba", + 6 + ], + [ + "ACaA", + "acbCc", + 8 + ], + [ + "ACaA", + "cc", + 7 + ], + [ + "ACaAC", + "cABCBAc", + 7 + ], + [ + "ACaAcABa", + "cCAACC", + 10 + ], + [ + "ACaB", + "ABAbccB", + 9 + ], + [ + "ACaB", + "bAAAaAbAA", + 13 + ], + [ + "ACaBBBCB", + "AaAC", + 10 + ], + [ + "ACaBBaAa", + "AcaBcBbcB", + 9 + ], + [ + "ACaBCB", + "cc", + 10 + ], + [ + "ACaBCBb", + "b", + 12 + ], + [ + "ACaBacCc", + "bb", + 15 + ], + [ + "ACaBcb", + "BcCc", + 9 + ], + [ + "ACaCACc", + "c", + 12 + ], + [ + "ACaCBccBc", + "CcABCcBcb", + 9 + ], + [ + "ACaCCBA", + "AAcacC", + 8 + ], + [ + "ACaa", + "BAAc", + 7 + ], + [ + "ACaaBAbc", + "ACAccba", + 9 + ], + [ + "ACaabb", + "BCAb", + 7 + ], + [ + "ACaacBa", + "cBCBAc", + 11 + ], + [ + "ACabABBA", + "CAcCbB", + 10 + ], + [ + "ACabC", + "B", + 9 + ], + [ + "ACabac", + "BACcbCcbB", + 10 + ], + [ + "ACabbcA", + "aCacc", + 7 + ], + [ + "ACaccaa", + "AA", + 11 + ], + [ + "ACb", + "A", + 4 + ], + [ + "ACb", + "cBAab", + 6 + ], + [ + "ACb", + "ccbccbB", + 11 + ], + [ + "ACbA", + "AaBacA", + 7 + ], + [ + "ACbA", + "BaCCbA", + 5 + ], + [ + "ACbA", + "abACa", + 7 + ], + [ + "ACbACcbaB", + "ccc", + 14 + ], + [ + "ACbAbaCBC", + "acbaba", + 9 + ], + [ + "ACbB", + "aCACBAbb", + 9 + ], + [ + "ACbBA", + "CACB", + 6 + ], + [ + "ACbBCC", + "bcbCaAB", + 11 + ], + [ + "ACbBa", + "B", + 8 + ], + [ + "ACbBaCab", + "cbB", + 11 + ], + [ + "ACbCCbBb", + "aaca", + 14 + ], + [ + "ACbCaA", + "bAbC", + 8 + ], + [ + "ACbCb", + "c", + 9 + ], + [ + "ACbCc", + "ABc", + 5 + ], + [ + "ACbCcbA", + "accAAAaCc", + 15 + ], + [ + "ACba", + "acABAcbC", + 11 + ], + [ + "ACba", + "bCabba", + 6 + ], + [ + "ACbaAaA", + "BaaAbcC", + 12 + ], + [ + "ACbaAbB", + "AaBbbbb", + 8 + ], + [ + "ACbaAc", + "ABaBbCBcB", + 12 + ], + [ + "ACbaCAC", + "bBcaC", + 8 + ], + [ + "ACbaCaB", + "cbaA", + 8 + ], + [ + "ACbaaaB", + "CAcA", + 10 + ], + [ + "ACbabABB", + "BCBABBAc", + 11 + ], + [ + "ACbabcac", + "ABBA", + 11 + ], + [ + "ACbbBB", + "cAbbaC", + 8 + ], + [ + "ACbbBb", + "abAAbCab", + 10 + ], + [ + "ACbbCc", + "AccCbBAAB", + 11 + ], + [ + "ACbbca", + "cbABC", + 9 + ], + [ + "ACbbccB", + "b", + 12 + ], + [ + "ACbcBBc", + "CBacBbCbA", + 11 + ], + [ + "ACbcCba", + "abBBc", + 10 + ], + [ + "ACbcCccA", + "BBaA", + 13 + ], + [ + "ACc", + "AABbabcbb", + 14 + ], + [ + "ACc", + "ABbCcC", + 6 + ], + [ + "ACc", + "ABcBaB", + 8 + ], + [ + "ACc", + "a", + 5 + ], + [ + "ACc", + "b", + 6 + ], + [ + "ACc", + "baCBbbCbc", + 13 + ], + [ + "ACc", + "bcAcC", + 6 + ], + [ + "ACc", + "c", + 4 + ], + [ + "ACcA", + "CbcBBcbb", + 13 + ], + [ + "ACcA", + "aBBA", + 5 + ], + [ + "ACcAAb", + "ccAa", + 6 + ], + [ + "ACcABac", + "cA", + 10 + ], + [ + "ACcAc", + "baC", + 8 + ], + [ + "ACcBCBbbB", + "aA", + 17 + ], + [ + "ACcBa", + "ABBbBAbca", + 12 + ], + [ + "ACcBa", + "abbaca", + 9 + ], + [ + "ACcBba", + "baaAcAcA", + 12 + ], + [ + "ACcBbaa", + "CbCcCCBAC", + 12 + ], + [ + "ACcC", + "AcCABAC", + 8 + ], + [ + "ACcCACb", + "CABB", + 9 + ], + [ + "ACcCC", + "ccabBBC", + 11 + ], + [ + "ACcCa", + "Bcb", + 8 + ], + [ + "ACcCacAa", + "CbCba", + 10 + ], + [ + "ACcCc", + "bbBCC", + 7 + ], + [ + "ACca", + "cBBCBcbC", + 12 + ], + [ + "ACcaCAb", + "aaA", + 9 + ], + [ + "ACcaaAb", + "CaCAc", + 8 + ], + [ + "ACcabc", + "AAACb", + 8 + ], + [ + "ACcac", + "abBCBCc", + 9 + ], + [ + "ACcbB", + "caBaa", + 10 + ], + [ + "ACcbC", + "aCA", + 7 + ], + [ + "ACcbaBb", + "aCACCCAaA", + 12 + ], + [ + "ACcbbC", + "cacb", + 8 + ], + [ + "ACcbcCBB", + "A", + 14 + ], + [ + "ACcc", + "Cca", + 4 + ], + [ + "ACcca", + "accBbB", + 8 + ], + [ + "ACccabBC", + "Bb", + 14 + ], + [ + "ACccb", + "C", + 8 + ], + [ + "ACccbCccb", + "BbCacaA", + 14 + ], + [ + "ACccca", + "A", + 10 + ], + [ + "Aa", + "A", + 2 + ], + [ + "Aa", + "AAcac", + 6 + ], + [ + "Aa", + "ABBa", + 4 + ], + [ + "Aa", + "AbAabCcB", + 12 + ], + [ + "Aa", + "AbCCCCbcC", + 16 + ], + [ + "Aa", + "AbccAA", + 9 + ], + [ + "Aa", + "B", + 4 + ], + [ + "Aa", + "BA", + 3 + ], + [ + "Aa", + "BB", + 4 + ], + [ + "Aa", + "BBaccBAc", + 14 + ], + [ + "Aa", + "BCAaBb", + 8 + ], + [ + "Aa", + "BaBBAc", + 10 + ], + [ + "Aa", + "BaBcCaBc", + 13 + ], + [ + "Aa", + "BaCc", + 6 + ], + [ + "Aa", + "BabcCcAb", + 14 + ], + [ + "Aa", + "BbBB", + 8 + ], + [ + "Aa", + "C", + 4 + ], + [ + "Aa", + "CAabcaaAB", + 14 + ], + [ + "Aa", + "CAbbCbCB", + 14 + ], + [ + "Aa", + "CBBaBccb", + 14 + ], + [ + "Aa", + "CBCAccba", + 12 + ], + [ + "Aa", + "a", + 2 + ], + [ + "Aa", + "aAc", + 4 + ], + [ + "Aa", + "aacb", + 5 + ], + [ + "Aa", + "acAAacaB", + 12 + ], + [ + "Aa", + "acaA", + 5 + ], + [ + "Aa", + "acbc", + 7 + ], + [ + "Aa", + "b", + 4 + ], + [ + "Aa", + "bBA", + 5 + ], + [ + "Aa", + "bBABbc", + 10 + ], + [ + "Aa", + "baABcc", + 10 + ], + [ + "Aa", + "babbc", + 8 + ], + [ + "Aa", + "bbabBCac", + 13 + ], + [ + "Aa", + "cAAB", + 5 + ], + [ + "Aa", + "cC", + 4 + ], + [ + "Aa", + "caCAB", + 8 + ], + [ + "Aa", + "ccabB", + 8 + ], + [ + "AaA", + "Acbc", + 6 + ], + [ + "AaA", + "BBAcB", + 8 + ], + [ + "AaA", + "BaAbb", + 6 + ], + [ + "AaA", + "CAcBB", + 8 + ], + [ + "AaA", + "Cc", + 6 + ], + [ + "AaA", + "a", + 4 + ], + [ + "AaA", + "bAcaab", + 7 + ], + [ + "AaA", + "bCbCac", + 10 + ], + [ + "AaA", + "bCcaBAa", + 10 + ], + [ + "AaA", + "cAbaCAbB", + 10 + ], + [ + "AaAA", + "bcacBb", + 10 + ], + [ + "AaAABca", + "aACbAbaa", + 9 + ], + [ + "AaAAbA", + "CAbA", + 6 + ], + [ + "AaAAbBCcc", + "bbcAb", + 14 + ], + [ + "AaAAcbcbB", + "aAcCCBba", + 11 + ], + [ + "AaABbA", + "BBaACcACA", + 12 + ], + [ + "AaABc", + "cCcaBB", + 9 + ], + [ + "AaABcBAbb", + "BABAbaB", + 11 + ], + [ + "AaACCAb", + "C", + 12 + ], + [ + "AaACCaac", + "aabBbAbCA", + 13 + ], + [ + "AaACa", + "BBb", + 10 + ], + [ + "AaAaABB", + "CABcCCcCA", + 16 + ], + [ + "AaAaBbCc", + "B", + 14 + ], + [ + "AaAaa", + "cba", + 8 + ], + [ + "AaAabb", + "CACAA", + 9 + ], + [ + "AaAaccCB", + "bAaacBbaA", + 12 + ], + [ + "AaAb", + "cABAcb", + 6 + ], + [ + "AaAbAaAb", + "a", + 14 + ], + [ + "AaAbAbbB", + "aA", + 12 + ], + [ + "AaAbBba", + "CCBac", + 12 + ], + [ + "AaAbb", + "BbaB", + 8 + ], + [ + "AaAbbc", + "cAAcCC", + 8 + ], + [ + "AaAbc", + "a", + 8 + ], + [ + "AaAc", + "aAaCA", + 6 + ], + [ + "AaAcA", + "BCAAAba", + 8 + ], + [ + "AaAccaBbc", + "baAcAACaa", + 11 + ], + [ + "AaB", + "AbbAbb", + 8 + ], + [ + "AaB", + "Bca", + 6 + ], + [ + "AaB", + "bbaAb", + 7 + ], + [ + "AaB", + "bcABBBCc", + 12 + ], + [ + "AaB", + "caAb", + 5 + ], + [ + "AaBA", + "cBAB", + 6 + ], + [ + "AaBACC", + "BCAAbB", + 10 + ], + [ + "AaBACaBA", + "cAc", + 13 + ], + [ + "AaBAa", + "c", + 10 + ], + [ + "AaBAc", + "CcACba", + 10 + ], + [ + "AaBAcBcaa", + "cb", + 15 + ], + [ + "AaBBAC", + "ACAca", + 9 + ], + [ + "AaBBAcbcc", + "CbCcBb", + 14 + ], + [ + "AaBBbcA", + "A", + 12 + ], + [ + "AaBCcbCB", + "CCcAb", + 11 + ], + [ + "AaBa", + "abA", + 4 + ], + [ + "AaBa", + "bbbCabA", + 10 + ], + [ + "AaBaaaCBa", + "A", + 16 + ], + [ + "AaBabBCb", + "aBac", + 9 + ], + [ + "AaBbB", + "bBaa", + 8 + ], + [ + "AaBba", + "ab", + 6 + ], + [ + "AaBbba", + "caAbBAa", + 7 + ], + [ + "AaBbbaac", + "Cbcca", + 12 + ], + [ + "AaBbbbA", + "AabcBAa", + 7 + ], + [ + "AaBc", + "bAaaBaCCB", + 11 + ], + [ + "AaBcA", + "aCbCbB", + 9 + ], + [ + "AaBcAbBC", + "CBCACaBBA", + 12 + ], + [ + "AaBccbA", + "BBcaaccb", + 10 + ], + [ + "AaC", + "AACcabcAa", + 13 + ], + [ + "AaC", + "ABAaabA", + 10 + ], + [ + "AaC", + "Acc", + 3 + ], + [ + "AaC", + "aCCB", + 5 + ], + [ + "AaC", + "bbbbbbAA", + 15 + ], + [ + "AaCA", + "CCc", + 6 + ], + [ + "AaCAAAcac", + "ABB", + 16 + ], + [ + "AaCAAbaa", + "CCbABc", + 11 + ], + [ + "AaCACCa", + "BCcBACc", + 10 + ], + [ + "AaCACCbcc", + "CAacc", + 10 + ], + [ + "AaCAcAcB", + "bbA", + 14 + ], + [ + "AaCB", + "BbBC", + 8 + ], + [ + "AaCB", + "bCCbBAA", + 10 + ], + [ + "AaCBa", + "ACAbC", + 7 + ], + [ + "AaCBaC", + "Ba", + 8 + ], + [ + "AaCBaaAAC", + "CaBc", + 13 + ], + [ + "AaCBbBBa", + "CBbAcCBb", + 12 + ], + [ + "AaCCAAC", + "ACaBb", + 9 + ], + [ + "AaCCAbcBB", + "BCaab", + 13 + ], + [ + "AaCCCB", + "AaaAA", + 8 + ], + [ + "AaCCCBB", + "bB", + 11 + ], + [ + "AaCCcbB", + "BCcaCcB", + 9 + ], + [ + "AaCCcc", + "cbc", + 9 + ], + [ + "AaCaAAa", + "ccccBbcaC", + 15 + ], + [ + "AaCaCccb", + "aCB", + 11 + ], + [ + "AaCaaaA", + "a", + 12 + ], + [ + "AaCaac", + "CBabAA", + 10 + ], + [ + "AaCac", + "AbaBC", + 7 + ], + [ + "AaCbbbBaB", + "ccC", + 16 + ], + [ + "AaCbcCb", + "ccAAaB", + 12 + ], + [ + "AaCc", + "a", + 6 + ], + [ + "AaCcABAa", + "B", + 14 + ], + [ + "AaCcAbC", + "Bb", + 12 + ], + [ + "AaCcBBcc", + "cBb", + 11 + ], + [ + "AaCcaCBaA", + "ABca", + 12 + ], + [ + "AaCcab", + "bBcB", + 9 + ], + [ + "AaCcacA", + "BBBAcbC", + 13 + ], + [ + "AaCcbBbCa", + "BBBAaabCb", + 14 + ], + [ + "AaCcc", + "abcBAb", + 10 + ], + [ + "AaCccBBCb", + "cB", + 14 + ], + [ + "AaCccbC", + "baaaaAb", + 11 + ], + [ + "Aaa", + "BaAA", + 5 + ], + [ + "Aaa", + "CbabcBBB", + 14 + ], + [ + "Aaa", + "aAa", + 2 + ], + [ + "Aaa", + "aBB", + 5 + ], + [ + "Aaa", + "bAAbBaBcc", + 13 + ], + [ + "Aaa", + "ca", + 4 + ], + [ + "AaaA", + "aBabbB", + 9 + ], + [ + "AaaA", + "baCb", + 6 + ], + [ + "AaaAAC", + "a", + 10 + ], + [ + "AaaAAaC", + "b", + 14 + ], + [ + "AaaACAcbA", + "CBAcAC", + 12 + ], + [ + "AaaACa", + "BABcccC", + 11 + ], + [ + "AaaAbBAab", + "bacccCc", + 16 + ], + [ + "AaaAcBCB", + "Bbbb", + 14 + ], + [ + "AaaAcb", + "AcabAA", + 8 + ], + [ + "AaaB", + "aaCAC", + 6 + ], + [ + "AaaBABa", + "bBaC", + 11 + ], + [ + "AaaBCaCC", + "c", + 15 + ], + [ + "AaaBa", + "CBCBc", + 8 + ], + [ + "AaaC", + "aaAc", + 3 + ], + [ + "AaaC", + "b", + 8 + ], + [ + "AaaC", + "caaBCAABc", + 12 + ], + [ + "AaaCB", + "ABcbBCCA", + 12 + ], + [ + "AaaCcbcc", + "B", + 15 + ], + [ + "Aaaa", + "abCBCBa", + 11 + ], + [ + "AaaaA", + "CccAB", + 9 + ], + [ + "AaaaBcb", + "BCabBBBC", + 11 + ], + [ + "AaaaCCC", + "BBcaacaCB", + 11 + ], + [ + "AaaacbC", + "CcAcBACcb", + 13 + ], + [ + "AaabA", + "cB", + 9 + ], + [ + "AaabACBca", + "bAc", + 12 + ], + [ + "AaabCAC", + "bCaacCbB", + 10 + ], + [ + "Aaaba", + "BbccCaa", + 12 + ], + [ + "AaabaBba", + "aBaB", + 9 + ], + [ + "Aaababb", + "BcbBCcc", + 13 + ], + [ + "AaabcBb", + "abab", + 8 + ], + [ + "Aaac", + "BAbaab", + 6 + ], + [ + "AaacACBc", + "ACbbCaABA", + 12 + ], + [ + "AaaccCBcb", + "CBabaCACb", + 11 + ], + [ + "AaacccCc", + "c", + 14 + ], + [ + "Aab", + "BcBaaCBC", + 12 + ], + [ + "Aab", + "CBBaACcBA", + 15 + ], + [ + "Aab", + "a", + 4 + ], + [ + "AabA", + "acCbacA", + 9 + ], + [ + "AabAAcBBB", + "aa", + 15 + ], + [ + "AabAbBbcB", + "AcCcA", + 14 + ], + [ + "AabAccB", + "AcabBCb", + 8 + ], + [ + "AabBABc", + "AAabbCcCc", + 9 + ], + [ + "AabBCAaC", + "aBcCbc", + 10 + ], + [ + "AabBCC", + "A", + 10 + ], + [ + "AabBaBcBB", + "cbcc", + 14 + ], + [ + "AabBacAaa", + "aAc", + 13 + ], + [ + "AabBba", + "bcabb", + 8 + ], + [ + "AabBbc", + "CcAaA", + 12 + ], + [ + "AabBcBca", + "Ca", + 13 + ], + [ + "AabBcbc", + "ac", + 10 + ], + [ + "AabCbA", + "B", + 11 + ], + [ + "AabCbC", + "ccBbc", + 8 + ], + [ + "Aaba", + "BBaa", + 6 + ], + [ + "AabaACCC", + "aaBBcccCa", + 10 + ], + [ + "AabaCCccc", + "BaB", + 15 + ], + [ + "AabbA", + "AB", + 7 + ], + [ + "AabbABCBb", + "aBB", + 12 + ], + [ + "AabbB", + "AA", + 7 + ], + [ + "AabbB", + "bCCC", + 10 + ], + [ + "AabbbbbC", + "bBbBaB", + 10 + ], + [ + "AabbcCACc", + "AAa", + 14 + ], + [ + "Aabc", + "bBCbc", + 6 + ], + [ + "Aabc", + "bbA", + 6 + ], + [ + "AabcAAbCc", + "Aa", + 14 + ], + [ + "AabcBBb", + "bAbAcCBB", + 8 + ], + [ + "AabcBb", + "bb", + 8 + ], + [ + "AabcC", + "BbbBcbbC", + 10 + ], + [ + "AabcbCa", + "CB", + 12 + ], + [ + "Aac", + "Bccc", + 6 + ], + [ + "Aac", + "CBABCbaA", + 12 + ], + [ + "Aac", + "Cb", + 6 + ], + [ + "Aac", + "a", + 4 + ], + [ + "Aac", + "aBbCCaaa", + 13 + ], + [ + "Aac", + "baBAcA", + 8 + ], + [ + "Aac", + "c", + 4 + ], + [ + "Aac", + "caAABac", + 8 + ], + [ + "AacA", + "ACcBA", + 4 + ], + [ + "AacA", + "BaaAccBcA", + 11 + ], + [ + "AacAABbaa", + "a", + 16 + ], + [ + "AacABAB", + "CCc", + 12 + ], + [ + "AacAcbbC", + "cbCa", + 12 + ], + [ + "AacBBCc", + "BcBAA", + 10 + ], + [ + "AacBaA", + "AAa", + 7 + ], + [ + "AacBbaCBB", + "CcbC", + 12 + ], + [ + "AacBbcccc", + "CbACCaBab", + 18 + ], + [ + "AacC", + "BcBcAbb", + 12 + ], + [ + "AacCaBcaB", + "CAAb", + 13 + ], + [ + "AacCacC", + "CaABC", + 9 + ], + [ + "AacCcCcAC", + "CCBBabBA", + 16 + ], + [ + "AacCcc", + "Aab", + 8 + ], + [ + "AacaaCc", + "bAaA", + 10 + ], + [ + "AacacB", + "aaBBB", + 7 + ], + [ + "AacacBC", + "CBBcAcba", + 10 + ], + [ + "AacacBb", + "AAabbcaC", + 10 + ], + [ + "Aacb", + "c", + 6 + ], + [ + "AacbAAA", + "BbcBaCCCb", + 14 + ], + [ + "Aacbaa", + "aCBbbCaAc", + 12 + ], + [ + "Aacc", + "ACAA", + 6 + ], + [ + "Aacc", + "CBAcB", + 7 + ], + [ + "AaccAB", + "baAcAcbcc", + 11 + ], + [ + "AaccABc", + "bB", + 12 + ], + [ + "AaccAaAb", + "acb", + 10 + ], + [ + "AaccB", + "ac", + 6 + ], + [ + "AaccBcc", + "BC", + 11 + ], + [ + "AaccC", + "bAbacBAa", + 10 + ], + [ + "AaccaAc", + "Bc", + 12 + ], + [ + "AaccaBa", + "B", + 12 + ], + [ + "AaccaCcBb", + "bABCca", + 13 + ], + [ + "Aaccac", + "c", + 10 + ], + [ + "AacccAa", + "AC", + 11 + ], + [ + "AacccAcC", + "ab", + 14 + ], + [ + "AacccBBcC", + "Bb", + 15 + ], + [ + "Ab", + "A", + 2 + ], + [ + "Ab", + "AA", + 2 + ], + [ + "Ab", + "AaabCAAA", + 12 + ], + [ + "Ab", + "AbACAaCAA", + 14 + ], + [ + "Ab", + "AbCCAAACc", + 14 + ], + [ + "Ab", + "AbCbAa", + 8 + ], + [ + "Ab", + "Ac", + 2 + ], + [ + "Ab", + "AcaABbc", + 10 + ], + [ + "Ab", + "BAcCa", + 8 + ], + [ + "Ab", + "BBc", + 5 + ], + [ + "Ab", + "BbcAcCCaa", + 16 + ], + [ + "Ab", + "CABa", + 5 + ], + [ + "Ab", + "CAaB", + 5 + ], + [ + "Ab", + "CCBcAbbc", + 12 + ], + [ + "Ab", + "CaBc", + 6 + ], + [ + "Ab", + "CbBCAbaBc", + 14 + ], + [ + "Ab", + "aCAccA", + 10 + ], + [ + "Ab", + "aab", + 3 + ], + [ + "Ab", + "acaCBAa", + 12 + ], + [ + "Ab", + "bA", + 4 + ], + [ + "Ab", + "bCBc", + 7 + ], + [ + "Ab", + "c", + 4 + ], + [ + "Ab", + "cBBB", + 7 + ], + [ + "Ab", + "cC", + 4 + ], + [ + "Ab", + "cCAaBbbBC", + 14 + ], + [ + "Ab", + "cCaAcc", + 10 + ], + [ + "Ab", + "caA", + 5 + ], + [ + "Ab", + "caCacCcBC", + 16 + ], + [ + "Ab", + "cbcacAC", + 12 + ], + [ + "Ab", + "ccAbB", + 6 + ], + [ + "Ab", + "ccb", + 4 + ], + [ + "AbA", + "BCBAaC", + 9 + ], + [ + "AbA", + "BbBAaA", + 8 + ], + [ + "AbA", + "CcBa", + 6 + ], + [ + "AbA", + "aAC", + 5 + ], + [ + "AbA", + "b", + 4 + ], + [ + "AbA", + "caABB", + 7 + ], + [ + "AbA", + "ccc", + 6 + ], + [ + "AbAA", + "CBba", + 6 + ], + [ + "AbAAC", + "BAAC", + 3 + ], + [ + "AbAAC", + "bbab", + 7 + ], + [ + "AbAACaAb", + "C", + 14 + ], + [ + "AbAACbbBB", + "BCbaa", + 13 + ], + [ + "AbAAbC", + "caCaAAAbA", + 11 + ], + [ + "AbAAcbBa", + "BabBBCa", + 11 + ], + [ + "AbAB", + "Ab", + 4 + ], + [ + "AbAB", + "Bcb", + 6 + ], + [ + "AbAB", + "ac", + 7 + ], + [ + "AbABCa", + "cC", + 10 + ], + [ + "AbABa", + "BAaaCB", + 9 + ], + [ + "AbACABc", + "aBCACA", + 8 + ], + [ + "AbACBCA", + "aBB", + 10 + ], + [ + "AbACaa", + "AcAba", + 6 + ], + [ + "AbACbA", + "A", + 10 + ], + [ + "AbACbAA", + "aACA", + 7 + ], + [ + "AbACccccb", + "cCbbCBA", + 15 + ], + [ + "AbAaABB", + "BcaaA", + 9 + ], + [ + "AbAaAb", + "CB", + 11 + ], + [ + "AbAaC", + "AacbbACba", + 11 + ], + [ + "AbAaCAab", + "CabaacCaA", + 9 + ], + [ + "AbAaaa", + "AaC", + 8 + ], + [ + "AbAacaaac", + "abACABAc", + 8 + ], + [ + "AbAb", + "bbccBB", + 9 + ], + [ + "AbAbCba", + "BCbA", + 8 + ], + [ + "AbAbabac", + "bc", + 12 + ], + [ + "AbAbbBaab", + "bbabb", + 10 + ], + [ + "AbAc", + "BcbBCbC", + 11 + ], + [ + "AbAcACAa", + "cBcBBA", + 11 + ], + [ + "AbAcB", + "c", + 8 + ], + [ + "AbAcbCbca", + "AcBaaB", + 13 + ], + [ + "AbAccAbBc", + "aACcAACbA", + 11 + ], + [ + "AbAccBCa", + "BACCAaA", + 10 + ], + [ + "AbB", + "AABC", + 4 + ], + [ + "AbB", + "AbCbCCc", + 9 + ], + [ + "AbB", + "BcaAbAAAb", + 13 + ], + [ + "AbB", + "bBBA", + 5 + ], + [ + "AbB", + "cAaaaB", + 8 + ], + [ + "AbB", + "cbbABB", + 7 + ], + [ + "AbBAcCAC", + "CAAbcCC", + 9 + ], + [ + "AbBB", + "AAAAC", + 8 + ], + [ + "AbBBabc", + "Bcb", + 10 + ], + [ + "AbBBbCaA", + "AaCccAAA", + 11 + ], + [ + "AbBBcaAaa", + "bcbBbcCb", + 13 + ], + [ + "AbBCAacC", + "c", + 14 + ], + [ + "AbBCAcaa", + "aa", + 12 + ], + [ + "AbBCBbA", + "abbcBb", + 5 + ], + [ + "AbBaABC", + "AabAAbc", + 6 + ], + [ + "AbBaBB", + "AAaAca", + 9 + ], + [ + "AbBaCC", + "CAb", + 10 + ], + [ + "AbBaaAb", + "ACcBcca", + 11 + ], + [ + "AbBabBa", + "bccBAbb", + 10 + ], + [ + "AbBb", + "A", + 6 + ], + [ + "AbBb", + "BbaAB", + 7 + ], + [ + "AbBbA", + "babCBABbb", + 11 + ], + [ + "AbBbAABc", + "AbAa", + 9 + ], + [ + "AbBbCb", + "bcAACCcac", + 15 + ], + [ + "AbBbb", + "aCAC", + 9 + ], + [ + "AbBbbacbC", + "CcbccAb", + 14 + ], + [ + "AbBbcb", + "Ab", + 8 + ], + [ + "AbBbcbabC", + "Ba", + 14 + ], + [ + "AbBcBaaCc", + "BbcAB", + 13 + ], + [ + "AbBcaaCCA", + "aba", + 13 + ], + [ + "AbBcb", + "BAaAcb", + 6 + ], + [ + "AbBcc", + "AaccBc", + 6 + ], + [ + "AbBcccB", + "cB", + 10 + ], + [ + "AbC", + "BccBcC", + 9 + ], + [ + "AbC", + "C", + 4 + ], + [ + "AbCAA", + "CCcCcacBa", + 14 + ], + [ + "AbCABa", + "ACBC", + 6 + ], + [ + "AbCACa", + "BcaBacAA", + 12 + ], + [ + "AbCACcBbB", + "C", + 16 + ], + [ + "AbCAc", + "BbCbcBCAb", + 12 + ], + [ + "AbCB", + "Caa", + 8 + ], + [ + "AbCB", + "acbAc", + 7 + ], + [ + "AbCB", + "caaaba", + 10 + ], + [ + "AbCBbB", + "BacABACaB", + 13 + ], + [ + "AbCBbbC", + "cACb", + 10 + ], + [ + "AbCCcAbc", + "abB", + 12 + ], + [ + "AbCCca", + "C", + 10 + ], + [ + "AbCCcacba", + "aaAaabcb", + 13 + ], + [ + "AbCa", + "CcAaCAaA", + 10 + ], + [ + "AbCa", + "aBcccBBa", + 11 + ], + [ + "AbCaA", + "bBbAB", + 8 + ], + [ + "AbCaAAbab", + "BCbCcb", + 13 + ], + [ + "AbCaC", + "AbABC", + 4 + ], + [ + "AbCaabBCB", + "Cb", + 14 + ], + [ + "AbCabbc", + "BcCaB", + 9 + ], + [ + "AbCacAacb", + "aaAAAAC", + 12 + ], + [ + "AbCb", + "A", + 6 + ], + [ + "AbCb", + "BbaBcaCb", + 10 + ], + [ + "AbCbC", + "Cc", + 7 + ], + [ + "AbCbaB", + "aCac", + 7 + ], + [ + "AbCc", + "bAaCac", + 6 + ], + [ + "AbCcBBACC", + "cACC", + 10 + ], + [ + "AbCcbaBCA", + "cccCAbbCA", + 11 + ], + [ + "Aba", + "ACA", + 3 + ], + [ + "Aba", + "C", + 6 + ], + [ + "Aba", + "aB", + 4 + ], + [ + "Aba", + "bccccA", + 11 + ], + [ + "Aba", + "cabbcC", + 9 + ], + [ + "AbaAACBCb", + "CACabC", + 13 + ], + [ + "AbaAabca", + "CBCBCA", + 12 + ], + [ + "AbaAb", + "cb", + 8 + ], + [ + "AbaB", + "aCaB", + 3 + ], + [ + "AbaBAaCbC", + "cbbacCbA", + 10 + ], + [ + "AbaBAbaB", + "cbaC", + 12 + ], + [ + "AbaBBcbAA", + "bCaaC", + 14 + ], + [ + "AbaBCa", + "B", + 10 + ], + [ + "AbaBCbaB", + "acBcb", + 10 + ], + [ + "AbaBaca", + "acAAABBB", + 13 + ], + [ + "AbaBcCba", + "accBCABAB", + 12 + ], + [ + "AbaC", + "BAAb", + 7 + ], + [ + "AbaC", + "aA", + 6 + ], + [ + "AbaCb", + "B", + 9 + ], + [ + "AbaCbBc", + "ACBAaCAcA", + 11 + ], + [ + "Abaa", + "aAcBb", + 8 + ], + [ + "Abaa", + "cbbAaabCc", + 12 + ], + [ + "AbaaAbab", + "CCaaBc", + 11 + ], + [ + "AbaaAc", + "bAba", + 8 + ], + [ + "AbaaabCBb", + "aa", + 14 + ], + [ + "Abab", + "bbbBb", + 6 + ], + [ + "Abab", + "cab", + 4 + ], + [ + "AbabBBb", + "CaAAc", + 12 + ], + [ + "AbabCC", + "CACcAabA", + 12 + ], + [ + "AbabcCbb", + "AbcCcbB", + 7 + ], + [ + "AbacAa", + "bCAAabcCa", + 10 + ], + [ + "AbacB", + "CBaCBAcBa", + 11 + ], + [ + "AbacBCc", + "B", + 12 + ], + [ + "AbacBbBCC", + "bC", + 14 + ], + [ + "AbacaaCB", + "B", + 14 + ], + [ + "AbacaaaBC", + "AacAa", + 9 + ], + [ + "Abacb", + "AcccbAb", + 8 + ], + [ + "Abb", + "Aba", + 2 + ], + [ + "Abb", + "Ac", + 4 + ], + [ + "Abb", + "BCcba", + 8 + ], + [ + "AbbA", + "BCb", + 6 + ], + [ + "AbbABab", + "baacCBb", + 11 + ], + [ + "AbbACbab", + "ccAcA", + 12 + ], + [ + "AbbAcA", + "CabbA", + 7 + ], + [ + "AbbB", + "b", + 6 + ], + [ + "AbbBbCbAC", + "bCCaBA", + 13 + ], + [ + "AbbBbb", + "BBcAbaAbB", + 11 + ], + [ + "AbbBcaaBa", + "aAAAaCAba", + 13 + ], + [ + "AbbCACaB", + "CbBBAbcB", + 9 + ], + [ + "AbbCB", + "AAC", + 6 + ], + [ + "AbbCBbCA", + "aAa", + 14 + ], + [ + "AbbCCA", + "bBBcbaAcC", + 13 + ], + [ + "AbbCCaBCB", + "AabbCB", + 9 + ], + [ + "AbbCCcAAb", + "ABCbbBCC", + 13 + ], + [ + "AbbCaCCa", + "B", + 15 + ], + [ + "AbbCbBC", + "Cc", + 11 + ], + [ + "AbbCcA", + "BaaCcBac", + 11 + ], + [ + "AbbaBacBC", + "BaCaCBcC", + 10 + ], + [ + "Abbaa", + "aCbBbc", + 8 + ], + [ + "Abbb", + "bBab", + 5 + ], + [ + "Abbbba", + "BbbaA", + 6 + ], + [ + "AbbcBbA", + "cCbCcaC", + 11 + ], + [ + "Abc", + "CBAaABCCc", + 13 + ], + [ + "Abc", + "Cab", + 5 + ], + [ + "Abc", + "ba", + 4 + ], + [ + "Abc", + "cCBCa", + 8 + ], + [ + "AbcAAAa", + "CBcBBAabc", + 11 + ], + [ + "AbcABaa", + "cCcBCb", + 10 + ], + [ + "AbcAcA", + "B", + 11 + ], + [ + "AbcB", + "AbaCBBaA", + 9 + ], + [ + "AbcBAA", + "BAAb", + 8 + ], + [ + "AbcBBaBB", + "CCBACAA", + 13 + ], + [ + "AbcBCcAA", + "abbABCcCa", + 8 + ], + [ + "AbcCACAbB", + "aBcCb", + 10 + ], + [ + "AbcCAacab", + "a", + 16 + ], + [ + "AbcCa", + "cBAaab", + 9 + ], + [ + "AbcCbbc", + "ACccaBbAB", + 10 + ], + [ + "AbcaA", + "cac", + 6 + ], + [ + "AbcaBABac", + "aA", + 14 + ], + [ + "AbcaBbBcA", + "CBbA", + 11 + ], + [ + "AbcaCAAAB", + "ac", + 15 + ], + [ + "AbcacabA", + "ABbaAC", + 10 + ], + [ + "Abcb", + "AbCCcbb", + 6 + ], + [ + "AbcbA", + "b", + 8 + ], + [ + "AbcbABc", + "bCBCabbBb", + 12 + ], + [ + "AbcbB", + "A", + 8 + ], + [ + "AbcbbC", + "bABbBAa", + 10 + ], + [ + "Abcc", + "bAABaA", + 9 + ], + [ + "Abcc", + "cAABAAa", + 11 + ], + [ + "AbccB", + "cA", + 8 + ], + [ + "Abccc", + "bba", + 8 + ], + [ + "Ac", + "ACbAa", + 7 + ], + [ + "Ac", + "AbB", + 4 + ], + [ + "Ac", + "BCB", + 5 + ], + [ + "Ac", + "BCacCBaBb", + 15 + ], + [ + "Ac", + "BaaCB", + 8 + ], + [ + "Ac", + "BacBbABCa", + 15 + ], + [ + "Ac", + "Bacc", + 5 + ], + [ + "Ac", + "BbaBaACcC", + 14 + ], + [ + "Ac", + "BccaAa", + 10 + ], + [ + "Ac", + "CA", + 4 + ], + [ + "Ac", + "CABacA", + 8 + ], + [ + "Ac", + "CABbbCA", + 11 + ], + [ + "Ac", + "CAa", + 4 + ], + [ + "Ac", + "CBCaAcBaB", + 14 + ], + [ + "Ac", + "CCA", + 5 + ], + [ + "Ac", + "CCcbBBc", + 12 + ], + [ + "Ac", + "CbBBBBbBA", + 18 + ], + [ + "Ac", + "Cbba", + 8 + ], + [ + "Ac", + "aCaa", + 6 + ], + [ + "Ac", + "aCbca", + 7 + ], + [ + "Ac", + "aaBC", + 6 + ], + [ + "Ac", + "aaCAa", + 8 + ], + [ + "Ac", + "aaaA", + 7 + ], + [ + "Ac", + "aabca", + 7 + ], + [ + "Ac", + "abcAAaB", + 11 + ], + [ + "Ac", + "acaBBbaAC", + 15 + ], + [ + "Ac", + "bAaa", + 6 + ], + [ + "Ac", + "bCCCCC", + 11 + ], + [ + "Ac", + "baAcB", + 6 + ], + [ + "Ac", + "bc", + 2 + ], + [ + "Ac", + "cB", + 4 + ], + [ + "Ac", + "cBaaaAAAb", + 16 + ], + [ + "Ac", + "cC", + 3 + ], + [ + "Ac", + "cCAcbCA", + 10 + ], + [ + "Ac", + "cCcCAAA", + 12 + ], + [ + "Ac", + "cbAAcc", + 8 + ], + [ + "AcA", + "ABAACCbc", + 12 + ], + [ + "AcA", + "BBBb", + 8 + ], + [ + "AcA", + "CcabCab", + 11 + ], + [ + "AcA", + "acA", + 1 + ], + [ + "AcA", + "bAbCc", + 7 + ], + [ + "AcA", + "bccBB", + 8 + ], + [ + "AcA", + "cCCA", + 5 + ], + [ + "AcAAAb", + "Acba", + 7 + ], + [ + "AcAABAc", + "bCaa", + 11 + ], + [ + "AcAABBc", + "c", + 12 + ], + [ + "AcAACA", + "cCb", + 8 + ], + [ + "AcAACBb", + "AbaA", + 9 + ], + [ + "AcAAbb", + "abBbA", + 9 + ], + [ + "AcAAcBaB", + "caB", + 10 + ], + [ + "AcABCCba", + "Ca", + 12 + ], + [ + "AcABa", + "aAbBBCA", + 9 + ], + [ + "AcAC", + "c", + 6 + ], + [ + "AcACB", + "aBBCbBabC", + 13 + ], + [ + "AcACCBA", + "c", + 12 + ], + [ + "AcACCaACA", + "aCAAAcABC", + 12 + ], + [ + "AcACaA", + "Ac", + 8 + ], + [ + "AcACcC", + "bABBAcC", + 8 + ], + [ + "AcACccA", + "CaacccB", + 8 + ], + [ + "AcAa", + "b", + 8 + ], + [ + "AcAaaCBA", + "abB", + 12 + ], + [ + "AcAac", + "BBCCC", + 9 + ], + [ + "AcAb", + "cCBBcBCAc", + 14 + ], + [ + "AcAbA", + "cCbbBcb", + 11 + ], + [ + "AcAbBabb", + "BBCBa", + 12 + ], + [ + "AcAbBcABC", + "baCcCcb", + 15 + ], + [ + "AcAbCB", + "ccCCaC", + 10 + ], + [ + "AcAba", + "CcBcBcC", + 11 + ], + [ + "AcAbb", + "bAAbc", + 6 + ], + [ + "AcAcB", + "aAcBAbC", + 8 + ], + [ + "AcAcCB", + "bc", + 10 + ], + [ + "AcAcCCCbb", + "BAaBC", + 14 + ], + [ + "AcAcbacA", + "cb", + 12 + ], + [ + "AcB", + "AbCbCa", + 8 + ], + [ + "AcB", + "CCABca", + 8 + ], + [ + "AcB", + "aBA", + 5 + ], + [ + "AcB", + "b", + 5 + ], + [ + "AcB", + "bCB", + 3 + ], + [ + "AcB", + "cBBaB", + 8 + ], + [ + "AcB", + "caBcC", + 7 + ], + [ + "AcB", + "caCCCaA", + 12 + ], + [ + "AcBAAa", + "ac", + 9 + ], + [ + "AcBAbbAA", + "ACCB", + 12 + ], + [ + "AcBB", + "AAAccBcA", + 10 + ], + [ + "AcBB", + "BaccCCACc", + 15 + ], + [ + "AcBB", + "bBCA", + 8 + ], + [ + "AcBB", + "cCAaaBaBb", + 12 + ], + [ + "AcBBAC", + "AaCA", + 8 + ], + [ + "AcBBACA", + "aAA", + 9 + ], + [ + "AcBBACCaC", + "abBcCAC", + 8 + ], + [ + "AcBBaB", + "aC", + 10 + ], + [ + "AcBBbbaBc", + "CC", + 16 + ], + [ + "AcBBbcb", + "ABBAAc", + 8 + ], + [ + "AcBBcabc", + "a", + 14 + ], + [ + "AcBC", + "ACabcCbBB", + 12 + ], + [ + "AcBC", + "AacAcBCcA", + 10 + ], + [ + "AcBC", + "bCbcAbbA", + 13 + ], + [ + "AcBCAcb", + "AB", + 10 + ], + [ + "AcBCCaAbc", + "ca", + 14 + ], + [ + "AcBCCb", + "aCcCAccc", + 11 + ], + [ + "AcBCaccAA", + "cBAcc", + 9 + ], + [ + "AcBCb", + "aBbaBac", + 11 + ], + [ + "AcBCcbCb", + "AAABCa", + 11 + ], + [ + "AcBCcbbaB", + "bBbC", + 14 + ], + [ + "AcBa", + "BBbCBAA", + 10 + ], + [ + "AcBaCCbCa", + "bbBBb", + 14 + ], + [ + "AcBaCCc", + "aaCcca", + 8 + ], + [ + "AcBaacCb", + "BBbbCbcC", + 13 + ], + [ + "AcBbAb", + "BabcbBbc", + 11 + ], + [ + "AcBbAc", + "cbAbC", + 7 + ], + [ + "AcBbaac", + "bA", + 11 + ], + [ + "AcBbbbB", + "ACaa", + 11 + ], + [ + "AcBc", + "abAcbb", + 7 + ], + [ + "AcBcAcA", + "aaCBAaAAa", + 11 + ], + [ + "AcBcBBB", + "a", + 13 + ], + [ + "AcBcCba", + "BCb", + 8 + ], + [ + "AcBca", + "Ab", + 7 + ], + [ + "AcBcbbA", + "ABb", + 8 + ], + [ + "AcBcbbA", + "BB", + 11 + ], + [ + "AcBcbcA", + "B", + 12 + ], + [ + "AcBccbbbC", + "CbBAAbB", + 13 + ], + [ + "AcBcccC", + "b", + 13 + ], + [ + "AcC", + "ACAbc", + 6 + ], + [ + "AcC", + "bBBA", + 8 + ], + [ + "AcC", + "bbCBACbcA", + 14 + ], + [ + "AcC", + "c", + 4 + ], + [ + "AcC", + "cBBa", + 8 + ], + [ + "AcCACC", + "bbAcCCcc", + 8 + ], + [ + "AcCACaCA", + "CBcCCB", + 11 + ], + [ + "AcCAb", + "bCBAACBC", + 12 + ], + [ + "AcCAbA", + "Bac", + 11 + ], + [ + "AcCAbcaBb", + "Cb", + 14 + ], + [ + "AcCAcCCCA", + "AcCC", + 10 + ], + [ + "AcCBA", + "a", + 9 + ], + [ + "AcCBBaBb", + "AC", + 12 + ], + [ + "AcCBba", + "CaaBCAa", + 10 + ], + [ + "AcCCAA", + "BcA", + 8 + ], + [ + "AcCCBcc", + "bbBACCa", + 13 + ], + [ + "AcCCCbb", + "AcaAc", + 9 + ], + [ + "AcCCb", + "bb", + 8 + ], + [ + "AcCCba", + "BC", + 10 + ], + [ + "AcCCcBACB", + "cb", + 15 + ], + [ + "AcCCccCB", + "baaCaAaB", + 12 + ], + [ + "AcCa", + "AAaCcC", + 8 + ], + [ + "AcCaAcccA", + "AaaaBaCBB", + 13 + ], + [ + "AcCaBCACC", + "a", + 16 + ], + [ + "AcCaC", + "CAcC", + 6 + ], + [ + "AcCaa", + "Ccab", + 6 + ], + [ + "AcCabb", + "BbCBa", + 9 + ], + [ + "AcCb", + "A", + 6 + ], + [ + "AcCbA", + "BaCcaC", + 9 + ], + [ + "AcCbA", + "aA", + 7 + ], + [ + "AcCbBb", + "CCAcb", + 7 + ], + [ + "AcCba", + "cBBbCbCc", + 12 + ], + [ + "AcCbac", + "cCBa", + 5 + ], + [ + "AcCbbbc", + "BbBbABCBc", + 12 + ], + [ + "AcCbc", + "ABBaaAc", + 10 + ], + [ + "AcCc", + "BBBAA", + 10 + ], + [ + "AcCc", + "CABBBCaCb", + 13 + ], + [ + "AcCc", + "acCbACCcc", + 11 + ], + [ + "AcCcA", + "AbCbabBc", + 11 + ], + [ + "AcCcABb", + "cCBaAc", + 9 + ], + [ + "AcCcBB", + "AAaCAaA", + 10 + ], + [ + "AcCcabBCB", + "BcA", + 15 + ], + [ + "AcCcb", + "bC", + 8 + ], + [ + "AcCccABB", + "bbCbbCB", + 12 + ], + [ + "AcCccbBBb", + "ACABAa", + 12 + ], + [ + "Aca", + "BaAA", + 6 + ], + [ + "Aca", + "CCBCCB", + 11 + ], + [ + "Aca", + "cA", + 3 + ], + [ + "AcaAAA", + "CcbbaB", + 9 + ], + [ + "AcaABAaCb", + "CcCACC", + 12 + ], + [ + "AcaABCa", + "bacAcA", + 9 + ], + [ + "AcaAcBC", + "ccbAaa", + 10 + ], + [ + "AcaBACCb", + "ACacBaBAb", + 8 + ], + [ + "AcaBAabCb", + "ACACAbaCB", + 9 + ], + [ + "AcaBC", + "ABacC", + 4 + ], + [ + "AcaBCa", + "AbBC", + 6 + ], + [ + "AcaBacc", + "CBB", + 11 + ], + [ + "AcaBcba", + "AbAbCBcC", + 10 + ], + [ + "AcaC", + "Aca", + 2 + ], + [ + "AcaCB", + "C", + 8 + ], + [ + "AcaCBB", + "cbacccC", + 11 + ], + [ + "AcaCBb", + "CCcaBC", + 8 + ], + [ + "AcaCa", + "bCA", + 7 + ], + [ + "AcaCaC", + "BB", + 12 + ], + [ + "AcaCbcC", + "aBBCccaC", + 9 + ], + [ + "AcaCc", + "CaaCBBb", + 10 + ], + [ + "AcaCc", + "aBaCb", + 5 + ], + [ + "AcaCcAc", + "acA", + 8 + ], + [ + "Acaa", + "BACcCA", + 7 + ], + [ + "AcaaA", + "bacbCca", + 10 + ], + [ + "Acaaa", + "ACccca", + 6 + ], + [ + "AcaaaaaBA", + "b", + 17 + ], + [ + "AcaaabbAC", + "AACbc", + 12 + ], + [ + "AcaabBaAc", + "aCAbBBCaA", + 10 + ], + [ + "AcaacaAAB", + "CA", + 15 + ], + [ + "AcaacbaC", + "A", + 14 + ], + [ + "Acab", + "AB", + 5 + ], + [ + "AcabA", + "BCcca", + 8 + ], + [ + "AcabBAcB", + "B", + 14 + ], + [ + "AcabCaab", + "cCCaBB", + 9 + ], + [ + "AcabcC", + "AC", + 8 + ], + [ + "Acabca", + "cCCC", + 9 + ], + [ + "AcacaAbbb", + "abB", + 13 + ], + [ + "AcacaBC", + "bbaCB", + 9 + ], + [ + "AcacaCCCc", + "aBbbcACA", + 14 + ], + [ + "AcaccB", + "aaBc", + 7 + ], + [ + "Acb", + "BcbA", + 4 + ], + [ + "Acb", + "BccCaB", + 9 + ], + [ + "Acb", + "aC", + 4 + ], + [ + "Acb", + "bAccAa", + 8 + ], + [ + "Acb", + "ccAcbaB", + 8 + ], + [ + "AcbA", + "cA", + 4 + ], + [ + "AcbAAcaA", + "Cba", + 11 + ], + [ + "AcbAB", + "cbBbAa", + 8 + ], + [ + "AcbACBAaA", + "cc", + 15 + ], + [ + "AcbB", + "C", + 7 + ], + [ + "AcbBa", + "aAABbACcB", + 13 + ], + [ + "AcbBaCb", + "bCcacBbA", + 12 + ], + [ + "AcbBaba", + "CbbCBaB", + 9 + ], + [ + "AcbBb", + "abBbA", + 5 + ], + [ + "AcbC", + "bbCaA", + 8 + ], + [ + "AcbCAC", + "CcACABBb", + 10 + ], + [ + "AcbCAc", + "aaBCaAbAa", + 12 + ], + [ + "AcbCBcc", + "aA", + 13 + ], + [ + "AcbCaCb", + "ccAABC", + 10 + ], + [ + "AcbCcBCa", + "bbbcAcB", + 11 + ], + [ + "AcbCcbCa", + "CcaABBcCa", + 11 + ], + [ + "Acba", + "aACbbBcc", + 11 + ], + [ + "AcbaCAA", + "bAaBbaca", + 10 + ], + [ + "Acbab", + "acBc", + 6 + ], + [ + "AcbbAcCa", + "cCb", + 12 + ], + [ + "AcbbC", + "B", + 9 + ], + [ + "Acbbb", + "cCbCAACA", + 13 + ], + [ + "AcbbcAB", + "cca", + 9 + ], + [ + "Acbc", + "AbCaCB", + 8 + ], + [ + "Acbc", + "Bac", + 6 + ], + [ + "AcbcBB", + "ABBBB", + 5 + ], + [ + "AcbcBcA", + "AaaBaba", + 11 + ], + [ + "AcbcCbcbA", + "ac", + 15 + ], + [ + "Acc", + "BbBCABBb", + 14 + ], + [ + "Acc", + "aAbBbBca", + 12 + ], + [ + "Acc", + "aa", + 5 + ], + [ + "Acc", + "aaBcC", + 6 + ], + [ + "Acc", + "bCbAaCab", + 13 + ], + [ + "AccA", + "BCBA", + 5 + ], + [ + "AccA", + "aC", + 6 + ], + [ + "AccAB", + "Bcb", + 7 + ], + [ + "AccABcbBC", + "AAcBcAcc", + 9 + ], + [ + "AccACBbA", + "c", + 14 + ], + [ + "AccAbcC", + "cbbB", + 10 + ], + [ + "AccBbab", + "bcAaaaA", + 10 + ], + [ + "AccC", + "BBbca", + 8 + ], + [ + "AccCBBACa", + "b", + 17 + ], + [ + "AccCCCcaa", + "aabC", + 15 + ], + [ + "AccCcAA", + "CCbAaABCA", + 13 + ], + [ + "Acca", + "C", + 7 + ], + [ + "Acca", + "aB", + 7 + ], + [ + "AccaCABA", + "CBBBc", + 13 + ], + [ + "AccaaAbbC", + "BaAB", + 13 + ], + [ + "Accb", + "baBaaCaCa", + 15 + ], + [ + "Accbbbb", + "bA", + 12 + ], + [ + "Accbcc", + "aaAAcb", + 9 + ], + [ + "Accc", + "ABbAB", + 8 + ], + [ + "AcccAC", + "BAAbCacBb", + 13 + ], + [ + "AcccAbbB", + "BaBCa", + 14 + ], + [ + "AcccBAAbC", + "CCbCb", + 13 + ], + [ + "AcccCACac", + "BAbccaC", + 11 + ], + [ + "AcccCabab", + "bBAAaBaA", + 13 + ], + [ + "AcccCb", + "BACacbcC", + 9 + ], + [ + "AcccaCb", + "CBBCcaCB", + 8 + ], + [ + "Acccac", + "acCaAcaCb", + 9 + ], + [ + "B", + "A", + 2 + ], + [ + "B", + "AAABB", + 8 + ], + [ + "B", + "AAAcc", + 10 + ], + [ + "B", + "AABBcC", + 10 + ], + [ + "B", + "AABCBb", + 10 + ], + [ + "B", + "AAC", + 6 + ], + [ + "B", + "AACA", + 8 + ], + [ + "B", + "AACaaaa", + 14 + ], + [ + "B", + "AAcaBa", + 10 + ], + [ + "B", + "AAcacbab", + 15 + ], + [ + "B", + "ABBc", + 6 + ], + [ + "B", + "ABCBcBCB", + 14 + ], + [ + "B", + "ABaAba", + 10 + ], + [ + "B", + "ABaB", + 6 + ], + [ + "B", + "ABaBba", + 10 + ], + [ + "B", + "ABaaCcBa", + 14 + ], + [ + "B", + "ABc", + 4 + ], + [ + "B", + "ACB", + 4 + ], + [ + "B", + "ACCCCCBc", + 14 + ], + [ + "B", + "ACbbC", + 9 + ], + [ + "B", + "ACbbCA", + 11 + ], + [ + "B", + "AaA", + 6 + ], + [ + "B", + "AaACbbaaB", + 16 + ], + [ + "B", + "AaAaCCbaa", + 17 + ], + [ + "B", + "AaBaBcba", + 14 + ], + [ + "B", + "AabcAaa", + 13 + ], + [ + "B", + "AacCacAb", + 15 + ], + [ + "B", + "AaccbBacB", + 16 + ], + [ + "B", + "Ab", + 3 + ], + [ + "B", + "AbBc", + 6 + ], + [ + "B", + "AbaBCcaBa", + 16 + ], + [ + "B", + "Abc", + 5 + ], + [ + "B", + "AcA", + 6 + ], + [ + "B", + "AcBA", + 6 + ], + [ + "B", + "AcBaBbCc", + 14 + ], + [ + "B", + "AcCc", + 8 + ], + [ + "B", + "AcaC", + 8 + ], + [ + "B", + "AccBacc", + 12 + ], + [ + "B", + "B", + 0 + ], + [ + "B", + "BAA", + 4 + ], + [ + "B", + "BBAbCc", + 10 + ], + [ + "B", + "BBAccA", + 10 + ], + [ + "B", + "BBBCb", + 8 + ], + [ + "B", + "BBa", + 4 + ], + [ + "B", + "BBaAcacab", + 16 + ], + [ + "B", + "BBc", + 4 + ], + [ + "B", + "BC", + 2 + ], + [ + "B", + "BCC", + 4 + ], + [ + "B", + "BCCbaBA", + 12 + ], + [ + "B", + "BCbCb", + 8 + ], + [ + "B", + "BCcC", + 6 + ], + [ + "B", + "BCcCccC", + 12 + ], + [ + "B", + "BCcb", + 6 + ], + [ + "B", + "BCcc", + 6 + ], + [ + "B", + "Ba", + 2 + ], + [ + "B", + "BaBCAaCAa", + 16 + ], + [ + "B", + "Baca", + 6 + ], + [ + "B", + "BacbcaCaC", + 16 + ], + [ + "B", + "BbcCCbAbb", + 16 + ], + [ + "B", + "BcACbAAC", + 14 + ], + [ + "B", + "BcACbbbc", + 14 + ], + [ + "B", + "BcabCBbab", + 16 + ], + [ + "B", + "C", + 2 + ], + [ + "B", + "CAAb", + 7 + ], + [ + "B", + "CAAba", + 9 + ], + [ + "B", + "CACcA", + 10 + ], + [ + "B", + "CB", + 2 + ], + [ + "B", + "CBCcAcbb", + 14 + ], + [ + "B", + "CBc", + 4 + ], + [ + "B", + "CBcA", + 6 + ], + [ + "B", + "CBcCC", + 8 + ], + [ + "B", + "CCaaCaac", + 16 + ], + [ + "B", + "CCcBBCb", + 12 + ], + [ + "B", + "Ca", + 4 + ], + [ + "B", + "CaCC", + 8 + ], + [ + "B", + "Caa", + 6 + ], + [ + "B", + "Cab", + 5 + ], + [ + "B", + "Cacbc", + 9 + ], + [ + "B", + "Cb", + 3 + ], + [ + "B", + "Cbc", + 5 + ], + [ + "B", + "CbcaAaACC", + 17 + ], + [ + "B", + "CbccCbca", + 15 + ], + [ + "B", + "Cc", + 4 + ], + [ + "B", + "CcAacCAA", + 16 + ], + [ + "B", + "CcBb", + 6 + ], + [ + "B", + "CcbBb", + 8 + ], + [ + "B", + "Ccc", + 6 + ], + [ + "B", + "a", + 2 + ], + [ + "B", + "aAA", + 6 + ], + [ + "B", + "aAACAb", + 11 + ], + [ + "B", + "aABCB", + 8 + ], + [ + "B", + "aACaCCBbA", + 16 + ], + [ + "B", + "aB", + 2 + ], + [ + "B", + "aBBbc", + 8 + ], + [ + "B", + "aBabc", + 8 + ], + [ + "B", + "aBcbCA", + 10 + ], + [ + "B", + "aBccCCBC", + 14 + ], + [ + "B", + "aC", + 4 + ], + [ + "B", + "aCBBAAc", + 12 + ], + [ + "B", + "aCBcA", + 8 + ], + [ + "B", + "aCCaAabB", + 14 + ], + [ + "B", + "aCCcbbac", + 15 + ], + [ + "B", + "aCa", + 6 + ], + [ + "B", + "aCaBABACa", + 16 + ], + [ + "B", + "aCcbCA", + 11 + ], + [ + "B", + "aaBBac", + 10 + ], + [ + "B", + "aaBCC", + 8 + ], + [ + "B", + "aab", + 5 + ], + [ + "B", + "aabBcbBa", + 14 + ], + [ + "B", + "aacbAB", + 10 + ], + [ + "B", + "abA", + 5 + ], + [ + "B", + "abAAA", + 9 + ], + [ + "B", + "abBBCBBcb", + 16 + ], + [ + "B", + "abC", + 5 + ], + [ + "B", + "abCcacAC", + 15 + ], + [ + "B", + "ac", + 4 + ], + [ + "B", + "acAbAB", + 10 + ], + [ + "B", + "acBcBba", + 12 + ], + [ + "B", + "b", + 1 + ], + [ + "B", + "bA", + 3 + ], + [ + "B", + "bAAbcbb", + 13 + ], + [ + "B", + "bABAacc", + 12 + ], + [ + "B", + "bACA", + 7 + ], + [ + "B", + "bAaAbBbcb", + 16 + ], + [ + "B", + "bAc", + 5 + ], + [ + "B", + "bB", + 2 + ], + [ + "B", + "bC", + 3 + ], + [ + "B", + "bCAbccaCA", + 17 + ], + [ + "B", + "bCCA", + 7 + ], + [ + "B", + "bCabCB", + 10 + ], + [ + "B", + "bCabcCa", + 13 + ], + [ + "B", + "ba", + 3 + ], + [ + "B", + "baba", + 7 + ], + [ + "B", + "babaa", + 9 + ], + [ + "B", + "bb", + 3 + ], + [ + "B", + "bbc", + 5 + ], + [ + "B", + "bbcbCCCb", + 15 + ], + [ + "B", + "bc", + 3 + ], + [ + "B", + "bcCBCacb", + 14 + ], + [ + "B", + "bcaAcbbB", + 14 + ], + [ + "B", + "c", + 2 + ], + [ + "B", + "cABAAb", + 10 + ], + [ + "B", + "cAaaACc", + 14 + ], + [ + "B", + "cAcCA", + 10 + ], + [ + "B", + "cAccC", + 10 + ], + [ + "B", + "cB", + 2 + ], + [ + "B", + "cBBBa", + 8 + ], + [ + "B", + "cBaCCba", + 12 + ], + [ + "B", + "cBbbaAaBC", + 16 + ], + [ + "B", + "cBcCaA", + 10 + ], + [ + "B", + "cC", + 4 + ], + [ + "B", + "cCABB", + 8 + ], + [ + "B", + "cCBAacA", + 12 + ], + [ + "B", + "cCbBBAccB", + 16 + ], + [ + "B", + "cCbcaBaca", + 16 + ], + [ + "B", + "cCcBaC", + 10 + ], + [ + "B", + "cCcbcaCcc", + 17 + ], + [ + "B", + "cabBca", + 10 + ], + [ + "B", + "cabccaAAB", + 16 + ], + [ + "B", + "cb", + 3 + ], + [ + "B", + "cbAACcCCb", + 17 + ], + [ + "B", + "cbAC", + 7 + ], + [ + "B", + "cbBbCC", + 10 + ], + [ + "B", + "cbC", + 5 + ], + [ + "B", + "cbCaba", + 11 + ], + [ + "B", + "cbCbBBaa", + 14 + ], + [ + "B", + "cbaaAAA", + 13 + ], + [ + "B", + "cbaaCAb", + 13 + ], + [ + "B", + "cbbCaccA", + 15 + ], + [ + "B", + "cbbb", + 7 + ], + [ + "B", + "cbcCa", + 9 + ], + [ + "B", + "ccABaB", + 10 + ], + [ + "B", + "ccAc", + 8 + ], + [ + "B", + "ccCbCbc", + 13 + ], + [ + "B", + "ccabaC", + 11 + ], + [ + "B", + "ccb", + 5 + ], + [ + "BA", + "A", + 2 + ], + [ + "BA", + "ABaabAbAc", + 14 + ], + [ + "BA", + "B", + 2 + ], + [ + "BA", + "BBABbCAaB", + 14 + ], + [ + "BA", + "BBcaC", + 7 + ], + [ + "BA", + "BBcacAbcb", + 14 + ], + [ + "BA", + "BCbCbbcAB", + 14 + ], + [ + "BA", + "CACCAaac", + 14 + ], + [ + "BA", + "CAaaacb", + 12 + ], + [ + "BA", + "CBC", + 4 + ], + [ + "BA", + "aACbbcba", + 14 + ], + [ + "BA", + "ab", + 4 + ], + [ + "BA", + "abCAa", + 7 + ], + [ + "BA", + "b", + 3 + ], + [ + "BA", + "bABaAca", + 10 + ], + [ + "BA", + "baCCBbC", + 12 + ], + [ + "BA", + "bbBcB", + 8 + ], + [ + "BA", + "bbbCC", + 9 + ], + [ + "BA", + "bbbaBA", + 8 + ], + [ + "BA", + "bbbbCBb", + 12 + ], + [ + "BA", + "cBABaC", + 8 + ], + [ + "BA", + "cBBbbA", + 8 + ], + [ + "BA", + "cC", + 4 + ], + [ + "BA", + "ccB", + 6 + ], + [ + "BA", + "ccCa", + 7 + ], + [ + "BAA", + "A", + 4 + ], + [ + "BAA", + "abA", + 4 + ], + [ + "BAA", + "acCAc", + 8 + ], + [ + "BAA", + "bB", + 5 + ], + [ + "BAA", + "bbcACCCAB", + 13 + ], + [ + "BAA", + "bcBC", + 7 + ], + [ + "BAA", + "cBaCaBc", + 10 + ], + [ + "BAAA", + "B", + 6 + ], + [ + "BAAA", + "BBCacaC", + 10 + ], + [ + "BAAA", + "bBAc", + 5 + ], + [ + "BAAAAAA", + "CbcbAc", + 12 + ], + [ + "BAAAACb", + "cbcACabBc", + 13 + ], + [ + "BAAAC", + "cbCBcbCC", + 12 + ], + [ + "BAAAaCCAB", + "bcCB", + 12 + ], + [ + "BAAAabC", + "CCaaaAcc", + 11 + ], + [ + "BAAAbcBa", + "aCcAAAcc", + 12 + ], + [ + "BAABC", + "bccab", + 9 + ], + [ + "BAABaC", + "Cbb", + 11 + ], + [ + "BAABabAb", + "ACC", + 14 + ], + [ + "BAAC", + "bB", + 7 + ], + [ + "BAAC", + "ccaBab", + 10 + ], + [ + "BAAC", + "ccbC", + 6 + ], + [ + "BAACAA", + "a", + 11 + ], + [ + "BAACaC", + "Cac", + 7 + ], + [ + "BAAaA", + "a", + 8 + ], + [ + "BAAaACaC", + "bb", + 15 + ], + [ + "BAAaB", + "ccAcbA", + 9 + ], + [ + "BAAaa", + "b", + 9 + ], + [ + "BAAaa", + "cacCaBc", + 11 + ], + [ + "BAAaaac", + "c", + 12 + ], + [ + "BAAaabB", + "aaAAA", + 9 + ], + [ + "BAAaac", + "BCaCcCAB", + 12 + ], + [ + "BAAacA", + "ccBAcCAc", + 11 + ], + [ + "BAAb", + "AA", + 4 + ], + [ + "BAAbAC", + "BbAccCba", + 10 + ], + [ + "BAAbCbbC", + "CCCBBc", + 11 + ], + [ + "BAAbacbC", + "aBAabc", + 9 + ], + [ + "BAAbbACC", + "CCABb", + 11 + ], + [ + "BAAcCBa", + "ACcA", + 9 + ], + [ + "BAAcaBBCa", + "AccB", + 12 + ], + [ + "BAAcac", + "Bb", + 10 + ], + [ + "BAAcc", + "CACbabA", + 11 + ], + [ + "BAB", + "AcbBaaBa", + 11 + ], + [ + "BAB", + "BB", + 2 + ], + [ + "BAB", + "Caa", + 5 + ], + [ + "BAB", + "cc", + 6 + ], + [ + "BABA", + "abbccc", + 11 + ], + [ + "BABA", + "caCca", + 8 + ], + [ + "BABB", + "bBCCBcAcb", + 13 + ], + [ + "BABBAAc", + "caAaa", + 10 + ], + [ + "BABBbCA", + "bAca", + 9 + ], + [ + "BABBc", + "BCCcAcCC", + 11 + ], + [ + "BABCB", + "AB", + 6 + ], + [ + "BABCcBbA", + "CBb", + 10 + ], + [ + "BABa", + "abbbaccAa", + 14 + ], + [ + "BABabAB", + "b", + 12 + ], + [ + "BABacA", + "abcBA", + 8 + ], + [ + "BABb", + "cC", + 8 + ], + [ + "BABbC", + "BaA", + 7 + ], + [ + "BABbb", + "Ccc", + 10 + ], + [ + "BABc", + "aB", + 5 + ], + [ + "BABcACCaC", + "CbbBaCbaC", + 10 + ], + [ + "BABcBA", + "CA", + 9 + ], + [ + "BABcBCaBc", + "CBAaBCC", + 11 + ], + [ + "BABcBcBa", + "bCBACcc", + 11 + ], + [ + "BABcaBB", + "bAaabb", + 7 + ], + [ + "BABcb", + "CcCAaC", + 11 + ], + [ + "BABcbcaa", + "BbbCcAAab", + 11 + ], + [ + "BABccba", + "cCbbbA", + 10 + ], + [ + "BAC", + "BB", + 4 + ], + [ + "BAC", + "BBacAbC", + 8 + ], + [ + "BAC", + "BaacBaC", + 9 + ], + [ + "BAC", + "BbbBaB", + 9 + ], + [ + "BAC", + "CAAaa", + 8 + ], + [ + "BAC", + "CBBbBccbc", + 15 + ], + [ + "BAC", + "b", + 5 + ], + [ + "BAC", + "babAAcA", + 10 + ], + [ + "BACACcCcc", + "cbB", + 16 + ], + [ + "BACB", + "AaCABa", + 7 + ], + [ + "BACBAACba", + "BaA", + 13 + ], + [ + "BACBCAC", + "A", + 12 + ], + [ + "BACBaB", + "Bcbc", + 8 + ], + [ + "BACBbCbB", + "ACaAAaCb", + 12 + ], + [ + "BACC", + "ab", + 7 + ], + [ + "BACCBcbaa", + "ab", + 15 + ], + [ + "BACCCAaCA", + "bCCcBb", + 12 + ], + [ + "BACCbABA", + "AAAAcAB", + 10 + ], + [ + "BACCbAac", + "AcBCaacB", + 10 + ], + [ + "BACCc", + "BbAAcA", + 7 + ], + [ + "BACCc", + "aBbbBBCa", + 12 + ], + [ + "BACaC", + "CB", + 8 + ], + [ + "BACab", + "bCA", + 6 + ], + [ + "BACb", + "AcBC", + 6 + ], + [ + "BACbAbCbC", + "BbC", + 12 + ], + [ + "BACbbaaAc", + "ACabC", + 11 + ], + [ + "BACcBbcCb", + "AcbB", + 11 + ], + [ + "BACcbBbc", + "AC", + 12 + ], + [ + "BACccabb", + "bAcAAa", + 10 + ], + [ + "BACcccA", + "aacC", + 10 + ], + [ + "BAa", + "AC", + 4 + ], + [ + "BAa", + "AbCBcA", + 9 + ], + [ + "BAa", + "CabbAabb", + 11 + ], + [ + "BAa", + "cBaAa", + 4 + ], + [ + "BAaA", + "BCB", + 6 + ], + [ + "BAaABbB", + "ABabABcbC", + 9 + ], + [ + "BAaAbCc", + "acb", + 10 + ], + [ + "BAaAcCb", + "AbbC", + 10 + ], + [ + "BAaAcbB", + "Aa", + 10 + ], + [ + "BAaBBaAb", + "bBaBcaAAa", + 9 + ], + [ + "BAaBaB", + "A", + 10 + ], + [ + "BAaBbCc", + "cacBaAcaB", + 13 + ], + [ + "BAaBbabc", + "A", + 14 + ], + [ + "BAaBcCaaa", + "ab", + 15 + ], + [ + "BAaBcCb", + "aCAA", + 11 + ], + [ + "BAaCB", + "BBb", + 7 + ], + [ + "BAaCB", + "aABACA", + 7 + ], + [ + "BAaCaA", + "acB", + 9 + ], + [ + "BAaCabCCa", + "b", + 16 + ], + [ + "BAaCbAC", + "bA", + 10 + ], + [ + "BAaCbB", + "aCcbbAAA", + 13 + ], + [ + "BAaCcc", + "bc", + 9 + ], + [ + "BAaaACaA", + "Ccbcaa", + 12 + ], + [ + "BAaaCCb", + "bCBC", + 11 + ], + [ + "BAab", + "c", + 8 + ], + [ + "BAab", + "ccaba", + 6 + ], + [ + "BAabAbBB", + "ABaBaaBa", + 10 + ], + [ + "BAabCA", + "Cb", + 10 + ], + [ + "BAabCCA", + "CCbBcb", + 11 + ], + [ + "BAac", + "bBbcaca", + 8 + ], + [ + "BAacBb", + "cABAca", + 9 + ], + [ + "BAacbBbCb", + "bBAca", + 13 + ], + [ + "BAacbaBC", + "ABCbcaCAc", + 12 + ], + [ + "BAaccAba", + "BAbBbCA", + 11 + ], + [ + "BAb", + "Aa", + 4 + ], + [ + "BAb", + "AbaccbCbC", + 14 + ], + [ + "BAb", + "BaCa", + 5 + ], + [ + "BAb", + "CCaBA", + 8 + ], + [ + "BAb", + "CbCb", + 5 + ], + [ + "BAb", + "caAAC", + 8 + ], + [ + "BAb", + "ccCAAAABC", + 15 + ], + [ + "BAbABaBbC", + "CAAcAb", + 11 + ], + [ + "BAbACcA", + "aBaaCcc", + 8 + ], + [ + "BAbAa", + "ABbCbabac", + 11 + ], + [ + "BAbAa", + "c", + 10 + ], + [ + "BAbAc", + "cBc", + 7 + ], + [ + "BAbAcABa", + "ac", + 13 + ], + [ + "BAbAcbB", + "aCAcBB", + 6 + ], + [ + "BAbBA", + "BcaCBcaBa", + 11 + ], + [ + "BAbBAB", + "ABBCCb", + 8 + ], + [ + "BAbBBaB", + "abaA", + 9 + ], + [ + "BAbBCc", + "aaAcAcAAC", + 14 + ], + [ + "BAbBc", + "ABcAAABb", + 10 + ], + [ + "BAbCCbBC", + "bc", + 13 + ], + [ + "BAbCbBacB", + "acBca", + 12 + ], + [ + "BAbCc", + "BBbcBAab", + 11 + ], + [ + "BAbCcB", + "CbacAaaa", + 14 + ], + [ + "BAbCcBB", + "ccaBBcACC", + 14 + ], + [ + "BAba", + "Bc", + 6 + ], + [ + "BAbaBCAB", + "bbCbBa", + 11 + ], + [ + "BAbaBbBc", + "baAC", + 11 + ], + [ + "BAbaCc", + "C", + 10 + ], + [ + "BAbabca", + "cBabaCb", + 8 + ], + [ + "BAbacCaa", + "CCa", + 11 + ], + [ + "BAbb", + "baBaBaB", + 9 + ], + [ + "BAbbBAA", + "ACbcccc", + 12 + ], + [ + "BAbc", + "B", + 6 + ], + [ + "BAbc", + "bABCB", + 5 + ], + [ + "BAbc", + "bcBAb", + 6 + ], + [ + "BAbcAcA", + "ccA", + 8 + ], + [ + "BAbcaBab", + "CaACACbcB", + 13 + ], + [ + "BAbccAcB", + "BA", + 12 + ], + [ + "BAbccaBA", + "CCCcaa", + 10 + ], + [ + "BAc", + "AAAccAa", + 10 + ], + [ + "BAc", + "Bbc", + 2 + ], + [ + "BAc", + "ba", + 4 + ], + [ + "BAcA", + "Ac", + 4 + ], + [ + "BAcAA", + "acbCAA", + 7 + ], + [ + "BAcAACc", + "accA", + 9 + ], + [ + "BAcAAb", + "AbC", + 10 + ], + [ + "BAcAB", + "aAacCcbac", + 13 + ], + [ + "BAcACCb", + "cccBC", + 10 + ], + [ + "BAcACcBA", + "BCAbccA", + 7 + ], + [ + "BAcAcC", + "aAcBb", + 8 + ], + [ + "BAcBa", + "CCAbBCc", + 10 + ], + [ + "BAcBcba", + "aaa", + 11 + ], + [ + "BAcCBCbaA", + "bCb", + 13 + ], + [ + "BAcCC", + "ACCaC", + 5 + ], + [ + "BAcCCBAbA", + "b", + 16 + ], + [ + "BAcCaB", + "cCBBCaa", + 10 + ], + [ + "BAcCbC", + "CAB", + 9 + ], + [ + "BAcCbaC", + "CCBBaCabB", + 14 + ], + [ + "BAcCbc", + "Cb", + 8 + ], + [ + "BAcCcAACa", + "aacaCaA", + 11 + ], + [ + "BAcaBBBc", + "a", + 14 + ], + [ + "BAcaBc", + "CAbaa", + 8 + ], + [ + "BAcaC", + "cAcaCA", + 4 + ], + [ + "BAcaab", + "ACbA", + 8 + ], + [ + "BAcab", + "BaCbca", + 7 + ], + [ + "BAcbA", + "AbA", + 4 + ], + [ + "BAcbA", + "bACBCbbCA", + 10 + ], + [ + "BAcbAcCB", + "ac", + 13 + ], + [ + "BAcbBCC", + "bBaba", + 11 + ], + [ + "BAcbCC", + "c", + 10 + ], + [ + "BAcbCc", + "B", + 10 + ], + [ + "BAcbabcB", + "aAa", + 12 + ], + [ + "BAcbbba", + "Cb", + 11 + ], + [ + "BAcbcABbA", + "baABcBCa", + 10 + ], + [ + "BAccAAA", + "AaaC", + 10 + ], + [ + "BAccAAca", + "BBCbbCcab", + 11 + ], + [ + "BAccAbCB", + "Cba", + 13 + ], + [ + "BAccCAb", + "cCBcCcac", + 11 + ], + [ + "BAccCAbC", + "BCabCBA", + 11 + ], + [ + "BAccCCcA", + "CbbBaCB", + 14 + ], + [ + "BAccCcCB", + "bcCAB", + 9 + ], + [ + "BAcca", + "cBcCBBcbC", + 13 + ], + [ + "BAccaAaC", + "cbBcAaA", + 10 + ], + [ + "BAcccCbb", + "Bb", + 12 + ], + [ + "BB", + "A", + 4 + ], + [ + "BB", + "AACBAacBB", + 14 + ], + [ + "BB", + "ABaA", + 6 + ], + [ + "BB", + "ACbbCcc", + 12 + ], + [ + "BB", + "AbAABC", + 9 + ], + [ + "BB", + "AbbbBBa", + 10 + ], + [ + "BB", + "BC", + 2 + ], + [ + "BB", + "Ba", + 2 + ], + [ + "BB", + "BbcAaACB", + 12 + ], + [ + "BB", + "CAcaACbBb", + 15 + ], + [ + "BB", + "CBabcc", + 9 + ], + [ + "BB", + "CaCBb", + 7 + ], + [ + "BB", + "CaaAAaAAc", + 18 + ], + [ + "BB", + "Cab", + 5 + ], + [ + "BB", + "Cb", + 3 + ], + [ + "BB", + "CbAAC", + 9 + ], + [ + "BB", + "CbcbCcBc", + 13 + ], + [ + "BB", + "Ccccc", + 10 + ], + [ + "BB", + "a", + 4 + ], + [ + "BB", + "aAAbcc", + 11 + ], + [ + "BB", + "aACBABa", + 10 + ], + [ + "BB", + "aACbBCaac", + 15 + ], + [ + "BB", + "aAcCCb", + 11 + ], + [ + "BB", + "aCACcBC", + 12 + ], + [ + "BB", + "aCa", + 6 + ], + [ + "BB", + "aa", + 4 + ], + [ + "BB", + "bAABCCabC", + 15 + ], + [ + "BB", + "bABBCb", + 8 + ], + [ + "BB", + "bBacaAb", + 11 + ], + [ + "BB", + "bc", + 3 + ], + [ + "BB", + "cBBcCBaAa", + 14 + ], + [ + "BB", + "cCaAaBc", + 12 + ], + [ + "BB", + "cCb", + 5 + ], + [ + "BB", + "cCc", + 6 + ], + [ + "BB", + "caBcCA", + 10 + ], + [ + "BB", + "cac", + 6 + ], + [ + "BB", + "cbb", + 4 + ], + [ + "BB", + "ccaC", + 8 + ], + [ + "BBA", + "BB", + 2 + ], + [ + "BBA", + "BCCaaAb", + 10 + ], + [ + "BBA", + "Bb", + 3 + ], + [ + "BBA", + "Bba", + 2 + ], + [ + "BBA", + "CBbBab", + 7 + ], + [ + "BBA", + "aaBbAc", + 7 + ], + [ + "BBA", + "ab", + 5 + ], + [ + "BBA", + "bAAaBCbA", + 11 + ], + [ + "BBA", + "cbcBbC", + 9 + ], + [ + "BBAACb", + "BBaBbb", + 5 + ], + [ + "BBAAb", + "abaBbac", + 10 + ], + [ + "BBAAbbCc", + "a", + 15 + ], + [ + "BBAAcAb", + "cCBCaBCA", + 12 + ], + [ + "BBAAcbba", + "aCACbcCc", + 13 + ], + [ + "BBABA", + "bbccbbb", + 11 + ], + [ + "BBABACCCB", + "c", + 17 + ], + [ + "BBABBAca", + "aCCAAcCA", + 13 + ], + [ + "BBABBaBA", + "CaAaaa", + 11 + ], + [ + "BBABBaaBB", + "CccbccAc", + 16 + ], + [ + "BBABa", + "b", + 9 + ], + [ + "BBABcC", + "aCAA", + 10 + ], + [ + "BBABccb", + "C", + 13 + ], + [ + "BBAC", + "bBCAcBaC", + 9 + ], + [ + "BBACB", + "bAb", + 6 + ], + [ + "BBACC", + "CBccc", + 6 + ], + [ + "BBACC", + "aCBBBB", + 10 + ], + [ + "BBACaBC", + "C", + 12 + ], + [ + "BBACcCbBa", + "CCCcCC", + 12 + ], + [ + "BBAbA", + "AbCaCcB", + 12 + ], + [ + "BBAbCcacC", + "aBaacBcb", + 11 + ], + [ + "BBAba", + "BCbBcB", + 9 + ], + [ + "BBAbcB", + "BBc", + 6 + ], + [ + "BBAbcBBaA", + "bCcAB", + 13 + ], + [ + "BBAbcC", + "BacA", + 7 + ], + [ + "BBAcA", + "bBcaAacbb", + 11 + ], + [ + "BBAcC", + "cC", + 6 + ], + [ + "BBB", + "BaBbB", + 4 + ], + [ + "BBB", + "Bbcbc", + 6 + ], + [ + "BBB", + "CC", + 6 + ], + [ + "BBB", + "CCCAbc", + 11 + ], + [ + "BBB", + "CcbcBc", + 9 + ], + [ + "BBB", + "aaAbb", + 8 + ], + [ + "BBBAAA", + "AA", + 8 + ], + [ + "BBBAAAcB", + "BAcAcCCA", + 11 + ], + [ + "BBBACc", + "AaBCBb", + 10 + ], + [ + "BBBAbAaAB", + "aAcBABA", + 13 + ], + [ + "BBBAccBbC", + "ccbCbAb", + 14 + ], + [ + "BBBB", + "baABcbb", + 9 + ], + [ + "BBBBCCacA", + "bbCCc", + 10 + ], + [ + "BBBBcCA", + "bBAabcB", + 10 + ], + [ + "BBBBccCCC", + "C", + 16 + ], + [ + "BBBCABbb", + "cAAaAB", + 12 + ], + [ + "BBBCab", + "abBACbBc", + 10 + ], + [ + "BBBa", + "CCabbCcaB", + 14 + ], + [ + "BBBa", + "cAa", + 6 + ], + [ + "BBBaCA", + "AAbbaaACB", + 12 + ], + [ + "BBBaaBb", + "cBcaac", + 8 + ], + [ + "BBBab", + "bAa", + 7 + ], + [ + "BBBac", + "aaCcCBcAB", + 15 + ], + [ + "BBBb", + "B", + 6 + ], + [ + "BBBbCCb", + "BbBaCc", + 6 + ], + [ + "BBBba", + "BCaC", + 8 + ], + [ + "BBBbcBcCA", + "BbBB", + 11 + ], + [ + "BBBbccc", + "A", + 14 + ], + [ + "BBBc", + "cCAba", + 9 + ], + [ + "BBBcAB", + "AbCAAbc", + 10 + ], + [ + "BBBcBAa", + "AbBCCa", + 8 + ], + [ + "BBBcBabbB", + "aCC", + 16 + ], + [ + "BBBcbBA", + "AbACCCbCb", + 14 + ], + [ + "BBBcc", + "CCbbabCb", + 12 + ], + [ + "BBBccBaaB", + "BcCB", + 11 + ], + [ + "BBC", + "CaAAAaCbB", + 16 + ], + [ + "BBC", + "Cbcbcc", + 9 + ], + [ + "BBC", + "abBBacA", + 9 + ], + [ + "BBC", + "b", + 5 + ], + [ + "BBC", + "bCBAA", + 7 + ], + [ + "BBC", + "bcCaAbb", + 11 + ], + [ + "BBC", + "cba", + 5 + ], + [ + "BBCA", + "BAcCC", + 6 + ], + [ + "BBCAbbbc", + "BAa", + 12 + ], + [ + "BBCAcb", + "Ca", + 9 + ], + [ + "BBCBb", + "aac", + 9 + ], + [ + "BBCBbc", + "CaaBB", + 9 + ], + [ + "BBCBcaBb", + "ccCcCbBC", + 11 + ], + [ + "BBCBcb", + "CBcCBcacC", + 10 + ], + [ + "BBCC", + "C", + 6 + ], + [ + "BBCCBC", + "aCbbA", + 9 + ], + [ + "BBCCBab", + "cBCaaC", + 8 + ], + [ + "BBCCCbaCB", + "AAA", + 17 + ], + [ + "BBCCaBbB", + "BaBAcCbC", + 11 + ], + [ + "BBCCccBCB", + "bCaaCA", + 13 + ], + [ + "BBCa", + "aB", + 6 + ], + [ + "BBCaa", + "AccACcAAC", + 14 + ], + [ + "BBCabCCBB", + "BcAcCaCC", + 12 + ], + [ + "BBCbB", + "BBb", + 4 + ], + [ + "BBCbB", + "CB", + 6 + ], + [ + "BBCbB", + "caABAb", + 10 + ], + [ + "BBCbc", + "BAAbcaaBc", + 11 + ], + [ + "BBCc", + "BabAb", + 7 + ], + [ + "BBCc", + "cbabab", + 10 + ], + [ + "BBCcbACcB", + "Ab", + 15 + ], + [ + "BBCccCAba", + "aCcCCBAb", + 9 + ], + [ + "BBa", + "AcBcBAb", + 9 + ], + [ + "BBa", + "Ccb", + 6 + ], + [ + "BBa", + "aCCcbCAc", + 14 + ], + [ + "BBa", + "bBaCBa", + 6 + ], + [ + "BBa", + "cbAcBBaA", + 10 + ], + [ + "BBaA", + "bAAaBAAAB", + 12 + ], + [ + "BBaAAccbb", + "CABB", + 14 + ], + [ + "BBaACBaB", + "cbcC", + 13 + ], + [ + "BBaAab", + "BCB", + 9 + ], + [ + "BBaAcAAcb", + "cbCBBCAcb", + 11 + ], + [ + "BBaAcB", + "ACbAcb", + 7 + ], + [ + "BBaBbcB", + "C", + 13 + ], + [ + "BBaCB", + "cC", + 8 + ], + [ + "BBaCCA", + "ABAcc", + 7 + ], + [ + "BBaCccb", + "Cbcbb", + 9 + ], + [ + "BBaa", + "ba", + 5 + ], + [ + "BBaaCCBA", + "AbCbC", + 12 + ], + [ + "BBaaCca", + "aaBBcbAB", + 13 + ], + [ + "BBaaa", + "B", + 8 + ], + [ + "BBaab", + "bbAcbB", + 7 + ], + [ + "BBaabcA", + "BACBAC", + 10 + ], + [ + "BBaacbcaB", + "Abacab", + 10 + ], + [ + "BBaacc", + "C", + 11 + ], + [ + "BBabBa", + "BbBBcAACB", + 13 + ], + [ + "BBabcBab", + "abB", + 10 + ], + [ + "BBabcbb", + "BbbCbA", + 6 + ], + [ + "BBac", + "cBAB", + 5 + ], + [ + "BBacAcaAa", + "Bba", + 13 + ], + [ + "BBacCaBBa", + "aa", + 14 + ], + [ + "BBacCc", + "bcaBA", + 9 + ], + [ + "BBacaABc", + "Cbbaac", + 10 + ], + [ + "BBacb", + "AbbaCBCb", + 9 + ], + [ + "BBacb", + "abCACCBBA", + 14 + ], + [ + "BBb", + "BAcaAaca", + 14 + ], + [ + "BBb", + "BBa", + 2 + ], + [ + "BBb", + "CAcBCAAc", + 14 + ], + [ + "BBb", + "aBACcCCC", + 14 + ], + [ + "BBb", + "acbCc", + 8 + ], + [ + "BBbA", + "ca", + 7 + ], + [ + "BBbAACb", + "ACCbb", + 10 + ], + [ + "BBbABAaAB", + "cAbaCba", + 13 + ], + [ + "BBbABbac", + "cAB", + 12 + ], + [ + "BBbAabbCA", + "A", + 16 + ], + [ + "BBbAbcB", + "AcAAcbABa", + 12 + ], + [ + "BBbAcaAB", + "cBB", + 12 + ], + [ + "BBbAcc", + "bBAb", + 7 + ], + [ + "BBbB", + "ccABABc", + 10 + ], + [ + "BBbBB", + "a", + 10 + ], + [ + "BBbBBbba", + "aACbb", + 12 + ], + [ + "BBbBBcacc", + "AcAa", + 15 + ], + [ + "BBbBCbBc", + "BbABC", + 9 + ], + [ + "BBbBaa", + "bbBbbbaAb", + 9 + ], + [ + "BBbCCCCbc", + "ccaAB", + 15 + ], + [ + "BBbCCcbAc", + "bABcac", + 11 + ], + [ + "BBbCbcb", + "Ab", + 12 + ], + [ + "BBba", + "a", + 6 + ], + [ + "BBbaBc", + "ac", + 8 + ], + [ + "BBbab", + "AcAB", + 8 + ], + [ + "BBbabb", + "CCbAa", + 9 + ], + [ + "BBbabbab", + "bCBBbaA", + 9 + ], + [ + "BBbb", + "BA", + 6 + ], + [ + "BBbbACc", + "A", + 12 + ], + [ + "BBbbCCBB", + "AaCcBAAA", + 15 + ], + [ + "BBbcABBbC", + "AaC", + 14 + ], + [ + "BBbcB", + "ACbA", + 8 + ], + [ + "BBbcCac", + "cbb", + 11 + ], + [ + "BBbccCCBB", + "BbaBcb", + 12 + ], + [ + "BBc", + "ABCbAA", + 9 + ], + [ + "BBc", + "BbbABAACA", + 13 + ], + [ + "BBc", + "BcccAbBaC", + 13 + ], + [ + "BBc", + "aBaCccA", + 10 + ], + [ + "BBc", + "aC", + 5 + ], + [ + "BBc", + "aCacBbCCa", + 14 + ], + [ + "BBcAAA", + "Acbc", + 10 + ], + [ + "BBcAAac", + "acCcAbc", + 9 + ], + [ + "BBcABAA", + "BbBaABaC", + 7 + ], + [ + "BBcB", + "AAacBC", + 8 + ], + [ + "BBcB", + "aAaabB", + 10 + ], + [ + "BBcB", + "acb", + 5 + ], + [ + "BBcB", + "bAcAAbac", + 12 + ], + [ + "BBcBACa", + "CBACA", + 6 + ], + [ + "BBcBCB", + "c", + 10 + ], + [ + "BBcBbCBA", + "cBaaAca", + 12 + ], + [ + "BBcBbcA", + "bBbca", + 6 + ], + [ + "BBcC", + "AcAcAcCc", + 12 + ], + [ + "BBcCBCac", + "ababc", + 12 + ], + [ + "BBcCC", + "ccB", + 7 + ], + [ + "BBcCCabAA", + "BCC", + 12 + ], + [ + "BBcCCcab", + "bCcc", + 10 + ], + [ + "BBcCa", + "BBAA", + 5 + ], + [ + "BBcCcb", + "BCb", + 6 + ], + [ + "BBca", + "b", + 7 + ], + [ + "BBcaA", + "AaCCAbCCC", + 15 + ], + [ + "BBcaA", + "b", + 9 + ], + [ + "BBcaACbB", + "AbCb", + 11 + ], + [ + "BBcaC", + "CCccCCCC", + 12 + ], + [ + "BBcaa", + "aBaa", + 4 + ], + [ + "BBcaa", + "bAAAC", + 8 + ], + [ + "BBcaa", + "ccCCcABA", + 12 + ], + [ + "BBcaaCBB", + "BbCcbC", + 10 + ], + [ + "BBcab", + "aaBc", + 8 + ], + [ + "BBcbA", + "BcBabbA", + 6 + ], + [ + "BBcbaA", + "caBbCcaa", + 9 + ], + [ + "BBcbbaB", + "ccCbbAccB", + 10 + ], + [ + "BBcbbabC", + "BB", + 12 + ], + [ + "BBcc", + "AcbAAB", + 11 + ], + [ + "BBcc", + "CCcBccBbC", + 12 + ], + [ + "BBccAb", + "aCACbAC", + 11 + ], + [ + "BBccB", + "BcB", + 4 + ], + [ + "BBccc", + "BBAbCAcbB", + 11 + ], + [ + "BBcccCAAB", + "ABABBAca", + 14 + ], + [ + "BC", + "A", + 4 + ], + [ + "BC", + "AAcba", + 9 + ], + [ + "BC", + "AC", + 2 + ], + [ + "BC", + "ACBACCA", + 10 + ], + [ + "BC", + "AaA", + 6 + ], + [ + "BC", + "AaCABABAb", + 16 + ], + [ + "BC", + "Ac", + 3 + ], + [ + "BC", + "AcCCcc", + 10 + ], + [ + "BC", + "B", + 2 + ], + [ + "BC", + "BAbC", + 4 + ], + [ + "BC", + "BC", + 0 + ], + [ + "BC", + "BCCCC", + 6 + ], + [ + "BC", + "BbAaaBAbb", + 16 + ], + [ + "BC", + "BbB", + 4 + ], + [ + "BC", + "BcB", + 3 + ], + [ + "BC", + "C", + 2 + ], + [ + "BC", + "CA", + 4 + ], + [ + "BC", + "CaaaCAcaC", + 16 + ], + [ + "BC", + "CbCC", + 5 + ], + [ + "BC", + "CcC", + 4 + ], + [ + "BC", + "CcCCCab", + 12 + ], + [ + "BC", + "CcaAbbbcb", + 16 + ], + [ + "BC", + "CccAb", + 9 + ], + [ + "BC", + "aAA", + 6 + ], + [ + "BC", + "aAbbcbac", + 14 + ], + [ + "BC", + "aCbAaAbBB", + 16 + ], + [ + "BC", + "abbba", + 9 + ], + [ + "BC", + "acAACAC", + 12 + ], + [ + "BC", + "acbCA", + 7 + ], + [ + "BC", + "acccbAAB", + 15 + ], + [ + "BC", + "bAABa", + 8 + ], + [ + "BC", + "bBBAcBbCC", + 14 + ], + [ + "BC", + "bC", + 1 + ], + [ + "BC", + "bCaCaCaa", + 13 + ], + [ + "BC", + "bCbaCa", + 9 + ], + [ + "BC", + "bCbaaaAAC", + 15 + ], + [ + "BC", + "babCAbca", + 13 + ], + [ + "BC", + "babbBBaB", + 14 + ], + [ + "BC", + "bbCA", + 5 + ], + [ + "BC", + "c", + 3 + ], + [ + "BC", + "cAAB", + 8 + ], + [ + "BC", + "cABCBCAB", + 12 + ], + [ + "BC", + "cBaACA", + 8 + ], + [ + "BC", + "cBbaAcB", + 11 + ], + [ + "BC", + "cCCBb", + 8 + ], + [ + "BC", + "cb", + 4 + ], + [ + "BC", + "cbBBB", + 8 + ], + [ + "BC", + "cba", + 5 + ], + [ + "BC", + "cbaB", + 7 + ], + [ + "BC", + "cbaCbBAC", + 12 + ], + [ + "BC", + "cbbCabA", + 11 + ], + [ + "BC", + "ccAACb", + 10 + ], + [ + "BC", + "ccccbb", + 11 + ], + [ + "BCA", + "A", + 4 + ], + [ + "BCA", + "AbcCbCaA", + 11 + ], + [ + "BCA", + "abccbBCC", + 12 + ], + [ + "BCAABABCB", + "abBbBaB", + 11 + ], + [ + "BCAABc", + "bBACcBa", + 9 + ], + [ + "BCAAbBc", + "AaABC", + 8 + ], + [ + "BCAAbbbc", + "A", + 14 + ], + [ + "BCAAcbb", + "CAaCAcBbC", + 9 + ], + [ + "BCAAccAa", + "Aaaa", + 10 + ], + [ + "BCABBA", + "AbBba", + 8 + ], + [ + "BCABBBAa", + "bCAbBA", + 6 + ], + [ + "BCABa", + "b", + 9 + ], + [ + "BCABcB", + "bcAAbCb", + 7 + ], + [ + "BCABcCCc", + "CACcbBAc", + 10 + ], + [ + "BCABccC", + "B", + 12 + ], + [ + "BCABccaB", + "cAaCbBCc", + 13 + ], + [ + "BCAC", + "CAcCB", + 6 + ], + [ + "BCACBaACB", + "aaCaC", + 11 + ], + [ + "BCACBaba", + "BbAaAbc", + 9 + ], + [ + "BCACBb", + "aCbCA", + 8 + ], + [ + "BCACb", + "CAABCa", + 8 + ], + [ + "BCACcABBB", + "C", + 16 + ], + [ + "BCACcCAC", + "aBcAaaB", + 12 + ], + [ + "BCACcb", + "AC", + 8 + ], + [ + "BCAa", + "A", + 6 + ], + [ + "BCAa", + "Cc", + 6 + ], + [ + "BCAacBCB", + "CaCC", + 9 + ], + [ + "BCAbBAbAc", + "aBcbB", + 13 + ], + [ + "BCAbBaCB", + "caCba", + 11 + ], + [ + "BCAbCB", + "ccBcBCC", + 10 + ], + [ + "BCAbaCC", + "aB", + 12 + ], + [ + "BCAbbAcBA", + "A", + 16 + ], + [ + "BCAbbBA", + "BBAAAbac", + 10 + ], + [ + "BCAbc", + "Cb", + 6 + ], + [ + "BCAbcaBCC", + "ccBacBbA", + 13 + ], + [ + "BCAbccbb", + "bAcaCCbAB", + 12 + ], + [ + "BCAc", + "BaBb", + 6 + ], + [ + "BCAcC", + "Ccc", + 5 + ], + [ + "BCAcCabcc", + "CBC", + 14 + ], + [ + "BCAcabbBc", + "bcbC", + 12 + ], + [ + "BCB", + "caa", + 6 + ], + [ + "BCB", + "ccB", + 3 + ], + [ + "BCBA", + "B", + 6 + ], + [ + "BCBA", + "bAB", + 5 + ], + [ + "BCBAACcc", + "aBB", + 14 + ], + [ + "BCBACbAbA", + "ccABAa", + 11 + ], + [ + "BCBACbCb", + "cBA", + 11 + ], + [ + "BCBAaBcA", + "baC", + 12 + ], + [ + "BCBAabB", + "Bcb", + 9 + ], + [ + "BCBAb", + "CccbcCcBb", + 13 + ], + [ + "BCBAcbbC", + "AccaABA", + 13 + ], + [ + "BCBB", + "A", + 8 + ], + [ + "BCBBA", + "ACAC", + 8 + ], + [ + "BCBBACa", + "AbbAA", + 9 + ], + [ + "BCBBbCbC", + "Ccb", + 11 + ], + [ + "BCBBbab", + "cCAccAbb", + 11 + ], + [ + "BCBBcCa", + "BCCCBbA", + 9 + ], + [ + "BCBBcaCBA", + "CbBCCBacA", + 10 + ], + [ + "BCBBccB", + "B", + 12 + ], + [ + "BCBC", + "CbaBa", + 7 + ], + [ + "BCBC", + "cabAcCaCc", + 13 + ], + [ + "BCBCAaB", + "CAcb", + 9 + ], + [ + "BCBCBaAA", + "b", + 15 + ], + [ + "BCBCBbbc", + "CBBA", + 10 + ], + [ + "BCBCbbBC", + "CACcaACaB", + 14 + ], + [ + "BCBCc", + "aBAA", + 8 + ], + [ + "BCBaACb", + "aCB", + 9 + ], + [ + "BCBaAcb", + "AaC", + 11 + ], + [ + "BCBaC", + "BC", + 6 + ], + [ + "BCBaCCabc", + "aAcbC", + 12 + ], + [ + "BCBb", + "AaaBabaAa", + 14 + ], + [ + "BCBbAABB", + "A", + 14 + ], + [ + "BCBbBCaA", + "B", + 14 + ], + [ + "BCBbc", + "AbBba", + 6 + ], + [ + "BCBbcbBC", + "ca", + 14 + ], + [ + "BCBcB", + "bbC", + 7 + ], + [ + "BCBcaACa", + "bbCaabC", + 10 + ], + [ + "BCBcabB", + "aaBaaaAac", + 14 + ], + [ + "BCC", + "AabbC", + 7 + ], + [ + "BCC", + "AbbBBa", + 10 + ], + [ + "BCC", + "CCBcABb", + 11 + ], + [ + "BCCA", + "bcbbc", + 8 + ], + [ + "BCCA", + "cBBbacAc", + 11 + ], + [ + "BCCAAbbC", + "ccCB", + 12 + ], + [ + "BCCABc", + "c", + 10 + ], + [ + "BCCAaba", + "CAbB", + 8 + ], + [ + "BCCB", + "cBca", + 7 + ], + [ + "BCCBCC", + "ACCBaa", + 6 + ], + [ + "BCCBbcAAA", + "aaaCCB", + 16 + ], + [ + "BCCCAbA", + "CabCcbc", + 10 + ], + [ + "BCCCCAB", + "BC", + 10 + ], + [ + "BCCCCBAB", + "cABCcc", + 13 + ], + [ + "BCCCb", + "cCCAc", + 6 + ], + [ + "BCCaAcbB", + "Cabccaa", + 12 + ], + [ + "BCCaB", + "cAaAcAa", + 12 + ], + [ + "BCCaBABCc", + "a", + 16 + ], + [ + "BCCaCBCAA", + "cBbCaccaA", + 9 + ], + [ + "BCCac", + "CbC", + 7 + ], + [ + "BCCbAc", + "AcCAaBcCc", + 12 + ], + [ + "BCCbCbaB", + "caa", + 13 + ], + [ + "BCCbaBBbC", + "baBAB", + 11 + ], + [ + "BCCbb", + "aAAcc", + 10 + ], + [ + "BCCbbb", + "BCaB", + 7 + ], + [ + "BCCbc", + "BBaAbbBCC", + 13 + ], + [ + "BCCbc", + "caBaAbbC", + 11 + ], + [ + "BCCcaAccC", + "bacbC", + 11 + ], + [ + "BCCcbAcBa", + "CA", + 14 + ], + [ + "BCCcbaBc", + "CcCcCAba", + 9 + ], + [ + "BCCccbaC", + "C", + 14 + ], + [ + "BCa", + "CBbbAac", + 10 + ], + [ + "BCa", + "aAbCCb", + 9 + ], + [ + "BCa", + "bbcAB", + 7 + ], + [ + "BCa", + "c", + 5 + ], + [ + "BCaABBaAB", + "acCcBAC", + 13 + ], + [ + "BCaAa", + "AC", + 8 + ], + [ + "BCaAaCac", + "aaAB", + 11 + ], + [ + "BCaAba", + "a", + 10 + ], + [ + "BCaAcAbC", + "B", + 14 + ], + [ + "BCaBAC", + "bCAcCAaB", + 10 + ], + [ + "BCaBcCB", + "BaAA", + 10 + ], + [ + "BCaCAc", + "CBAaBc", + 8 + ], + [ + "BCaCCCcc", + "ccbaBCaC", + 12 + ], + [ + "BCaCbbbc", + "aaAAa", + 14 + ], + [ + "BCaa", + "bc", + 6 + ], + [ + "BCaaAbaB", + "ccCA", + 13 + ], + [ + "BCaaab", + "cAbBBa", + 11 + ], + [ + "BCaaabC", + "Bbbcb", + 10 + ], + [ + "BCaabcbA", + "BabcCAb", + 8 + ], + [ + "BCabaB", + "BaBAbcB", + 7 + ], + [ + "BCabacC", + "a", + 12 + ], + [ + "BCabbbABB", + "BBCcABb", + 10 + ], + [ + "BCabbcCCC", + "ABcCAcbc", + 13 + ], + [ + "BCabcaAAA", + "Baa", + 12 + ], + [ + "BCacBBAAB", + "aBC", + 14 + ], + [ + "BCacBBbB", + "CBCB", + 10 + ], + [ + "BCacCB", + "bB", + 9 + ], + [ + "BCacCba", + "BaBbaAAba", + 10 + ], + [ + "BCb", + "BBa", + 4 + ], + [ + "BCb", + "bBCCa", + 6 + ], + [ + "BCb", + "bCAAAAC", + 11 + ], + [ + "BCbA", + "Bccc", + 5 + ], + [ + "BCbAAC", + "aA", + 9 + ], + [ + "BCbAcbcCB", + "cbBcba", + 11 + ], + [ + "BCbBCacaC", + "AACB", + 16 + ], + [ + "BCbBa", + "cbbBC", + 6 + ], + [ + "BCbBaa", + "aCAAbACc", + 12 + ], + [ + "BCbBca", + "bBaB", + 8 + ], + [ + "BCbCA", + "cB", + 8 + ], + [ + "BCbCccA", + "aaABcCAB", + 11 + ], + [ + "BCbaAABaa", + "AA", + 14 + ], + [ + "BCbaBAb", + "cAAAcbbaA", + 15 + ], + [ + "BCbaCbBAc", + "CBCcabcAb", + 10 + ], + [ + "BCbaaCCaa", + "cCbac", + 11 + ], + [ + "BCbaabbBC", + "abcCBbB", + 11 + ], + [ + "BCbaccCC", + "bbBc", + 11 + ], + [ + "BCbbc", + "AcCbBaACc", + 11 + ], + [ + "BCbbcbbB", + "AbbCca", + 11 + ], + [ + "BCbc", + "cbcCCcBAA", + 13 + ], + [ + "BCbcBbaC", + "babCBCACb", + 9 + ], + [ + "BCbcaACBB", + "aab", + 14 + ], + [ + "BCbccccB", + "Ca", + 14 + ], + [ + "BCc", + "AAaCBcAbc", + 13 + ], + [ + "BCc", + "AcBbBbcba", + 14 + ], + [ + "BCc", + "CAcB", + 6 + ], + [ + "BCc", + "bABBC", + 7 + ], + [ + "BCcA", + "Aac", + 6 + ], + [ + "BCcA", + "bbbCc", + 7 + ], + [ + "BCcACaB", + "CBcbcaBAA", + 11 + ], + [ + "BCcACaCca", + "cca", + 12 + ], + [ + "BCcAcb", + "bbcacbb", + 6 + ], + [ + "BCcBBAccb", + "cBB", + 12 + ], + [ + "BCcBBacB", + "B", + 14 + ], + [ + "BCcBBc", + "ca", + 10 + ], + [ + "BCcBac", + "Cb", + 9 + ], + [ + "BCcBbBAb", + "BBcBBcA", + 7 + ], + [ + "BCcBbBCc", + "A", + 16 + ], + [ + "BCcBc", + "a", + 10 + ], + [ + "BCcCB", + "CABB", + 6 + ], + [ + "BCcCC", + "baB", + 9 + ], + [ + "BCcCcaaB", + "CAaa", + 10 + ], + [ + "BCca", + "aBcCcA", + 5 + ], + [ + "BCcaAc", + "aaAAA", + 9 + ], + [ + "BCcaBbAb", + "A", + 14 + ], + [ + "BCcab", + "CA", + 7 + ], + [ + "BCcacCbcc", + "CBcabaBCC", + 11 + ], + [ + "BCcb", + "CCbBACCcc", + 12 + ], + [ + "BCcb", + "Ca", + 6 + ], + [ + "BCcb", + "bC", + 5 + ], + [ + "BCcbAc", + "B", + 10 + ], + [ + "BCcbAcBAA", + "AacbBc", + 12 + ], + [ + "BCcbBac", + "Aaa", + 12 + ], + [ + "BCcbaC", + "cB", + 9 + ], + [ + "BCcbc", + "BBa", + 7 + ], + [ + "BCccAac", + "ABB", + 12 + ], + [ + "BCccBb", + "Cc", + 8 + ], + [ + "BCccCC", + "BBA", + 10 + ], + [ + "Ba", + "AAACAbbb", + 15 + ], + [ + "Ba", + "AAaBBbBaa", + 14 + ], + [ + "Ba", + "ABBaAabBa", + 14 + ], + [ + "Ba", + "AaccaB", + 10 + ], + [ + "Ba", + "AcABCBc", + 12 + ], + [ + "Ba", + "AcB", + 6 + ], + [ + "Ba", + "AcaAcb", + 10 + ], + [ + "Ba", + "B", + 2 + ], + [ + "Ba", + "BAcBc", + 7 + ], + [ + "Ba", + "Ba", + 0 + ], + [ + "Ba", + "BcAACc", + 9 + ], + [ + "Ba", + "BcCa", + 4 + ], + [ + "Ba", + "BcbBb", + 8 + ], + [ + "Ba", + "C", + 4 + ], + [ + "Ba", + "CABbaBcb", + 12 + ], + [ + "Ba", + "CBBAAB", + 9 + ], + [ + "Ba", + "CC", + 4 + ], + [ + "Ba", + "CCCcABBC", + 14 + ], + [ + "Ba", + "CbCbCa", + 9 + ], + [ + "Ba", + "Cc", + 4 + ], + [ + "Ba", + "a", + 2 + ], + [ + "Ba", + "aA", + 3 + ], + [ + "Ba", + "aB", + 4 + ], + [ + "Ba", + "aCB", + 6 + ], + [ + "Ba", + "aCbCa", + 7 + ], + [ + "Ba", + "acBbb", + 8 + ], + [ + "Ba", + "b", + 3 + ], + [ + "Ba", + "bcBCAbcCB", + 15 + ], + [ + "Ba", + "c", + 4 + ], + [ + "Ba", + "cAaAABbCB", + 16 + ], + [ + "Ba", + "cBBa", + 4 + ], + [ + "Ba", + "cbBaCAb", + 10 + ], + [ + "Ba", + "ccBcACA", + 11 + ], + [ + "Ba", + "ccC", + 6 + ], + [ + "BaA", + "CACaA", + 6 + ], + [ + "BaA", + "CBAbbaca", + 11 + ], + [ + "BaA", + "aaBB", + 6 + ], + [ + "BaA", + "bA", + 3 + ], + [ + "BaA", + "baACAbcA", + 11 + ], + [ + "BaA", + "cbc", + 6 + ], + [ + "BaA", + "ccBAAB", + 7 + ], + [ + "BaAAA", + "BB", + 8 + ], + [ + "BaAAa", + "ca", + 8 + ], + [ + "BaAAaCBaA", + "ACCC", + 14 + ], + [ + "BaAAcCA", + "abCCBA", + 9 + ], + [ + "BaAAcc", + "aaAAbac", + 6 + ], + [ + "BaAAccaCA", + "CcABcBCc", + 12 + ], + [ + "BaAB", + "BBAB", + 2 + ], + [ + "BaAB", + "ac", + 6 + ], + [ + "BaAB", + "bBB", + 5 + ], + [ + "BaABAACBA", + "bAb", + 14 + ], + [ + "BaABCaACb", + "bCbabAaBb", + 13 + ], + [ + "BaABa", + "abC", + 7 + ], + [ + "BaABcbab", + "cAaca", + 10 + ], + [ + "BaACAcCc", + "BC", + 12 + ], + [ + "BaACB", + "bcAa", + 7 + ], + [ + "BaACBAbAC", + "Bac", + 13 + ], + [ + "BaACaCbC", + "AACACCC", + 6 + ], + [ + "BaAa", + "BBCC", + 6 + ], + [ + "BaAa", + "BcbccbCC", + 14 + ], + [ + "BaAa", + "aAbB", + 6 + ], + [ + "BaAaAaAB", + "Ccab", + 13 + ], + [ + "BaAaaAAb", + "ABBCBAcB", + 13 + ], + [ + "BaAacA", + "bACCCb", + 9 + ], + [ + "BaAb", + "AbCBcCba", + 12 + ], + [ + "BaAbCBa", + "CCCcAb", + 13 + ], + [ + "BaAbab", + "aAbaBCc", + 7 + ], + [ + "BaAbcCCB", + "CBcA", + 13 + ], + [ + "BaAcAB", + "BabCCCaC", + 10 + ], + [ + "BaAcAa", + "abaCCCBAA", + 11 + ], + [ + "BaAcAbbC", + "ABaBBAC", + 10 + ], + [ + "BaAcB", + "CBAACbCa", + 9 + ], + [ + "BaAcCbb", + "Abb", + 8 + ], + [ + "BaAcCbca", + "BcCbCAAcB", + 12 + ], + [ + "BaAcbcb", + "c", + 12 + ], + [ + "BaB", + "CACAb", + 8 + ], + [ + "BaB", + "aCACaB", + 8 + ], + [ + "BaB", + "bc", + 5 + ], + [ + "BaB", + "cBBB", + 4 + ], + [ + "BaB", + "cCacaaB", + 10 + ], + [ + "BaBA", + "cABACbbA", + 10 + ], + [ + "BaBAA", + "bbAacbA", + 9 + ], + [ + "BaBAB", + "acAaABBA", + 11 + ], + [ + "BaBABabC", + "C", + 14 + ], + [ + "BaBACA", + "ACAcbbccb", + 15 + ], + [ + "BaBAc", + "BaBABaaC", + 7 + ], + [ + "BaBB", + "aBBCaA", + 8 + ], + [ + "BaBBaABA", + "AaabaABb", + 7 + ], + [ + "BaBBb", + "BC", + 8 + ], + [ + "BaBBc", + "C", + 9 + ], + [ + "BaBBcAaAc", + "C", + 17 + ], + [ + "BaBBcbcb", + "bbabb", + 10 + ], + [ + "BaBCAbab", + "A", + 14 + ], + [ + "BaBCBC", + "BA", + 9 + ], + [ + "BaBCaCac", + "cACc", + 10 + ], + [ + "BaBCc", + "cBcCbAab", + 13 + ], + [ + "BaBa", + "bBBABAabb", + 11 + ], + [ + "BaBa", + "bCAbaAbCb", + 13 + ], + [ + "BaBaBB", + "C", + 12 + ], + [ + "BaBb", + "CC", + 8 + ], + [ + "BaBb", + "bbAbCcbBc", + 13 + ], + [ + "BaBbABA", + "ababcCAc", + 11 + ], + [ + "BaBbBb", + "cCAAb", + 10 + ], + [ + "BaBbC", + "BBACac", + 8 + ], + [ + "BaBbabbCb", + "b", + 16 + ], + [ + "BaBc", + "CB", + 6 + ], + [ + "BaBcACac", + "AbCaBA", + 11 + ], + [ + "BaBcB", + "AaabaaBAa", + 13 + ], + [ + "BaBcBbbAa", + "BCACcab", + 13 + ], + [ + "BaBcCA", + "CbCACA", + 8 + ], + [ + "BaBcCA", + "bCa", + 8 + ], + [ + "BaBcaCCbB", + "BCC", + 12 + ], + [ + "BaBcacC", + "ACB", + 12 + ], + [ + "BaC", + "ABAbc", + 6 + ], + [ + "BaC", + "ABbb", + 6 + ], + [ + "BaC", + "ACa", + 5 + ], + [ + "BaC", + "Aaba", + 6 + ], + [ + "BaC", + "BACccaaBA", + 13 + ], + [ + "BaC", + "BC", + 2 + ], + [ + "BaC", + "Bccb", + 5 + ], + [ + "BaC", + "a", + 4 + ], + [ + "BaC", + "bCbbBcB", + 12 + ], + [ + "BaC", + "baBcbC", + 7 + ], + [ + "BaC", + "cBAabACAa", + 12 + ], + [ + "BaC", + "cBaBAaCc", + 10 + ], + [ + "BaCAA", + "cbbcBBbb", + 14 + ], + [ + "BaCAAbbB", + "BAcB", + 10 + ], + [ + "BaCAB", + "cC", + 8 + ], + [ + "BaCABCB", + "bB", + 11 + ], + [ + "BaCABccaB", + "CAacBCCA", + 12 + ], + [ + "BaCAaAc", + "bCa", + 9 + ], + [ + "BaCB", + "B", + 6 + ], + [ + "BaCBa", + "BbAbaBC", + 9 + ], + [ + "BaCBaCcCC", + "aCCAc", + 11 + ], + [ + "BaCBbCB", + "acB", + 9 + ], + [ + "BaCBc", + "ABCB", + 6 + ], + [ + "BaCBcBC", + "cc", + 11 + ], + [ + "BaCCAcAb", + "Bab", + 10 + ], + [ + "BaCCC", + "CcBCabAAa", + 14 + ], + [ + "BaCCCAcb", + "bbcAaA", + 12 + ], + [ + "BaCCCbb", + "bCCaaCb", + 9 + ], + [ + "BaCCbAA", + "acCBcBB", + 10 + ], + [ + "BaCCc", + "Ca", + 8 + ], + [ + "BaCCcCcc", + "baAbcaCc", + 8 + ], + [ + "BaCa", + "bbAba", + 6 + ], + [ + "BaCaAAaca", + "CCbCb", + 15 + ], + [ + "BaCaCCABa", + "bCaC", + 11 + ], + [ + "BaCb", + "bbaA", + 7 + ], + [ + "BaCb", + "cABC", + 7 + ], + [ + "BaCbAB", + "BAcbaAC", + 6 + ], + [ + "BaCbBA", + "bcAacBaa", + 10 + ], + [ + "BaCbBCaa", + "acBCAAcA", + 11 + ], + [ + "BaCbBcbB", + "bc", + 12 + ], + [ + "BaCbbbBaa", + "CcCAcCCC", + 16 + ], + [ + "BaCc", + "Bc", + 4 + ], + [ + "BaCc", + "CCBcbAAA", + 13 + ], + [ + "BaCcBbAb", + "BcaAaBa", + 11 + ], + [ + "BaCcCcab", + "abBAcBA", + 12 + ], + [ + "BaCcCcbAc", + "BacCAaaaA", + 11 + ], + [ + "BaCcaAabB", + "BBc", + 14 + ], + [ + "BaCcaBAa", + "AaCb", + 11 + ], + [ + "BaCccaaaA", + "cBacBCA", + 12 + ], + [ + "Baa", + "A", + 5 + ], + [ + "Baa", + "AcccabBa", + 12 + ], + [ + "Baa", + "BaaBCABcB", + 12 + ], + [ + "Baa", + "CAAa", + 5 + ], + [ + "Baa", + "CBBcBcC", + 12 + ], + [ + "Baa", + "CCABBacBb", + 14 + ], + [ + "Baa", + "CbABbAcbb", + 15 + ], + [ + "Baa", + "CbCaAbc", + 10 + ], + [ + "Baa", + "bBaBbabAc", + 12 + ], + [ + "Baa", + "bBccbbaAC", + 13 + ], + [ + "Baa", + "bcAbaAACA", + 14 + ], + [ + "BaaA", + "CaBBc", + 8 + ], + [ + "BaaA", + "baBabC", + 7 + ], + [ + "BaaABa", + "bCbcaa", + 9 + ], + [ + "BaaACcAAc", + "bccAaa", + 11 + ], + [ + "BaaAaCc", + "cB", + 13 + ], + [ + "BaaB", + "C", + 8 + ], + [ + "BaaB", + "cAa", + 5 + ], + [ + "BaaBAbAb", + "baccCC", + 13 + ], + [ + "BaaBBcA", + "ccC", + 12 + ], + [ + "BaaC", + "bCb", + 7 + ], + [ + "BaaC", + "cacAcCBcC", + 13 + ], + [ + "BaaCACAaB", + "cAaCabab", + 9 + ], + [ + "BaaCBCBBc", + "ac", + 14 + ], + [ + "BaaCbAC", + "AbCAbca", + 11 + ], + [ + "BaaCcCa", + "cBACb", + 11 + ], + [ + "BaaaBcCab", + "BaBbbbAaC", + 11 + ], + [ + "BaaaC", + "accb", + 8 + ], + [ + "Baaaa", + "B", + 8 + ], + [ + "Baaaa", + "CaA", + 7 + ], + [ + "BaaababB", + "bCAcBCB", + 11 + ], + [ + "BaaacbA", + "aBCba", + 8 + ], + [ + "Baab", + "cCAAcBa", + 11 + ], + [ + "Baab", + "ccaAACcAC", + 15 + ], + [ + "BaabA", + "b", + 8 + ], + [ + "BaabAA", + "A", + 10 + ], + [ + "BaabBAcC", + "aaBCaab", + 10 + ], + [ + "BaabBcc", + "cCCAaCbc", + 12 + ], + [ + "BaabCBCC", + "CcCaB", + 14 + ], + [ + "BaabCa", + "cAaAB", + 9 + ], + [ + "BaabCb", + "CA", + 10 + ], + [ + "Baabacaa", + "bAcbccB", + 10 + ], + [ + "Baabb", + "bBbAbbA", + 7 + ], + [ + "BaabbAaA", + "BBA", + 11 + ], + [ + "BaabcAb", + "aBaC", + 10 + ], + [ + "Baac", + "AaCacBCA", + 10 + ], + [ + "Baac", + "CcBaBAb", + 9 + ], + [ + "Baac", + "a", + 6 + ], + [ + "Baac", + "aaAB", + 5 + ], + [ + "Baac", + "cCcBC", + 9 + ], + [ + "Baac", + "ccCb", + 8 + ], + [ + "BaacCABbA", + "cA", + 14 + ], + [ + "Bab", + "BaCABaCa", + 11 + ], + [ + "Bab", + "C", + 6 + ], + [ + "Bab", + "a", + 4 + ], + [ + "Bab", + "acabAacac", + 14 + ], + [ + "Bab", + "bbCaccBaB", + 13 + ], + [ + "BabA", + "a", + 6 + ], + [ + "BabA", + "cbAc", + 6 + ], + [ + "BabAAccaB", + "abb", + 13 + ], + [ + "BabACA", + "b", + 10 + ], + [ + "BabAaC", + "baCCBcC", + 9 + ], + [ + "BabAb", + "Aa", + 8 + ], + [ + "BabAbACA", + "CBAaCaaa", + 12 + ], + [ + "BabAbCA", + "CccAab", + 12 + ], + [ + "BabBBAaCa", + "AcCAccAB", + 15 + ], + [ + "BabBa", + "ABbACcCcb", + 15 + ], + [ + "BabBcA", + "ACC", + 10 + ], + [ + "BabBcBcA", + "acbCABcB", + 10 + ], + [ + "BabC", + "aABb", + 6 + ], + [ + "BabCaBca", + "AA", + 14 + ], + [ + "Baba", + "BaBCbCBB", + 10 + ], + [ + "BabaBaAA", + "AaB", + 11 + ], + [ + "BabacAbAb", + "cCaA", + 14 + ], + [ + "Babb", + "CcAa", + 8 + ], + [ + "Babb", + "aaACcbc", + 10 + ], + [ + "BabbA", + "CaCb", + 6 + ], + [ + "BabbAaaBA", + "BbCcACC", + 13 + ], + [ + "BabbAccb", + "cacBB", + 11 + ], + [ + "BabbBcBA", + "cAabCbba", + 11 + ], + [ + "BabbCBb", + "aCCcBcB", + 10 + ], + [ + "BabbCCbCA", + "AbAcBa", + 12 + ], + [ + "BabbcBAAa", + "aCacA", + 12 + ], + [ + "BabcBAbcc", + "CabA", + 12 + ], + [ + "BabcCbCA", + "cbC", + 10 + ], + [ + "BabcaC", + "ABB", + 10 + ], + [ + "Babcac", + "bcccAbBC", + 11 + ], + [ + "Bac", + "BBcaBcC", + 8 + ], + [ + "Bac", + "CbcAbAbB", + 14 + ], + [ + "Bac", + "bacBAccb", + 11 + ], + [ + "Bac", + "bbACab", + 9 + ], + [ + "BacAa", + "bBCb", + 8 + ], + [ + "BacAaaCaB", + "ccaaAb", + 10 + ], + [ + "BacAb", + "aBBaBa", + 9 + ], + [ + "BacAbA", + "caAaBbCAb", + 11 + ], + [ + "BacBBa", + "AbBBAAA", + 10 + ], + [ + "BacBCAB", + "cCBaBCc", + 10 + ], + [ + "BacBab", + "CbBABcB", + 10 + ], + [ + "BacCAaBAB", + "ccAb", + 12 + ], + [ + "BacCBBCc", + "B", + 14 + ], + [ + "BacCCaA", + "bcaBA", + 9 + ], + [ + "BacCCcbB", + "cCbaaCBB", + 12 + ], + [ + "BacCa", + "cCBBB", + 10 + ], + [ + "BacCab", + "bA", + 10 + ], + [ + "BacCabcAc", + "CCbBC", + 12 + ], + [ + "BacCccBa", + "ABCBA", + 10 + ], + [ + "BacaB", + "bbac", + 7 + ], + [ + "BacaC", + "AAC", + 6 + ], + [ + "BacaCaBB", + "bB", + 13 + ], + [ + "BacaCbA", + "caBCAa", + 9 + ], + [ + "BacbB", + "CcaACc", + 10 + ], + [ + "BacbC", + "AAabcbbCB", + 10 + ], + [ + "BacbCbBca", + "cCcCC", + 13 + ], + [ + "BacbbCaAa", + "aCACaC", + 11 + ], + [ + "Bacc", + "b", + 7 + ], + [ + "BaccACa", + "B", + 12 + ], + [ + "BaccAaacb", + "A", + 16 + ], + [ + "BaccBcCBB", + "acb", + 13 + ], + [ + "BaccCB", + "BaC", + 6 + ], + [ + "Bacca", + "Ac", + 7 + ], + [ + "BaccaCC", + "CcbA", + 11 + ], + [ + "Baccb", + "aCc", + 5 + ], + [ + "Baccba", + "cbaaBcbc", + 9 + ], + [ + "Bb", + "AAABBB", + 9 + ], + [ + "Bb", + "AAccaCAaa", + 18 + ], + [ + "Bb", + "AaA", + 6 + ], + [ + "Bb", + "AaAAc", + 10 + ], + [ + "Bb", + "B", + 2 + ], + [ + "Bb", + "BACBbABA", + 12 + ], + [ + "Bb", + "BBaBb", + 6 + ], + [ + "Bb", + "BacCBA", + 9 + ], + [ + "Bb", + "BbCBCABAC", + 14 + ], + [ + "Bb", + "Bba", + 2 + ], + [ + "Bb", + "BcBAACA", + 11 + ], + [ + "Bb", + "CC", + 4 + ], + [ + "Bb", + "CcaaBa", + 10 + ], + [ + "Bb", + "a", + 4 + ], + [ + "Bb", + "aAbbb", + 7 + ], + [ + "Bb", + "aBa", + 4 + ], + [ + "Bb", + "aBbcCbAAC", + 14 + ], + [ + "Bb", + "aCCAB", + 9 + ], + [ + "Bb", + "aCccacCB", + 15 + ], + [ + "Bb", + "aacA", + 8 + ], + [ + "Bb", + "abBaBbAa", + 12 + ], + [ + "Bb", + "b", + 2 + ], + [ + "Bb", + "bAcCbc", + 9 + ], + [ + "Bb", + "bBaCBc", + 9 + ], + [ + "Bb", + "bBbBCccc", + 12 + ], + [ + "Bb", + "bCCc", + 7 + ], + [ + "Bb", + "bCaBcC", + 10 + ], + [ + "Bb", + "bCcbbc", + 9 + ], + [ + "Bb", + "baB", + 4 + ], + [ + "Bb", + "bc", + 3 + ], + [ + "Bb", + "bcCaacCC", + 15 + ], + [ + "Bb", + "bcaBccAcb", + 14 + ], + [ + "Bb", + "cab", + 4 + ], + [ + "Bb", + "cbAACCBb", + 12 + ], + [ + "Bb", + "cbabCcbb", + 13 + ], + [ + "Bb", + "cc", + 4 + ], + [ + "BbA", + "BCaAcABab", + 14 + ], + [ + "BbA", + "C", + 6 + ], + [ + "BbA", + "aacCbAc", + 10 + ], + [ + "BbA", + "cbCcbaAAA", + 13 + ], + [ + "BbAAaA", + "AbbBccC", + 11 + ], + [ + "BbAAaA", + "bBc", + 10 + ], + [ + "BbABB", + "BBAACAa", + 9 + ], + [ + "BbABBbAa", + "acaCCbbcB", + 14 + ], + [ + "BbABC", + "c", + 9 + ], + [ + "BbABa", + "accBbBcBb", + 12 + ], + [ + "BbABaacaA", + "b", + 16 + ], + [ + "BbAC", + "CaCCBcAa", + 12 + ], + [ + "BbAC", + "caAcaab", + 11 + ], + [ + "BbACAbcB", + "aaaAB", + 11 + ], + [ + "BbAa", + "ACcA", + 7 + ], + [ + "BbAa", + "cCA", + 6 + ], + [ + "BbAaAaaa", + "cBbbcCB", + 14 + ], + [ + "BbAaCab", + "cA", + 12 + ], + [ + "BbAaa", + "Bbbcacaa", + 7 + ], + [ + "BbAac", + "b", + 8 + ], + [ + "BbAb", + "CccCbabaC", + 13 + ], + [ + "BbAbC", + "CABA", + 7 + ], + [ + "BbAbC", + "ccA", + 8 + ], + [ + "BbAbCab", + "bcabABC", + 10 + ], + [ + "BbAbCcBab", + "CAaAbcbAC", + 12 + ], + [ + "BbAbCcaAC", + "ABbcCa", + 11 + ], + [ + "BbAbbcbb", + "B", + 14 + ], + [ + "BbAbc", + "aABB", + 7 + ], + [ + "BbAcaaaa", + "bBccaac", + 8 + ], + [ + "BbAcbca", + "acCCcbBCB", + 13 + ], + [ + "BbB", + "ACbcc", + 8 + ], + [ + "BbB", + "Acaca", + 10 + ], + [ + "BbB", + "bBcb", + 5 + ], + [ + "BbBA", + "CA", + 6 + ], + [ + "BbBABCcA", + "aaC", + 13 + ], + [ + "BbBAaBa", + "b", + 12 + ], + [ + "BbBAb", + "aaCCcb", + 10 + ], + [ + "BbBAbABAc", + "cBbbBCcB", + 12 + ], + [ + "BbBBCbca", + "cbBcCbC", + 7 + ], + [ + "BbBBa", + "cC", + 10 + ], + [ + "BbBBaBBba", + "bAC", + 15 + ], + [ + "BbBBabAb", + "cbB", + 12 + ], + [ + "BbBC", + "cbbbcaA", + 9 + ], + [ + "BbBCAbb", + "baCCbBbb", + 9 + ], + [ + "BbBCbAb", + "BbCcBbbac", + 9 + ], + [ + "BbBa", + "aCaaaA", + 10 + ], + [ + "BbBa", + "caCcb", + 10 + ], + [ + "BbBaC", + "BA", + 7 + ], + [ + "BbBaCbCcB", + "baAbCbaCc", + 11 + ], + [ + "BbBaaCBbc", + "bcAAAbC", + 11 + ], + [ + "BbBacBCca", + "c", + 16 + ], + [ + "BbBbA", + "BbaaA", + 4 + ], + [ + "BbBbBAb", + "CbcCbAaCc", + 13 + ], + [ + "BbBbBa", + "A", + 11 + ], + [ + "BbBbBbC", + "cBbacbBa", + 10 + ], + [ + "BbBbbbBAb", + "AabCcBa", + 13 + ], + [ + "BbBcBc", + "bcaaC", + 9 + ], + [ + "BbBcaAC", + "cB", + 12 + ], + [ + "BbBcabAa", + "BaBAaACc", + 10 + ], + [ + "BbBcbbC", + "bCBAabbaa", + 11 + ], + [ + "BbC", + "A", + 6 + ], + [ + "BbC", + "Cc", + 5 + ], + [ + "BbC", + "aAAAc", + 9 + ], + [ + "BbC", + "aAAbca", + 9 + ], + [ + "BbC", + "bAaBabC", + 8 + ], + [ + "BbC", + "bBCcCa", + 8 + ], + [ + "BbC", + "baCACBbc", + 11 + ], + [ + "BbC", + "bcBccBcBa", + 14 + ], + [ + "BbCAACcac", + "AcCbB", + 14 + ], + [ + "BbCAACcb", + "b", + 14 + ], + [ + "BbCAaCaC", + "BBc", + 12 + ], + [ + "BbCAbc", + "aaa", + 11 + ], + [ + "BbCAcCaCC", + "CCcB", + 13 + ], + [ + "BbCAcaab", + "BCbACaABc", + 9 + ], + [ + "BbCBCB", + "bAAccbCc", + 11 + ], + [ + "BbCBCbAc", + "CcACA", + 11 + ], + [ + "BbCCAAab", + "ccCCC", + 12 + ], + [ + "BbCCABABa", + "Acaab", + 14 + ], + [ + "BbCCBBb", + "aacCb", + 9 + ], + [ + "BbCCCBCC", + "BCA", + 12 + ], + [ + "BbCCa", + "aaaCAc", + 9 + ], + [ + "BbCCcCcCc", + "AaAAA", + 18 + ], + [ + "BbCCcbc", + "BaaBCc", + 9 + ], + [ + "BbCa", + "aCC", + 6 + ], + [ + "BbCaB", + "A", + 9 + ], + [ + "BbCaBAA", + "AbAABc", + 9 + ], + [ + "BbCaCbACB", + "AAA", + 15 + ], + [ + "BbCaCcC", + "aAAcA", + 11 + ], + [ + "BbCaCcaC", + "A", + 15 + ], + [ + "BbCbC", + "bAACAAcAC", + 13 + ], + [ + "BbCbCCb", + "AbBAA", + 11 + ], + [ + "BbCbaAB", + "C", + 12 + ], + [ + "BbCbaB", + "aAcC", + 11 + ], + [ + "BbCbaBB", + "Cabb", + 8 + ], + [ + "BbCbbBc", + "b", + 12 + ], + [ + "BbCbbb", + "cCcAcBAcA", + 16 + ], + [ + "BbCbcc", + "AAACbaaAa", + 14 + ], + [ + "BbCc", + "A", + 8 + ], + [ + "BbCc", + "aac", + 6 + ], + [ + "BbCcCACB", + "cB", + 12 + ], + [ + "BbCcaBBC", + "CB", + 12 + ], + [ + "BbCccBCB", + "cCcbBb", + 9 + ], + [ + "Bba", + "ABBBcACb", + 12 + ], + [ + "Bba", + "AbAcAbCcA", + 14 + ], + [ + "Bba", + "CaBCAaaaB", + 14 + ], + [ + "Bba", + "CacBBCBA", + 12 + ], + [ + "Bba", + "aBAcbCC", + 10 + ], + [ + "Bba", + "aCCcAaAc", + 14 + ], + [ + "Bba", + "abcA", + 5 + ], + [ + "Bba", + "bcCa", + 5 + ], + [ + "BbaAB", + "BbB", + 4 + ], + [ + "BbaABacc", + "bccbc", + 11 + ], + [ + "BbaAbBCAA", + "caAcCbc", + 12 + ], + [ + "BbaAcAb", + "bacACCbC", + 9 + ], + [ + "BbaB", + "aBbAaCb", + 7 + ], + [ + "BbaB", + "bBbBAbBC", + 9 + ], + [ + "BbaBCB", + "bcA", + 9 + ], + [ + "BbaBcbacc", + "CCBAC", + 14 + ], + [ + "BbaC", + "C", + 6 + ], + [ + "BbaCBC", + "C", + 10 + ], + [ + "BbaCCCb", + "Cca", + 11 + ], + [ + "BbaCa", + "AcCC", + 8 + ], + [ + "BbaCa", + "ccbA", + 9 + ], + [ + "BbaCcBba", + "ACb", + 11 + ], + [ + "BbaCcC", + "cbCCAAbcc", + 11 + ], + [ + "Bbaa", + "abbaAA", + 6 + ], + [ + "BbaaAbAA", + "Acc", + 14 + ], + [ + "BbaaBAb", + "CBbaCbaBB", + 9 + ], + [ + "BbaacA", + "ccAbCabAa", + 12 + ], + [ + "BbaacBcbC", + "cabbCaC", + 12 + ], + [ + "Bbab", + "BCBb", + 4 + ], + [ + "BbabA", + "Cbc", + 8 + ], + [ + "BbabBc", + "AcA", + 11 + ], + [ + "BbabC", + "ab", + 6 + ], + [ + "BbabCcBA", + "AabACBc", + 9 + ], + [ + "Bbaba", + "AAa", + 7 + ], + [ + "BbabbBb", + "b", + 12 + ], + [ + "Bbac", + "bbb", + 5 + ], + [ + "BbacB", + "CBcBB", + 7 + ], + [ + "BbacCc", + "Cb", + 10 + ], + [ + "Bbacaa", + "AaAaac", + 8 + ], + [ + "Bbb", + "ACCCCc", + 12 + ], + [ + "Bbb", + "BCABAa", + 9 + ], + [ + "Bbb", + "BabbbBcCA", + 12 + ], + [ + "Bbb", + "acaCCaa", + 14 + ], + [ + "Bbb", + "bAAcBa", + 10 + ], + [ + "Bbb", + "ccacA", + 10 + ], + [ + "BbbA", + "ACccA", + 8 + ], + [ + "BbbAAB", + "baBAb", + 7 + ], + [ + "BbbABccc", + "AbaABca", + 8 + ], + [ + "BbbAC", + "bcAaBBBca", + 14 + ], + [ + "BbbAaAba", + "a", + 14 + ], + [ + "BbbB", + "Bcc", + 6 + ], + [ + "BbbBCCA", + "cBBb", + 11 + ], + [ + "BbbBCba", + "BA", + 11 + ], + [ + "BbbBcaa", + "b", + 12 + ], + [ + "BbbCAaA", + "cbbBaBaCA", + 9 + ], + [ + "BbbCAb", + "AACC", + 10 + ], + [ + "BbbCAc", + "cbaB", + 9 + ], + [ + "BbbCBcac", + "bAbaBCba", + 10 + ], + [ + "BbbCCB", + "C", + 10 + ], + [ + "BbbCCBAc", + "cbbBcCCAC", + 8 + ], + [ + "Bbba", + "AAaAB", + 9 + ], + [ + "Bbba", + "abAc", + 6 + ], + [ + "BbbaAC", + "aBABcAAaB", + 12 + ], + [ + "BbbaC", + "AbBaaAaA", + 11 + ], + [ + "BbbaabCCA", + "CbcAb", + 13 + ], + [ + "BbbacCbb", + "AaccA", + 11 + ], + [ + "BbbbCAaA", + "cACCaCcAC", + 15 + ], + [ + "BbbbbAc", + "AbbcCb", + 10 + ], + [ + "BbbbcA", + "AaCcBabb", + 14 + ], + [ + "BbbbcbbA", + "bAA", + 12 + ], + [ + "Bbbc", + "CbccaAc", + 10 + ], + [ + "BbbcABb", + "bbbcc", + 7 + ], + [ + "BbbcB", + "bbacbbc", + 8 + ], + [ + "BbbcbAcbB", + "aCaCbaAc", + 13 + ], + [ + "Bbbcbcab", + "caCaAAbc", + 14 + ], + [ + "BbcA", + "CBaA", + 5 + ], + [ + "BbcA", + "CBcAB", + 5 + ], + [ + "BbcABcB", + "AcA", + 10 + ], + [ + "BbcACB", + "BaaCCBBC", + 10 + ], + [ + "BbcACCcB", + "bcbbaaBba", + 14 + ], + [ + "BbcAbCa", + "CbbaCba", + 9 + ], + [ + "BbcAcaB", + "Aca", + 8 + ], + [ + "BbcAccCab", + "abCCaA", + 11 + ], + [ + "BbcB", + "aACCccCaA", + 16 + ], + [ + "BbcBbB", + "baacAca", + 11 + ], + [ + "BbcBbbaC", + "Ab", + 14 + ], + [ + "BbcC", + "AccAcaBaC", + 14 + ], + [ + "BbcCB", + "bBca", + 6 + ], + [ + "BbcCBaB", + "AcCcaCbb", + 11 + ], + [ + "BbcCaab", + "cACaC", + 10 + ], + [ + "BbcaBbCCb", + "acBBcc", + 11 + ], + [ + "BbcaCcaa", + "AbcccaBB", + 9 + ], + [ + "BbcaaACb", + "A", + 14 + ], + [ + "BbcbACAa", + "a", + 14 + ], + [ + "BbcbBCCA", + "AcaCB", + 12 + ], + [ + "BbcbCcCCc", + "a", + 18 + ], + [ + "Bbcbaa", + "a", + 10 + ], + [ + "BbcbbbBab", + "aaBcBcCB", + 14 + ], + [ + "BbcbccB", + "bAACb", + 10 + ], + [ + "Bbcc", + "caAACBBb", + 15 + ], + [ + "BbccBcb", + "BCAbccb", + 8 + ], + [ + "BbccC", + "CaaAC", + 8 + ], + [ + "Bbcca", + "bBcb", + 6 + ], + [ + "BbccccCC", + "aAbcc", + 12 + ], + [ + "Bc", + "A", + 4 + ], + [ + "Bc", + "AB", + 4 + ], + [ + "Bc", + "ABAccAcC", + 12 + ], + [ + "Bc", + "ABBbBBbb", + 14 + ], + [ + "Bc", + "AaA", + 6 + ], + [ + "Bc", + "AaaBaCcCc", + 14 + ], + [ + "Bc", + "AabBBC", + 9 + ], + [ + "Bc", + "Aac", + 4 + ], + [ + "Bc", + "Aba", + 5 + ], + [ + "Bc", + "Abccbabbc", + 15 + ], + [ + "Bc", + "AcAbBC", + 9 + ], + [ + "Bc", + "B", + 2 + ], + [ + "Bc", + "BACaACBC", + 13 + ], + [ + "Bc", + "BBcBCbCB", + 12 + ], + [ + "Bc", + "BcBAAAaA", + 12 + ], + [ + "Bc", + "BcaaABCcc", + 14 + ], + [ + "Bc", + "C", + 3 + ], + [ + "Bc", + "CBCccCbaA", + 14 + ], + [ + "Bc", + "CCaBABaBA", + 16 + ], + [ + "Bc", + "CaBCBbBbc", + 14 + ], + [ + "Bc", + "CbaBCbb", + 11 + ], + [ + "Bc", + "a", + 4 + ], + [ + "Bc", + "aC", + 3 + ], + [ + "Bc", + "abAbBBcc", + 12 + ], + [ + "Bc", + "abaCAABA", + 14 + ], + [ + "Bc", + "abaabAbc", + 13 + ], + [ + "Bc", + "abcbBBB", + 11 + ], + [ + "Bc", + "ac", + 2 + ], + [ + "Bc", + "acCCcb", + 10 + ], + [ + "Bc", + "acCacaaAa", + 16 + ], + [ + "Bc", + "ba", + 3 + ], + [ + "Bc", + "cC", + 3 + ], + [ + "Bc", + "cb", + 4 + ], + [ + "Bc", + "cbACCabca", + 15 + ], + [ + "BcA", + "AC", + 5 + ], + [ + "BcA", + "BAaB", + 5 + ], + [ + "BcA", + "BBc", + 4 + ], + [ + "BcA", + "CBababB", + 11 + ], + [ + "BcA", + "CcB", + 4 + ], + [ + "BcA", + "CcCb", + 6 + ], + [ + "BcA", + "a", + 5 + ], + [ + "BcA", + "bAcab", + 6 + ], + [ + "BcA", + "bBAbb", + 7 + ], + [ + "BcA", + "bbbc", + 7 + ], + [ + "BcA", + "c", + 4 + ], + [ + "BcAABaB", + "bACcAc", + 10 + ], + [ + "BcAAaA", + "BcCAbaBb", + 8 + ], + [ + "BcAB", + "aBCCcACc", + 10 + ], + [ + "BcABAc", + "BaAa", + 7 + ], + [ + "BcABaAaA", + "aCCaCcb", + 13 + ], + [ + "BcABaa", + "CaaBBaa", + 7 + ], + [ + "BcAC", + "BCAbcbCAa", + 11 + ], + [ + "BcACAA", + "aCb", + 9 + ], + [ + "BcACB", + "bCcC", + 6 + ], + [ + "BcACBaBCa", + "BCcBAbACc", + 10 + ], + [ + "BcACC", + "aa", + 9 + ], + [ + "BcAa", + "Cb", + 7 + ], + [ + "BcAaA", + "CBBc", + 9 + ], + [ + "BcAaA", + "abBbBBcB", + 14 + ], + [ + "BcAaACA", + "cbCABAaCb", + 10 + ], + [ + "BcAaCCBB", + "cBbCaBbA", + 11 + ], + [ + "BcAaCbB", + "ACB", + 8 + ], + [ + "BcAaaaC", + "cC", + 10 + ], + [ + "BcAb", + "BB", + 5 + ], + [ + "BcAb", + "CC", + 7 + ], + [ + "BcAbAbCac", + "bab", + 13 + ], + [ + "BcAbB", + "B", + 8 + ], + [ + "BcAbabBA", + "acb", + 12 + ], + [ + "BcAbabBBB", + "BA", + 14 + ], + [ + "BcAbabC", + "BBbaCAB", + 10 + ], + [ + "BcAbbcC", + "AaAcbC", + 8 + ], + [ + "BcAbc", + "BAC", + 5 + ], + [ + "BcAbc", + "BbbcbBabB", + 11 + ], + [ + "BcAbcAAC", + "A", + 14 + ], + [ + "BcAc", + "bC", + 6 + ], + [ + "BcAcAaACb", + "aAbBBB", + 14 + ], + [ + "BcAcB", + "caaAbbccB", + 12 + ], + [ + "BcAcaccb", + "cbAbAb", + 11 + ], + [ + "BcAcba", + "aA", + 10 + ], + [ + "BcAcc", + "BCaCBcAcC", + 9 + ], + [ + "BcB", + "AcCCAC", + 10 + ], + [ + "BcB", + "BBAcaAaB", + 10 + ], + [ + "BcB", + "BabAcacCA", + 14 + ], + [ + "BcB", + "aaBcAb", + 7 + ], + [ + "BcB", + "abcC", + 5 + ], + [ + "BcB", + "bcBBCbab", + 11 + ], + [ + "BcB", + "cAAc", + 8 + ], + [ + "BcB", + "ca", + 4 + ], + [ + "BcB", + "caBaaAAb", + 13 + ], + [ + "BcBA", + "CAabC", + 9 + ], + [ + "BcBA", + "baaC", + 7 + ], + [ + "BcBAAc", + "cBBaaabBB", + 14 + ], + [ + "BcBAB", + "aCaAaBb", + 9 + ], + [ + "BcBABCB", + "aaB", + 11 + ], + [ + "BcBAccAc", + "c", + 14 + ], + [ + "BcBBBA", + "ACc", + 11 + ], + [ + "BcBBC", + "cCABb", + 7 + ], + [ + "BcBBbb", + "bbBAa", + 8 + ], + [ + "BcBBbcAaA", + "CA", + 15 + ], + [ + "BcBC", + "c", + 6 + ], + [ + "BcBCA", + "cAaCC", + 8 + ], + [ + "BcBCAAAcc", + "abc", + 15 + ], + [ + "BcBCBBC", + "BbC", + 9 + ], + [ + "BcBCbAc", + "cBBCaC", + 8 + ], + [ + "BcBCcbccc", + "BcBC", + 10 + ], + [ + "BcBCccAa", + "acb", + 13 + ], + [ + "BcBa", + "aCB", + 5 + ], + [ + "BcBaAcAAc", + "bccBBBcBc", + 11 + ], + [ + "BcBaC", + "acBbcABAa", + 11 + ], + [ + "BcBab", + "CbCACC", + 10 + ], + [ + "BcBb", + "acAABAA", + 10 + ], + [ + "BcBbA", + "Ccba", + 5 + ], + [ + "BcBbAbABB", + "a", + 17 + ], + [ + "BcBbbCAa", + "baACcBCcC", + 14 + ], + [ + "BcBbbCa", + "AcCBAa", + 9 + ], + [ + "BcBbc", + "CcABb", + 6 + ], + [ + "BcBc", + "cBBcc", + 6 + ], + [ + "BcBcAbbc", + "babC", + 11 + ], + [ + "BcBcBc", + "cAAc", + 8 + ], + [ + "BcC", + "ABabcbC", + 8 + ], + [ + "BcC", + "Ac", + 4 + ], + [ + "BcC", + "C", + 4 + ], + [ + "BcC", + "acbcaAaa", + 13 + ], + [ + "BcC", + "bAbB", + 7 + ], + [ + "BcCA", + "ccaBaaAac", + 14 + ], + [ + "BcCAABBB", + "BCabBB", + 6 + ], + [ + "BcCAaAC", + "acCaB", + 8 + ], + [ + "BcCAaBc", + "Bcab", + 7 + ], + [ + "BcCAbB", + "ACaccCB", + 10 + ], + [ + "BcCAbaACc", + "aCAAcCBC", + 12 + ], + [ + "BcCAbcbA", + "bccAbCC", + 7 + ], + [ + "BcCAcA", + "BbB", + 10 + ], + [ + "BcCBABA", + "accb", + 10 + ], + [ + "BcCBAaC", + "b", + 13 + ], + [ + "BcCBbabcc", + "cCb", + 12 + ], + [ + "BcCBc", + "ba", + 9 + ], + [ + "BcCBcaAcc", + "B", + 16 + ], + [ + "BcCBcaCbC", + "CA", + 15 + ], + [ + "BcCCAA", + "caaA", + 7 + ], + [ + "BcCCBaaa", + "AaaCBb", + 12 + ], + [ + "BcCCCAA", + "b", + 13 + ], + [ + "BcCCaaaA", + "BccaAabBa", + 9 + ], + [ + "BcCCbCac", + "AcAa", + 12 + ], + [ + "BcCa", + "AB", + 8 + ], + [ + "BcCa", + "cB", + 6 + ], + [ + "BcCaACC", + "cbACaA", + 9 + ], + [ + "BcCaACCc", + "aaaCb", + 11 + ], + [ + "BcCaBbCAC", + "AbaAc", + 12 + ], + [ + "BcCaBc", + "CCAAB", + 8 + ], + [ + "BcCaCacc", + "CaCbbbc", + 10 + ], + [ + "BcCaaC", + "AcC", + 8 + ], + [ + "BcCb", + "aBacB", + 6 + ], + [ + "BcCbAcCb", + "CAA", + 12 + ], + [ + "BcCbCCCa", + "CBCC", + 9 + ], + [ + "BcCbaBabc", + "abcbB", + 13 + ], + [ + "BcCbbb", + "ccBCb", + 6 + ], + [ + "BcCc", + "bBb", + 7 + ], + [ + "BcCcBBb", + "aCCC", + 10 + ], + [ + "BcCcBcAb", + "aacbBbC", + 13 + ], + [ + "BcCca", + "CCcCaaB", + 8 + ], + [ + "Bca", + "AcbCBab", + 10 + ], + [ + "Bca", + "Bb", + 4 + ], + [ + "Bca", + "Bcc", + 2 + ], + [ + "Bca", + "CAAbA", + 9 + ], + [ + "Bca", + "CcBc", + 6 + ], + [ + "Bca", + "aAAccCBB", + 14 + ], + [ + "Bca", + "aCbbBBcCb", + 14 + ], + [ + "Bca", + "ac", + 4 + ], + [ + "Bca", + "c", + 4 + ], + [ + "BcaAAbACa", + "cAaacBB", + 13 + ], + [ + "BcaAaC", + "B", + 10 + ], + [ + "BcaB", + "A", + 7 + ], + [ + "BcaB", + "ABC", + 7 + ], + [ + "BcaB", + "AcAacA", + 8 + ], + [ + "BcaB", + "CAba", + 7 + ], + [ + "BcaB", + "cc", + 6 + ], + [ + "BcaBACC", + "aabAcbb", + 10 + ], + [ + "BcaBACbA", + "cB", + 12 + ], + [ + "BcaBAc", + "CAcBaCC", + 10 + ], + [ + "BcaBb", + "bABA", + 6 + ], + [ + "BcaBcab", + "aAaA", + 10 + ], + [ + "BcaC", + "abbAb", + 8 + ], + [ + "BcaC", + "ba", + 5 + ], + [ + "BcaC", + "ccaCBCB", + 8 + ], + [ + "BcaCBAbA", + "BA", + 12 + ], + [ + "BcaCC", + "CAbBbB", + 12 + ], + [ + "BcaCCbb", + "bbb", + 9 + ], + [ + "BcaCc", + "AaCABAACA", + 13 + ], + [ + "Bcaa", + "C", + 7 + ], + [ + "Bcaa", + "CbBABaa", + 8 + ], + [ + "Bcaa", + "cbbBcc", + 10 + ], + [ + "BcaaAc", + "AcaCCb", + 8 + ], + [ + "BcaaBBa", + "bBBCAAb", + 12 + ], + [ + "BcaaBcB", + "cCBbbAAcA", + 13 + ], + [ + "Bcaaba", + "ACbcA", + 10 + ], + [ + "Bcaabc", + "Bba", + 8 + ], + [ + "BcaacbcC", + "CBBBbCCA", + 12 + ], + [ + "Bcab", + "AcABabB", + 8 + ], + [ + "Bcab", + "abA", + 6 + ], + [ + "BcabB", + "BcbCc", + 6 + ], + [ + "BcabBB", + "BbAbbbA", + 7 + ], + [ + "BcabCA", + "b", + 10 + ], + [ + "BcabCac", + "BbAAaca", + 9 + ], + [ + "Bcaba", + "aCcbA", + 6 + ], + [ + "BcabaABA", + "CAbB", + 10 + ], + [ + "Bcac", + "CcCAbaaa", + 12 + ], + [ + "Bcac", + "ccc", + 4 + ], + [ + "BcacAC", + "abBc", + 9 + ], + [ + "BcacAaca", + "acbAbc", + 10 + ], + [ + "BcacCB", + "cbabacC", + 9 + ], + [ + "BcacaBC", + "ACCac", + 9 + ], + [ + "BcacabbA", + "Bcb", + 10 + ], + [ + "Bcacc", + "b", + 9 + ], + [ + "Bcb", + "AaAcacaB", + 13 + ], + [ + "Bcb", + "Cc", + 4 + ], + [ + "Bcb", + "aBBC", + 6 + ], + [ + "BcbAACc", + "aBBcA", + 11 + ], + [ + "BcbAAb", + "ab", + 9 + ], + [ + "BcbAC", + "AcC", + 6 + ], + [ + "BcbAaaacc", + "cc", + 14 + ], + [ + "BcbB", + "BbcbBbBC", + 8 + ], + [ + "BcbB", + "aB", + 6 + ], + [ + "BcbBcB", + "bCbb", + 7 + ], + [ + "BcbCA", + "bCc", + 6 + ], + [ + "BcbCAAba", + "CCaa", + 10 + ], + [ + "BcbCBCA", + "BcBa", + 7 + ], + [ + "BcbCC", + "b", + 8 + ], + [ + "BcbCCcc", + "Abb", + 12 + ], + [ + "BcbCabC", + "A", + 13 + ], + [ + "BcbCcB", + "cbaccCa", + 9 + ], + [ + "Bcba", + "ACa", + 5 + ], + [ + "Bcbb", + "baaAa", + 9 + ], + [ + "BcbbA", + "BBb", + 5 + ], + [ + "BcbbC", + "ccaBAABCC", + 12 + ], + [ + "BcbcA", + "bcBcAAcB", + 8 + ], + [ + "BcbcB", + "Ccc", + 6 + ], + [ + "Bcc", + "Ab", + 6 + ], + [ + "Bcc", + "BCAbacBc", + 10 + ], + [ + "Bcc", + "aacb", + 6 + ], + [ + "Bcc", + "baAa", + 7 + ], + [ + "BccABAbcA", + "Aba", + 13 + ], + [ + "BccACA", + "aa", + 10 + ], + [ + "BccAcAbbC", + "caC", + 13 + ], + [ + "BccBA", + "BACCAC", + 7 + ], + [ + "BccBAAbb", + "aac", + 14 + ], + [ + "BccBCbAA", + "BBCCC", + 10 + ], + [ + "BccBaAaa", + "AACAbbbbB", + 16 + ], + [ + "BccBac", + "CCabACa", + 10 + ], + [ + "BccC", + "ac", + 6 + ], + [ + "BccC", + "bCA", + 6 + ], + [ + "BccCa", + "caaBBaaB", + 14 + ], + [ + "BccCab", + "Cbcbac", + 8 + ], + [ + "BccCacBC", + "BBbA", + 13 + ], + [ + "BccCcA", + "BcCBCAB", + 6 + ], + [ + "Bcca", + "AAb", + 8 + ], + [ + "BccaA", + "cCC", + 7 + ], + [ + "BccaA", + "ccc", + 6 + ], + [ + "BccaBbB", + "AA", + 13 + ], + [ + "Bccac", + "CcbaCCa", + 9 + ], + [ + "Bccb", + "AcbC", + 6 + ], + [ + "BccbB", + "bbccA", + 7 + ], + [ + "BccbBCAA", + "AA", + 12 + ], + [ + "BccbBaCbb", + "CbcBBCAA", + 11 + ], + [ + "BccbacAAc", + "CAac", + 12 + ], + [ + "BccbbACa", + "acCAbCAc", + 10 + ], + [ + "BcccAC", + "cccBbBaac", + 12 + ], + [ + "BcccBB", + "bABCc", + 10 + ], + [ + "BcccBBb", + "Cbacbaa", + 11 + ], + [ + "C", + "A", + 2 + ], + [ + "C", + "AAA", + 6 + ], + [ + "C", + "AAAb", + 8 + ], + [ + "C", + "AAB", + 6 + ], + [ + "C", + "AAacba", + 11 + ], + [ + "C", + "AAbb", + 8 + ], + [ + "C", + "ABA", + 6 + ], + [ + "C", + "ABAB", + 8 + ], + [ + "C", + "ABAcBAabA", + 17 + ], + [ + "C", + "ABCB", + 6 + ], + [ + "C", + "ABCbbbBAC", + 16 + ], + [ + "C", + "ABabc", + 9 + ], + [ + "C", + "ACCCcAcAa", + 16 + ], + [ + "C", + "ACc", + 4 + ], + [ + "C", + "ACcbaABc", + 14 + ], + [ + "C", + "AaAAa", + 10 + ], + [ + "C", + "AaAa", + 8 + ], + [ + "C", + "AaAbcaBb", + 15 + ], + [ + "C", + "AabbbC", + 10 + ], + [ + "C", + "AacCCABaB", + 16 + ], + [ + "C", + "AacaaaB", + 13 + ], + [ + "C", + "Ab", + 4 + ], + [ + "C", + "AbBbBACab", + 16 + ], + [ + "C", + "AbBcCcBAb", + 16 + ], + [ + "C", + "AbC", + 4 + ], + [ + "C", + "AbCCaCbc", + 14 + ], + [ + "C", + "Abb", + 6 + ], + [ + "C", + "AbbCcBb", + 12 + ], + [ + "C", + "Acbc", + 7 + ], + [ + "C", + "B", + 2 + ], + [ + "C", + "BAAbAbCa", + 14 + ], + [ + "C", + "BAAc", + 7 + ], + [ + "C", + "BACcBbAcB", + 16 + ], + [ + "C", + "BBBaAcB", + 13 + ], + [ + "C", + "BBacaaA", + 13 + ], + [ + "C", + "BC", + 2 + ], + [ + "C", + "BCCbA", + 8 + ], + [ + "C", + "BCba", + 6 + ], + [ + "C", + "Ba", + 4 + ], + [ + "C", + "BaA", + 6 + ], + [ + "C", + "BaBCCBcb", + 14 + ], + [ + "C", + "BaBcbbCBA", + 16 + ], + [ + "C", + "BaaC", + 6 + ], + [ + "C", + "BabbcCBa", + 14 + ], + [ + "C", + "BacccCB", + 12 + ], + [ + "C", + "BbABc", + 9 + ], + [ + "C", + "BbAaAAC", + 12 + ], + [ + "C", + "BbBBcc", + 11 + ], + [ + "C", + "BbCBCB", + 10 + ], + [ + "C", + "BbcCCbAC", + 14 + ], + [ + "C", + "BcB", + 5 + ], + [ + "C", + "BcBBBbAaa", + 17 + ], + [ + "C", + "BcCAcacAB", + 16 + ], + [ + "C", + "BcCB", + 6 + ], + [ + "C", + "BcacCaB", + 12 + ], + [ + "C", + "BccAaa", + 11 + ], + [ + "C", + "BccaAa", + 11 + ], + [ + "C", + "C", + 0 + ], + [ + "C", + "CA", + 2 + ], + [ + "C", + "CAAbCa", + 10 + ], + [ + "C", + "CABBB", + 8 + ], + [ + "C", + "CAaAa", + 8 + ], + [ + "C", + "CAbAABb", + 12 + ], + [ + "C", + "CBBCaABbB", + 16 + ], + [ + "C", + "CBaacB", + 10 + ], + [ + "C", + "CBc", + 4 + ], + [ + "C", + "CC", + 2 + ], + [ + "C", + "CCA", + 4 + ], + [ + "C", + "CCBbccA", + 12 + ], + [ + "C", + "CCc", + 4 + ], + [ + "C", + "CCcbbCBCc", + 16 + ], + [ + "C", + "CCcc", + 6 + ], + [ + "C", + "CCccCaCa", + 14 + ], + [ + "C", + "Ca", + 2 + ], + [ + "C", + "CaA", + 4 + ], + [ + "C", + "Caab", + 6 + ], + [ + "C", + "Cacaacba", + 14 + ], + [ + "C", + "Cb", + 2 + ], + [ + "C", + "CbaCBcAb", + 14 + ], + [ + "C", + "CbbBCbC", + 12 + ], + [ + "C", + "Cc", + 2 + ], + [ + "C", + "CcAcCA", + 10 + ], + [ + "C", + "CcBBCbBB", + 14 + ], + [ + "C", + "CcCBBbB", + 12 + ], + [ + "C", + "a", + 2 + ], + [ + "C", + "aA", + 4 + ], + [ + "C", + "aAABBb", + 12 + ], + [ + "C", + "aACBaca", + 12 + ], + [ + "C", + "aAaCB", + 8 + ], + [ + "C", + "aAaaBcaB", + 15 + ], + [ + "C", + "aAabb", + 10 + ], + [ + "C", + "aAccAABB", + 15 + ], + [ + "C", + "aBAaa", + 10 + ], + [ + "C", + "aBbab", + 10 + ], + [ + "C", + "aCBccCbBc", + 16 + ], + [ + "C", + "aCCBcbcBc", + 16 + ], + [ + "C", + "aCCC", + 6 + ], + [ + "C", + "aCcB", + 6 + ], + [ + "C", + "aCcccA", + 10 + ], + [ + "C", + "aa", + 4 + ], + [ + "C", + "aaBA", + 8 + ], + [ + "C", + "aaBAbA", + 12 + ], + [ + "C", + "aaBabBB", + 14 + ], + [ + "C", + "aaCAC", + 8 + ], + [ + "C", + "aaCBb", + 8 + ], + [ + "C", + "aaaBcBBc", + 15 + ], + [ + "C", + "aaab", + 8 + ], + [ + "C", + "aab", + 6 + ], + [ + "C", + "aacCCabb", + 14 + ], + [ + "C", + "abBbAcaCc", + 16 + ], + [ + "C", + "abbbAaaC", + 14 + ], + [ + "C", + "abcBBB", + 11 + ], + [ + "C", + "ac", + 3 + ], + [ + "C", + "b", + 2 + ], + [ + "C", + "bAAAccb", + 13 + ], + [ + "C", + "bAAaCBaCa", + 16 + ], + [ + "C", + "bAaABACCb", + 16 + ], + [ + "C", + "bAbAcCAc", + 14 + ], + [ + "C", + "bBABA", + 10 + ], + [ + "C", + "bBB", + 6 + ], + [ + "C", + "bBacA", + 9 + ], + [ + "C", + "bBcbbCabb", + 16 + ], + [ + "C", + "bC", + 2 + ], + [ + "C", + "bCcAcACba", + 16 + ], + [ + "C", + "ba", + 4 + ], + [ + "C", + "baAA", + 8 + ], + [ + "C", + "baAba", + 10 + ], + [ + "C", + "baCABab", + 12 + ], + [ + "C", + "baaA", + 8 + ], + [ + "C", + "baaB", + 8 + ], + [ + "C", + "baaCbCb", + 12 + ], + [ + "C", + "bbABBCA", + 12 + ], + [ + "C", + "bbABcCb", + 12 + ], + [ + "C", + "bbCab", + 8 + ], + [ + "C", + "bbacCaabC", + 16 + ], + [ + "C", + "bbbcaAb", + 13 + ], + [ + "C", + "bc", + 3 + ], + [ + "C", + "bcAca", + 9 + ], + [ + "C", + "bcBAABAAC", + 16 + ], + [ + "C", + "bcBcA", + 9 + ], + [ + "C", + "bcC", + 4 + ], + [ + "C", + "bcCAb", + 8 + ], + [ + "C", + "bcaAb", + 9 + ], + [ + "C", + "bcacBAC", + 12 + ], + [ + "C", + "bcb", + 5 + ], + [ + "C", + "bcbBba", + 11 + ], + [ + "C", + "bcbacaAA", + 15 + ], + [ + "C", + "bccC", + 6 + ], + [ + "C", + "bccccCA", + 12 + ], + [ + "C", + "c", + 1 + ], + [ + "C", + "cAc", + 5 + ], + [ + "C", + "cAcBCbCb", + 14 + ], + [ + "C", + "cAcaABCA", + 14 + ], + [ + "C", + "cBAA", + 7 + ], + [ + "C", + "cBBB", + 7 + ], + [ + "C", + "cBc", + 5 + ], + [ + "C", + "cBccbAA", + 13 + ], + [ + "C", + "cC", + 2 + ], + [ + "C", + "cCBAAB", + 10 + ], + [ + "C", + "cCaACAAC", + 14 + ], + [ + "C", + "cCbA", + 6 + ], + [ + "C", + "cCbbABa", + 12 + ], + [ + "C", + "cCcabCbBb", + 16 + ], + [ + "C", + "ca", + 3 + ], + [ + "C", + "caCACCCaB", + 16 + ], + [ + "C", + "cabCa", + 8 + ], + [ + "C", + "cacACaBB", + 14 + ], + [ + "C", + "cacBaACc", + 14 + ], + [ + "C", + "cbACabc", + 12 + ], + [ + "C", + "cbCCB", + 8 + ], + [ + "C", + "cbcC", + 6 + ], + [ + "C", + "cc", + 3 + ], + [ + "C", + "ccBAbBBC", + 14 + ], + [ + "C", + "ccBaC", + 8 + ], + [ + "C", + "ccaCbbCbb", + 16 + ], + [ + "C", + "ccabC", + 8 + ], + [ + "C", + "ccbBbCCc", + 14 + ], + [ + "CA", + "A", + 2 + ], + [ + "CA", + "AAa", + 4 + ], + [ + "CA", + "Aaacbb", + 11 + ], + [ + "CA", + "AcC", + 5 + ], + [ + "CA", + "BBaB", + 7 + ], + [ + "CA", + "BcAcbBC", + 11 + ], + [ + "CA", + "C", + 2 + ], + [ + "CA", + "CBCAa", + 6 + ], + [ + "CA", + "CacbbBaa", + 13 + ], + [ + "CA", + "CcBcBAB", + 10 + ], + [ + "CA", + "CcbCaBB", + 11 + ], + [ + "CA", + "a", + 3 + ], + [ + "CA", + "aAABAaC", + 12 + ], + [ + "CA", + "aABBa", + 8 + ], + [ + "CA", + "abbCC", + 8 + ], + [ + "CA", + "acbb", + 7 + ], + [ + "CA", + "bAbAAcbA", + 13 + ], + [ + "CA", + "bAcBcACC", + 13 + ], + [ + "CA", + "bCBaBBaB", + 13 + ], + [ + "CA", + "bbbB", + 8 + ], + [ + "CA", + "cAaaaA", + 9 + ], + [ + "CA", + "caCBCcaaA", + 14 + ], + [ + "CAA", + "CCbc", + 6 + ], + [ + "CAA", + "CbCcba", + 9 + ], + [ + "CAA", + "bb", + 6 + ], + [ + "CAA", + "c", + 5 + ], + [ + "CAA", + "cACAaa", + 7 + ], + [ + "CAA", + "cAaabbacA", + 13 + ], + [ + "CAAA", + "bb", + 8 + ], + [ + "CAAAAAcCB", + "bC", + 16 + ], + [ + "CAAAB", + "ba", + 9 + ], + [ + "CAAABaBAc", + "CaaC", + 12 + ], + [ + "CAAACa", + "AAcbAAc", + 9 + ], + [ + "CAAACaAC", + "aABBcbcBa", + 15 + ], + [ + "CAAAaBAa", + "BCBc", + 14 + ], + [ + "CAAAba", + "CacBaB", + 8 + ], + [ + "CAAAbb", + "cCaCb", + 8 + ], + [ + "CAAB", + "CbcCbBBA", + 12 + ], + [ + "CAABAAcBC", + "bccb", + 14 + ], + [ + "CAABAAcbB", + "ABBa", + 13 + ], + [ + "CAABCaaBa", + "aBCACcBca", + 12 + ], + [ + "CAABCcAAa", + "ccCB", + 15 + ], + [ + "CAABbaA", + "AbBaAac", + 10 + ], + [ + "CAAC", + "cacABc", + 7 + ], + [ + "CAACAAC", + "Ab", + 12 + ], + [ + "CAACAbca", + "Bb", + 14 + ], + [ + "CAACCAc", + "CAAB", + 8 + ], + [ + "CAACb", + "CA", + 6 + ], + [ + "CAAa", + "cBCC", + 7 + ], + [ + "CAAaBaAC", + "AaccBBB", + 13 + ], + [ + "CAAaaA", + "CaAaACca", + 7 + ], + [ + "CAAab", + "b", + 8 + ], + [ + "CAAabac", + "Accbbc", + 8 + ], + [ + "CAAbCbCcC", + "B", + 17 + ], + [ + "CAAbb", + "caC", + 8 + ], + [ + "CAAbbAbb", + "BC", + 15 + ], + [ + "CAAcBB", + "aCBCbAAb", + 13 + ], + [ + "CAAccAcC", + "abA", + 13 + ], + [ + "CAB", + "ABabCcc", + 12 + ], + [ + "CAB", + "ABccbC", + 10 + ], + [ + "CAB", + "CABba", + 4 + ], + [ + "CAB", + "CcbB", + 4 + ], + [ + "CAB", + "aababa", + 10 + ], + [ + "CAB", + "bC", + 6 + ], + [ + "CAB", + "cAbbABAac", + 13 + ], + [ + "CABA", + "CaabCCc", + 10 + ], + [ + "CABAAa", + "abC", + 10 + ], + [ + "CABACacA", + "cAbaaABC", + 10 + ], + [ + "CABACcA", + "B", + 12 + ], + [ + "CABAa", + "aac", + 8 + ], + [ + "CABAcBa", + "b", + 13 + ], + [ + "CABBAa", + "bbBcabcC", + 13 + ], + [ + "CABBBAa", + "B", + 12 + ], + [ + "CABBBCaa", + "ACb", + 12 + ], + [ + "CABBBb", + "cacaAACa", + 14 + ], + [ + "CABC", + "cCbacA", + 9 + ], + [ + "CABCAcaC", + "B", + 14 + ], + [ + "CABa", + "B", + 6 + ], + [ + "CABaCc", + "BCaaaAAcb", + 11 + ], + [ + "CABab", + "baB", + 6 + ], + [ + "CABacBA", + "BaACb", + 10 + ], + [ + "CABb", + "bCcBaCba", + 10 + ], + [ + "CABbABcBA", + "aBaAccabA", + 10 + ], + [ + "CABbbC", + "CbACCAcc", + 11 + ], + [ + "CABcAaAb", + "bb", + 13 + ], + [ + "CABcaa", + "C", + 10 + ], + [ + "CABcaa", + "aCaBABAab", + 10 + ], + [ + "CABcabCAa", + "AcbaBcCA", + 11 + ], + [ + "CABcbCAc", + "ABAcc", + 9 + ], + [ + "CABcbbA", + "BBbcA", + 8 + ], + [ + "CABcbcacA", + "cb", + 14 + ], + [ + "CAC", + "aCAAaABb", + 12 + ], + [ + "CAC", + "abCCACaBc", + 12 + ], + [ + "CAC", + "bbcbB", + 9 + ], + [ + "CAC", + "caBAa", + 7 + ], + [ + "CAC", + "ccBaBcb", + 11 + ], + [ + "CACAACccb", + "bc", + 16 + ], + [ + "CACABBA", + "cCACAcCcC", + 10 + ], + [ + "CACACAcBB", + "aBAACCc", + 12 + ], + [ + "CACAabc", + "cbAaBbbbB", + 13 + ], + [ + "CACAcaAC", + "ACcACc", + 8 + ], + [ + "CACAcbC", + "Cc", + 10 + ], + [ + "CACB", + "Cbc", + 5 + ], + [ + "CACBb", + "C", + 8 + ], + [ + "CACC", + "bCa", + 6 + ], + [ + "CACCAAB", + "bACabAC", + 8 + ], + [ + "CACCAb", + "abBBB", + 10 + ], + [ + "CACCCBA", + "cabaac", + 12 + ], + [ + "CACCc", + "ba", + 9 + ], + [ + "CACaAcc", + "acaBbCbb", + 13 + ], + [ + "CACaCBBc", + "a", + 14 + ], + [ + "CACaabcBb", + "aCabba", + 10 + ], + [ + "CACacaABb", + "b", + 16 + ], + [ + "CACb", + "ABbb", + 6 + ], + [ + "CACb", + "AabbaCa", + 11 + ], + [ + "CACbA", + "bCbbC", + 8 + ], + [ + "CACbaCB", + "caacaaC", + 9 + ], + [ + "CACbaaCa", + "bBacacB", + 12 + ], + [ + "CACbbBBc", + "Bc", + 12 + ], + [ + "CACbc", + "Cc", + 6 + ], + [ + "CACbcAcac", + "cCAcA", + 10 + ], + [ + "CACbcba", + "caABaCb", + 10 + ], + [ + "CACcBabCc", + "baAbbaBB", + 13 + ], + [ + "CACcCacC", + "ABcC", + 10 + ], + [ + "CACccCAC", + "B", + 16 + ], + [ + "CAa", + "Ab", + 4 + ], + [ + "CAa", + "CabcCc", + 9 + ], + [ + "CAa", + "aaCAbaBc", + 10 + ], + [ + "CAa", + "bABABaCA", + 12 + ], + [ + "CAa", + "bBAaB", + 6 + ], + [ + "CAa", + "bca", + 4 + ], + [ + "CAa", + "cbC", + 5 + ], + [ + "CAaAAaA", + "abAbbcbaC", + 14 + ], + [ + "CAaAAbaaB", + "CAcBB", + 11 + ], + [ + "CAaAcb", + "bBCBB", + 11 + ], + [ + "CAaBAA", + "AacAcBABB", + 11 + ], + [ + "CAaBB", + "Cc", + 8 + ], + [ + "CAaBBACa", + "CAaacBccC", + 9 + ], + [ + "CAaBC", + "b", + 9 + ], + [ + "CAaBbbaBA", + "BBB", + 13 + ], + [ + "CAaC", + "AaBCacAba", + 14 + ], + [ + "CAaC", + "BcccCbBb", + 13 + ], + [ + "CAaCBbcab", + "CbC", + 13 + ], + [ + "CAaCc", + "AA", + 7 + ], + [ + "CAaCcabB", + "cBABCb", + 11 + ], + [ + "CAaCccCc", + "A", + 14 + ], + [ + "CAaa", + "bcABBaAb", + 10 + ], + [ + "CAaa", + "cbabABAC", + 12 + ], + [ + "CAaaB", + "b", + 9 + ], + [ + "CAaabBcC", + "a", + 14 + ], + [ + "CAaabbCac", + "bAC", + 14 + ], + [ + "CAaabcaB", + "cabCacbaA", + 12 + ], + [ + "CAabABbAa", + "bcbaCa", + 13 + ], + [ + "CAabac", + "baaABbB", + 10 + ], + [ + "CAabb", + "b", + 8 + ], + [ + "CAabb", + "cACACBaBB", + 10 + ], + [ + "CAac", + "aaB", + 5 + ], + [ + "CAac", + "cccBB", + 9 + ], + [ + "CAacAB", + "a", + 10 + ], + [ + "CAaccC", + "cacbc", + 6 + ], + [ + "CAb", + "ACCCAcaA", + 12 + ], + [ + "CAb", + "Aca", + 6 + ], + [ + "CAb", + "BCcBBAA", + 10 + ], + [ + "CAb", + "C", + 4 + ], + [ + "CAb", + "CCAcbAB", + 8 + ], + [ + "CAb", + "CcCbCBC", + 10 + ], + [ + "CAb", + "acAc", + 5 + ], + [ + "CAb", + "bab", + 3 + ], + [ + "CAb", + "cA", + 3 + ], + [ + "CAbAAaAA", + "abc", + 13 + ], + [ + "CAbAc", + "ABBCCB", + 10 + ], + [ + "CAbB", + "acC", + 7 + ], + [ + "CAbBBBB", + "BCcaBbabB", + 10 + ], + [ + "CAbBCCBAC", + "baA", + 14 + ], + [ + "CAbBab", + "cbABcBc", + 10 + ], + [ + "CAbBc", + "bBcAcCA", + 11 + ], + [ + "CAbBc", + "bCAcbba", + 7 + ], + [ + "CAbC", + "AaAc", + 6 + ], + [ + "CAbC", + "cBAC", + 5 + ], + [ + "CAbCBaBb", + "cAbcBa", + 6 + ], + [ + "CAbCCC", + "c", + 11 + ], + [ + "CAbCabbA", + "BbAABACba", + 12 + ], + [ + "CAbCcc", + "babBA", + 9 + ], + [ + "CAba", + "abbB", + 6 + ], + [ + "CAbaAbBBC", + "CbBBAbB", + 9 + ], + [ + "CAbaAcCCC", + "AcbB", + 14 + ], + [ + "CAbaBb", + "A", + 10 + ], + [ + "CAbaa", + "cc", + 9 + ], + [ + "CAbacbba", + "cBCccabA", + 10 + ], + [ + "CAbbAA", + "BAAaCbC", + 12 + ], + [ + "CAbbAAcC", + "CBBACbBCB", + 12 + ], + [ + "CAbbBCcB", + "Abca", + 10 + ], + [ + "CAbbBbC", + "ABcaca", + 11 + ], + [ + "CAbbbAC", + "bcB", + 11 + ], + [ + "CAbbcCABA", + "CbB", + 12 + ], + [ + "CAbc", + "B", + 7 + ], + [ + "CAbcA", + "CAcaccACb", + 10 + ], + [ + "CAbcACCB", + "BB", + 13 + ], + [ + "CAbcBAa", + "bccBACB", + 10 + ], + [ + "CAbcCca", + "cAc", + 9 + ], + [ + "CAbcaBbca", + "ccaacBaaa", + 12 + ], + [ + "CAc", + "AAcacbcC", + 12 + ], + [ + "CAc", + "AbbAbbcc", + 12 + ], + [ + "CAc", + "BAB", + 4 + ], + [ + "CAc", + "ab", + 5 + ], + [ + "CAc", + "b", + 6 + ], + [ + "CAc", + "bbaaac", + 9 + ], + [ + "CAcAaCcaC", + "AAa", + 12 + ], + [ + "CAcAbaaA", + "ccBcBc", + 12 + ], + [ + "CAcAcC", + "BAbCb", + 9 + ], + [ + "CAcAca", + "CCbb", + 9 + ], + [ + "CAcAcbbAc", + "Cca", + 13 + ], + [ + "CAcB", + "cBcaaCcB", + 10 + ], + [ + "CAcBbCccb", + "BBAbAbAB", + 15 + ], + [ + "CAcBbbAaA", + "aACbbCbaa", + 9 + ], + [ + "CAcBbcbCa", + "bcBc", + 12 + ], + [ + "CAcBcBC", + "abCaCb", + 11 + ], + [ + "CAcC", + "CBcB", + 4 + ], + [ + "CAcCACCA", + "cAAa", + 10 + ], + [ + "CAcCaCBCC", + "aac", + 14 + ], + [ + "CAca", + "AaBACbAab", + 13 + ], + [ + "CAcaABcab", + "aCCbC", + 14 + ], + [ + "CAcaaa", + "bbccA", + 9 + ], + [ + "CAcaacBB", + "c", + 14 + ], + [ + "CAcb", + "B", + 7 + ], + [ + "CAcb", + "aBCBAb", + 8 + ], + [ + "CAcbBA", + "bBAaba", + 9 + ], + [ + "CAcbBB", + "CCcCBA", + 6 + ], + [ + "CAcbBacb", + "AbbbB", + 10 + ], + [ + "CAcbCCaaC", + "bccB", + 14 + ], + [ + "CAcbCbc", + "bAcCA", + 8 + ], + [ + "CAcbbabC", + "abAccCaac", + 11 + ], + [ + "CAcbcA", + "BBca", + 8 + ], + [ + "CAcbcB", + "Ab", + 8 + ], + [ + "CAcc", + "b", + 8 + ], + [ + "CAccAaAcc", + "bccbAB", + 12 + ], + [ + "CAccBaAC", + "abbAAaB", + 13 + ], + [ + "CAccBaaCc", + "BCAb", + 15 + ], + [ + "CAccBbA", + "bcBbBcBc", + 13 + ], + [ + "CAccac", + "aAc", + 8 + ], + [ + "CB", + "A", + 4 + ], + [ + "CB", + "ABac", + 6 + ], + [ + "CB", + "AC", + 4 + ], + [ + "CB", + "ACbbcbb", + 11 + ], + [ + "CB", + "ACcCCBAC", + 12 + ], + [ + "CB", + "AaAAcBc", + 11 + ], + [ + "CB", + "AaBCab", + 9 + ], + [ + "CB", + "BCc", + 4 + ], + [ + "CB", + "BaCaB", + 6 + ], + [ + "CB", + "BccbcabCB", + 14 + ], + [ + "CB", + "C", + 2 + ], + [ + "CB", + "CAAAb", + 7 + ], + [ + "CB", + "CCba", + 5 + ], + [ + "CB", + "CaAcA", + 8 + ], + [ + "CB", + "CcCaAccb", + 13 + ], + [ + "CB", + "a", + 4 + ], + [ + "CB", + "aAa", + 6 + ], + [ + "CB", + "aBCBaBbC", + 12 + ], + [ + "CB", + "aCbcAc", + 9 + ], + [ + "CB", + "ac", + 4 + ], + [ + "CB", + "bAa", + 6 + ], + [ + "CB", + "bBAAbcb", + 12 + ], + [ + "CB", + "bCB", + 2 + ], + [ + "CB", + "bCaCCcaCA", + 16 + ], + [ + "CB", + "ba", + 4 + ], + [ + "CB", + "baBCcCc", + 12 + ], + [ + "CB", + "bbcbCB", + 8 + ], + [ + "CB", + "bcaab", + 8 + ], + [ + "CB", + "c", + 3 + ], + [ + "CB", + "cACca", + 8 + ], + [ + "CB", + "cBCbAB", + 8 + ], + [ + "CB", + "cCB", + 2 + ], + [ + "CB", + "cbb", + 4 + ], + [ + "CB", + "cbbBbACCA", + 15 + ], + [ + "CBA", + "ba", + 4 + ], + [ + "CBA", + "cbcBb", + 7 + ], + [ + "CBAA", + "ABBaBcB", + 11 + ], + [ + "CBAA", + "Ba", + 5 + ], + [ + "CBAA", + "bcc", + 7 + ], + [ + "CBAABa", + "BAaBA", + 4 + ], + [ + "CBAAC", + "CBAac", + 2 + ], + [ + "CBAAa", + "cccbAb", + 9 + ], + [ + "CBAAaac", + "bcAAb", + 10 + ], + [ + "CBAAbCc", + "bbaABBB", + 9 + ], + [ + "CBAAbbBC", + "CbBAaAc", + 10 + ], + [ + "CBAAc", + "AAA", + 6 + ], + [ + "CBAAc", + "bCbBbAAaC", + 9 + ], + [ + "CBAB", + "A", + 6 + ], + [ + "CBABAbcBA", + "b", + 16 + ], + [ + "CBABAcBc", + "cAb", + 12 + ], + [ + "CBABCacb", + "aCCbbBABA", + 14 + ], + [ + "CBABaa", + "cBbcCcc", + 11 + ], + [ + "CBABbbCa", + "BbAaA", + 11 + ], + [ + "CBABbcCCC", + "cCAC", + 12 + ], + [ + "CBABc", + "cCc", + 7 + ], + [ + "CBABccBbc", + "caAaaACbb", + 13 + ], + [ + "CBACAA", + "CCc", + 8 + ], + [ + "CBACAcC", + "aCbbc", + 10 + ], + [ + "CBACa", + "BACaBBaB", + 10 + ], + [ + "CBACbcB", + "a", + 13 + ], + [ + "CBACc", + "baCCCA", + 9 + ], + [ + "CBACcAccA", + "aAb", + 15 + ], + [ + "CBAaAC", + "ccbC", + 9 + ], + [ + "CBAaBaC", + "bCccccCb", + 14 + ], + [ + "CBAaCB", + "acabB", + 8 + ], + [ + "CBAaCa", + "Cabb", + 8 + ], + [ + "CBAaCc", + "cBBBBBaC", + 11 + ], + [ + "CBAabb", + "bbCabaBa", + 10 + ], + [ + "CBAacCa", + "Bccbacb", + 11 + ], + [ + "CBAb", + "cCAcbc", + 7 + ], + [ + "CBAbCcaB", + "aC", + 13 + ], + [ + "CBAba", + "CbbabA", + 5 + ], + [ + "CBAbabb", + "BABa", + 7 + ], + [ + "CBAbba", + "ba", + 8 + ], + [ + "CBAcAAbcb", + "BBBBBbABA", + 15 + ], + [ + "CBAcC", + "acbabBA", + 11 + ], + [ + "CBAccB", + "cb", + 9 + ], + [ + "CBAccab", + "cbB", + 11 + ], + [ + "CBB", + "Aa", + 6 + ], + [ + "CBB", + "BbAaC", + 9 + ], + [ + "CBB", + "CB", + 2 + ], + [ + "CBB", + "CCA", + 4 + ], + [ + "CBB", + "CcbCb", + 6 + ], + [ + "CBB", + "baBB", + 4 + ], + [ + "CBB", + "cAcBBccA", + 11 + ], + [ + "CBB", + "cBccaB", + 7 + ], + [ + "CBBABB", + "BbBb", + 6 + ], + [ + "CBBABC", + "AABcaac", + 10 + ], + [ + "CBBAbACb", + "CCBCbAbcB", + 8 + ], + [ + "CBBBA", + "bB", + 7 + ], + [ + "CBBBBaAC", + "ca", + 13 + ], + [ + "CBBBBbbcC", + "BaAbCaB", + 14 + ], + [ + "CBBBb", + "bCbaBBAb", + 7 + ], + [ + "CBBBbCbcA", + "ABCCcABc", + 13 + ], + [ + "CBBC", + "ACaca", + 8 + ], + [ + "CBBC", + "cB", + 5 + ], + [ + "CBBCAAB", + "b", + 13 + ], + [ + "CBBCAb", + "CBA", + 6 + ], + [ + "CBBCCAB", + "AbCa", + 10 + ], + [ + "CBBCCa", + "c", + 11 + ], + [ + "CBBCabAa", + "Cca", + 11 + ], + [ + "CBBaCc", + "CbbA", + 7 + ], + [ + "CBBab", + "acBCcA", + 9 + ], + [ + "CBBabb", + "BBCcBb", + 7 + ], + [ + "CBBacBacB", + "caCCccBc", + 12 + ], + [ + "CBBbAb", + "Bbab", + 5 + ], + [ + "CBBba", + "bcCcb", + 9 + ], + [ + "CBBbaAcbc", + "ABcABaAAc", + 11 + ], + [ + "CBBbbbabc", + "baAaBC", + 12 + ], + [ + "CBBbcaaC", + "bABABABB", + 13 + ], + [ + "CBBc", + "abCABc", + 6 + ], + [ + "CBBcACB", + "abBbC", + 9 + ], + [ + "CBBcBcc", + "A", + 14 + ], + [ + "CBBcbA", + "ccbBAca", + 9 + ], + [ + "CBBcbaBc", + "C", + 14 + ], + [ + "CBBcbaC", + "bBcAAbaaC", + 9 + ], + [ + "CBBccBCCB", + "bacCC", + 11 + ], + [ + "CBBccc", + "aBabc", + 8 + ], + [ + "CBC", + "ACB", + 4 + ], + [ + "CBC", + "CAbCabB", + 9 + ], + [ + "CBC", + "aCaAaAC", + 10 + ], + [ + "CBCAA", + "C", + 8 + ], + [ + "CBCAABa", + "BBcCbBa", + 7 + ], + [ + "CBCAACB", + "bBBcAAB", + 7 + ], + [ + "CBCACAa", + "ABbA", + 10 + ], + [ + "CBCAaCA", + "BbaAbac", + 10 + ], + [ + "CBCAacCc", + "cCb", + 12 + ], + [ + "CBCB", + "aAAaA", + 10 + ], + [ + "CBCBBA", + "acc", + 11 + ], + [ + "CBCBBCAA", + "ABC", + 12 + ], + [ + "CBCBC", + "aBccbCB", + 8 + ], + [ + "CBCBCC", + "BAbc", + 8 + ], + [ + "CBCC", + "CbaaA", + 7 + ], + [ + "CBCCBC", + "aACAA", + 10 + ], + [ + "CBCCBCcCb", + "Ba", + 16 + ], + [ + "CBCCCB", + "cacbAbbaA", + 15 + ], + [ + "CBCCCbaB", + "cacAbc", + 12 + ], + [ + "CBCCacb", + "a", + 12 + ], + [ + "CBCCbcc", + "BbbBcbCBc", + 11 + ], + [ + "CBCCcCbA", + "CBaAa", + 11 + ], + [ + "CBCa", + "aaAbbabA", + 13 + ], + [ + "CBCa", + "b", + 7 + ], + [ + "CBCaA", + "ab", + 8 + ], + [ + "CBCaAaBaa", + "acBbAa", + 12 + ], + [ + "CBCaB", + "caa", + 7 + ], + [ + "CBCacBBBB", + "BcabACCb", + 12 + ], + [ + "CBCb", + "AabACCa", + 11 + ], + [ + "CBCb", + "aABc", + 7 + ], + [ + "CBCbBa", + "abaCaB", + 9 + ], + [ + "CBCbbc", + "CcBCBCcbA", + 9 + ], + [ + "CBCbccaA", + "AbCbbCba", + 9 + ], + [ + "CBCc", + "bbcCBBAcb", + 12 + ], + [ + "CBCcB", + "BAa", + 8 + ], + [ + "CBCcBbb", + "ccaCBbA", + 8 + ], + [ + "CBCcccacB", + "BA", + 15 + ], + [ + "CBa", + "ACaba", + 5 + ], + [ + "CBa", + "CAaB", + 4 + ], + [ + "CBa", + "CBBCccc", + 10 + ], + [ + "CBa", + "CacAccB", + 11 + ], + [ + "CBa", + "c", + 5 + ], + [ + "CBaAAa", + "caCcaBAA", + 9 + ], + [ + "CBaAC", + "CBb", + 6 + ], + [ + "CBaAbaaAA", + "CbbcC", + 13 + ], + [ + "CBaB", + "aabBAbbC", + 12 + ], + [ + "CBaBBAa", + "AaAcA", + 10 + ], + [ + "CBaBCABC", + "AAA", + 13 + ], + [ + "CBaBaCcB", + "cBaAbBAAa", + 12 + ], + [ + "CBaBaa", + "AAB", + 9 + ], + [ + "CBaCAbC", + "BbCaCC", + 7 + ], + [ + "CBaCBba", + "bcABB", + 10 + ], + [ + "CBaCCAB", + "cBcBAcA", + 10 + ], + [ + "CBaCabccB", + "Bba", + 14 + ], + [ + "CBaaA", + "AacbaC", + 10 + ], + [ + "CBaaAcac", + "aacbcbACc", + 13 + ], + [ + "CBaaB", + "CbaAcB", + 4 + ], + [ + "CBaaBc", + "Ba", + 8 + ], + [ + "CBaaCaCa", + "c", + 15 + ], + [ + "CBaaaBB", + "B", + 12 + ], + [ + "CBaab", + "BaabBcba", + 10 + ], + [ + "CBaab", + "bBB", + 7 + ], + [ + "CBaabAB", + "CBCC", + 10 + ], + [ + "CBaacACCC", + "a", + 16 + ], + [ + "CBab", + "CB", + 4 + ], + [ + "CBab", + "aBcc", + 6 + ], + [ + "CBabACCaA", + "A", + 16 + ], + [ + "CBabCbbaC", + "AcbAc", + 12 + ], + [ + "CBacA", + "acBCCaCB", + 10 + ], + [ + "CBacaCBCB", + "aB", + 14 + ], + [ + "CBacbacB", + "CaBa", + 9 + ], + [ + "CBb", + "Cbb", + 1 + ], + [ + "CBb", + "a", + 6 + ], + [ + "CBb", + "bBbcc", + 6 + ], + [ + "CBb", + "bCaaaA", + 10 + ], + [ + "CBbA", + "bAaCbBC", + 10 + ], + [ + "CBbAAa", + "aabB", + 10 + ], + [ + "CBbAB", + "A", + 8 + ], + [ + "CBbAB", + "bbb", + 6 + ], + [ + "CBbACca", + "CbCAcB", + 7 + ], + [ + "CBbACcbC", + "bCcbBAb", + 12 + ], + [ + "CBbBB", + "C", + 8 + ], + [ + "CBbBB", + "CBCBcCBa", + 8 + ], + [ + "CBbBBCaBB", + "AbAca", + 13 + ], + [ + "CBbCA", + "aca", + 8 + ], + [ + "CBbCCB", + "BAbC", + 8 + ], + [ + "CBbCCCa", + "Ca", + 10 + ], + [ + "CBbCCb", + "CACbBBb", + 8 + ], + [ + "CBbCbbBc", + "ABaA", + 14 + ], + [ + "CBbaAcAAc", + "ccAACB", + 12 + ], + [ + "CBbaAca", + "bB", + 12 + ], + [ + "CBbaB", + "B", + 8 + ], + [ + "CBbaBBCaC", + "baaCcA", + 12 + ], + [ + "CBbaC", + "c", + 9 + ], + [ + "CBbaCa", + "cbbcAa", + 6 + ], + [ + "CBbaCbB", + "AcCcACbA", + 10 + ], + [ + "CBbabC", + "abB", + 8 + ], + [ + "CBbb", + "C", + 6 + ], + [ + "CBbb", + "a", + 8 + ], + [ + "CBbbbaB", + "B", + 12 + ], + [ + "CBbc", + "BaAABc", + 9 + ], + [ + "CBbcBAAB", + "cAbCAA", + 8 + ], + [ + "CBbcbb", + "cBCaC", + 8 + ], + [ + "CBc", + "Bcab", + 6 + ], + [ + "CBc", + "CBAAacc", + 8 + ], + [ + "CBc", + "abaCa", + 8 + ], + [ + "CBc", + "cAabccaaA", + 14 + ], + [ + "CBcA", + "CCA", + 3 + ], + [ + "CBcAAaccC", + "abBcAbaBC", + 10 + ], + [ + "CBcAaCCCb", + "aB", + 15 + ], + [ + "CBcAbAA", + "BabCcAAc", + 11 + ], + [ + "CBcAcB", + "CbbAAA", + 7 + ], + [ + "CBcB", + "a", + 8 + ], + [ + "CBcB", + "bcCBCCcbb", + 11 + ], + [ + "CBcBA", + "cBbCb", + 7 + ], + [ + "CBcBBABcc", + "bbBcabA", + 13 + ], + [ + "CBcBC", + "cAbCAAbcA", + 13 + ], + [ + "CBcBaaACB", + "cCc", + 14 + ], + [ + "CBcBb", + "c", + 8 + ], + [ + "CBcC", + "bCBBbBa", + 10 + ], + [ + "CBcC", + "c", + 6 + ], + [ + "CBcCC", + "aB", + 8 + ], + [ + "CBca", + "cC", + 6 + ], + [ + "CBcaAa", + "A", + 10 + ], + [ + "CBcaAba", + "AaAAaaCaA", + 13 + ], + [ + "CBcaBCc", + "AcBcb", + 9 + ], + [ + "CBcabbbba", + "bCCBc", + 15 + ], + [ + "CBcacCbCC", + "bCAaab", + 13 + ], + [ + "CBcb", + "Acb", + 4 + ], + [ + "CBcb", + "CbcABCA", + 8 + ], + [ + "CBcb", + "cBAac", + 7 + ], + [ + "CBcbCbc", + "cBBaBc", + 7 + ], + [ + "CBcbCcaBc", + "BAACAaC", + 11 + ], + [ + "CBcba", + "abCA", + 7 + ], + [ + "CBcbab", + "ABBabBC", + 9 + ], + [ + "CBcbbaC", + "ABcCa", + 8 + ], + [ + "CBcbcAAA", + "aaAbb", + 14 + ], + [ + "CBcbcbC", + "c", + 12 + ], + [ + "CBccaC", + "CAAa", + 8 + ], + [ + "CBccaCaaa", + "ccbBabcBB", + 15 + ], + [ + "CBccac", + "aB", + 10 + ], + [ + "CBccbaAbb", + "bBaacaC", + 14 + ], + [ + "CBccbbc", + "ACaAaCB", + 13 + ], + [ + "CC", + "AA", + 4 + ], + [ + "CC", + "AAaacAc", + 12 + ], + [ + "CC", + "ACACbCABB", + 14 + ], + [ + "CC", + "ACBaCAb", + 10 + ], + [ + "CC", + "ACaaB", + 8 + ], + [ + "CC", + "ACcCAaabb", + 14 + ], + [ + "CC", + "AacCBBc", + 11 + ], + [ + "CC", + "BaAACABCC", + 14 + ], + [ + "CC", + "BaBcaCbb", + 13 + ], + [ + "CC", + "Bc", + 3 + ], + [ + "CC", + "CBC", + 2 + ], + [ + "CC", + "CCAAAbab", + 12 + ], + [ + "CC", + "CCc", + 2 + ], + [ + "CC", + "Cb", + 2 + ], + [ + "CC", + "CbbBb", + 8 + ], + [ + "CC", + "CcAc", + 5 + ], + [ + "CC", + "a", + 4 + ], + [ + "CC", + "aACcC", + 6 + ], + [ + "CC", + "aBC", + 4 + ], + [ + "CC", + "aBbc", + 7 + ], + [ + "CC", + "aa", + 4 + ], + [ + "CC", + "bA", + 4 + ], + [ + "CC", + "c", + 3 + ], + [ + "CC", + "cBBB", + 7 + ], + [ + "CC", + "cBcCbBcab", + 15 + ], + [ + "CC", + "cCabBBC", + 10 + ], + [ + "CC", + "cCbBB", + 7 + ], + [ + "CCA", + "A", + 4 + ], + [ + "CCA", + "BaaabCA", + 10 + ], + [ + "CCA", + "CBaCacAB", + 10 + ], + [ + "CCA", + "aba", + 5 + ], + [ + "CCA", + "bb", + 6 + ], + [ + "CCAA", + "ABBCA", + 8 + ], + [ + "CCAA", + "BcCbBA", + 7 + ], + [ + "CCAA", + "babAabAA", + 12 + ], + [ + "CCAA", + "cAcC", + 7 + ], + [ + "CCAABbAAc", + "CA", + 14 + ], + [ + "CCAABc", + "BacACaaB", + 11 + ], + [ + "CCAACAbaa", + "BA", + 16 + ], + [ + "CCAAaB", + "CaCCcCa", + 10 + ], + [ + "CCAAbabbc", + "cc", + 15 + ], + [ + "CCAAcCCcA", + "ABcACaBc", + 13 + ], + [ + "CCAAcb", + "C", + 10 + ], + [ + "CCAB", + "bbc", + 8 + ], + [ + "CCABAAB", + "BCABbccB", + 8 + ], + [ + "CCABBCcbB", + "CabB", + 11 + ], + [ + "CCABCCAaa", + "CBCc", + 11 + ], + [ + "CCABb", + "Bcc", + 9 + ], + [ + "CCABcCBAa", + "bbBa", + 13 + ], + [ + "CCABcaC", + "caCc", + 10 + ], + [ + "CCABcbBaC", + "cAAaAAaC", + 11 + ], + [ + "CCAC", + "aBAccBA", + 11 + ], + [ + "CCACb", + "BABcBc", + 10 + ], + [ + "CCACbACc", + "Aabbbac", + 11 + ], + [ + "CCACcaCB", + "ABbCACbB", + 11 + ], + [ + "CCAa", + "aACCbaaac", + 11 + ], + [ + "CCAb", + "ACCBba", + 6 + ], + [ + "CCAbBcABA", + "cAaCBc", + 12 + ], + [ + "CCAbBcb", + "baCB", + 10 + ], + [ + "CCAbCAb", + "BaCCaa", + 10 + ], + [ + "CCAbaC", + "BBbcaa", + 10 + ], + [ + "CCAbaCBa", + "bcccA", + 12 + ], + [ + "CCAcAB", + "ccAAbCa", + 9 + ], + [ + "CCAcACA", + "acBA", + 9 + ], + [ + "CCAcBAa", + "aCacBaBAA", + 8 + ], + [ + "CCAcC", + "BbcBbC", + 9 + ], + [ + "CCAcCB", + "cBcaBBBA", + 11 + ], + [ + "CCAcaC", + "CcaB", + 6 + ], + [ + "CCAcaaca", + "cC", + 13 + ], + [ + "CCAcacccc", + "cAcabcB", + 9 + ], + [ + "CCAcbCb", + "ACCa", + 9 + ], + [ + "CCAcbbCBc", + "CcAbBCa", + 8 + ], + [ + "CCB", + "ACbaAACcB", + 12 + ], + [ + "CCB", + "Cc", + 3 + ], + [ + "CCB", + "abaAB", + 8 + ], + [ + "CCB", + "baCac", + 8 + ], + [ + "CCBA", + "Aaaaa", + 9 + ], + [ + "CCBAA", + "a", + 9 + ], + [ + "CCBABcc", + "BCABb", + 8 + ], + [ + "CCBAC", + "bCCcaCAc", + 9 + ], + [ + "CCBAbAC", + "bCA", + 10 + ], + [ + "CCBAc", + "BC", + 7 + ], + [ + "CCBAcaacb", + "aCCAA", + 13 + ], + [ + "CCBBCBccb", + "BBAa", + 14 + ], + [ + "CCBBbB", + "CbcAACa", + 11 + ], + [ + "CCBBccC", + "c", + 12 + ], + [ + "CCBC", + "CBCaABac", + 9 + ], + [ + "CCBCAaAA", + "CaC", + 12 + ], + [ + "CCBCBCcc", + "bcCccbAbb", + 13 + ], + [ + "CCBCb", + "c", + 9 + ], + [ + "CCBaAaB", + "bACAC", + 11 + ], + [ + "CCBaAaB", + "cbcCBca", + 11 + ], + [ + "CCBaAcba", + "BaaaCAA", + 11 + ], + [ + "CCBaBbbBC", + "a", + 16 + ], + [ + "CCBaCcAa", + "ccBbACCb", + 10 + ], + [ + "CCBbAAAB", + "CCcaBabc", + 11 + ], + [ + "CCBbACc", + "bbbaacBb", + 12 + ], + [ + "CCBbB", + "cBBBACC", + 10 + ], + [ + "CCBbBC", + "bAcCCab", + 12 + ], + [ + "CCBbabCB", + "bCcaB", + 10 + ], + [ + "CCBbca", + "bc", + 8 + ], + [ + "CCBcB", + "ACbbCa", + 8 + ], + [ + "CCBca", + "BacCaaAA", + 12 + ], + [ + "CCBcbbC", + "cB", + 11 + ], + [ + "CCC", + "CcaB", + 5 + ], + [ + "CCC", + "baaaC", + 8 + ], + [ + "CCCAABC", + "CC", + 10 + ], + [ + "CCCAbbBCb", + "cBBaaBab", + 12 + ], + [ + "CCCAc", + "BaccCaB", + 9 + ], + [ + "CCCBAbcc", + "accAb", + 10 + ], + [ + "CCCBBcab", + "ACCA", + 11 + ], + [ + "CCCBCaAcC", + "aaCcAbAa", + 14 + ], + [ + "CCCBbbbC", + "aCb", + 12 + ], + [ + "CCCBcBBaa", + "aBACAbAA", + 14 + ], + [ + "CCCBccaB", + "ccBcc", + 8 + ], + [ + "CCCC", + "bBcAaAbaC", + 15 + ], + [ + "CCCCA", + "BBACa", + 7 + ], + [ + "CCCCA", + "bAcAbbC", + 13 + ], + [ + "CCCCA", + "cccAC", + 7 + ], + [ + "CCCCAbaa", + "CaBaccBB", + 14 + ], + [ + "CCCCBC", + "ABbBc", + 9 + ], + [ + "CCCCCa", + "BCACA", + 7 + ], + [ + "CCCCaBCA", + "Bacbcab", + 13 + ], + [ + "CCCCbaC", + "b", + 12 + ], + [ + "CCCCbbba", + "BAbcAbcBb", + 14 + ], + [ + "CCCCcA", + "bbCCbbc", + 10 + ], + [ + "CCCCcBAC", + "acACBcC", + 9 + ], + [ + "CCCa", + "bAb", + 8 + ], + [ + "CCCaABacb", + "bacBBcAA", + 14 + ], + [ + "CCCaCcA", + "bAcAC", + 10 + ], + [ + "CCCaCcbBA", + "bAbc", + 15 + ], + [ + "CCCaaCaBA", + "AbAbBCb", + 15 + ], + [ + "CCCabaaab", + "cAbca", + 12 + ], + [ + "CCCacacb", + "CAcCBcA", + 10 + ], + [ + "CCCb", + "C", + 6 + ], + [ + "CCCbBBB", + "A", + 14 + ], + [ + "CCCba", + "BbAcaC", + 10 + ], + [ + "CCCbbAA", + "a", + 13 + ], + [ + "CCCbbaA", + "cCB", + 10 + ], + [ + "CCCbbcc", + "BCA", + 12 + ], + [ + "CCCc", + "CBbBBaBBa", + 16 + ], + [ + "CCCcBBba", + "CcBbcAa", + 9 + ], + [ + "CCCcBaA", + "CCCBAAAcA", + 9 + ], + [ + "CCa", + "Ca", + 2 + ], + [ + "CCa", + "CbabbAAcA", + 14 + ], + [ + "CCa", + "bbbCBA", + 9 + ], + [ + "CCa", + "cCAcbAbCC", + 14 + ], + [ + "CCaA", + "c", + 7 + ], + [ + "CCaAA", + "BBACcB", + 11 + ], + [ + "CCaAAb", + "cBa", + 9 + ], + [ + "CCaABbBaA", + "CcACab", + 11 + ], + [ + "CCaAcb", + "ABbBCaCa", + 13 + ], + [ + "CCaBAcbAC", + "CBbc", + 11 + ], + [ + "CCaBBA", + "bAbBB", + 8 + ], + [ + "CCaCAAbA", + "AA", + 12 + ], + [ + "CCaCACBcb", + "caC", + 13 + ], + [ + "CCaCAaA", + "BCAaCaa", + 7 + ], + [ + "CCaCB", + "CAAA", + 7 + ], + [ + "CCaCBcAC", + "bcCa", + 12 + ], + [ + "CCaCCC", + "CACcBa", + 8 + ], + [ + "CCaCaCc", + "BcCba", + 11 + ], + [ + "CCaCaCcBA", + "a", + 16 + ], + [ + "CCaCabaAa", + "CcccAacAC", + 11 + ], + [ + "CCaCb", + "bAcaCbCAb", + 11 + ], + [ + "CCaCbaaaC", + "CaCBCBBc", + 10 + ], + [ + "CCaaBbbA", + "BAAc", + 14 + ], + [ + "CCaaCbCab", + "aBbB", + 13 + ], + [ + "CCaaaaccC", + "AABcca", + 12 + ], + [ + "CCaacBa", + "a", + 12 + ], + [ + "CCabA", + "acbCAAbb", + 10 + ], + [ + "CCabA", + "bbaacCA", + 10 + ], + [ + "CCabCAac", + "ABABA", + 12 + ], + [ + "CCabcCbc", + "BCbc", + 9 + ], + [ + "CCac", + "a", + 6 + ], + [ + "CCacAac", + "bbBbaC", + 11 + ], + [ + "CCacAbCcb", + "bCbBa", + 14 + ], + [ + "CCacBca", + "C", + 12 + ], + [ + "CCacCb", + "cBAC", + 8 + ], + [ + "CCacab", + "Aa", + 9 + ], + [ + "CCacbb", + "CAb", + 7 + ], + [ + "CCacbcB", + "Cca", + 9 + ], + [ + "CCb", + "BAbBAaB", + 12 + ], + [ + "CCb", + "CAAAbca", + 10 + ], + [ + "CCb", + "bAc", + 6 + ], + [ + "CCb", + "bcabBaB", + 11 + ], + [ + "CCb", + "cbCcaAaac", + 15 + ], + [ + "CCbA", + "AABAC", + 7 + ], + [ + "CCbA", + "BbBCabCaa", + 13 + ], + [ + "CCbAAa", + "BcABbC", + 11 + ], + [ + "CCbABCC", + "a", + 13 + ], + [ + "CCbACCBa", + "BbbaBbC", + 12 + ], + [ + "CCbAaaA", + "aB", + 12 + ], + [ + "CCbAbC", + "cAacBCa", + 10 + ], + [ + "CCbAbbBB", + "abcaA", + 13 + ], + [ + "CCbB", + "Aa", + 8 + ], + [ + "CCbB", + "cbaBCBBA", + 10 + ], + [ + "CCbBBB", + "CACCacCBc", + 12 + ], + [ + "CCbBCC", + "BbCAbcAA", + 12 + ], + [ + "CCbBbaBa", + "BcbccCAc", + 13 + ], + [ + "CCbCBCbB", + "cCbbB", + 7 + ], + [ + "CCbCbA", + "ABACcA", + 8 + ], + [ + "CCbCbcacC", + "bBC", + 13 + ], + [ + "CCba", + "aBaAcAaCC", + 15 + ], + [ + "CCba", + "caCAcc", + 9 + ], + [ + "CCba", + "cbaCcba", + 7 + ], + [ + "CCbaB", + "Ba", + 7 + ], + [ + "CCbaBB", + "CCaccA", + 8 + ], + [ + "CCbaCC", + "aBbcaa", + 10 + ], + [ + "CCbaaBcAB", + "a", + 16 + ], + [ + "CCbaba", + "ACbaBAAb", + 8 + ], + [ + "CCbb", + "aBbacACBa", + 14 + ], + [ + "CCbbACcA", + "CBabaAA", + 9 + ], + [ + "CCbbAabCa", + "cAABb", + 13 + ], + [ + "CCbbBabb", + "aBBcc", + 13 + ], + [ + "CCbbaBC", + "cBC", + 9 + ], + [ + "CCbbca", + "bAC", + 9 + ], + [ + "CCbbcaCBA", + "CCaAaBBAB", + 10 + ], + [ + "CCbcAac", + "a", + 12 + ], + [ + "CCbcBC", + "aabbAc", + 9 + ], + [ + "CCbcBca", + "B", + 12 + ], + [ + "CCbcCAc", + "Bb", + 12 + ], + [ + "CCbcb", + "cBaC", + 8 + ], + [ + "CCbcc", + "aBaccBcB", + 11 + ], + [ + "CCc", + "A", + 6 + ], + [ + "CCc", + "Ac", + 4 + ], + [ + "CCc", + "Bc", + 4 + ], + [ + "CCc", + "Cacbb", + 6 + ], + [ + "CCc", + "bCcbAbbAB", + 14 + ], + [ + "CCcAC", + "CABCA", + 7 + ], + [ + "CCcACBCC", + "B", + 14 + ], + [ + "CCcACc", + "cACCCA", + 8 + ], + [ + "CCcAaaba", + "CCCBcABca", + 9 + ], + [ + "CCcAc", + "abaaaCCc", + 13 + ], + [ + "CCcB", + "aCAaBc", + 8 + ], + [ + "CCcBAB", + "CacAbbcbB", + 11 + ], + [ + "CCcBAcC", + "bB", + 12 + ], + [ + "CCcBbAb", + "aBbC", + 10 + ], + [ + "CCcBcaB", + "cBbb", + 9 + ], + [ + "CCcCaaAC", + "CAAbccC", + 12 + ], + [ + "CCcCb", + "B", + 9 + ], + [ + "CCcCbacba", + "AAa", + 15 + ], + [ + "CCcCcABB", + "cAcBabacb", + 13 + ], + [ + "CCcCcccAB", + "BAaACCCAB", + 11 + ], + [ + "CCca", + "Acc", + 5 + ], + [ + "CCca", + "a", + 6 + ], + [ + "CCcaBCabB", + "cAabc", + 11 + ], + [ + "CCcaC", + "bbCACAA", + 10 + ], + [ + "CCcaCca", + "CabacBb", + 9 + ], + [ + "CCcaaBaB", + "ccaAabb", + 9 + ], + [ + "CCcaaabbc", + "BCaCC", + 13 + ], + [ + "CCcabA", + "bCCAAcaBC", + 9 + ], + [ + "CCcacbB", + "Babb", + 9 + ], + [ + "CCcb", + "C", + 6 + ], + [ + "CCcbB", + "abB", + 6 + ], + [ + "CCcbBBC", + "aAAaCCCc", + 14 + ], + [ + "CCcbC", + "ACcBBBBc", + 10 + ], + [ + "CCcbC", + "a", + 10 + ], + [ + "CCcbCACab", + "Accba", + 11 + ], + [ + "CCcbcaaaA", + "ccaaAbaaB", + 12 + ], + [ + "CCccAAB", + "CCaaa", + 8 + ], + [ + "CCccB", + "AACBAbC", + 11 + ], + [ + "CCcca", + "baAaCccaa", + 10 + ], + [ + "CCccaAA", + "b", + 14 + ], + [ + "CCccbb", + "babC", + 10 + ], + [ + "Ca", + "ABCCb", + 8 + ], + [ + "Ca", + "AaCcCBaab", + 14 + ], + [ + "Ca", + "Aac", + 4 + ], + [ + "Ca", + "BAAABca", + 11 + ], + [ + "Ca", + "BACaCCb", + 10 + ], + [ + "Ca", + "BAc", + 5 + ], + [ + "Ca", + "BBAA", + 7 + ], + [ + "Ca", + "BCB", + 4 + ], + [ + "Ca", + "BCBbBaAC", + 12 + ], + [ + "Ca", + "BaCCAcBAa", + 14 + ], + [ + "Ca", + "BabB", + 6 + ], + [ + "Ca", + "BababbBb", + 14 + ], + [ + "Ca", + "BbCB", + 6 + ], + [ + "Ca", + "Bbb", + 6 + ], + [ + "Ca", + "CAbc", + 5 + ], + [ + "Ca", + "CBAbac", + 8 + ], + [ + "Ca", + "CBB", + 4 + ], + [ + "Ca", + "CBaA", + 4 + ], + [ + "Ca", + "CCAB", + 5 + ], + [ + "Ca", + "CCaCBaaA", + 12 + ], + [ + "Ca", + "CCbaAA", + 8 + ], + [ + "Ca", + "CCbb", + 6 + ], + [ + "Ca", + "Cb", + 2 + ], + [ + "Ca", + "aACCba", + 8 + ], + [ + "Ca", + "aB", + 4 + ], + [ + "Ca", + "aBBA", + 7 + ], + [ + "Ca", + "aac", + 4 + ], + [ + "Ca", + "acBacBcAA", + 15 + ], + [ + "Ca", + "b", + 4 + ], + [ + "Ca", + "bAbBbbAa", + 14 + ], + [ + "Ca", + "bBCA", + 5 + ], + [ + "Ca", + "bbBAAAa", + 12 + ], + [ + "Ca", + "c", + 3 + ], + [ + "Ca", + "cCBCBbAAa", + 14 + ], + [ + "Ca", + "caBabaBc", + 13 + ], + [ + "Ca", + "ccCaCCC", + 10 + ], + [ + "CaA", + "BcBcAb", + 9 + ], + [ + "CaA", + "CCBBA", + 6 + ], + [ + "CaA", + "aBa", + 5 + ], + [ + "CaA", + "aBcbcb", + 11 + ], + [ + "CaA", + "bBcCBcbcc", + 16 + ], + [ + "CaA", + "bCABC", + 7 + ], + [ + "CaA", + "bCcBaAaA", + 10 + ], + [ + "CaA", + "c", + 5 + ], + [ + "CaAA", + "bacCbbA", + 10 + ], + [ + "CaAABbc", + "c", + 12 + ], + [ + "CaAAC", + "c", + 9 + ], + [ + "CaAACB", + "bB", + 10 + ], + [ + "CaAAa", + "AcCbA", + 9 + ], + [ + "CaAAbcCa", + "a", + 14 + ], + [ + "CaAB", + "BCaCaCB", + 7 + ], + [ + "CaAB", + "Ba", + 6 + ], + [ + "CaAB", + "bCb", + 7 + ], + [ + "CaABBc", + "b", + 11 + ], + [ + "CaABCBA", + "bBb", + 11 + ], + [ + "CaABa", + "B", + 8 + ], + [ + "CaABbACB", + "BA", + 12 + ], + [ + "CaABbC", + "AAacAc", + 9 + ], + [ + "CaAC", + "BBCbCcaaC", + 11 + ], + [ + "CaAC", + "aCAABab", + 9 + ], + [ + "CaAC", + "acCBbcbA", + 13 + ], + [ + "CaACB", + "B", + 8 + ], + [ + "CaACbacC", + "BAbabAAB", + 12 + ], + [ + "CaACbc", + "CBA", + 8 + ], + [ + "CaACcBACc", + "aAcc", + 10 + ], + [ + "CaAa", + "Bababa", + 7 + ], + [ + "CaAa", + "ccAC", + 5 + ], + [ + "CaAaAC", + "ACa", + 9 + ], + [ + "CaAaACCc", + "BaabbBCbC", + 12 + ], + [ + "CaAaBbB", + "cbAb", + 9 + ], + [ + "CaAaa", + "cAAACBa", + 7 + ], + [ + "CaAab", + "BBbcbaa", + 12 + ], + [ + "CaAabcABB", + "ACcBacC", + 14 + ], + [ + "CaAbC", + "bC", + 6 + ], + [ + "CaAbbBa", + "c", + 13 + ], + [ + "CaAc", + "Ac", + 4 + ], + [ + "CaAc", + "abB", + 6 + ], + [ + "CaAcCAb", + "cABCaAA", + 9 + ], + [ + "CaAcCa", + "bBabcCCC", + 10 + ], + [ + "CaAca", + "bcAcBAABA", + 13 + ], + [ + "CaAcb", + "aBbACB", + 8 + ], + [ + "CaAcc", + "ACc", + 5 + ], + [ + "CaB", + "B", + 4 + ], + [ + "CaB", + "C", + 4 + ], + [ + "CaB", + "acbCAcC", + 11 + ], + [ + "CaB", + "bbAaAaBB", + 12 + ], + [ + "CaB", + "cabbb", + 6 + ], + [ + "CaBA", + "cbcAB", + 7 + ], + [ + "CaBAAB", + "BBAC", + 8 + ], + [ + "CaBAAB", + "a", + 10 + ], + [ + "CaBAAaBB", + "AACB", + 10 + ], + [ + "CaBAbCb", + "baA", + 10 + ], + [ + "CaBAcBCcb", + "A", + 16 + ], + [ + "CaBAcc", + "AACCaA", + 11 + ], + [ + "CaBAcc", + "bAcBbA", + 11 + ], + [ + "CaBB", + "aCCBbcaba", + 13 + ], + [ + "CaBB", + "babABcb", + 9 + ], + [ + "CaBBBa", + "Cc", + 10 + ], + [ + "CaBBBbBB", + "CAAaC", + 13 + ], + [ + "CaBBCccC", + "bAac", + 13 + ], + [ + "CaBBaA", + "a", + 10 + ], + [ + "CaBBabBcc", + "b", + 16 + ], + [ + "CaBBcC", + "BA", + 10 + ], + [ + "CaBBccac", + "accCBA", + 11 + ], + [ + "CaBC", + "CaaacC", + 6 + ], + [ + "CaBCACabA", + "CbcABbc", + 10 + ], + [ + "CaBCBbC", + "ccbBbaC", + 8 + ], + [ + "CaBCCcaCc", + "CaC", + 12 + ], + [ + "CaBaaBcA", + "C", + 14 + ], + [ + "CaBacBc", + "c", + 12 + ], + [ + "CaBba", + "bbcCaAa", + 10 + ], + [ + "CaBbac", + "A", + 11 + ], + [ + "CaBcAc", + "CAAab", + 8 + ], + [ + "CaBcBAbB", + "BABCCca", + 12 + ], + [ + "CaBcaA", + "bcC", + 9 + ], + [ + "CaBccaAc", + "bBa", + 12 + ], + [ + "CaC", + "aC", + 2 + ], + [ + "CaCA", + "bcBA", + 6 + ], + [ + "CaCAAbCcB", + "aBCc", + 11 + ], + [ + "CaCABCcbA", + "bB", + 16 + ], + [ + "CaCACCaA", + "BCBBaaBCA", + 13 + ], + [ + "CaCAbBA", + "bCBb", + 10 + ], + [ + "CaCB", + "AB", + 5 + ], + [ + "CaCB", + "bAb", + 6 + ], + [ + "CaCBa", + "ACabCC", + 8 + ], + [ + "CaCBa", + "abBaa", + 6 + ], + [ + "CaCBaaC", + "bcACBa", + 8 + ], + [ + "CaCBbBBb", + "bab", + 12 + ], + [ + "CaCBc", + "cAC", + 6 + ], + [ + "CaCCbB", + "babA", + 8 + ], + [ + "CaCCbc", + "BAbcCcBB", + 11 + ], + [ + "CaCa", + "Aab", + 6 + ], + [ + "CaCa", + "CCccAab", + 9 + ], + [ + "CaCa", + "CcbcAAC", + 10 + ], + [ + "CaCa", + "abCCa", + 6 + ], + [ + "CaCaAB", + "aBb", + 9 + ], + [ + "CaCb", + "bCab", + 4 + ], + [ + "CaCbBcCCC", + "CaBBab", + 11 + ], + [ + "CaCbbCAcb", + "aABcAc", + 10 + ], + [ + "CaCbbaB", + "ABB", + 10 + ], + [ + "CaCc", + "A", + 7 + ], + [ + "CaCc", + "ccBbc", + 7 + ], + [ + "CaCcAAb", + "baCBCB", + 9 + ], + [ + "CaCcB", + "AA", + 9 + ], + [ + "CaCcBa", + "cAc", + 8 + ], + [ + "CaCcaa", + "CABabbB", + 11 + ], + [ + "CaCcbBA", + "CAbccCaa", + 9 + ], + [ + "Caa", + "Acc", + 6 + ], + [ + "Caa", + "BAcBcBCbb", + 16 + ], + [ + "Caa", + "abbAb", + 9 + ], + [ + "CaaABcBab", + "acACccaCa", + 12 + ], + [ + "CaaAaAa", + "bbaabAc", + 9 + ], + [ + "CaaAaAaba", + "aaCBc", + 13 + ], + [ + "CaaAbCcAb", + "bc", + 14 + ], + [ + "CaaBAab", + "CcC", + 12 + ], + [ + "CaaBcB", + "Caaa", + 6 + ], + [ + "CaaC", + "AAbBaC", + 7 + ], + [ + "CaaCA", + "A", + 8 + ], + [ + "CaaCbCB", + "c", + 13 + ], + [ + "Caaa", + "BBaBcA", + 9 + ], + [ + "CaaaCabaC", + "CAa", + 13 + ], + [ + "Caaab", + "a", + 8 + ], + [ + "CaaabAbc", + "ACc", + 12 + ], + [ + "CaaabCbB", + "ABcB", + 11 + ], + [ + "Caaabcc", + "babAaAC", + 10 + ], + [ + "Caaac", + "AAbbccabb", + 15 + ], + [ + "Caab", + "BacAc", + 7 + ], + [ + "CaacAaCb", + "AbccbacB", + 10 + ], + [ + "CaacCb", + "acbcCABBB", + 13 + ], + [ + "Caacaccbc", + "bCcbB", + 13 + ], + [ + "CaacccACC", + "baBCAaCA", + 12 + ], + [ + "Cab", + "AbBCbcBbc", + 14 + ], + [ + "Cab", + "AcC", + 6 + ], + [ + "Cab", + "BCA", + 5 + ], + [ + "Cab", + "BaB", + 3 + ], + [ + "Cab", + "c", + 5 + ], + [ + "CabA", + "b", + 6 + ], + [ + "CabAabA", + "cbCaBBb", + 10 + ], + [ + "CabAbcCB", + "acbCa", + 10 + ], + [ + "CabB", + "AACcCBcab", + 14 + ], + [ + "CabB", + "BabB", + 2 + ], + [ + "CabB", + "Ccba", + 4 + ], + [ + "CabBCa", + "AaCaab", + 10 + ], + [ + "CabBacbC", + "C", + 14 + ], + [ + "CabBbab", + "Bc", + 12 + ], + [ + "CabBbc", + "BbBCbcBca", + 12 + ], + [ + "CabBcC", + "AaAcCAC", + 9 + ], + [ + "CabCB", + "AaCBCab", + 8 + ], + [ + "CabCaAABb", + "BbaB", + 12 + ], + [ + "CabCb", + "BcCbacbb", + 10 + ], + [ + "Caba", + "AA", + 6 + ], + [ + "Caba", + "CBbBBbCC", + 12 + ], + [ + "CabaAAcbc", + "aA", + 14 + ], + [ + "CabaAaab", + "Bccb", + 13 + ], + [ + "CabaBCc", + "acBcBb", + 11 + ], + [ + "CabaCAC", + "bAaa", + 10 + ], + [ + "CababAAcB", + "a", + 16 + ], + [ + "Cabb", + "aBbABaA", + 11 + ], + [ + "CabbAAABB", + "ccA", + 15 + ], + [ + "CabbACc", + "ABCCca", + 10 + ], + [ + "CabbB", + "BabCaAC", + 10 + ], + [ + "CabbB", + "CbBbAccbc", + 12 + ], + [ + "CabbCaa", + "bbaBbcacC", + 10 + ], + [ + "CabbaAba", + "CABaCBAbA", + 9 + ], + [ + "CabbbAACB", + "Babac", + 12 + ], + [ + "CabcB", + "aBAbaA", + 9 + ], + [ + "CabcBaC", + "Cac", + 8 + ], + [ + "CabcaABb", + "cBBc", + 12 + ], + [ + "CabcaBcB", + "bAABcbCA", + 12 + ], + [ + "Cabcb", + "Ba", + 8 + ], + [ + "Cabccb", + "BBBA", + 11 + ], + [ + "Cac", + "A", + 5 + ], + [ + "Cac", + "BAcb", + 5 + ], + [ + "Cac", + "BCcCCac", + 8 + ], + [ + "Cac", + "Bc", + 4 + ], + [ + "Cac", + "CBaacCcCb", + 12 + ], + [ + "Cac", + "cC", + 4 + ], + [ + "Cac", + "cbACbC", + 9 + ], + [ + "CacA", + "BaBabBAA", + 12 + ], + [ + "CacA", + "CacbC", + 4 + ], + [ + "CacAb", + "acCAb", + 4 + ], + [ + "CacAcAa", + "ACbcC", + 10 + ], + [ + "CacAcBc", + "caABbAAAA", + 13 + ], + [ + "CacBBBC", + "B", + 12 + ], + [ + "CacBCa", + "CcbcBA", + 7 + ], + [ + "CacBaCbca", + "aaBaaaBc", + 11 + ], + [ + "CacBbbB", + "CaCbbaBbb", + 7 + ], + [ + "CacBc", + "bBbAC", + 9 + ], + [ + "CacC", + "AcC", + 3 + ], + [ + "CacCbaAcc", + "bCaAaCB", + 13 + ], + [ + "CacaAc", + "aAbC", + 8 + ], + [ + "Cacab", + "AaBCAa", + 8 + ], + [ + "Cacab", + "c", + 8 + ], + [ + "CacacC", + "AABCCAA", + 12 + ], + [ + "Cacb", + "ac", + 4 + ], + [ + "CacbB", + "BCbcBaa", + 9 + ], + [ + "CacbC", + "bBbCaBBB", + 11 + ], + [ + "CacbC", + "cCAAcCa", + 9 + ], + [ + "CacbCAccB", + "AAaBBcbBc", + 14 + ], + [ + "Cacc", + "AACc", + 4 + ], + [ + "CaccAC", + "BabBAaC", + 8 + ], + [ + "CaccBca", + "aCbb", + 10 + ], + [ + "CaccaAbbC", + "BBbC", + 13 + ], + [ + "CaccaCCa", + "cc", + 12 + ], + [ + "Cb", + "A", + 4 + ], + [ + "Cb", + "AACB", + 5 + ], + [ + "Cb", + "AACCbcBc", + 12 + ], + [ + "Cb", + "ABcAcaCcC", + 16 + ], + [ + "Cb", + "ACCBAaCaA", + 15 + ], + [ + "Cb", + "AaBCBCc", + 11 + ], + [ + "Cb", + "Aaa", + 6 + ], + [ + "Cb", + "AacabCcB", + 13 + ], + [ + "Cb", + "Ac", + 4 + ], + [ + "Cb", + "BABB", + 7 + ], + [ + "Cb", + "BBcAabC", + 11 + ], + [ + "Cb", + "Ba", + 4 + ], + [ + "Cb", + "BaaB", + 7 + ], + [ + "Cb", + "BbCaabCCC", + 14 + ], + [ + "Cb", + "CA", + 2 + ], + [ + "Cb", + "CCcBaAB", + 11 + ], + [ + "Cb", + "Cbb", + 2 + ], + [ + "Cb", + "CcBccBacC", + 15 + ], + [ + "Cb", + "aBcaCb", + 8 + ], + [ + "Cb", + "aCBCcAACA", + 15 + ], + [ + "Cb", + "aaAbc", + 8 + ], + [ + "Cb", + "aaCBBaB", + 11 + ], + [ + "Cb", + "aaaB", + 7 + ], + [ + "Cb", + "abBaC", + 8 + ], + [ + "Cb", + "abaaaCABA", + 15 + ], + [ + "Cb", + "acBbAAca", + 13 + ], + [ + "Cb", + "acbbabbCC", + 15 + ], + [ + "Cb", + "bcCCBA", + 9 + ], + [ + "Cb", + "c", + 3 + ], + [ + "Cb", + "cAbcbCA", + 11 + ], + [ + "Cb", + "cAcCbBA", + 10 + ], + [ + "Cb", + "cB", + 2 + ], + [ + "Cb", + "cBcB", + 6 + ], + [ + "Cb", + "caacb", + 7 + ], + [ + "Cb", + "cbCBBbacA", + 14 + ], + [ + "Cb", + "cbcbccA", + 11 + ], + [ + "CbA", + "AAC", + 6 + ], + [ + "CbA", + "BBCBaCC", + 10 + ], + [ + "CbA", + "BBcBB", + 8 + ], + [ + "CbA", + "baaA", + 6 + ], + [ + "CbA", + "c", + 5 + ], + [ + "CbA", + "caBAbA", + 7 + ], + [ + "CbAABaAC", + "A", + 14 + ], + [ + "CbAACACcC", + "ba", + 15 + ], + [ + "CbAACa", + "AaCaAccab", + 11 + ], + [ + "CbAAaAB", + "BCaBCcaaC", + 12 + ], + [ + "CbAAb", + "bacAabaAB", + 11 + ], + [ + "CbAAcAb", + "caC", + 11 + ], + [ + "CbAAcC", + "ABbcaCa", + 10 + ], + [ + "CbABACcaB", + "Babb", + 14 + ], + [ + "CbABC", + "b", + 8 + ], + [ + "CbABaBaAC", + "acaC", + 12 + ], + [ + "CbAC", + "A", + 6 + ], + [ + "CbAC", + "c", + 7 + ], + [ + "CbACaB", + "aBcA", + 9 + ], + [ + "CbACb", + "bcABcCC", + 10 + ], + [ + "CbACc", + "BbabcaBCA", + 13 + ], + [ + "CbACcABba", + "baABAcBc", + 12 + ], + [ + "CbAaAaaa", + "ACbBACbbc", + 13 + ], + [ + "CbAaabbC", + "A", + 14 + ], + [ + "CbAacB", + "c", + 10 + ], + [ + "CbAacBB", + "CacbBBbBA", + 12 + ], + [ + "CbAb", + "baBac", + 8 + ], + [ + "CbAbBaC", + "aCAaACb", + 11 + ], + [ + "CbAba", + "CbaA", + 4 + ], + [ + "CbAbb", + "Bc", + 9 + ], + [ + "CbAc", + "a", + 7 + ], + [ + "CbAcAC", + "bcbCB", + 8 + ], + [ + "CbAcB", + "aac", + 7 + ], + [ + "CbAcBCcaa", + "ccABcacAc", + 11 + ], + [ + "CbAcCb", + "AC", + 8 + ], + [ + "CbAcaAAA", + "accCbbACC", + 15 + ], + [ + "CbAcc", + "AABbcBBc", + 11 + ], + [ + "CbB", + "ABcCCBb", + 10 + ], + [ + "CbB", + "B", + 4 + ], + [ + "CbB", + "BB", + 3 + ], + [ + "CbB", + "BBb", + 4 + ], + [ + "CbB", + "ababacC", + 11 + ], + [ + "CbB", + "bAaaABc", + 12 + ], + [ + "CbB", + "cCb", + 4 + ], + [ + "CbBABACb", + "BCcBAA", + 10 + ], + [ + "CbBABBaA", + "BacaabAc", + 13 + ], + [ + "CbBAb", + "cB", + 7 + ], + [ + "CbBB", + "CcBCBCcAC", + 12 + ], + [ + "CbBBB", + "BCCcb", + 9 + ], + [ + "CbBBaC", + "ab", + 10 + ], + [ + "CbBBcCCBb", + "B", + 16 + ], + [ + "CbBCCbbB", + "cC", + 13 + ], + [ + "CbBa", + "a", + 6 + ], + [ + "CbBa", + "aAb", + 7 + ], + [ + "CbBabA", + "CcCB", + 9 + ], + [ + "CbBb", + "aBccCBA", + 11 + ], + [ + "CbBbC", + "CCCbbC", + 5 + ], + [ + "CbBbbba", + "BaCCABCcC", + 15 + ], + [ + "CbBbc", + "C", + 8 + ], + [ + "CbBc", + "aAaAAbBA", + 12 + ], + [ + "CbBcB", + "b", + 8 + ], + [ + "CbC", + "AcacbAB", + 11 + ], + [ + "CbC", + "BCAc", + 5 + ], + [ + "CbC", + "Bc", + 4 + ], + [ + "CbC", + "CbB", + 2 + ], + [ + "CbC", + "b", + 4 + ], + [ + "CbCAAbb", + "bAAaC", + 8 + ], + [ + "CbCABcaC", + "aCcAACB", + 12 + ], + [ + "CbCACA", + "baAac", + 8 + ], + [ + "CbCAa", + "cCbabBb", + 10 + ], + [ + "CbCB", + "BAcbcAba", + 11 + ], + [ + "CbCBBb", + "cAbACcA", + 11 + ], + [ + "CbCBC", + "cacCccCb", + 11 + ], + [ + "CbCBCAB", + "bBBcC", + 9 + ], + [ + "CbCBcCAaa", + "aAAaAa", + 14 + ], + [ + "CbCCCc", + "BcBCaba", + 10 + ], + [ + "CbCCbAccA", + "cCbBB", + 13 + ], + [ + "CbCCcCCaB", + "bcaaab", + 11 + ], + [ + "CbCa", + "cBBaCacA", + 10 + ], + [ + "CbCaAaB", + "acaa", + 9 + ], + [ + "CbCaB", + "ACbaa", + 6 + ], + [ + "CbCaB", + "AcbAa", + 7 + ], + [ + "CbCaBCb", + "bcA", + 10 + ], + [ + "CbCaa", + "ABCBCcAb", + 10 + ], + [ + "CbCaa", + "ba", + 6 + ], + [ + "CbCaaaC", + "bAcBcBaAa", + 12 + ], + [ + "CbCb", + "Bbc", + 5 + ], + [ + "CbCbaBa", + "AbacBbabc", + 10 + ], + [ + "CbCbcC", + "Ca", + 10 + ], + [ + "CbCc", + "ACC", + 5 + ], + [ + "CbCc", + "Cabbb", + 6 + ], + [ + "CbCcAaBaA", + "cbC", + 13 + ], + [ + "CbCcAcAc", + "AcBaCaAC", + 11 + ], + [ + "CbCcBAb", + "c", + 12 + ], + [ + "CbCcBC", + "CacBbCAc", + 10 + ], + [ + "CbCcBac", + "AAbAC", + 11 + ], + [ + "Cba", + "ABBBbaab", + 12 + ], + [ + "Cba", + "AcbAbB", + 8 + ], + [ + "Cba", + "C", + 4 + ], + [ + "Cba", + "CCCbbbC", + 10 + ], + [ + "Cba", + "CCaaAa", + 8 + ], + [ + "Cba", + "CcBCCAAAA", + 14 + ], + [ + "Cba", + "aABbaC", + 8 + ], + [ + "CbaA", + "CAbCBaB", + 8 + ], + [ + "CbaA", + "CBb", + 5 + ], + [ + "CbaABAC", + "aBCBCBc", + 12 + ], + [ + "CbaAaBCaB", + "AcCcB", + 12 + ], + [ + "CbaAcBb", + "C", + 12 + ], + [ + "CbaAcc", + "acaCaaccA", + 10 + ], + [ + "CbaBA", + "ab", + 7 + ], + [ + "CbaBBcBaB", + "bB", + 14 + ], + [ + "CbaBa", + "CBC", + 6 + ], + [ + "CbaBb", + "CCCbcB", + 8 + ], + [ + "CbaBba", + "BC", + 10 + ], + [ + "CbaBcAcbC", + "cc", + 14 + ], + [ + "CbaC", + "B", + 7 + ], + [ + "CbaCA", + "BAbaAacA", + 9 + ], + [ + "CbaCABBb", + "cAB", + 11 + ], + [ + "CbaCABcbA", + "BbaCbC", + 10 + ], + [ + "CbaCAaCc", + "a", + 14 + ], + [ + "CbaCAcCba", + "BCcaB", + 12 + ], + [ + "CbaCbCA", + "ccBBAcBc", + 12 + ], + [ + "CbaaA", + "BA", + 7 + ], + [ + "CbaaBA", + "AcccAAaac", + 14 + ], + [ + "CbabAACaC", + "cABaCcbB", + 13 + ], + [ + "CbabACa", + "A", + 12 + ], + [ + "CbabAac", + "aaaB", + 9 + ], + [ + "CbabAcC", + "cbb", + 9 + ], + [ + "CbabBBBcc", + "c", + 16 + ], + [ + "CbabBCCab", + "bB", + 14 + ], + [ + "CbabC", + "CacBB", + 7 + ], + [ + "CbabbBbb", + "BaAABCC", + 11 + ], + [ + "Cbabc", + "aACbC", + 7 + ], + [ + "CbabcB", + "CBcbAcb", + 6 + ], + [ + "CbacAab", + "c", + 12 + ], + [ + "CbacCAB", + "cCC", + 10 + ], + [ + "CbacCCb", + "caaC", + 9 + ], + [ + "CbacCaCAB", + "Cbbba", + 12 + ], + [ + "Cbacaca", + "BACAc", + 8 + ], + [ + "Cbb", + "Ababcb", + 8 + ], + [ + "Cbb", + "Bb", + 3 + ], + [ + "Cbb", + "CACbbBCb", + 10 + ], + [ + "Cbb", + "CBaABccaA", + 14 + ], + [ + "Cbb", + "abcb", + 4 + ], + [ + "Cbb", + "bACBBCCaa", + 14 + ], + [ + "Cbb", + "caCCACBaB", + 14 + ], + [ + "Cbb", + "cbAcABac", + 12 + ], + [ + "CbbA", + "cAACAA", + 9 + ], + [ + "CbbAACbC", + "ccaABC", + 9 + ], + [ + "CbbABCCA", + "CBCABCA", + 5 + ], + [ + "CbbAb", + "B", + 9 + ], + [ + "CbbAbbac", + "bCBbca", + 10 + ], + [ + "CbbAcaCbC", + "CAbBbcAc", + 11 + ], + [ + "CbbB", + "A", + 8 + ], + [ + "CbbB", + "C", + 6 + ], + [ + "CbbBA", + "BBCabAB", + 10 + ], + [ + "CbbBAbcA", + "CcCCAaBb", + 12 + ], + [ + "CbbBAcCba", + "BBbbCaBA", + 11 + ], + [ + "CbbBaBcB", + "cCabACB", + 10 + ], + [ + "CbbCCacBc", + "cbbAcacab", + 8 + ], + [ + "CbbaAacC", + "bcbcbbaBa", + 13 + ], + [ + "CbbaCBAb", + "aBCBBcC", + 13 + ], + [ + "CbbbBb", + "BA", + 10 + ], + [ + "CbbbaA", + "aacCccBbB", + 15 + ], + [ + "CbbbaACba", + "aCBba", + 12 + ], + [ + "Cbbbab", + "AABAbbc", + 11 + ], + [ + "Cbbc", + "bcaAb", + 9 + ], + [ + "Cbbc", + "cba", + 5 + ], + [ + "CbbcBcAc", + "BbC", + 12 + ], + [ + "CbbcCBacB", + "AaC", + 15 + ], + [ + "Cbbcbb", + "bBaBCBA", + 10 + ], + [ + "CbbcbcabC", + "AcBcBcba", + 10 + ], + [ + "Cbbcc", + "B", + 9 + ], + [ + "Cbbcc", + "CcbA", + 6 + ], + [ + "CbbccBAaB", + "cCA", + 13 + ], + [ + "Cbbccc", + "BcA", + 9 + ], + [ + "Cbc", + "A", + 6 + ], + [ + "Cbc", + "BAa", + 6 + ], + [ + "Cbc", + "BaabcacC", + 12 + ], + [ + "Cbc", + "CBbAc", + 4 + ], + [ + "Cbc", + "aCCbab", + 8 + ], + [ + "Cbc", + "baB", + 6 + ], + [ + "Cbc", + "bcB", + 4 + ], + [ + "Cbc", + "caACbaC", + 9 + ], + [ + "Cbc", + "cbabc", + 5 + ], + [ + "CbcAB", + "AabCABAb", + 9 + ], + [ + "CbcAaaBa", + "aACA", + 12 + ], + [ + "CbcB", + "CBcC", + 3 + ], + [ + "CbcBCbB", + "CAAacC", + 11 + ], + [ + "CbcBb", + "aaCACAAcC", + 15 + ], + [ + "CbcBcb", + "AabcC", + 9 + ], + [ + "CbcBcbC", + "aCa", + 13 + ], + [ + "CbcCAAc", + "aaBBbbc", + 12 + ], + [ + "CbcCAB", + "bbaCCcc", + 9 + ], + [ + "CbcCB", + "c", + 8 + ], + [ + "CbcCBB", + "aB", + 10 + ], + [ + "CbcCCa", + "BB", + 11 + ], + [ + "CbcCcA", + "aCaacCaAa", + 10 + ], + [ + "Cbca", + "cABAAaaA", + 12 + ], + [ + "CbcaC", + "bCcabCa", + 8 + ], + [ + "Cbcb", + "AA", + 8 + ], + [ + "Cbcb", + "AaCc", + 7 + ], + [ + "Cbcb", + "CbBAa", + 6 + ], + [ + "CbcbA", + "bccbACcC", + 10 + ], + [ + "CbcbB", + "aC", + 9 + ], + [ + "CbcbBCBC", + "cBB", + 10 + ], + [ + "CbcbC", + "a", + 10 + ], + [ + "Cbcbb", + "cccAB", + 6 + ], + [ + "Cbcbcbc", + "CbaccAcCC", + 9 + ], + [ + "Cbcc", + "BbAcAabc", + 10 + ], + [ + "Cbcc", + "bbBBA", + 8 + ], + [ + "CbccCAcBA", + "acCA", + 12 + ], + [ + "CbccaACc", + "AC", + 12 + ], + [ + "Cc", + "AAbABC", + 11 + ], + [ + "Cc", + "AAcbCAca", + 12 + ], + [ + "Cc", + "ABaC", + 7 + ], + [ + "Cc", + "AC", + 3 + ], + [ + "Cc", + "ACCcCa", + 8 + ], + [ + "Cc", + "AaCCC", + 7 + ], + [ + "Cc", + "BBCBCbbb", + 13 + ], + [ + "Cc", + "BbAbcC", + 10 + ], + [ + "Cc", + "Bc", + 2 + ], + [ + "Cc", + "Bccba", + 7 + ], + [ + "Cc", + "CABACbAcB", + 14 + ], + [ + "Cc", + "CAaCbCA", + 11 + ], + [ + "Cc", + "CCCCAaC", + 11 + ], + [ + "Cc", + "CCbCaAb", + 11 + ], + [ + "Cc", + "Ccb", + 2 + ], + [ + "Cc", + "a", + 4 + ], + [ + "Cc", + "aAABCBacb", + 14 + ], + [ + "Cc", + "aAAccbC", + 11 + ], + [ + "Cc", + "aBBCbc", + 8 + ], + [ + "Cc", + "aCAcaCca", + 12 + ], + [ + "Cc", + "bB", + 4 + ], + [ + "Cc", + "baABAABbC", + 17 + ], + [ + "Cc", + "bbacA", + 8 + ], + [ + "Cc", + "bc", + 2 + ], + [ + "Cc", + "c", + 2 + ], + [ + "Cc", + "cAaAAbc", + 11 + ], + [ + "Cc", + "cBbbBbcA", + 13 + ], + [ + "Cc", + "ca", + 3 + ], + [ + "Cc", + "ccAC", + 5 + ], + [ + "Cc", + "ccCb", + 5 + ], + [ + "CcA", + "BbcbaAB", + 10 + ], + [ + "CcA", + "aCA", + 3 + ], + [ + "CcA", + "bAAbca", + 9 + ], + [ + "CcA", + "bBccA", + 5 + ], + [ + "CcA", + "bCCBb", + 7 + ], + [ + "CcA", + "cBAbaC", + 9 + ], + [ + "CcAA", + "bcACbc", + 8 + ], + [ + "CcAAAAC", + "abCa", + 12 + ], + [ + "CcAAAB", + "bBAbaC", + 9 + ], + [ + "CcAAAcCb", + "cAcBcBBC", + 11 + ], + [ + "CcAABaC", + "BbC", + 10 + ], + [ + "CcAABbc", + "BCaAbab", + 9 + ], + [ + "CcAACB", + "b", + 11 + ], + [ + "CcAAaC", + "CAbaab", + 7 + ], + [ + "CcAB", + "BbcCBc", + 8 + ], + [ + "CcAB", + "accAaa", + 7 + ], + [ + "CcABACACb", + "abBBbCAA", + 12 + ], + [ + "CcABBccA", + "cc", + 12 + ], + [ + "CcABb", + "a", + 9 + ], + [ + "CcABbabBA", + "cCA", + 14 + ], + [ + "CcABcAaa", + "Ba", + 12 + ], + [ + "CcACAbc", + "AbBB", + 11 + ], + [ + "CcACbaCA", + "abbBaBbBa", + 16 + ], + [ + "CcACcCAa", + "AaB", + 13 + ], + [ + "CcAa", + "aAbBCCc", + 13 + ], + [ + "CcAa", + "ccBC", + 5 + ], + [ + "CcAaA", + "cbcC", + 8 + ], + [ + "CcAaB", + "babCBbCAC", + 15 + ], + [ + "CcAaCABA", + "cbaBaCCCb", + 12 + ], + [ + "CcAaCcbcB", + "aBbaCAAC", + 13 + ], + [ + "CcAac", + "Cabaac", + 5 + ], + [ + "CcAacBAaC", + "bCACB", + 12 + ], + [ + "CcAb", + "b", + 6 + ], + [ + "CcAbBcBaa", + "CBc", + 12 + ], + [ + "CcAbaaA", + "cCa", + 10 + ], + [ + "CcAbcaB", + "bcA", + 9 + ], + [ + "CcAc", + "AAaaABABA", + 16 + ], + [ + "CcAcAB", + "aabAabCcb", + 14 + ], + [ + "CcAcCcC", + "cACbbac", + 10 + ], + [ + "CcAcCcc", + "A", + 12 + ], + [ + "CcB", + "AbcBBCAac", + 14 + ], + [ + "CcB", + "Ac", + 4 + ], + [ + "CcB", + "Ccb", + 1 + ], + [ + "CcB", + "ba", + 6 + ], + [ + "CcB", + "cab", + 4 + ], + [ + "CcB", + "cbc", + 5 + ], + [ + "CcBABc", + "cAAC", + 7 + ], + [ + "CcBACb", + "ac", + 10 + ], + [ + "CcBAaAa", + "aCCcB", + 12 + ], + [ + "CcBB", + "bab", + 7 + ], + [ + "CcBBA", + "B", + 8 + ], + [ + "CcBBAb", + "aBCAAc", + 10 + ], + [ + "CcBBCAAC", + "A", + 14 + ], + [ + "CcBBbac", + "Bb", + 10 + ], + [ + "CcBCBaa", + "bbbbB", + 11 + ], + [ + "CcBCCaAbC", + "aAaCaCA", + 14 + ], + [ + "CcBCCbABb", + "BbBCbccaC", + 14 + ], + [ + "CcBCaacCB", + "CAbCcbA", + 11 + ], + [ + "CcBCc", + "C", + 8 + ], + [ + "CcBCc", + "cBcba", + 7 + ], + [ + "CcBCccbb", + "abaAAAa", + 15 + ], + [ + "CcBaBb", + "BAabCcBcB", + 12 + ], + [ + "CcBaa", + "abBac", + 6 + ], + [ + "CcBabaabc", + "bCB", + 15 + ], + [ + "CcBacBC", + "aa", + 12 + ], + [ + "CcBb", + "AAB", + 6 + ], + [ + "CcBb", + "BaAcbA", + 9 + ], + [ + "CcBbC", + "A", + 10 + ], + [ + "CcBbaCbb", + "abcBCCBab", + 11 + ], + [ + "CcBbbaB", + "baCb", + 11 + ], + [ + "CcBc", + "aBabCbbcB", + 13 + ], + [ + "CcBc", + "cabcACa", + 10 + ], + [ + "CcBcABAC", + "AAC", + 10 + ], + [ + "CcBcBCBaa", + "CBA", + 13 + ], + [ + "CcC", + "CBAacacBa", + 13 + ], + [ + "CcC", + "CBbcac", + 7 + ], + [ + "CcCAA", + "cB", + 8 + ], + [ + "CcCABC", + "ACA", + 8 + ], + [ + "CcCACCb", + "CbAbCccC", + 11 + ], + [ + "CcCAaCAaB", + "ABbAAaBb", + 12 + ], + [ + "CcCAbB", + "abb", + 8 + ], + [ + "CcCAbCBc", + "cbaCBaB", + 11 + ], + [ + "CcCB", + "ABbCBAc", + 10 + ], + [ + "CcCB", + "bcaabaccc", + 14 + ], + [ + "CcCB", + "cbBaC", + 8 + ], + [ + "CcCBA", + "CbAbcb", + 9 + ], + [ + "CcCBCcCA", + "BbCcaa", + 10 + ], + [ + "CcCBb", + "aBBC", + 8 + ], + [ + "CcCBc", + "BCBb", + 6 + ], + [ + "CcCC", + "b", + 8 + ], + [ + "CcCCAB", + "CCbB", + 6 + ], + [ + "CcCCBACCa", + "ABAABAAAb", + 14 + ], + [ + "CcCCacbB", + "aACA", + 13 + ], + [ + "CcCaA", + "baa", + 7 + ], + [ + "CcCaaaaA", + "bCbbACC", + 13 + ], + [ + "CcCacAB", + "BCCBacCcb", + 10 + ], + [ + "CcCacbC", + "ACBabB", + 9 + ], + [ + "CcCbB", + "BABCbb", + 7 + ], + [ + "CcCbCA", + "aBcA", + 8 + ], + [ + "CcCbCbBbc", + "ccabB", + 11 + ], + [ + "CcCba", + "BCb", + 6 + ], + [ + "CcCbaAbB", + "aBbcaCB", + 11 + ], + [ + "CcCbcaC", + "CcBbaCbCb", + 9 + ], + [ + "CcCc", + "cBAACa", + 9 + ], + [ + "CcCcAB", + "aCBbA", + 9 + ], + [ + "CcCcAc", + "baBacaB", + 11 + ], + [ + "CcCcBB", + "bcbBbcAbB", + 11 + ], + [ + "CcCcCCAb", + "BCBBaABab", + 13 + ], + [ + "CcCca", + "bCaBAB", + 10 + ], + [ + "CcCcaB", + "aAacCCb", + 10 + ], + [ + "CcCcbCb", + "BBBCBaCC", + 12 + ], + [ + "CcCcbCb", + "cC", + 10 + ], + [ + "CcCccCbbc", + "cabBaCB", + 14 + ], + [ + "Cca", + "AbbaBABCA", + 16 + ], + [ + "Cca", + "AcacBcc", + 10 + ], + [ + "Cca", + "a", + 4 + ], + [ + "Cca", + "b", + 6 + ], + [ + "Cca", + "bAbaCBB", + 12 + ], + [ + "CcaAB", + "B", + 8 + ], + [ + "CcaABA", + "a", + 10 + ], + [ + "CcaAC", + "BaCbAbaAa", + 12 + ], + [ + "CcaACB", + "BcBbAAA", + 10 + ], + [ + "CcaACCA", + "bCacCB", + 8 + ], + [ + "CcaAa", + "cCC", + 8 + ], + [ + "CcaAbCCC", + "AbCBCb", + 10 + ], + [ + "CcaAcb", + "bcBAa", + 8 + ], + [ + "CcaAcc", + "babAAAcbB", + 13 + ], + [ + "CcaB", + "BbaCbBbCB", + 14 + ], + [ + "CcaBA", + "ACCCABCBC", + 12 + ], + [ + "CcaBaBC", + "bacAbAab", + 11 + ], + [ + "CcaBaa", + "A", + 11 + ], + [ + "CcaBcBAB", + "Ac", + 13 + ], + [ + "CcaBcC", + "A", + 11 + ], + [ + "CcaCAaabB", + "CABCacccB", + 11 + ], + [ + "CcaCCAAA", + "BCAaCCcc", + 10 + ], + [ + "CcaCa", + "BAa", + 7 + ], + [ + "CcaCabAcb", + "BaaaBAC", + 10 + ], + [ + "CcaCacbba", + "bccAB", + 13 + ], + [ + "CcaCbbA", + "CcB", + 9 + ], + [ + "CcaCcBc", + "cbaCa", + 9 + ], + [ + "Ccaa", + "AabAcaC", + 10 + ], + [ + "CcaaA", + "aaCAA", + 7 + ], + [ + "CcaaAAbc", + "aABCaCacc", + 13 + ], + [ + "CcaaBC", + "abBCaC", + 10 + ], + [ + "Ccaaa", + "cc", + 7 + ], + [ + "CcaaaAB", + "bc", + 12 + ], + [ + "Ccaaaa", + "ABbbbb", + 12 + ], + [ + "Ccaaabccc", + "cA", + 15 + ], + [ + "CcaabbCCA", + "Bbc", + 14 + ], + [ + "Ccab", + "AC", + 7 + ], + [ + "Ccab", + "Cba", + 4 + ], + [ + "Ccab", + "abBAaBB", + 11 + ], + [ + "Ccab", + "abbBCaBb", + 11 + ], + [ + "CcabACcb", + "cCAaC", + 10 + ], + [ + "Ccac", + "cbCCA", + 8 + ], + [ + "CcacB", + "cCBbaCB", + 7 + ], + [ + "CcacBabBC", + "CaBBaB", + 8 + ], + [ + "CcacC", + "AbbacBa", + 10 + ], + [ + "CcacCABB", + "ba", + 14 + ], + [ + "CcacCaA", + "CaAC", + 8 + ], + [ + "CcacaBB", + "B", + 12 + ], + [ + "CcacbC", + "cCb", + 7 + ], + [ + "Ccb", + "AcbABaCC", + 12 + ], + [ + "Ccb", + "CAA", + 4 + ], + [ + "Ccb", + "CbAcC", + 6 + ], + [ + "Ccb", + "c", + 4 + ], + [ + "CcbA", + "BccAc", + 6 + ], + [ + "CcbA", + "aabCBb", + 10 + ], + [ + "CcbA", + "bABb", + 7 + ], + [ + "CcbAACA", + "bcc", + 11 + ], + [ + "CcbAACB", + "acBBAcac", + 10 + ], + [ + "CcbAAaA", + "ccBCaCa", + 8 + ], + [ + "CcbACBA", + "A", + 12 + ], + [ + "CcbACC", + "bbaC", + 7 + ], + [ + "CcbAaBcAA", + "bAcac", + 11 + ], + [ + "CcbAc", + "AcbbBBBa", + 12 + ], + [ + "CcbBAbCcC", + "AAb", + 14 + ], + [ + "CcbBaCC", + "ABcA", + 11 + ], + [ + "CcbBac", + "BCAAA", + 10 + ], + [ + "CcbBbBBA", + "AbB", + 12 + ], + [ + "CcbBbbbbb", + "bb", + 14 + ], + [ + "CcbBc", + "cBAcacB", + 11 + ], + [ + "CcbBcAC", + "BbCcAbcbB", + 11 + ], + [ + "CcbBcaA", + "bbcca", + 8 + ], + [ + "CcbBcc", + "bbcc", + 5 + ], + [ + "CcbCA", + "a", + 9 + ], + [ + "CcbCA", + "aabAA", + 6 + ], + [ + "CcbCbB", + "CACab", + 7 + ], + [ + "CcbCbCA", + "BcaCaCAb", + 8 + ], + [ + "CcbCc", + "AC", + 8 + ], + [ + "CcbCc", + "cBbbc", + 5 + ], + [ + "CcbCcC", + "c", + 10 + ], + [ + "CcbaccBCb", + "bbCBA", + 13 + ], + [ + "CcbbABb", + "CbCbacB", + 8 + ], + [ + "CcbbaAbbB", + "bc", + 16 + ], + [ + "Ccbbb", + "CBAcACB", + 9 + ], + [ + "CcbbbC", + "cBacabCb", + 11 + ], + [ + "CcbbbCbc", + "BbCAaBaB", + 15 + ], + [ + "CcbbcABBa", + "BcAcCcBCB", + 13 + ], + [ + "Ccbc", + "ABAaaBAb", + 15 + ], + [ + "Ccc", + "B", + 6 + ], + [ + "Ccc", + "BABa", + 8 + ], + [ + "Ccc", + "BcaBAc", + 8 + ], + [ + "Ccc", + "CBB", + 4 + ], + [ + "Ccc", + "CC", + 3 + ], + [ + "Ccc", + "aaaaCC", + 10 + ], + [ + "Ccc", + "ac", + 4 + ], + [ + "Ccc", + "bb", + 6 + ], + [ + "CccABA", + "AAbBcA", + 10 + ], + [ + "CccACCB", + "AcbaC", + 9 + ], + [ + "CccAaB", + "baCaBcCa", + 12 + ], + [ + "CccAb", + "aABBc", + 10 + ], + [ + "CccAcbbca", + "c", + 16 + ], + [ + "CccBBBcB", + "bBbbCa", + 11 + ], + [ + "CccBBbC", + "Bba", + 10 + ], + [ + "CccBa", + "B", + 8 + ], + [ + "CccBa", + "caBA", + 5 + ], + [ + "CccBaaAB", + "C", + 14 + ], + [ + "CccBbBCb", + "a", + 16 + ], + [ + "CccBbca", + "BacAbCBbC", + 12 + ], + [ + "CccCAa", + "CcBcBCCc", + 8 + ], + [ + "CccCCa", + "Ba", + 10 + ], + [ + "CccCa", + "aA", + 9 + ], + [ + "CccCb", + "baA", + 10 + ], + [ + "Ccca", + "A", + 7 + ], + [ + "CccaABbBb", + "aAcB", + 12 + ], + [ + "CccaBBCb", + "BBbaaCCC", + 12 + ], + [ + "Cccaa", + "BbbC", + 10 + ], + [ + "CccacCBb", + "ccBa", + 10 + ], + [ + "CccbABBbb", + "B", + 16 + ], + [ + "Cccbbc", + "CCcBcBa", + 7 + ], + [ + "Cccc", + "BaCbb", + 9 + ], + [ + "CcccAB", + "aCBAB", + 7 + ], + [ + "CcccAbbA", + "BCBcBc", + 12 + ], + [ + "CcccBacc", + "BCAcB", + 11 + ], + [ + "CcccBcCB", + "cCAb", + 12 + ], + [ + "a", + "AA", + 3 + ], + [ + "a", + "AABaCbca", + 14 + ], + [ + "a", + "AACaBBAC", + 14 + ], + [ + "a", + "ABCaa", + 8 + ], + [ + "a", + "ABaaBCCb", + 14 + ], + [ + "a", + "ABab", + 6 + ], + [ + "a", + "ABcB", + 7 + ], + [ + "a", + "ACbcCBCB", + 15 + ], + [ + "a", + "ACbcaA", + 10 + ], + [ + "a", + "AaAA", + 6 + ], + [ + "a", + "AaABacaAA", + 16 + ], + [ + "a", + "AaAbBca", + 12 + ], + [ + "a", + "AabBCaab", + 14 + ], + [ + "a", + "AabCbCb", + 12 + ], + [ + "a", + "AaccB", + 8 + ], + [ + "a", + "Ab", + 3 + ], + [ + "a", + "AbBBaB", + 10 + ], + [ + "a", + "AbCb", + 7 + ], + [ + "a", + "AbCc", + 7 + ], + [ + "a", + "AbbbBacAa", + 16 + ], + [ + "a", + "AbcCaCbac", + 16 + ], + [ + "a", + "AcABaA", + 10 + ], + [ + "a", + "AcACCA", + 11 + ], + [ + "a", + "AcCbc", + 9 + ], + [ + "a", + "AcaB", + 6 + ], + [ + "a", + "B", + 2 + ], + [ + "a", + "BA", + 3 + ], + [ + "a", + "BABAAcBBc", + 17 + ], + [ + "a", + "BABaBa", + 10 + ], + [ + "a", + "BAC", + 5 + ], + [ + "a", + "BAaAbAc", + 12 + ], + [ + "a", + "BAabccCBc", + 16 + ], + [ + "a", + "BAbaaa", + 10 + ], + [ + "a", + "BAbb", + 7 + ], + [ + "a", + "BBAcbBB", + 13 + ], + [ + "a", + "BBBaCab", + 12 + ], + [ + "a", + "BBC", + 6 + ], + [ + "a", + "BBaCbBAC", + 14 + ], + [ + "a", + "BBcca", + 8 + ], + [ + "a", + "BCA", + 5 + ], + [ + "a", + "BCBab", + 8 + ], + [ + "a", + "BaAAAcAbc", + 16 + ], + [ + "a", + "BaAcABBC", + 14 + ], + [ + "a", + "BaBcaC", + 10 + ], + [ + "a", + "BaC", + 4 + ], + [ + "a", + "BaabBAabb", + 16 + ], + [ + "a", + "BbCaCa", + 10 + ], + [ + "a", + "BbcACCA", + 13 + ], + [ + "a", + "Bbcba", + 8 + ], + [ + "a", + "BcAb", + 7 + ], + [ + "a", + "BcBABC", + 11 + ], + [ + "a", + "BcBaAacC", + 14 + ], + [ + "a", + "Bca", + 4 + ], + [ + "a", + "Bcabba", + 10 + ], + [ + "a", + "BccCbbAb", + 15 + ], + [ + "a", + "C", + 2 + ], + [ + "a", + "CA", + 3 + ], + [ + "a", + "CABAcBbc", + 15 + ], + [ + "a", + "CABCB", + 9 + ], + [ + "a", + "CAbC", + 7 + ], + [ + "a", + "CAba", + 6 + ], + [ + "a", + "CAcCAa", + 10 + ], + [ + "a", + "CAcc", + 7 + ], + [ + "a", + "CBA", + 5 + ], + [ + "a", + "CBABB", + 9 + ], + [ + "a", + "CBAa", + 6 + ], + [ + "a", + "CBBCcB", + 12 + ], + [ + "a", + "CBBcA", + 9 + ], + [ + "a", + "CBaCAC", + 10 + ], + [ + "a", + "CBbaCCbC", + 14 + ], + [ + "a", + "CCBc", + 8 + ], + [ + "a", + "CCcaC", + 8 + ], + [ + "a", + "Ca", + 2 + ], + [ + "a", + "CaAaC", + 8 + ], + [ + "a", + "CaBacbb", + 12 + ], + [ + "a", + "CaabacC", + 12 + ], + [ + "a", + "CbBc", + 8 + ], + [ + "a", + "CbbcAB", + 11 + ], + [ + "a", + "CcBBaaCc", + 14 + ], + [ + "a", + "CcBbabBAc", + 16 + ], + [ + "a", + "CcaACcB", + 12 + ], + [ + "a", + "Ccca", + 6 + ], + [ + "a", + "a", + 0 + ], + [ + "a", + "aA", + 2 + ], + [ + "a", + "aAACAbCC", + 14 + ], + [ + "a", + "aACABcAb", + 14 + ], + [ + "a", + "aAbaB", + 8 + ], + [ + "a", + "aBB", + 4 + ], + [ + "a", + "aBBCb", + 8 + ], + [ + "a", + "aBaCbb", + 10 + ], + [ + "a", + "aBb", + 4 + ], + [ + "a", + "aC", + 2 + ], + [ + "a", + "aCCCCcab", + 14 + ], + [ + "a", + "aCaBBABa", + 14 + ], + [ + "a", + "aCaC", + 6 + ], + [ + "a", + "aCb", + 4 + ], + [ + "a", + "aCcBaAa", + 12 + ], + [ + "a", + "aa", + 2 + ], + [ + "a", + "aaBbC", + 8 + ], + [ + "a", + "aaCA", + 6 + ], + [ + "a", + "ab", + 2 + ], + [ + "a", + "abACBBAcC", + 16 + ], + [ + "a", + "abBbBba", + 12 + ], + [ + "a", + "abCaAaCbC", + 16 + ], + [ + "a", + "aba", + 4 + ], + [ + "a", + "abcac", + 8 + ], + [ + "a", + "acAcBAbaB", + 16 + ], + [ + "a", + "acBcAA", + 10 + ], + [ + "a", + "accCCCc", + 12 + ], + [ + "a", + "b", + 2 + ], + [ + "a", + "bA", + 3 + ], + [ + "a", + "bAAaB", + 8 + ], + [ + "a", + "bABBa", + 8 + ], + [ + "a", + "bACca", + 8 + ], + [ + "a", + "bAbAccb", + 13 + ], + [ + "a", + "bAccbcaAB", + 16 + ], + [ + "a", + "bBAca", + 8 + ], + [ + "a", + "bBBC", + 8 + ], + [ + "a", + "bBBCaccC", + 14 + ], + [ + "a", + "bBCb", + 8 + ], + [ + "a", + "bBbC", + 8 + ], + [ + "a", + "bBbCABa", + 12 + ], + [ + "a", + "bC", + 4 + ], + [ + "a", + "bCBacAcC", + 14 + ], + [ + "a", + "bCC", + 6 + ], + [ + "a", + "bCCbaccA", + 14 + ], + [ + "a", + "bCbA", + 7 + ], + [ + "a", + "bCbBab", + 10 + ], + [ + "a", + "bCcaCbc", + 12 + ], + [ + "a", + "bCcaaCbB", + 14 + ], + [ + "a", + "ba", + 2 + ], + [ + "a", + "baa", + 4 + ], + [ + "a", + "baacacaba", + 16 + ], + [ + "a", + "babcA", + 8 + ], + [ + "a", + "babcCAA", + 12 + ], + [ + "a", + "bb", + 4 + ], + [ + "a", + "bbAc", + 7 + ], + [ + "a", + "bbB", + 6 + ], + [ + "a", + "bbBA", + 7 + ], + [ + "a", + "bbBBcaBc", + 14 + ], + [ + "a", + "bbBbAaAAc", + 16 + ], + [ + "a", + "bbCCaACb", + 14 + ], + [ + "a", + "bbCaca", + 10 + ], + [ + "a", + "bbaC", + 6 + ], + [ + "a", + "bbbAcAB", + 13 + ], + [ + "a", + "bbbBAABC", + 15 + ], + [ + "a", + "bbcCBcB", + 14 + ], + [ + "a", + "bcAca", + 8 + ], + [ + "a", + "bcAcacCB", + 14 + ], + [ + "a", + "bcaAcBAbC", + 16 + ], + [ + "a", + "bcb", + 6 + ], + [ + "a", + "bcc", + 6 + ], + [ + "a", + "c", + 2 + ], + [ + "a", + "cAC", + 5 + ], + [ + "a", + "cACBACca", + 14 + ], + [ + "a", + "cACaCa", + 10 + ], + [ + "a", + "cAa", + 4 + ], + [ + "a", + "cBAaa", + 8 + ], + [ + "a", + "cBbBbab", + 12 + ], + [ + "a", + "cC", + 4 + ], + [ + "a", + "cCBA", + 7 + ], + [ + "a", + "cCCa", + 6 + ], + [ + "a", + "cCCbaa", + 10 + ], + [ + "a", + "cCaCcb", + 10 + ], + [ + "a", + "cCacac", + 10 + ], + [ + "a", + "cCcBbCBAa", + 16 + ], + [ + "a", + "cabbcaBBc", + 16 + ], + [ + "a", + "cb", + 4 + ], + [ + "a", + "cbAcAab", + 12 + ], + [ + "a", + "cbAcCB", + 11 + ], + [ + "a", + "cbBaC", + 8 + ], + [ + "a", + "cbCcbC", + 12 + ], + [ + "a", + "cbaCbbBb", + 14 + ], + [ + "a", + "cbbAaCA", + 12 + ], + [ + "a", + "ccACCaBAa", + 16 + ], + [ + "a", + "ccACbaC", + 12 + ], + [ + "a", + "ccAbAC", + 11 + ], + [ + "a", + "ccAbbaBA", + 14 + ], + [ + "a", + "ccCBaCcB", + 14 + ], + [ + "a", + "ccac", + 6 + ], + [ + "aA", + "AAc", + 3 + ], + [ + "aA", + "ABcACbCcb", + 15 + ], + [ + "aA", + "ACcbCBA", + 11 + ], + [ + "aA", + "AacACCa", + 10 + ], + [ + "aA", + "B", + 4 + ], + [ + "aA", + "BabBBcCbC", + 16 + ], + [ + "aA", + "Babb", + 6 + ], + [ + "aA", + "BcAcB", + 8 + ], + [ + "aA", + "CAacB", + 8 + ], + [ + "aA", + "CBABBaAB", + 12 + ], + [ + "aA", + "CaBbbbA", + 10 + ], + [ + "aA", + "CcAabB", + 10 + ], + [ + "aA", + "CcaAb", + 6 + ], + [ + "aA", + "a", + 2 + ], + [ + "aA", + "aCAcAb", + 8 + ], + [ + "aA", + "aCBb", + 6 + ], + [ + "aA", + "aCacaAA", + 10 + ], + [ + "aA", + "aaACBacA", + 12 + ], + [ + "aA", + "aaC", + 3 + ], + [ + "aA", + "abbAaBC", + 10 + ], + [ + "aA", + "abbBBbc", + 12 + ], + [ + "aA", + "bAc", + 4 + ], + [ + "aA", + "bB", + 4 + ], + [ + "aA", + "bBCBC", + 10 + ], + [ + "aA", + "baCBAbCa", + 12 + ], + [ + "aA", + "cABBaA", + 8 + ], + [ + "aA", + "cBc", + 6 + ], + [ + "aA", + "cabbabbA", + 12 + ], + [ + "aA", + "ccbcB", + 10 + ], + [ + "aAA", + "aACbBCCb", + 12 + ], + [ + "aAA", + "ac", + 4 + ], + [ + "aAA", + "bAc", + 4 + ], + [ + "aAAA", + "AaAC", + 4 + ], + [ + "aAAAA", + "c", + 10 + ], + [ + "aAAAAC", + "CbaaCCBBa", + 14 + ], + [ + "aAAAAaAA", + "cbAabBb", + 13 + ], + [ + "aAAABb", + "BABBaB", + 9 + ], + [ + "aAAAC", + "bC", + 8 + ], + [ + "aAAAaAb", + "AAC", + 10 + ], + [ + "aAAAabBca", + "AB", + 14 + ], + [ + "aAAAcCbCB", + "CcBbABBB", + 15 + ], + [ + "aAAB", + "A", + 6 + ], + [ + "aAAB", + "bcabAb", + 7 + ], + [ + "aAAB", + "c", + 8 + ], + [ + "aAAB", + "cCAB", + 4 + ], + [ + "aAABCcCcC", + "CbBBCAB", + 14 + ], + [ + "aAABbBACb", + "aACb", + 10 + ], + [ + "aAACC", + "ccbbaBA", + 13 + ], + [ + "aAACaCa", + "ACbabAc", + 11 + ], + [ + "aAAaAAaa", + "ACBcbbcaA", + 14 + ], + [ + "aAAaaaB", + "BABbaaAbA", + 10 + ], + [ + "aAAabaAbA", + "bcCBbaBB", + 13 + ], + [ + "aAAacaaC", + "a", + 14 + ], + [ + "aAAb", + "aCAA", + 4 + ], + [ + "aAAbBbaA", + "BaaaAbb", + 11 + ], + [ + "aAAbCbCcC", + "cBC", + 14 + ], + [ + "aAAbbA", + "bcbbaBa", + 10 + ], + [ + "aAAc", + "AccBbB", + 10 + ], + [ + "aAAcA", + "BBBABa", + 9 + ], + [ + "aAAcA", + "bb", + 10 + ], + [ + "aAAcAA", + "aCAA", + 5 + ], + [ + "aAAcAa", + "CbCAa", + 7 + ], + [ + "aAAcAaa", + "bAAACb", + 8 + ], + [ + "aAAcB", + "AbcACA", + 8 + ], + [ + "aAAcBBba", + "BcaAcACb", + 11 + ], + [ + "aAAcCCbCB", + "C", + 16 + ], + [ + "aAAcCaCc", + "caACAaAa", + 10 + ], + [ + "aAAcCb", + "bbAbA", + 10 + ], + [ + "aAAcabaab", + "cAACAbb", + 8 + ], + [ + "aAAcbACab", + "bCcAaBbCC", + 15 + ], + [ + "aAAcc", + "aaAC", + 4 + ], + [ + "aAB", + "AAaAcCaa", + 12 + ], + [ + "aAB", + "AbCBB", + 7 + ], + [ + "aAB", + "AcaAB", + 4 + ], + [ + "aAB", + "CAbaA", + 7 + ], + [ + "aAB", + "CCBAcbaCC", + 15 + ], + [ + "aAB", + "aBcbbB", + 8 + ], + [ + "aAB", + "aCCcaBCC", + 11 + ], + [ + "aAB", + "bcbccABCA", + 14 + ], + [ + "aABA", + "cCac", + 8 + ], + [ + "aABAB", + "AaaBBcCA", + 11 + ], + [ + "aABACAa", + "CcBBbA", + 10 + ], + [ + "aABAaA", + "C", + 12 + ], + [ + "aABAb", + "BbBCC", + 8 + ], + [ + "aABAb", + "ca", + 9 + ], + [ + "aABAbab", + "a", + 12 + ], + [ + "aABAc", + "AabAabaB", + 10 + ], + [ + "aABAcCbbA", + "aB", + 14 + ], + [ + "aABB", + "CCAaaccbA", + 14 + ], + [ + "aABB", + "aCac", + 6 + ], + [ + "aABB", + "cb", + 7 + ], + [ + "aABBBBCc", + "cBAcbb", + 13 + ], + [ + "aABBBBa", + "CaBaCCBB", + 11 + ], + [ + "aABBCc", + "cc", + 9 + ], + [ + "aABBacCA", + "BBbacBc", + 9 + ], + [ + "aABBbA", + "aCBbC", + 6 + ], + [ + "aABBbaB", + "CbbBCbacb", + 10 + ], + [ + "aABCAa", + "bBbC", + 9 + ], + [ + "aABCB", + "cAB", + 6 + ], + [ + "aABCCcbB", + "CBbaCcbc", + 9 + ], + [ + "aABCaca", + "Bb", + 12 + ], + [ + "aABCbCba", + "CabccBaB", + 11 + ], + [ + "aABaBA", + "BC", + 10 + ], + [ + "aABaBbAAA", + "B", + 16 + ], + [ + "aABb", + "BC", + 6 + ], + [ + "aABbAa", + "bCbBcC", + 10 + ], + [ + "aABbBbCca", + "ABCCBAbAc", + 12 + ], + [ + "aABbaA", + "bcBC", + 10 + ], + [ + "aABbac", + "AbBbABAAb", + 12 + ], + [ + "aABbccca", + "BcaA", + 11 + ], + [ + "aABcACB", + "A", + 12 + ], + [ + "aABccB", + "A", + 10 + ], + [ + "aAC", + "BA", + 4 + ], + [ + "aAC", + "CAbbaab", + 11 + ], + [ + "aAC", + "CbC", + 4 + ], + [ + "aAC", + "b", + 6 + ], + [ + "aAC", + "bACCbC", + 8 + ], + [ + "aAC", + "bcaBacc", + 10 + ], + [ + "aACABAcCa", + "ccCB", + 13 + ], + [ + "aACBA", + "Aa", + 7 + ], + [ + "aACBACA", + "BaCBa", + 8 + ], + [ + "aACBBcBC", + "A", + 14 + ], + [ + "aACCA", + "Cb", + 8 + ], + [ + "aACCAAb", + "Bca", + 12 + ], + [ + "aACCBc", + "AcbAaCB", + 9 + ], + [ + "aACCa", + "ACccABA", + 10 + ], + [ + "aACCbAA", + "AAaa", + 9 + ], + [ + "aACCc", + "BBcc", + 7 + ], + [ + "aACCc", + "cbaBAC", + 10 + ], + [ + "aACaaA", + "bcACaCbA", + 8 + ], + [ + "aACacACa", + "aaBccaB", + 10 + ], + [ + "aACacCb", + "C", + 12 + ], + [ + "aACaccCAC", + "cC", + 14 + ], + [ + "aACbAC", + "AB", + 9 + ], + [ + "aACbBBcb", + "b", + 14 + ], + [ + "aACbbbaBC", + "aBBACCB", + 13 + ], + [ + "aACcaBb", + "ABabA", + 9 + ], + [ + "aACcbCa", + "b", + 12 + ], + [ + "aAa", + "BbBb", + 8 + ], + [ + "aAa", + "CBCBAabb", + 12 + ], + [ + "aAa", + "Cc", + 6 + ], + [ + "aAa", + "bCaaCBcAa", + 12 + ], + [ + "aAa", + "bc", + 6 + ], + [ + "aAaA", + "b", + 8 + ], + [ + "aAaAcc", + "B", + 12 + ], + [ + "aAaAccAb", + "BCAbabcAA", + 11 + ], + [ + "aAaBBCb", + "Cbbc", + 11 + ], + [ + "aAaBaBBBc", + "cAcCCCA", + 16 + ], + [ + "aAaBaBa", + "bBbBc", + 10 + ], + [ + "aAaCB", + "cCc", + 8 + ], + [ + "aAaCCCc", + "bbcBabaAA", + 16 + ], + [ + "aAaCaaAc", + "BCaA", + 10 + ], + [ + "aAaa", + "bb", + 8 + ], + [ + "aAaaAcCA", + "cBbcccB", + 13 + ], + [ + "aAaaBbbb", + "bCca", + 14 + ], + [ + "aAaaC", + "aCAC", + 5 + ], + [ + "aAaaCBa", + "aaCBCc", + 8 + ], + [ + "aAaaaA", + "aBACbaBAC", + 10 + ], + [ + "aAaabBcb", + "AcCAcBA", + 12 + ], + [ + "aAab", + "C", + 8 + ], + [ + "aAab", + "bCaB", + 5 + ], + [ + "aAab", + "bbaacCCB", + 12 + ], + [ + "aAabC", + "ccbBa", + 9 + ], + [ + "aAabCAc", + "aBCb", + 9 + ], + [ + "aAabCCBaa", + "bBC", + 14 + ], + [ + "aAabbbbB", + "CBAACBCCb", + 13 + ], + [ + "aAabbcCaA", + "A", + 16 + ], + [ + "aAac", + "cCBbCAaBB", + 14 + ], + [ + "aAacB", + "cAcbcBa", + 8 + ], + [ + "aAacBcCBa", + "cba", + 13 + ], + [ + "aAb", + "A", + 4 + ], + [ + "aAb", + "a", + 4 + ], + [ + "aAb", + "b", + 4 + ], + [ + "aAbA", + "bccaaaCAB", + 13 + ], + [ + "aAbABAA", + "bCBAcabBb", + 14 + ], + [ + "aAbAC", + "cACcCa", + 8 + ], + [ + "aAbACaBAA", + "CB", + 14 + ], + [ + "aAbAb", + "cBBabc", + 8 + ], + [ + "aAbAcCb", + "c", + 12 + ], + [ + "aAbBB", + "AC", + 8 + ], + [ + "aAbBaBcAA", + "C", + 17 + ], + [ + "aAbCAcbCC", + "BAAaA", + 14 + ], + [ + "aAbCBA", + "aCBaCABc", + 9 + ], + [ + "aAbCCACCb", + "AbcacbAb", + 11 + ], + [ + "aAbCCC", + "Aca", + 9 + ], + [ + "aAbCa", + "bABc", + 6 + ], + [ + "aAbCbCa", + "AabbBCbA", + 8 + ], + [ + "aAbCbbaba", + "CcBbccaB", + 14 + ], + [ + "aAbCc", + "cCa", + 8 + ], + [ + "aAba", + "BbcbcCBcC", + 16 + ], + [ + "aAbaBA", + "aBAAAA", + 7 + ], + [ + "aAbaBBba", + "Cb", + 14 + ], + [ + "aAbaCAA", + "cAB", + 11 + ], + [ + "aAbaaBA", + "bcCbaccBA", + 10 + ], + [ + "aAbb", + "bBBaACCBC", + 13 + ], + [ + "aAbbABabC", + "cbACbB", + 12 + ], + [ + "aAbbBab", + "caaA", + 11 + ], + [ + "aAbbCAA", + "BBbBcbA", + 8 + ], + [ + "aAbbCbCCa", + "AAB", + 14 + ], + [ + "aAbbCbcb", + "CBc", + 11 + ], + [ + "aAbbaB", + "a", + 10 + ], + [ + "aAbbacAb", + "BccBb", + 11 + ], + [ + "aAbbcbA", + "A", + 12 + ], + [ + "aAbcCaA", + "CCc", + 11 + ], + [ + "aAbcaABCA", + "BCAcbCab", + 13 + ], + [ + "aAbcaAa", + "CCababB", + 11 + ], + [ + "aAbcbbB", + "baba", + 10 + ], + [ + "aAc", + "aBbBCbac", + 11 + ], + [ + "aAc", + "abbAbaC", + 9 + ], + [ + "aAcA", + "A", + 6 + ], + [ + "aAcA", + "ACABBCB", + 10 + ], + [ + "aAcAAb", + "ACC", + 9 + ], + [ + "aAcAAbB", + "cAbbBaCBb", + 13 + ], + [ + "aAcAabacA", + "aCbBcA", + 9 + ], + [ + "aAcAacaba", + "caACb", + 11 + ], + [ + "aAcAbaCac", + "bBc", + 14 + ], + [ + "aAcAcAbaB", + "bcCCa", + 13 + ], + [ + "aAcB", + "aaaCC", + 6 + ], + [ + "aAcB", + "caC", + 6 + ], + [ + "aAcBACBB", + "a", + 14 + ], + [ + "aAcBC", + "aCca", + 6 + ], + [ + "aAcBbABB", + "AA", + 12 + ], + [ + "aAcBbAaBC", + "BbCbaCcaC", + 14 + ], + [ + "aAcCAaC", + "b", + 14 + ], + [ + "aAcCCcAc", + "baabCBAaA", + 12 + ], + [ + "aAcCccBB", + "AaAa", + 14 + ], + [ + "aAcaAaB", + "AcC", + 10 + ], + [ + "aAcaBaA", + "ACcaaA", + 5 + ], + [ + "aAcaaac", + "BaABaBaBA", + 10 + ], + [ + "aAcb", + "AABbA", + 5 + ], + [ + "aAcb", + "aABC", + 4 + ], + [ + "aAcbA", + "cbcAAC", + 8 + ], + [ + "aAcbBb", + "CbcccCBcC", + 14 + ], + [ + "aAcbBcca", + "A", + 14 + ], + [ + "aAcba", + "acBcBBBAc", + 12 + ], + [ + "aAcba", + "b", + 8 + ], + [ + "aAcc", + "CACC", + 4 + ], + [ + "aAccac", + "ACABCBBAC", + 12 + ], + [ + "aAccbCaba", + "BCBbBc", + 14 + ], + [ + "aB", + "A", + 3 + ], + [ + "aB", + "AA", + 3 + ], + [ + "aB", + "AB", + 1 + ], + [ + "aB", + "ABAb", + 5 + ], + [ + "aB", + "ACcb", + 6 + ], + [ + "aB", + "Aabaaa", + 9 + ], + [ + "aB", + "AccabABB", + 12 + ], + [ + "aB", + "B", + 2 + ], + [ + "aB", + "BBcbB", + 8 + ], + [ + "aB", + "BCc", + 6 + ], + [ + "aB", + "Bca", + 6 + ], + [ + "aB", + "C", + 4 + ], + [ + "aB", + "CAAaa", + 8 + ], + [ + "aB", + "CbccACC", + 13 + ], + [ + "aB", + "Cc", + 4 + ], + [ + "aB", + "CcAcCC", + 11 + ], + [ + "aB", + "aCbBBc", + 8 + ], + [ + "aB", + "aaAbCb", + 9 + ], + [ + "aB", + "aaaAb", + 7 + ], + [ + "aB", + "aabCACc", + 11 + ], + [ + "aB", + "abAC", + 5 + ], + [ + "aB", + "bB", + 2 + ], + [ + "aB", + "bBB", + 4 + ], + [ + "aB", + "bb", + 3 + ], + [ + "aB", + "bbbca", + 9 + ], + [ + "aB", + "bbc", + 5 + ], + [ + "aB", + "bc", + 4 + ], + [ + "aB", + "bcb", + 5 + ], + [ + "aB", + "cB", + 2 + ], + [ + "aB", + "cCC", + 6 + ], + [ + "aB", + "cc", + 4 + ], + [ + "aBA", + "BAaAaaCBc", + 14 + ], + [ + "aBAAA", + "CBCAbbcAA", + 10 + ], + [ + "aBAAB", + "BacBABcAc", + 10 + ], + [ + "aBAAaB", + "caAc", + 9 + ], + [ + "aBAAacaa", + "acabBBcBC", + 13 + ], + [ + "aBAAbCcB", + "BCB", + 10 + ], + [ + "aBAAcbCc", + "cBCBBcAAB", + 14 + ], + [ + "aBAB", + "aaCc", + 6 + ], + [ + "aBAB", + "bbaAbA", + 8 + ], + [ + "aBABa", + "bacAa", + 6 + ], + [ + "aBABaABc", + "AAaCCC", + 10 + ], + [ + "aBABcaABA", + "CBcbB", + 12 + ], + [ + "aBACC", + "a", + 8 + ], + [ + "aBACa", + "c", + 9 + ], + [ + "aBACba", + "C", + 10 + ], + [ + "aBACcAA", + "B", + 12 + ], + [ + "aBAa", + "aaB", + 5 + ], + [ + "aBAaC", + "cCACbbBb", + 14 + ], + [ + "aBAabaAB", + "cacCbb", + 13 + ], + [ + "aBAabba", + "AaBABbCBc", + 9 + ], + [ + "aBAacCbbb", + "aBaCaAc", + 10 + ], + [ + "aBAacc", + "aAaAAcABC", + 10 + ], + [ + "aBAb", + "aBBbAac", + 8 + ], + [ + "aBAbAC", + "aABAbCAc", + 5 + ], + [ + "aBAbaaab", + "CCbbAaba", + 11 + ], + [ + "aBAbbB", + "aCacbAB", + 7 + ], + [ + "aBAbbcbb", + "bcBAb", + 11 + ], + [ + "aBAcABbb", + "Ca", + 14 + ], + [ + "aBAcBa", + "CbBcCaa", + 9 + ], + [ + "aBAcBbC", + "aaAaBac", + 7 + ], + [ + "aBAca", + "AACACCcAa", + 11 + ], + [ + "aBAcabBA", + "BBACb", + 9 + ], + [ + "aBAcba", + "bBaaCcB", + 10 + ], + [ + "aBAccCaba", + "CAcabBBbC", + 14 + ], + [ + "aBAcca", + "ABAABbCa", + 8 + ], + [ + "aBB", + "AaAbaAaBb", + 13 + ], + [ + "aBB", + "AaCaB", + 6 + ], + [ + "aBB", + "Acbc", + 6 + ], + [ + "aBB", + "aC", + 4 + ], + [ + "aBB", + "aa", + 4 + ], + [ + "aBB", + "bbCAAaBBB", + 12 + ], + [ + "aBBA", + "BAAc", + 6 + ], + [ + "aBBABAaAA", + "AbCAcbAA", + 10 + ], + [ + "aBBABaaaa", + "bCC", + 17 + ], + [ + "aBBABca", + "bA", + 11 + ], + [ + "aBBACC", + "caaCB", + 9 + ], + [ + "aBBAc", + "aCAA", + 6 + ], + [ + "aBBB", + "AcBcBa", + 7 + ], + [ + "aBBBA", + "CcbaAB", + 9 + ], + [ + "aBBBABAB", + "BBA", + 10 + ], + [ + "aBBBACB", + "Aa", + 12 + ], + [ + "aBBBAaA", + "bB", + 11 + ], + [ + "aBBBB", + "AaBb", + 6 + ], + [ + "aBBBCCBbb", + "BCBca", + 12 + ], + [ + "aBBBaBaAa", + "cCCB", + 16 + ], + [ + "aBBC", + "AbabA", + 7 + ], + [ + "aBBC", + "CcbcBBCb", + 10 + ], + [ + "aBBC", + "cCbbBa", + 9 + ], + [ + "aBBCBac", + "AbacacaCC", + 12 + ], + [ + "aBBCBbab", + "bb", + 12 + ], + [ + "aBBCaCCAB", + "ccBAcA", + 12 + ], + [ + "aBBCbAb", + "cACACb", + 10 + ], + [ + "aBBCbB", + "aCabbA", + 8 + ], + [ + "aBBCcabCb", + "CCacAacc", + 14 + ], + [ + "aBBaB", + "BCaccaa", + 10 + ], + [ + "aBBaB", + "bACCbA", + 11 + ], + [ + "aBBaCCab", + "CBcAbcC", + 12 + ], + [ + "aBBaa", + "a", + 8 + ], + [ + "aBBabAb", + "bACbcAa", + 11 + ], + [ + "aBBac", + "BbAa", + 6 + ], + [ + "aBBacABac", + "CbCbc", + 13 + ], + [ + "aBBb", + "BCAaBa", + 9 + ], + [ + "aBBbA", + "aaa", + 7 + ], + [ + "aBBbB", + "bbBaba", + 7 + ], + [ + "aBBbba", + "bCCcacbB", + 14 + ], + [ + "aBBc", + "BccbaCCac", + 14 + ], + [ + "aBBcABB", + "BBcAbCBAB", + 8 + ], + [ + "aBBcBAab", + "CcCBBA", + 12 + ], + [ + "aBBcBBA", + "cC", + 12 + ], + [ + "aBBcBcb", + "BBBca", + 6 + ], + [ + "aBBcaB", + "AbBAa", + 6 + ], + [ + "aBBccB", + "abcac", + 7 + ], + [ + "aBBcca", + "bABb", + 10 + ], + [ + "aBBcccbCB", + "bCcab", + 12 + ], + [ + "aBC", + "AABCBaAAC", + 13 + ], + [ + "aBC", + "CcaCAB", + 10 + ], + [ + "aBC", + "aACCc", + 6 + ], + [ + "aBC", + "aaaCcCcB", + 12 + ], + [ + "aBC", + "bABBAa", + 9 + ], + [ + "aBC", + "bC", + 3 + ], + [ + "aBC", + "baCCa", + 6 + ], + [ + "aBC", + "bc", + 4 + ], + [ + "aBCA", + "AbbcbAb", + 9 + ], + [ + "aBCA", + "CBaAa", + 6 + ], + [ + "aBCAa", + "BbCCAbAAb", + 12 + ], + [ + "aBCAcBAa", + "BC", + 12 + ], + [ + "aBCAcBCAC", + "AABaCbBcA", + 12 + ], + [ + "aBCAccBCB", + "b", + 17 + ], + [ + "aBCBA", + "b", + 9 + ], + [ + "aBCBBCa", + "aCCAaa", + 8 + ], + [ + "aBCBC", + "bCccB", + 8 + ], + [ + "aBCBC", + "bbB", + 7 + ], + [ + "aBCBabb", + "a", + 12 + ], + [ + "aBCCcc", + "caAAc", + 10 + ], + [ + "aBCaB", + "cB", + 7 + ], + [ + "aBCaCa", + "aCA", + 7 + ], + [ + "aBCaCbC", + "BcaaBaABA", + 13 + ], + [ + "aBCab", + "cAacAcCaA", + 12 + ], + [ + "aBCababA", + "ccbABc", + 11 + ], + [ + "aBCac", + "CbCBbaAB", + 11 + ], + [ + "aBCb", + "acabaC", + 8 + ], + [ + "aBCbb", + "C", + 8 + ], + [ + "aBCbbB", + "bCcBb", + 7 + ], + [ + "aBCbcCBc", + "cBaCAc", + 10 + ], + [ + "aBCc", + "bABcbCa", + 9 + ], + [ + "aBCcAc", + "cCAaaAc", + 10 + ], + [ + "aBCcAcAC", + "BCcBaca", + 8 + ], + [ + "aBCcCBaa", + "b", + 15 + ], + [ + "aBCcCBbcC", + "ba", + 16 + ], + [ + "aBCcaBAaC", + "bBbcaCC", + 10 + ], + [ + "aBa", + "cBCbb", + 8 + ], + [ + "aBa", + "caB", + 4 + ], + [ + "aBaA", + "caBAC", + 5 + ], + [ + "aBaAaAcC", + "CAbBbbabc", + 13 + ], + [ + "aBaAcCBBA", + "AcAcc", + 12 + ], + [ + "aBaAcCC", + "Bc", + 10 + ], + [ + "aBaB", + "CBBbc", + 7 + ], + [ + "aBaB", + "bBAaA", + 6 + ], + [ + "aBaBC", + "CBbcaaBA", + 10 + ], + [ + "aBaBbA", + "CCabBBAaC", + 11 + ], + [ + "aBaBbCcc", + "aB", + 12 + ], + [ + "aBaBc", + "CcCAb", + 10 + ], + [ + "aBaC", + "A", + 7 + ], + [ + "aBaC", + "aa", + 4 + ], + [ + "aBaC", + "accAbAC", + 8 + ], + [ + "aBaCCAb", + "cbBC", + 11 + ], + [ + "aBaCaA", + "Aa", + 9 + ], + [ + "aBaCaC", + "CbaCccAc", + 9 + ], + [ + "aBaCaabAc", + "bCcACb", + 13 + ], + [ + "aBaCba", + "baB", + 8 + ], + [ + "aBaa", + "CBaBAABbB", + 12 + ], + [ + "aBaa", + "Cb", + 7 + ], + [ + "aBaaA", + "aAAaABCB", + 9 + ], + [ + "aBaabC", + "bCBbAabAC", + 9 + ], + [ + "aBaabCba", + "bCCaB", + 12 + ], + [ + "aBaabaB", + "AA", + 12 + ], + [ + "aBaacBbca", + "cCc", + 14 + ], + [ + "aBabACAA", + "acABb", + 12 + ], + [ + "aBabBcb", + "bAbA", + 10 + ], + [ + "aBabbaBbc", + "cbaccAb", + 12 + ], + [ + "aBac", + "c", + 6 + ], + [ + "aBacAAcA", + "aaCB", + 11 + ], + [ + "aBacBB", + "cb", + 9 + ], + [ + "aBacC", + "ACCCcAb", + 11 + ], + [ + "aBacCB", + "abccAac", + 9 + ], + [ + "aBaccCAa", + "aBcacaaCb", + 10 + ], + [ + "aBb", + "BCBAabbac", + 13 + ], + [ + "aBb", + "Ccb", + 4 + ], + [ + "aBb", + "aaac", + 6 + ], + [ + "aBb", + "bbcbbbAaC", + 15 + ], + [ + "aBb", + "cbCaBb", + 6 + ], + [ + "aBb", + "cbaB", + 6 + ], + [ + "aBbA", + "bbaaAbab", + 11 + ], + [ + "aBbACC", + "cCcccBCC", + 12 + ], + [ + "aBbAcCBCA", + "cCBab", + 12 + ], + [ + "aBbB", + "BacA", + 8 + ], + [ + "aBbB", + "aCcCb", + 7 + ], + [ + "aBbBA", + "aAcC", + 8 + ], + [ + "aBbBB", + "aBCc", + 6 + ], + [ + "aBbBCbBAa", + "Ac", + 16 + ], + [ + "aBbBa", + "bAa", + 6 + ], + [ + "aBbBbAbC", + "Abc", + 11 + ], + [ + "aBbBbaBA", + "AbbBCccC", + 10 + ], + [ + "aBbBbcBcb", + "abaBAAAAB", + 12 + ], + [ + "aBbC", + "bCbBAcBc", + 12 + ], + [ + "aBbCABBA", + "Caa", + 12 + ], + [ + "aBbCACaCb", + "A", + 16 + ], + [ + "aBbCBCaBC", + "aCcc", + 12 + ], + [ + "aBbCaa", + "cbAC", + 9 + ], + [ + "aBbCbbbBA", + "aA", + 14 + ], + [ + "aBbCbcCAb", + "BcAC", + 12 + ], + [ + "aBbCc", + "AcACCCba", + 12 + ], + [ + "aBba", + "BcAcCBB", + 12 + ], + [ + "aBbaAACBA", + "BacacbaC", + 12 + ], + [ + "aBbaAB", + "bbCc", + 9 + ], + [ + "aBbaBcC", + "c", + 12 + ], + [ + "aBbaCcbC", + "bbbbcab", + 10 + ], + [ + "aBbaaCcaA", + "bBABBAbCc", + 13 + ], + [ + "aBbabCc", + "CaCB", + 10 + ], + [ + "aBbb", + "Bb", + 4 + ], + [ + "aBbb", + "cccAbB", + 9 + ], + [ + "aBbbA", + "AAC", + 9 + ], + [ + "aBbbAB", + "C", + 12 + ], + [ + "aBbbCab", + "AaCBacaba", + 10 + ], + [ + "aBbbbBA", + "BcbbBBA", + 5 + ], + [ + "aBbcCBaCc", + "C", + 16 + ], + [ + "aBbcCba", + "BbAcaBac", + 9 + ], + [ + "aBc", + "A", + 5 + ], + [ + "aBc", + "Bac", + 4 + ], + [ + "aBc", + "bCCc", + 6 + ], + [ + "aBc", + "baC", + 5 + ], + [ + "aBcAA", + "ABc", + 5 + ], + [ + "aBcAABabC", + "cab", + 12 + ], + [ + "aBcAaAccc", + "BacacaA", + 12 + ], + [ + "aBcAabAA", + "aBcB", + 9 + ], + [ + "aBcAc", + "bCCbbCc", + 11 + ], + [ + "aBcB", + "c", + 6 + ], + [ + "aBcBBBA", + "BbBBaAAab", + 12 + ], + [ + "aBcBBCAbb", + "AAA", + 15 + ], + [ + "aBcBaa", + "bbB", + 9 + ], + [ + "aBcBbbCb", + "cAcBCca", + 11 + ], + [ + "aBcC", + "CCAAA", + 10 + ], + [ + "aBcCABCc", + "BCbbcC", + 9 + ], + [ + "aBcCBbAc", + "cAbABaAa", + 12 + ], + [ + "aBcCCbA", + "cbA", + 8 + ], + [ + "aBcCcbaAC", + "aBBbBaB", + 11 + ], + [ + "aBca", + "BacbCCcB", + 11 + ], + [ + "aBca", + "CBAcCcCA", + 11 + ], + [ + "aBcaCC", + "c", + 10 + ], + [ + "aBcaaBB", + "BAbBaACbc", + 12 + ], + [ + "aBcbABAAa", + "bCCc", + 16 + ], + [ + "aBcbCAb", + "abA", + 8 + ], + [ + "aBcba", + "cAbCC", + 9 + ], + [ + "aBccABa", + "baBbCAAB", + 9 + ], + [ + "aBccAbac", + "CAaaCbb", + 14 + ], + [ + "aBccacCBa", + "ccbc", + 12 + ], + [ + "aBcccC", + "CccbACAcc", + 12 + ], + [ + "aC", + "AABacca", + 11 + ], + [ + "aC", + "ABABACC", + 11 + ], + [ + "aC", + "AcaBa", + 8 + ], + [ + "aC", + "AcaCBcaCB", + 14 + ], + [ + "aC", + "BBbbBcA", + 13 + ], + [ + "aC", + "BCABB", + 8 + ], + [ + "aC", + "Ba", + 4 + ], + [ + "aC", + "BaACBc", + 8 + ], + [ + "aC", + "BacccCb", + 10 + ], + [ + "aC", + "BcACaaCa", + 12 + ], + [ + "aC", + "BcB", + 5 + ], + [ + "aC", + "CAAcA", + 8 + ], + [ + "aC", + "CBbB", + 8 + ], + [ + "aC", + "CCA", + 4 + ], + [ + "aC", + "CaAA", + 6 + ], + [ + "aC", + "a", + 2 + ], + [ + "aC", + "aACaBBaB", + 12 + ], + [ + "aC", + "abCBcb", + 8 + ], + [ + "aC", + "abcabC", + 8 + ], + [ + "aC", + "bA", + 4 + ], + [ + "aC", + "bABAabc", + 11 + ], + [ + "aC", + "bBAAbCAcB", + 15 + ], + [ + "aC", + "bBaaaA", + 10 + ], + [ + "aC", + "bCBA", + 6 + ], + [ + "aC", + "baaaCC", + 8 + ], + [ + "aC", + "babcC", + 6 + ], + [ + "aC", + "bbc", + 5 + ], + [ + "aC", + "caCbAcaCc", + 14 + ], + [ + "aC", + "cbCaCaB", + 10 + ], + [ + "aCA", + "BCcBBaBc", + 13 + ], + [ + "aCA", + "CAACacC", + 10 + ], + [ + "aCA", + "bAaaC", + 8 + ], + [ + "aCA", + "babAaaBaC", + 14 + ], + [ + "aCA", + "baccbBBC", + 13 + ], + [ + "aCA", + "cBCc", + 6 + ], + [ + "aCAAA", + "aB", + 8 + ], + [ + "aCAAAaAba", + "BAbB", + 14 + ], + [ + "aCAABBBBb", + "BBABB", + 11 + ], + [ + "aCAACBcA", + "aA", + 12 + ], + [ + "aCAAaaa", + "AcbacaACb", + 12 + ], + [ + "aCAAbCBbA", + "cBc", + 15 + ], + [ + "aCAAcbC", + "CAaAcCcCc", + 10 + ], + [ + "aCAB", + "AbabAb", + 7 + ], + [ + "aCAB", + "BA", + 6 + ], + [ + "aCAB", + "CBAC", + 6 + ], + [ + "aCABAcBac", + "CCBCcbCC", + 10 + ], + [ + "aCABBC", + "ABb", + 7 + ], + [ + "aCABaAaC", + "BCaaABcC", + 9 + ], + [ + "aCABaBca", + "c", + 14 + ], + [ + "aCABaa", + "C", + 10 + ], + [ + "aCACACAC", + "baAbACC", + 8 + ], + [ + "aCACBBC", + "aCACBaAac", + 7 + ], + [ + "aCACBaaA", + "acCcCB", + 10 + ], + [ + "aCACCca", + "aBA", + 10 + ], + [ + "aCACa", + "baBbABB", + 10 + ], + [ + "aCACcbaa", + "CbAbBCBb", + 14 + ], + [ + "aCAa", + "bBCCcc", + 10 + ], + [ + "aCAaCba", + "AabAc", + 9 + ], + [ + "aCAab", + "CCCcCCAA", + 13 + ], + [ + "aCAacCAAa", + "abAcBacA", + 10 + ], + [ + "aCAb", + "Aaac", + 6 + ], + [ + "aCAbCC", + "bca", + 9 + ], + [ + "aCAbCC", + "cCABABac", + 10 + ], + [ + "aCAbCaCca", + "cACA", + 12 + ], + [ + "aCAbaBab", + "BABbA", + 11 + ], + [ + "aCAbca", + "B", + 11 + ], + [ + "aCAcBbbC", + "acaAbACAB", + 12 + ], + [ + "aCAcaCB", + "CbC", + 10 + ], + [ + "aCAcacc", + "aA", + 10 + ], + [ + "aCAcbA", + "aa", + 9 + ], + [ + "aCAcbabB", + "Aabbca", + 12 + ], + [ + "aCAccCa", + "AaBca", + 8 + ], + [ + "aCB", + "A", + 5 + ], + [ + "aCB", + "aAaCbBcA", + 10 + ], + [ + "aCB", + "aBABAaccA", + 14 + ], + [ + "aCB", + "aBcAb", + 6 + ], + [ + "aCB", + "abCbBA", + 6 + ], + [ + "aCB", + "b", + 5 + ], + [ + "aCB", + "cCcaBbc", + 10 + ], + [ + "aCBA", + "BCcCccBA", + 10 + ], + [ + "aCBA", + "cCCbcA", + 7 + ], + [ + "aCBAabBa", + "aA", + 12 + ], + [ + "aCBAb", + "B", + 8 + ], + [ + "aCBAbb", + "c", + 11 + ], + [ + "aCBB", + "bAb", + 7 + ], + [ + "aCBBAAB", + "bcbCAAAbc", + 11 + ], + [ + "aCBBBAab", + "CBcBbBcb", + 9 + ], + [ + "aCBBCcC", + "aBaCAa", + 8 + ], + [ + "aCBBabca", + "bCaaC", + 11 + ], + [ + "aCBBbb", + "cb", + 9 + ], + [ + "aCBBcBBC", + "c", + 14 + ], + [ + "aCBCCa", + "AaaABcA", + 10 + ], + [ + "aCBCc", + "bacBbaaaA", + 13 + ], + [ + "aCBa", + "cAA", + 6 + ], + [ + "aCBaABA", + "ba", + 11 + ], + [ + "aCBaAC", + "a", + 10 + ], + [ + "aCBaacBc", + "cacacCBB", + 10 + ], + [ + "aCBb", + "Ba", + 6 + ], + [ + "aCBb", + "CaAc", + 8 + ], + [ + "aCBb", + "CaBb", + 4 + ], + [ + "aCBbABbA", + "CbBcaA", + 10 + ], + [ + "aCBbACC", + "cAaBBC", + 10 + ], + [ + "aCBbBAcBB", + "aabBbCcaB", + 9 + ], + [ + "aCBbBc", + "aBabCbbaC", + 10 + ], + [ + "aCBbcccA", + "cCA", + 11 + ], + [ + "aCBc", + "ABAAaC", + 10 + ], + [ + "aCBc", + "BCcc", + 4 + ], + [ + "aCBcB", + "bBCCAC", + 10 + ], + [ + "aCBcaC", + "A", + 11 + ], + [ + "aCC", + "AB", + 5 + ], + [ + "aCC", + "Ac", + 4 + ], + [ + "aCC", + "abABbCBc", + 11 + ], + [ + "aCC", + "cBAcBCcb", + 12 + ], + [ + "aCC", + "cCCcBaa", + 10 + ], + [ + "aCCAA", + "C", + 8 + ], + [ + "aCCAB", + "bbCB", + 6 + ], + [ + "aCCABabA", + "aCa", + 10 + ], + [ + "aCCAcCbA", + "cBbCc", + 13 + ], + [ + "aCCAccAA", + "CB", + 14 + ], + [ + "aCCBBB", + "cccacc", + 10 + ], + [ + "aCCBCcA", + "aAc", + 10 + ], + [ + "aCCBCcCC", + "acBCbA", + 9 + ], + [ + "aCCC", + "ACbCcBa", + 8 + ], + [ + "aCCCBAC", + "AB", + 11 + ], + [ + "aCCCBCBa", + "a", + 14 + ], + [ + "aCCCBaAAa", + "CcBb", + 13 + ], + [ + "aCCCCB", + "cCABAcbA", + 12 + ], + [ + "aCCCCbCc", + "B", + 15 + ], + [ + "aCCCCcCb", + "AAB", + 14 + ], + [ + "aCCCab", + "BAaBcaC", + 10 + ], + [ + "aCCCc", + "aBabBBaa", + 14 + ], + [ + "aCCaA", + "aAAbb", + 8 + ], + [ + "aCCaA", + "cAA", + 6 + ], + [ + "aCCaBCcb", + "BAcc", + 12 + ], + [ + "aCCaC", + "CcacABac", + 10 + ], + [ + "aCCbBBbCB", + "baAcABCC", + 13 + ], + [ + "aCCbbAC", + "BAcbcB", + 11 + ], + [ + "aCCbbbaaB", + "abbC", + 12 + ], + [ + "aCCc", + "bAa", + 8 + ], + [ + "aCCc", + "cbaB", + 8 + ], + [ + "aCCcABBCB", + "bbC", + 14 + ], + [ + "aCCcBBABA", + "bABaacb", + 15 + ], + [ + "aCCcBCCBc", + "a", + 16 + ], + [ + "aCCcbaa", + "B", + 13 + ], + [ + "aCCccBBa", + "baAB", + 14 + ], + [ + "aCa", + "B", + 6 + ], + [ + "aCa", + "BCcC", + 6 + ], + [ + "aCa", + "bbbbCBA", + 11 + ], + [ + "aCaAAACa", + "AcCAA", + 10 + ], + [ + "aCaAAb", + "BCBccaB", + 10 + ], + [ + "aCaABBc", + "aCAbcbB", + 8 + ], + [ + "aCaABbAb", + "aBc", + 12 + ], + [ + "aCaAb", + "aCc", + 6 + ], + [ + "aCaAcCBb", + "baCcbb", + 9 + ], + [ + "aCaAcaC", + "BBCcCcbc", + 11 + ], + [ + "aCaB", + "BacaaAcBA", + 11 + ], + [ + "aCaB", + "C", + 6 + ], + [ + "aCaBAC", + "ab", + 9 + ], + [ + "aCaBBa", + "B", + 10 + ], + [ + "aCaBCB", + "a", + 10 + ], + [ + "aCaBCCB", + "cAccc", + 10 + ], + [ + "aCaBa", + "aC", + 6 + ], + [ + "aCaBacB", + "AAbcaB", + 9 + ], + [ + "aCaC", + "BBcc", + 7 + ], + [ + "aCaC", + "CAAaCAB", + 9 + ], + [ + "aCaC", + "accBcAAbA", + 14 + ], + [ + "aCaCAAac", + "CcCAB", + 10 + ], + [ + "aCaCBaaBb", + "CC", + 14 + ], + [ + "aCaCacAba", + "cbaAbBB", + 13 + ], + [ + "aCaCccca", + "CbACAc", + 11 + ], + [ + "aCaa", + "BAbB", + 8 + ], + [ + "aCaaC", + "ABacC", + 5 + ], + [ + "aCaac", + "AcabAC", + 6 + ], + [ + "aCaacB", + "CA", + 9 + ], + [ + "aCaacacbC", + "b", + 16 + ], + [ + "aCab", + "AcccBcB", + 11 + ], + [ + "aCab", + "BaaacBbbA", + 12 + ], + [ + "aCabBacCB", + "AAc", + 14 + ], + [ + "aCabCBBB", + "CBBcBbBBB", + 10 + ], + [ + "aCabCbbb", + "CBCCCcA", + 12 + ], + [ + "aCabaA", + "bABbaB", + 8 + ], + [ + "aCabbbCA", + "Ba", + 14 + ], + [ + "aCabcb", + "bBBb", + 9 + ], + [ + "aCacA", + "BbAB", + 9 + ], + [ + "aCacCa", + "baABcBcAb", + 12 + ], + [ + "aCacCcAaC", + "CbAbBa", + 14 + ], + [ + "aCacbC", + "CcbABcb", + 10 + ], + [ + "aCb", + "AaBaAc", + 10 + ], + [ + "aCb", + "BB", + 5 + ], + [ + "aCb", + "a", + 4 + ], + [ + "aCb", + "cCbBC", + 6 + ], + [ + "aCbA", + "CcCccBc", + 11 + ], + [ + "aCbA", + "bBaC", + 8 + ], + [ + "aCbAa", + "AABbbcCAC", + 13 + ], + [ + "aCbBAA", + "BcCC", + 11 + ], + [ + "aCbBAB", + "bcCBb", + 8 + ], + [ + "aCbBB", + "B", + 8 + ], + [ + "aCbBCaB", + "aCcAcaAbB", + 9 + ], + [ + "aCbBb", + "CBbA", + 6 + ], + [ + "aCbCBB", + "CAaACaA", + 11 + ], + [ + "aCbCBc", + "ABaBAcAcC", + 13 + ], + [ + "aCbCcCBCB", + "CBbc", + 13 + ], + [ + "aCba", + "aCba", + 0 + ], + [ + "aCbaa", + "BacbBccb", + 11 + ], + [ + "aCbb", + "bBcCBAAcc", + 15 + ], + [ + "aCbbCCCB", + "AaAC", + 13 + ], + [ + "aCbbaBAa", + "BbB", + 11 + ], + [ + "aCbbc", + "BBCAb", + 8 + ], + [ + "aCbbcAcB", + "accCaaB", + 9 + ], + [ + "aCbca", + "AbAc", + 7 + ], + [ + "aCbcb", + "cBcacaa", + 11 + ], + [ + "aCbcc", + "cBCbBAbB", + 12 + ], + [ + "aCbcca", + "CBbCaaCC", + 11 + ], + [ + "aCbccb", + "cAAab", + 9 + ], + [ + "aCc", + "AaAbC", + 7 + ], + [ + "aCc", + "BCbb", + 6 + ], + [ + "aCc", + "CCABBCAa", + 13 + ], + [ + "aCc", + "aAB", + 4 + ], + [ + "aCc", + "bbAcb", + 8 + ], + [ + "aCc", + "bbCcccb", + 10 + ], + [ + "aCc", + "caCAC", + 5 + ], + [ + "aCcA", + "a", + 6 + ], + [ + "aCcA", + "aC", + 4 + ], + [ + "aCcA", + "aaAAaaCBa", + 13 + ], + [ + "aCcA", + "cABb", + 8 + ], + [ + "aCcAAA", + "AbaBACBC", + 13 + ], + [ + "aCcABAc", + "BC", + 11 + ], + [ + "aCcABCB", + "b", + 13 + ], + [ + "aCcACA", + "baCcaaAa", + 7 + ], + [ + "aCcAaAba", + "aCAca", + 8 + ], + [ + "aCcAbB", + "cBCAB", + 7 + ], + [ + "aCcB", + "CCbcBaBBb", + 12 + ], + [ + "aCcBbCAC", + "CACbBb", + 11 + ], + [ + "aCcCC", + "A", + 9 + ], + [ + "aCcCCa", + "CcCabCc", + 8 + ], + [ + "aCcCabC", + "BcACaABCC", + 10 + ], + [ + "aCcCcAaA", + "baaAacBAb", + 13 + ], + [ + "aCcCca", + "cBCbCCAcb", + 11 + ], + [ + "aCcaAABb", + "BCACAAb", + 8 + ], + [ + "aCcaCAA", + "AabCbBBAC", + 12 + ], + [ + "aCcacbabC", + "a", + 16 + ], + [ + "aCcbAb", + "CbbcbaCAB", + 11 + ], + [ + "aCcbB", + "aA", + 8 + ], + [ + "aCcbBbAcC", + "bBBc", + 11 + ], + [ + "aCcbaCbca", + "bcBCCcbC", + 12 + ], + [ + "aCcbb", + "ccAabbABa", + 13 + ], + [ + "aCcbbaccb", + "AaCaCaCC", + 12 + ], + [ + "aCcbcBBA", + "CaBccABCa", + 11 + ], + [ + "aCcbcb", + "AcaacBCc", + 10 + ], + [ + "aCcc", + "baCACCa", + 8 + ], + [ + "aCccAaBa", + "BAaBcB", + 12 + ], + [ + "aCccAb", + "bBbaAcCC", + 13 + ], + [ + "aCccBB", + "CCa", + 9 + ], + [ + "aCccaaABC", + "CcBac", + 11 + ], + [ + "aCcccAaba", + "ccBbaA", + 11 + ], + [ + "aa", + "AACcaACB", + 13 + ], + [ + "aa", + "AcBCa", + 7 + ], + [ + "aa", + "Bbaba", + 6 + ], + [ + "aa", + "Bbc", + 6 + ], + [ + "aa", + "BcaBA", + 7 + ], + [ + "aa", + "C", + 4 + ], + [ + "aa", + "CBcC", + 8 + ], + [ + "aa", + "CbB", + 6 + ], + [ + "aa", + "CbBC", + 8 + ], + [ + "aa", + "a", + 2 + ], + [ + "aa", + "aABACBBb", + 13 + ], + [ + "aa", + "aBC", + 4 + ], + [ + "aa", + "aBcaaCAC", + 12 + ], + [ + "aa", + "aCbbAaaCa", + 14 + ], + [ + "aa", + "aaAaA", + 6 + ], + [ + "aa", + "aaAbcb", + 8 + ], + [ + "aa", + "aabCb", + 6 + ], + [ + "aa", + "abCBc", + 8 + ], + [ + "aa", + "abCbAb", + 9 + ], + [ + "aa", + "acAAbAAB", + 13 + ], + [ + "aa", + "bAaB", + 5 + ], + [ + "aa", + "bB", + 4 + ], + [ + "aa", + "bBAaBCA", + 11 + ], + [ + "aa", + "bCaaBbCA", + 12 + ], + [ + "aa", + "baCCBCBB", + 14 + ], + [ + "aa", + "bbAabBcCc", + 15 + ], + [ + "aa", + "bbcAC", + 9 + ], + [ + "aa", + "cAaabc", + 8 + ], + [ + "aa", + "cB", + 4 + ], + [ + "aa", + "cBB", + 6 + ], + [ + "aa", + "cBcBAAbA", + 14 + ], + [ + "aa", + "cCAB", + 7 + ], + [ + "aa", + "cCB", + 6 + ], + [ + "aa", + "caccAcB", + 11 + ], + [ + "aa", + "cb", + 4 + ], + [ + "aa", + "cbbcCB", + 12 + ], + [ + "aaA", + "A", + 4 + ], + [ + "aaA", + "ACBACBC", + 11 + ], + [ + "aaA", + "bCCA", + 6 + ], + [ + "aaA", + "bcaaAB", + 6 + ], + [ + "aaAA", + "aab", + 4 + ], + [ + "aaAAaaAaB", + "BAA", + 14 + ], + [ + "aaAAbbAC", + "cCbBbCAab", + 14 + ], + [ + "aaAAcC", + "cabbCa", + 9 + ], + [ + "aaAB", + "cAa", + 6 + ], + [ + "aaAB", + "cCaBCcB", + 10 + ], + [ + "aaABAbAC", + "CCAB", + 12 + ], + [ + "aaABAbb", + "CC", + 14 + ], + [ + "aaABB", + "Ccb", + 9 + ], + [ + "aaABCC", + "acABACB", + 6 + ], + [ + "aaABCb", + "CABbAaa", + 12 + ], + [ + "aaABaaA", + "CaaaBBabc", + 9 + ], + [ + "aaABbbCbc", + "B", + 16 + ], + [ + "aaAC", + "Ac", + 5 + ], + [ + "aaAC", + "bccBBBb", + 14 + ], + [ + "aaACa", + "cbAAaCB", + 9 + ], + [ + "aaAaAcbBC", + "A", + 16 + ], + [ + "aaAaaaAb", + "bcBc", + 16 + ], + [ + "aaAabBCbc", + "B", + 16 + ], + [ + "aaAabCaAa", + "BbbbcA", + 13 + ], + [ + "aaAabbbaC", + "bbbCaAbC", + 14 + ], + [ + "aaAac", + "cBCCc", + 8 + ], + [ + "aaAbaBbBa", + "baaCCa", + 12 + ], + [ + "aaAbcbBa", + "BbBbaaC", + 12 + ], + [ + "aaAc", + "bbCBca", + 10 + ], + [ + "aaAccCbC", + "BBa", + 15 + ], + [ + "aaB", + "bAAa", + 6 + ], + [ + "aaB", + "cccCAcAaC", + 15 + ], + [ + "aaBA", + "ABccb", + 9 + ], + [ + "aaBA", + "aca", + 5 + ], + [ + "aaBABCc", + "Aaa", + 10 + ], + [ + "aaBABaCc", + "acBaac", + 7 + ], + [ + "aaBABbCAc", + "cCb", + 16 + ], + [ + "aaBB", + "BbbBbcAB", + 12 + ], + [ + "aaBB", + "bAaAaAB", + 8 + ], + [ + "aaBB", + "bBabBA", + 7 + ], + [ + "aaBBa", + "caaB", + 6 + ], + [ + "aaBC", + "BacaAB", + 8 + ], + [ + "aaBCAaaaB", + "aaACA", + 10 + ], + [ + "aaBCC", + "BAAaBb", + 9 + ], + [ + "aaBCCa", + "CA", + 9 + ], + [ + "aaBCCbAac", + "AcaaBacc", + 13 + ], + [ + "aaBa", + "BabbcC", + 9 + ], + [ + "aaBaAaCa", + "aBbcAcAb", + 11 + ], + [ + "aaBaC", + "bcCAbac", + 9 + ], + [ + "aaBaCc", + "BCAaCCb", + 9 + ], + [ + "aaBaa", + "AAb", + 7 + ], + [ + "aaBaa", + "ccba", + 7 + ], + [ + "aaBaaAcBA", + "aCcBCAc", + 12 + ], + [ + "aaBabACBC", + "CCCc", + 15 + ], + [ + "aaBabbBA", + "aAbB", + 9 + ], + [ + "aaBacaB", + "BCABCCCbc", + 13 + ], + [ + "aaBbAaBA", + "BAc", + 12 + ], + [ + "aaBbb", + "aA", + 7 + ], + [ + "aaBbcA", + "CBcb", + 8 + ], + [ + "aaBbcbb", + "C", + 13 + ], + [ + "aaBcBaBa", + "aaBaaaB", + 6 + ], + [ + "aaBccACb", + "bCCBccC", + 10 + ], + [ + "aaC", + "ABcAca", + 9 + ], + [ + "aaC", + "BAbaCaa", + 9 + ], + [ + "aaC", + "CaCbcCc", + 10 + ], + [ + "aaC", + "Cc", + 5 + ], + [ + "aaC", + "aCa", + 4 + ], + [ + "aaC", + "caBBCb", + 8 + ], + [ + "aaCA", + "B", + 8 + ], + [ + "aaCAA", + "BcbBC", + 10 + ], + [ + "aaCABbb", + "CCcbBAb", + 9 + ], + [ + "aaCACa", + "Bb", + 12 + ], + [ + "aaCAcbc", + "AaaAAa", + 9 + ], + [ + "aaCAccaAB", + "CcCABcA", + 10 + ], + [ + "aaCC", + "B", + 8 + ], + [ + "aaCCC", + "ABAcC", + 6 + ], + [ + "aaCCCc", + "cCAaaAbAb", + 14 + ], + [ + "aaCCa", + "CAA", + 7 + ], + [ + "aaCCbaCaB", + "cCCcCAccC", + 13 + ], + [ + "aaCCcbCA", + "acAcb", + 9 + ], + [ + "aaCa", + "aCBca", + 5 + ], + [ + "aaCa", + "cAAca", + 5 + ], + [ + "aaCaABa", + "ba", + 11 + ], + [ + "aaCaABbc", + "B", + 14 + ], + [ + "aaCaBaA", + "aBcAa", + 8 + ], + [ + "aaCaa", + "Ac", + 8 + ], + [ + "aaCacA", + "CbabcA", + 8 + ], + [ + "aaCacAAb", + "CcCAc", + 10 + ], + [ + "aaCacaBC", + "BBaCcA", + 11 + ], + [ + "aaCacaba", + "ACbc", + 11 + ], + [ + "aaCbAAB", + "ABc", + 12 + ], + [ + "aaCbabb", + "Bc", + 13 + ], + [ + "aaCbabc", + "C", + 12 + ], + [ + "aaCbbAAc", + "BaBa", + 12 + ], + [ + "aaCcAcc", + "aC", + 10 + ], + [ + "aaCcaBcB", + "ccAaAbaBC", + 12 + ], + [ + "aaCcaC", + "AAABCccC", + 8 + ], + [ + "aaCccbAaa", + "B", + 17 + ], + [ + "aaa", + "ABAbCbC", + 12 + ], + [ + "aaa", + "abABCcbA", + 12 + ], + [ + "aaa", + "abaC", + 4 + ], + [ + "aaa", + "baa", + 2 + ], + [ + "aaa", + "cCbC", + 8 + ], + [ + "aaaA", + "BaCacbbc", + 12 + ], + [ + "aaaA", + "aaaabAC", + 6 + ], + [ + "aaaAAb", + "abCC", + 10 + ], + [ + "aaaAAcb", + "cbABcb", + 8 + ], + [ + "aaaABb", + "BBCCbBaba", + 14 + ], + [ + "aaaACcA", + "aaa", + 8 + ], + [ + "aaaAac", + "CCAaC", + 7 + ], + [ + "aaaAb", + "ACc", + 9 + ], + [ + "aaaB", + "b", + 7 + ], + [ + "aaaBBB", + "CcACCaCB", + 13 + ], + [ + "aaaBCAbBc", + "baCaab", + 12 + ], + [ + "aaaBaBCAb", + "BaBccAb", + 9 + ], + [ + "aaaBbAC", + "baBCAc", + 7 + ], + [ + "aaaBbBA", + "a", + 12 + ], + [ + "aaaC", + "aca", + 4 + ], + [ + "aaaCAAcAA", + "cCacb", + 13 + ], + [ + "aaaCBacCc", + "aA", + 15 + ], + [ + "aaaCaBcCC", + "ACAbBb", + 13 + ], + [ + "aaaCaaC", + "C", + 12 + ], + [ + "aaaCaaCb", + "bC", + 14 + ], + [ + "aaaCb", + "bcBbaB", + 11 + ], + [ + "aaaCbC", + "AabAc", + 8 + ], + [ + "aaaCcB", + "A", + 11 + ], + [ + "aaaa", + "CacBC", + 8 + ], + [ + "aaaaB", + "aCBcbC", + 9 + ], + [ + "aaaaBBCc", + "aCcCcaab", + 14 + ], + [ + "aaaaBCc", + "bcbaB", + 10 + ], + [ + "aaaaC", + "CBb", + 10 + ], + [ + "aaabCBaAB", + "cbBccA", + 14 + ], + [ + "aaac", + "BAaB", + 5 + ], + [ + "aaacCCB", + "aaAaacA", + 8 + ], + [ + "aab", + "CcCcaACB", + 12 + ], + [ + "aab", + "ab", + 2 + ], + [ + "aab", + "b", + 4 + ], + [ + "aab", + "bBb", + 4 + ], + [ + "aab", + "ccbCc", + 8 + ], + [ + "aabAA", + "CBCcBcac", + 14 + ], + [ + "aabACB", + "AACA", + 7 + ], + [ + "aabACB", + "Ca", + 10 + ], + [ + "aabAacba", + "bCbcBC", + 11 + ], + [ + "aabAbBc", + "AbCaCcCB", + 13 + ], + [ + "aabBAA", + "CbaACAbAA", + 10 + ], + [ + "aabBBcB", + "CbACCCc", + 13 + ], + [ + "aabCAAc", + "CBaA", + 10 + ], + [ + "aabCAcB", + "BBCA", + 9 + ], + [ + "aabaCc", + "Acab", + 9 + ], + [ + "aabb", + "a", + 6 + ], + [ + "aabbA", + "bA", + 6 + ], + [ + "aabbCAA", + "AaAAAbbC", + 11 + ], + [ + "aabbacA", + "AbC", + 10 + ], + [ + "aabbcABba", + "AC", + 16 + ], + [ + "aabc", + "A", + 7 + ], + [ + "aabc", + "Baab", + 4 + ], + [ + "aabcA", + "cabBcCc", + 8 + ], + [ + "aabcBcB", + "Ab", + 11 + ], + [ + "aabcaAA", + "abccacA", + 6 + ], + [ + "aabcbBc", + "BaCaaaA", + 12 + ], + [ + "aabcbaaac", + "BbCbccCc", + 11 + ], + [ + "aac", + "BCC", + 5 + ], + [ + "aac", + "BbCaCBbBc", + 14 + ], + [ + "aac", + "C", + 5 + ], + [ + "aac", + "a", + 4 + ], + [ + "aacA", + "CABCabaa", + 12 + ], + [ + "aacAaCCA", + "CBCbB", + 13 + ], + [ + "aacAaCCAb", + "BBCAB", + 13 + ], + [ + "aacAcb", + "baAacaCAB", + 9 + ], + [ + "aacB", + "ABcCcBAca", + 13 + ], + [ + "aacB", + "CACAABc", + 10 + ], + [ + "aacB", + "c", + 6 + ], + [ + "aacBAabc", + "caCBa", + 9 + ], + [ + "aacBc", + "aBCaCbAc", + 8 + ], + [ + "aacC", + "Ba", + 6 + ], + [ + "aacC", + "Bc", + 6 + ], + [ + "aacC", + "CAbBAbCaA", + 14 + ], + [ + "aacCCb", + "ccBAc", + 10 + ], + [ + "aacCc", + "CaB", + 8 + ], + [ + "aacaA", + "Bbaa", + 7 + ], + [ + "aacaa", + "cCB", + 8 + ], + [ + "aacaaCbBc", + "BCab", + 13 + ], + [ + "aacabaBA", + "cbbA", + 9 + ], + [ + "aacac", + "ABBCabcc", + 10 + ], + [ + "aacacAaB", + "aAbbA", + 11 + ], + [ + "aacb", + "BCcAb", + 6 + ], + [ + "aacbAAC", + "BbabBAC", + 8 + ], + [ + "aacbAcA", + "acbccC", + 6 + ], + [ + "aacbCABAC", + "AAbaCAbbA", + 11 + ], + [ + "aacbb", + "BBAbAC", + 10 + ], + [ + "aacc", + "acACBAa", + 10 + ], + [ + "aaccAaABA", + "BAbBacAC", + 14 + ], + [ + "aacccAccB", + "BBCAb", + 14 + ], + [ + "ab", + "ABca", + 6 + ], + [ + "ab", + "ACA", + 5 + ], + [ + "ab", + "AaB", + 3 + ], + [ + "ab", + "B", + 3 + ], + [ + "ab", + "BAabAa", + 8 + ], + [ + "ab", + "BAacbb", + 8 + ], + [ + "ab", + "Ba", + 4 + ], + [ + "ab", + "BbaBBa", + 9 + ], + [ + "ab", + "CACABaC", + 12 + ], + [ + "ab", + "CCbaA", + 8 + ], + [ + "ab", + "CbBACbc", + 11 + ], + [ + "ab", + "CbcbcbB", + 12 + ], + [ + "ab", + "CcB", + 5 + ], + [ + "ab", + "CcacBC", + 9 + ], + [ + "ab", + "aBBAbbaB", + 12 + ], + [ + "ab", + "aBCbBCACa", + 14 + ], + [ + "ab", + "abAbbc", + 8 + ], + [ + "ab", + "abB", + 2 + ], + [ + "ab", + "bAbCcBAaA", + 15 + ], + [ + "ab", + "baBcBa", + 9 + ], + [ + "ab", + "bb", + 2 + ], + [ + "ab", + "c", + 4 + ], + [ + "ab", + "cAAabacc", + 12 + ], + [ + "ab", + "cABcCCb", + 11 + ], + [ + "ab", + "cCbbbCa", + 12 + ], + [ + "ab", + "cbcb", + 6 + ], + [ + "ab", + "ccb", + 4 + ], + [ + "ab", + "cccaaCAA", + 14 + ], + [ + "abA", + "AaacB", + 8 + ], + [ + "abA", + "BAB", + 5 + ], + [ + "abA", + "abca", + 3 + ], + [ + "abA", + "bAAcC", + 8 + ], + [ + "abA", + "bBbaa", + 7 + ], + [ + "abA", + "bbbAcabb", + 12 + ], + [ + "abA", + "cAbCCcbb", + 13 + ], + [ + "abA", + "cBaaC", + 8 + ], + [ + "abAAB", + "BAbACC", + 7 + ], + [ + "abAAcaCa", + "c", + 14 + ], + [ + "abAB", + "AaCBBbb", + 10 + ], + [ + "abABAA", + "aBABbaabA", + 8 + ], + [ + "abABcAaC", + "aCbAcb", + 10 + ], + [ + "abABcb", + "b", + 10 + ], + [ + "abAC", + "BAC", + 3 + ], + [ + "abACAC", + "CBCaaCcA", + 12 + ], + [ + "abACC", + "BbCbBb", + 10 + ], + [ + "abACCBBa", + "abb", + 11 + ], + [ + "abACCaABb", + "aAcbb", + 10 + ], + [ + "abACb", + "Ca", + 8 + ], + [ + "abACbBAaA", + "cAAcCaCaB", + 13 + ], + [ + "abACccA", + "bBaCBC", + 9 + ], + [ + "abAaAaCCC", + "cACCbAbCC", + 13 + ], + [ + "abAaBAAC", + "ABca", + 11 + ], + [ + "abAacCCaa", + "acbCAC", + 11 + ], + [ + "abAbAcCc", + "b", + 14 + ], + [ + "abAbbBC", + "CAbbBbBb", + 8 + ], + [ + "abAc", + "bC", + 5 + ], + [ + "abAcBBbBA", + "CabccbcaA", + 11 + ], + [ + "abAccAbba", + "caCACCC", + 14 + ], + [ + "abAccBA", + "ACAbbABaa", + 12 + ], + [ + "abAccCbBa", + "cbccBbBac", + 8 + ], + [ + "abB", + "BAAA", + 7 + ], + [ + "abB", + "BACbb", + 6 + ], + [ + "abB", + "BcaBabA", + 10 + ], + [ + "abB", + "a", + 4 + ], + [ + "abB", + "cbBaACaAB", + 14 + ], + [ + "abBA", + "AACBCAbA", + 11 + ], + [ + "abBAA", + "bA", + 6 + ], + [ + "abBAAcaA", + "AACCC", + 11 + ], + [ + "abBAAcbb", + "bCCcbb", + 8 + ], + [ + "abBAB", + "aa", + 7 + ], + [ + "abBABBA", + "BBCBccbaA", + 12 + ], + [ + "abBAaBa", + "bbaBCcbc", + 11 + ], + [ + "abBAaCacb", + "bbaca", + 10 + ], + [ + "abBAaCcc", + "ccCACB", + 12 + ], + [ + "abBAc", + "bB", + 6 + ], + [ + "abBAc", + "bBB", + 6 + ], + [ + "abBB", + "BbaBbCbb", + 10 + ], + [ + "abBBCc", + "b", + 10 + ], + [ + "abBBaAcBc", + "bbCaB", + 11 + ], + [ + "abBBaBbCc", + "Cac", + 14 + ], + [ + "abBBac", + "BAc", + 7 + ], + [ + "abBBb", + "A", + 9 + ], + [ + "abBBb", + "ACAAc", + 9 + ], + [ + "abBBbB", + "b", + 10 + ], + [ + "abBCACBBc", + "B", + 16 + ], + [ + "abBCBAB", + "cCA", + 10 + ], + [ + "abBCCb", + "AbaCcCcA", + 9 + ], + [ + "abBCCcc", + "BcBCCbCbb", + 11 + ], + [ + "abBCac", + "cCcbACcC", + 11 + ], + [ + "abBCcCbA", + "bC", + 12 + ], + [ + "abBa", + "cbabba", + 5 + ], + [ + "abBaA", + "CA", + 8 + ], + [ + "abBaAAc", + "BB", + 11 + ], + [ + "abBaBcabA", + "BBBAabAba", + 10 + ], + [ + "abBaCbB", + "CaCaacbC", + 9 + ], + [ + "abBabAb", + "Aacb", + 9 + ], + [ + "abBacbc", + "cAccCaaa", + 15 + ], + [ + "abBacca", + "bAACac", + 10 + ], + [ + "abBb", + "ABCaACb", + 10 + ], + [ + "abBb", + "BAABc", + 7 + ], + [ + "abBb", + "c", + 8 + ], + [ + "abBb", + "cAB", + 6 + ], + [ + "abBbBB", + "Aaccb", + 10 + ], + [ + "abBbC", + "aaccbac", + 9 + ], + [ + "abBbCBBa", + "C", + 14 + ], + [ + "abBbb", + "BBA", + 7 + ], + [ + "abBbba", + "CBbAAb", + 9 + ], + [ + "abBc", + "AABBCcBcc", + 12 + ], + [ + "abBc", + "bcbbCABca", + 12 + ], + [ + "abBcB", + "CbCaCca", + 10 + ], + [ + "abBcBBCA", + "BCCCacAac", + 15 + ], + [ + "abBcaBa", + "bcBCCc", + 11 + ], + [ + "abC", + "ACAbb", + 7 + ], + [ + "abC", + "Cc", + 5 + ], + [ + "abC", + "aAabBb", + 8 + ], + [ + "abC", + "b", + 4 + ], + [ + "abC", + "bccBAC", + 9 + ], + [ + "abC", + "bccabCBc", + 10 + ], + [ + "abC", + "cBA", + 5 + ], + [ + "abC", + "cCB", + 6 + ], + [ + "abCA", + "Acb", + 6 + ], + [ + "abCA", + "cc", + 7 + ], + [ + "abCAA", + "BAcbCCBc", + 11 + ], + [ + "abCAAcbCB", + "acCabB", + 9 + ], + [ + "abCAaA", + "AcbaAB", + 8 + ], + [ + "abCB", + "BABBbAABA", + 13 + ], + [ + "abCBB", + "Bb", + 7 + ], + [ + "abCBCB", + "baCaaa", + 10 + ], + [ + "abCC", + "CA", + 6 + ], + [ + "abCC", + "CCcCAcaA", + 13 + ], + [ + "abCCAacb", + "babaA", + 12 + ], + [ + "abCCBB", + "baB", + 8 + ], + [ + "abCCBBC", + "aAc", + 11 + ], + [ + "abCCCBaAC", + "CCBbCbBA", + 13 + ], + [ + "abCCaAca", + "bBCBCaC", + 10 + ], + [ + "abCCbBBaA", + "Ab", + 15 + ], + [ + "abCCc", + "BcbBabBc", + 12 + ], + [ + "abCCcAcBB", + "BaAAAaAB", + 13 + ], + [ + "abCa", + "ABA", + 5 + ], + [ + "abCaBC", + "bCCaCaA", + 10 + ], + [ + "abCaC", + "acc", + 6 + ], + [ + "abCaCAbB", + "aCaba", + 8 + ], + [ + "abCabA", + "ACba", + 6 + ], + [ + "abCabbccb", + "CcAcA", + 14 + ], + [ + "abCacaaC", + "aC", + 12 + ], + [ + "abCb", + "cBCBaA", + 8 + ], + [ + "abCbBCcAa", + "a", + 16 + ], + [ + "abCbaCC", + "CAabaabBB", + 14 + ], + [ + "abCbbba", + "CcbBCBAA", + 12 + ], + [ + "abCc", + "Ca", + 6 + ], + [ + "abCcAbbC", + "B", + 15 + ], + [ + "abCcCCC", + "BbAaca", + 11 + ], + [ + "abCcCc", + "ACacA", + 8 + ], + [ + "abCcaA", + "aca", + 6 + ], + [ + "abCcaABB", + "AbcBb", + 8 + ], + [ + "aba", + "CBb", + 5 + ], + [ + "aba", + "CBbbaAb", + 10 + ], + [ + "aba", + "aCccA", + 7 + ], + [ + "aba", + "acaB", + 4 + ], + [ + "aba", + "bcCCa", + 8 + ], + [ + "aba", + "cBB", + 5 + ], + [ + "abaAAA", + "cAbB", + 10 + ], + [ + "abaACCcC", + "abacCBA", + 7 + ], + [ + "abaAaccC", + "CCaacc", + 8 + ], + [ + "abaAbb", + "a", + 10 + ], + [ + "abaBCABc", + "aCcccB", + 11 + ], + [ + "abaBaCca", + "aAcAbaB", + 12 + ], + [ + "abaC", + "Bba", + 4 + ], + [ + "abaCACccC", + "BBBBB", + 17 + ], + [ + "abaCBABaB", + "abacbacc", + 9 + ], + [ + "abaCCbcA", + "AcBBc", + 11 + ], + [ + "abaCbB", + "cC", + 10 + ], + [ + "abaCbaCB", + "AAcC", + 11 + ], + [ + "abaCbaa", + "aCCaCCA", + 9 + ], + [ + "abaaACcB", + "cBBCBBAbC", + 16 + ], + [ + "abab", + "CcaCC", + 8 + ], + [ + "abab", + "aCAAaaaB", + 11 + ], + [ + "abab", + "acBbA", + 6 + ], + [ + "ababA", + "CBBC", + 8 + ], + [ + "ababACcC", + "BC", + 13 + ], + [ + "ababCBBbB", + "CbC", + 14 + ], + [ + "ababa", + "CABCcCcb", + 14 + ], + [ + "ababcCb", + "aCAbCc", + 7 + ], + [ + "abacA", + "ABb", + 8 + ], + [ + "abacABc", + "babCCAbb", + 8 + ], + [ + "abacAc", + "BacbCaaB", + 11 + ], + [ + "abacBBa", + "CbCAa", + 9 + ], + [ + "abacBbaCC", + "a", + 16 + ], + [ + "abacCb", + "b", + 10 + ], + [ + "abaca", + "cAB", + 9 + ], + [ + "abacaCbBc", + "bACcACB", + 10 + ], + [ + "abaccABb", + "cBcCc", + 12 + ], + [ + "abaccaAcA", + "B", + 17 + ], + [ + "abacccc", + "Cba", + 10 + ], + [ + "abb", + "B", + 5 + ], + [ + "abb", + "CbBBAc", + 9 + ], + [ + "abb", + "aC", + 4 + ], + [ + "abb", + "bbbcaca", + 10 + ], + [ + "abbAAABBb", + "CbCcB", + 14 + ], + [ + "abbAcB", + "BbaaBc", + 8 + ], + [ + "abbBBCcB", + "aaa", + 14 + ], + [ + "abbBbAbcc", + "c", + 16 + ], + [ + "abbBbbbcC", + "aBbBaB", + 10 + ], + [ + "abbCBA", + "aA", + 8 + ], + [ + "abbCBA", + "bb", + 8 + ], + [ + "abbCBabac", + "CBAB", + 12 + ], + [ + "abbCaBB", + "Ab", + 11 + ], + [ + "abbCaBC", + "aBcc", + 9 + ], + [ + "abbCbbBB", + "cbbaaca", + 12 + ], + [ + "abbCc", + "bC", + 6 + ], + [ + "abbaA", + "BabaAAaBb", + 11 + ], + [ + "abbaBaaBc", + "CAcBbc", + 13 + ], + [ + "abbaBbc", + "aABbAcc", + 8 + ], + [ + "abbaCcba", + "Cba", + 10 + ], + [ + "abbbA", + "ACAcc", + 9 + ], + [ + "abbbBAbAA", + "aCACcAbA", + 10 + ], + [ + "abbbCCCaC", + "acBCBABcC", + 13 + ], + [ + "abbbb", + "cCcbBcb", + 9 + ], + [ + "abbbc", + "C", + 9 + ], + [ + "abbbca", + "BBAcBbAB", + 12 + ], + [ + "abbcABB", + "ac", + 10 + ], + [ + "abbcB", + "ABbcCB", + 4 + ], + [ + "abbcBac", + "bACca", + 9 + ], + [ + "abbccAa", + "AcC", + 10 + ], + [ + "abbccb", + "cbCb", + 7 + ], + [ + "abc", + "AbC", + 2 + ], + [ + "abc", + "BAAb", + 7 + ], + [ + "abc", + "C", + 5 + ], + [ + "abc", + "aB", + 3 + ], + [ + "abcAA", + "CAAabC", + 11 + ], + [ + "abcAaaccb", + "cAcAAcbcA", + 11 + ], + [ + "abcAbB", + "AbcCacc", + 8 + ], + [ + "abcAcaB", + "acBcBb", + 7 + ], + [ + "abcAcbbb", + "CaABc", + 13 + ], + [ + "abcB", + "AaCcAbCa", + 11 + ], + [ + "abcB", + "bbab", + 5 + ], + [ + "abcBaBb", + "cBBa", + 8 + ], + [ + "abcBacc", + "ACBa", + 8 + ], + [ + "abcBb", + "BBbcccBB", + 9 + ], + [ + "abcBbBAb", + "cB", + 12 + ], + [ + "abcC", + "BCc", + 5 + ], + [ + "abcCAB", + "CbCcC", + 8 + ], + [ + "abcCBAc", + "ACCBaA", + 7 + ], + [ + "abcCaBcCB", + "AAba", + 15 + ], + [ + "abcCbBCA", + "Ba", + 13 + ], + [ + "abca", + "cbaccAA", + 9 + ], + [ + "abcaCB", + "CCaaAB", + 8 + ], + [ + "abcb", + "a", + 6 + ], + [ + "abcbbC", + "BBc", + 9 + ], + [ + "abcbbbcb", + "b", + 14 + ], + [ + "abccC", + "bbcBab", + 8 + ], + [ + "abccCBabC", + "AbABaaabc", + 10 + ], + [ + "abccCaB", + "Bbaa", + 10 + ], + [ + "abccCcAa", + "BCbb", + 13 + ], + [ + "abccaB", + "aCABaba", + 9 + ], + [ + "abccaC", + "ABbCB", + 9 + ], + [ + "abccaCcBB", + "AAB", + 14 + ], + [ + "abccbCC", + "BAc", + 11 + ], + [ + "ac", + "A", + 3 + ], + [ + "ac", + "AAaCcbBa", + 12 + ], + [ + "ac", + "AAcCbbCca", + 15 + ], + [ + "ac", + "ACAcCa", + 9 + ], + [ + "ac", + "ACCBbAcCc", + 15 + ], + [ + "ac", + "B", + 4 + ], + [ + "ac", + "BAab", + 6 + ], + [ + "ac", + "BCCBbccb", + 14 + ], + [ + "ac", + "BCc", + 4 + ], + [ + "ac", + "BaBbbAA", + 12 + ], + [ + "ac", + "BcCACbB", + 12 + ], + [ + "ac", + "CBA", + 6 + ], + [ + "ac", + "CccBcaB", + 12 + ], + [ + "ac", + "aB", + 2 + ], + [ + "ac", + "aBBCacBbC", + 14 + ], + [ + "ac", + "aC", + 1 + ], + [ + "ac", + "aCcCC", + 6 + ], + [ + "ac", + "aaCaCaca", + 12 + ], + [ + "ac", + "ab", + 2 + ], + [ + "ac", + "acacCAbBA", + 14 + ], + [ + "ac", + "bACaaCCCC", + 15 + ], + [ + "ac", + "bAbaCCcBC", + 14 + ], + [ + "ac", + "bCCaAaa", + 12 + ], + [ + "ac", + "cBAcc", + 7 + ], + [ + "acA", + "AaCCAaabc", + 13 + ], + [ + "acA", + "aABBBACc", + 12 + ], + [ + "acA", + "ac", + 2 + ], + [ + "acA", + "cBcBb", + 8 + ], + [ + "acAA", + "bc", + 6 + ], + [ + "acAAABBa", + "cbcC", + 13 + ], + [ + "acAACBA", + "BcbaCbbA", + 8 + ], + [ + "acAB", + "ccbAAAa", + 10 + ], + [ + "acABCCA", + "BCcABBAa", + 9 + ], + [ + "acABc", + "BBcABbCba", + 11 + ], + [ + "acAC", + "A", + 6 + ], + [ + "acACCB", + "AAcBCba", + 9 + ], + [ + "acAaaAcba", + "BabCcbCbb", + 15 + ], + [ + "acAaaaBc", + "BacCBc", + 10 + ], + [ + "acAabACa", + "acaCB", + 8 + ], + [ + "acAabBbA", + "cabCb", + 8 + ], + [ + "acAacCc", + "BBCC", + 11 + ], + [ + "acAb", + "cc", + 6 + ], + [ + "acAbabcBa", + "ABABcaB", + 11 + ], + [ + "acAc", + "ABa", + 6 + ], + [ + "acAc", + "CcBCaa", + 9 + ], + [ + "acAc", + "aBbCaB", + 8 + ], + [ + "acAcBCCa", + "BaB", + 13 + ], + [ + "acAcCAc", + "cAbab", + 9 + ], + [ + "acAcaC", + "B", + 12 + ], + [ + "acAcabB", + "baaacbB", + 7 + ], + [ + "acAcbcAC", + "ccaCbCcc", + 8 + ], + [ + "acB", + "ABcAcBAcb", + 13 + ], + [ + "acB", + "acb", + 1 + ], + [ + "acB", + "bCccA", + 8 + ], + [ + "acB", + "cbabb", + 7 + ], + [ + "acBA", + "BcAaBCBAA", + 11 + ], + [ + "acBAcc", + "AAabb", + 10 + ], + [ + "acBB", + "AaaAbB", + 7 + ], + [ + "acBB", + "cA", + 6 + ], + [ + "acBBAb", + "bCcAbBCAC", + 11 + ], + [ + "acBBAbacB", + "aaCBB", + 12 + ], + [ + "acBBBbAcb", + "BAa", + 14 + ], + [ + "acBBCC", + "ccAbcBbCb", + 10 + ], + [ + "acBBCc", + "bcCaAbAa", + 13 + ], + [ + "acBBbBa", + "Cba", + 9 + ], + [ + "acBBcCC", + "ABbb", + 10 + ], + [ + "acBCBcabA", + "caCbca", + 9 + ], + [ + "acBCCbab", + "ccA", + 12 + ], + [ + "acBCa", + "BabbAcb", + 10 + ], + [ + "acBa", + "AC", + 6 + ], + [ + "acBaA", + "ABBCC", + 7 + ], + [ + "acBaAacc", + "bbab", + 13 + ], + [ + "acBaBCab", + "ac", + 12 + ], + [ + "acBaBaC", + "bbccbac", + 10 + ], + [ + "acBacCbAc", + "bBBACbaAA", + 11 + ], + [ + "acBb", + "CA", + 7 + ], + [ + "acBb", + "bCBAAB", + 8 + ], + [ + "acBbAc", + "aaaBCA", + 8 + ], + [ + "acBbCca", + "acA", + 9 + ], + [ + "acBcCcaB", + "CC", + 13 + ], + [ + "acBcabcAC", + "Aac", + 13 + ], + [ + "acC", + "AABcbaC", + 9 + ], + [ + "acC", + "AcBAaC", + 7 + ], + [ + "acC", + "CabBabaBC", + 14 + ], + [ + "acC", + "b", + 6 + ], + [ + "acC", + "baBCBCbAC", + 13 + ], + [ + "acC", + "baaCBCBC", + 11 + ], + [ + "acCA", + "C", + 6 + ], + [ + "acCA", + "aabBCaaaC", + 13 + ], + [ + "acCAAaCB", + "ba", + 14 + ], + [ + "acCAB", + "BccCcCbB", + 10 + ], + [ + "acCAa", + "c", + 8 + ], + [ + "acCAabBcc", + "Bb", + 16 + ], + [ + "acCAb", + "abB", + 7 + ], + [ + "acCAcc", + "cccCCacCC", + 10 + ], + [ + "acCB", + "B", + 6 + ], + [ + "acCBAcb", + "acaBcA", + 6 + ], + [ + "acCBBA", + "caccBbabC", + 9 + ], + [ + "acCBBb", + "aCbc", + 7 + ], + [ + "acCBCbaBC", + "bCabBc", + 11 + ], + [ + "acCBaaAc", + "BAAABCA", + 13 + ], + [ + "acCC", + "BAB", + 8 + ], + [ + "acCCABBb", + "Bbcca", + 13 + ], + [ + "acCCCaAb", + "acCCbAcca", + 9 + ], + [ + "acCCab", + "aB", + 9 + ], + [ + "acCCbA", + "CCAbCbBA", + 9 + ], + [ + "acCCbBcc", + "aAAaA", + 14 + ], + [ + "acCCcaC", + "AcbBabcCb", + 13 + ], + [ + "acCCcab", + "ccab", + 6 + ], + [ + "acCa", + "aaAcAbBbB", + 14 + ], + [ + "acCaAA", + "BAbcAcbC", + 13 + ], + [ + "acCaABcbb", + "A", + 16 + ], + [ + "acCaC", + "abBACBCB", + 10 + ], + [ + "acCaCa", + "aBa", + 8 + ], + [ + "acCb", + "aACBa", + 5 + ], + [ + "acCbBBa", + "BbbACCccb", + 15 + ], + [ + "acCbCCCBb", + "B", + 16 + ], + [ + "acCbbBB", + "bcca", + 11 + ], + [ + "acCc", + "A", + 7 + ], + [ + "acCc", + "AABBa", + 9 + ], + [ + "acCcA", + "CBBcaBCCA", + 11 + ], + [ + "acCcAcB", + "b", + 13 + ], + [ + "acCcB", + "BBCCBA", + 7 + ], + [ + "acCcaAA", + "b", + 14 + ], + [ + "acCcacB", + "cbAccBcb", + 10 + ], + [ + "acCcc", + "AC", + 7 + ], + [ + "aca", + "ACAB", + 5 + ], + [ + "aca", + "AaAc", + 6 + ], + [ + "aca", + "cAAbacBCa", + 12 + ], + [ + "aca", + "cbCCabAaB", + 14 + ], + [ + "acaA", + "C", + 7 + ], + [ + "acaA", + "aCbcACABa", + 11 + ], + [ + "acaAAAbc", + "B", + 15 + ], + [ + "acaABAcA", + "Cacca", + 10 + ], + [ + "acaAcb", + "cbc", + 8 + ], + [ + "acaBA", + "baBCbCBBC", + 13 + ], + [ + "acaBcacBc", + "b", + 17 + ], + [ + "acaBccaC", + "C", + 14 + ], + [ + "acaC", + "bccCAccA", + 12 + ], + [ + "acaCAaBB", + "Bc", + 14 + ], + [ + "acaCBBB", + "A", + 13 + ], + [ + "acaCaA", + "BCB", + 10 + ], + [ + "acaCaC", + "c", + 10 + ], + [ + "acaCbC", + "acaabCaa", + 6 + ], + [ + "acaCcaAB", + "ABAaaaba", + 12 + ], + [ + "acaCcbcB", + "CcbACBBc", + 10 + ], + [ + "acaCcbcc", + "C", + 14 + ], + [ + "acaa", + "AabBa", + 6 + ], + [ + "acaaBAA", + "cBBbaAB", + 10 + ], + [ + "acaaCC", + "cAACA", + 6 + ], + [ + "acaaaCCA", + "AaC", + 11 + ], + [ + "acaacAbB", + "bCbb", + 12 + ], + [ + "acaaca", + "cBACccCa", + 11 + ], + [ + "acaacb", + "ccCbBca", + 10 + ], + [ + "acabCb", + "ccaCbA", + 6 + ], + [ + "acabaBCbB", + "cab", + 12 + ], + [ + "acabcA", + "AB", + 10 + ], + [ + "acacA", + "bcBACcaa", + 10 + ], + [ + "acacbA", + "A", + 10 + ], + [ + "acacbABa", + "bCbcBa", + 9 + ], + [ + "acacbBa", + "BAbA", + 10 + ], + [ + "acb", + "AabAbA", + 8 + ], + [ + "acb", + "BCCa", + 7 + ], + [ + "acb", + "cBCB", + 6 + ], + [ + "acbA", + "AcBCbCa", + 8 + ], + [ + "acbA", + "aAaBCAB", + 9 + ], + [ + "acbAA", + "bc", + 8 + ], + [ + "acbACbbA", + "a", + 14 + ], + [ + "acbAbacc", + "caAcB", + 10 + ], + [ + "acbB", + "aBAb", + 5 + ], + [ + "acbBBC", + "caB", + 8 + ], + [ + "acbBaAAb", + "bbBcABBaC", + 13 + ], + [ + "acbBaC", + "CaA", + 9 + ], + [ + "acbBc", + "abB", + 4 + ], + [ + "acbC", + "ABABaBbca", + 13 + ], + [ + "acbC", + "bbBbcaaA", + 13 + ], + [ + "acbCA", + "A", + 8 + ], + [ + "acbCA", + "cBb", + 7 + ], + [ + "acbCBb", + "acAbCCaBc", + 8 + ], + [ + "acbCaaAaB", + "CaCc", + 14 + ], + [ + "acbCabC", + "cBACbcBC", + 10 + ], + [ + "acbaBaA", + "BBcA", + 9 + ], + [ + "acbabAa", + "CaAbcbc", + 10 + ], + [ + "acbabbaB", + "c", + 14 + ], + [ + "acbb", + "AAa", + 7 + ], + [ + "acbb", + "AbCaBCcBA", + 13 + ], + [ + "acbb", + "BbAca", + 9 + ], + [ + "acbb", + "CBaCBcCbA", + 12 + ], + [ + "acbbA", + "AcCAAbc", + 9 + ], + [ + "acbbAbA", + "CCCaccab", + 13 + ], + [ + "acbbcABBB", + "BcCBbb", + 11 + ], + [ + "acbc", + "aBAbB", + 6 + ], + [ + "acbcAa", + "BaCC", + 10 + ], + [ + "acbcBbc", + "B", + 12 + ], + [ + "acbcCAC", + "ACaAab", + 11 + ], + [ + "acbcCab", + "BAb", + 10 + ], + [ + "acbcaacbc", + "CbccCCBcb", + 11 + ], + [ + "acbcbbcc", + "CcAbaCCbb", + 13 + ], + [ + "acbccACA", + "b", + 14 + ], + [ + "acbccBcB", + "CCcc", + 10 + ], + [ + "acbccCB", + "bbbaaCAAB", + 12 + ], + [ + "acc", + "C", + 5 + ], + [ + "acc", + "bAac", + 5 + ], + [ + "accA", + "CBBaA", + 8 + ], + [ + "accAA", + "C", + 9 + ], + [ + "accABbb", + "cBbAAbaC", + 12 + ], + [ + "accAac", + "CCcacb", + 7 + ], + [ + "accAb", + "bcbAbB", + 6 + ], + [ + "accAcbAa", + "B", + 15 + ], + [ + "accB", + "bBbAb", + 9 + ], + [ + "accBC", + "bCCCCab", + 10 + ], + [ + "accBbcCaa", + "aaCcaBACB", + 12 + ], + [ + "accC", + "CCcbBc", + 8 + ], + [ + "accC", + "aa", + 6 + ], + [ + "accCAcACa", + "AABbCCc", + 14 + ], + [ + "accCCaCB", + "aCBba", + 11 + ], + [ + "accCCcA", + "cBbA", + 10 + ], + [ + "accCaB", + "aBaB", + 6 + ], + [ + "accCbbC", + "cBBcaa", + 12 + ], + [ + "acca", + "BBCAcbaba", + 13 + ], + [ + "acca", + "BBcCC", + 7 + ], + [ + "accaACAAc", + "cbbCABA", + 12 + ], + [ + "accaaAcAb", + "ccB", + 13 + ], + [ + "accaaC", + "CbA", + 10 + ], + [ + "accab", + "AAaAcA", + 9 + ], + [ + "accabbcB", + "aa", + 12 + ], + [ + "accac", + "C", + 9 + ], + [ + "accb", + "CBCAcCaBB", + 13 + ], + [ + "accbAA", + "Ba", + 10 + ], + [ + "accbAa", + "Ca", + 9 + ], + [ + "accbBac", + "caC", + 9 + ], + [ + "accbCcBAc", + "cbA", + 12 + ], + [ + "accbaAc", + "ACAaCAAA", + 11 + ], + [ + "accbb", + "CCcC", + 7 + ], + [ + "acccAB", + "cb", + 9 + ], + [ + "acccC", + "baaaaB", + 10 + ], + [ + "acccaAaB", + "C", + 15 + ], + [ + "acccc", + "cAAC", + 7 + ], + [ + "b", + "A", + 2 + ], + [ + "b", + "AAbAaCb", + 12 + ], + [ + "b", + "ABBBC", + 9 + ], + [ + "b", + "ABbCCBC", + 12 + ], + [ + "b", + "ABc", + 5 + ], + [ + "b", + "ABcba", + 8 + ], + [ + "b", + "ACAAC", + 10 + ], + [ + "b", + "ACBbAcabc", + 16 + ], + [ + "b", + "ACBbCBcCC", + 16 + ], + [ + "b", + "ACCaA", + 10 + ], + [ + "b", + "Aa", + 4 + ], + [ + "b", + "AaAbBCA", + 12 + ], + [ + "b", + "Aac", + 6 + ], + [ + "b", + "AacaBc", + 11 + ], + [ + "b", + "AbaC", + 6 + ], + [ + "b", + "Abcba", + 8 + ], + [ + "b", + "Ac", + 4 + ], + [ + "b", + "AcCbB", + 8 + ], + [ + "b", + "AcCbBca", + 12 + ], + [ + "b", + "AcaaCaAa", + 16 + ], + [ + "b", + "B", + 1 + ], + [ + "b", + "BBA", + 5 + ], + [ + "b", + "BBaaabB", + 12 + ], + [ + "b", + "BBbaBcba", + 14 + ], + [ + "b", + "BCBaC", + 9 + ], + [ + "b", + "BCcAABb", + 12 + ], + [ + "b", + "Ba", + 3 + ], + [ + "b", + "BaC", + 5 + ], + [ + "b", + "BaCbBc", + 10 + ], + [ + "b", + "Bac", + 5 + ], + [ + "b", + "BacBAc", + 11 + ], + [ + "b", + "Bb", + 2 + ], + [ + "b", + "BbA", + 4 + ], + [ + "b", + "BbBacbb", + 12 + ], + [ + "b", + "BbacaCc", + 12 + ], + [ + "b", + "BbbcAcAab", + 16 + ], + [ + "b", + "Bc", + 3 + ], + [ + "b", + "BcBA", + 7 + ], + [ + "b", + "BcBCAAaCB", + 17 + ], + [ + "b", + "BcC", + 5 + ], + [ + "b", + "BcCa", + 7 + ], + [ + "b", + "C", + 2 + ], + [ + "b", + "CAB", + 5 + ], + [ + "b", + "CACCBca", + 13 + ], + [ + "b", + "CBABaBAB", + 15 + ], + [ + "b", + "CBCCa", + 9 + ], + [ + "b", + "CBCCcC", + 11 + ], + [ + "b", + "CBCcaBBAB", + 17 + ], + [ + "b", + "CBaBaaCbB", + 16 + ], + [ + "b", + "CBaabA", + 10 + ], + [ + "b", + "CCBABBcC", + 15 + ], + [ + "b", + "CCC", + 6 + ], + [ + "b", + "CCbCA", + 8 + ], + [ + "b", + "Ca", + 4 + ], + [ + "b", + "CaCBcA", + 11 + ], + [ + "b", + "Cabacc", + 10 + ], + [ + "b", + "CabccCBCB", + 16 + ], + [ + "b", + "CacAbAAac", + 16 + ], + [ + "b", + "CbA", + 4 + ], + [ + "b", + "CbcBbA", + 10 + ], + [ + "b", + "Cc", + 4 + ], + [ + "b", + "CcAABbA", + 12 + ], + [ + "b", + "CcabBB", + 10 + ], + [ + "b", + "CcacCcAcC", + 18 + ], + [ + "b", + "CcbCACB", + 12 + ], + [ + "b", + "Ccbc", + 6 + ], + [ + "b", + "a", + 2 + ], + [ + "b", + "aA", + 4 + ], + [ + "b", + "aABBCcC", + 13 + ], + [ + "b", + "aABccbaCc", + 16 + ], + [ + "b", + "aACCCCba", + 14 + ], + [ + "b", + "aACCa", + 10 + ], + [ + "b", + "aAaBA", + 9 + ], + [ + "b", + "aAacBab", + 12 + ], + [ + "b", + "aB", + 3 + ], + [ + "b", + "aBCAac", + 11 + ], + [ + "b", + "aBCBC", + 9 + ], + [ + "b", + "aBCbacab", + 14 + ], + [ + "b", + "aBaCa", + 9 + ], + [ + "b", + "aBc", + 5 + ], + [ + "b", + "aC", + 4 + ], + [ + "b", + "aCBA", + 7 + ], + [ + "b", + "aCCa", + 8 + ], + [ + "b", + "aa", + 4 + ], + [ + "b", + "aabCCBca", + 14 + ], + [ + "b", + "aabbAb", + 10 + ], + [ + "b", + "aabbcC", + 10 + ], + [ + "b", + "ab", + 2 + ], + [ + "b", + "abB", + 4 + ], + [ + "b", + "abBBcb", + 10 + ], + [ + "b", + "abCCBCA", + 12 + ], + [ + "b", + "abcACcaa", + 14 + ], + [ + "b", + "abcBccCa", + 14 + ], + [ + "b", + "abca", + 6 + ], + [ + "b", + "ac", + 4 + ], + [ + "b", + "acACCaAca", + 18 + ], + [ + "b", + "acC", + 6 + ], + [ + "b", + "aca", + 6 + ], + [ + "b", + "acaabCC", + 12 + ], + [ + "b", + "b", + 0 + ], + [ + "b", + "bACAbB", + 10 + ], + [ + "b", + "bBAccb", + 10 + ], + [ + "b", + "bBBC", + 6 + ], + [ + "b", + "bBbaAA", + 10 + ], + [ + "b", + "bC", + 2 + ], + [ + "b", + "bCA", + 4 + ], + [ + "b", + "bCBCAbaCA", + 16 + ], + [ + "b", + "bCCbA", + 8 + ], + [ + "b", + "bCaAC", + 8 + ], + [ + "b", + "bCaCAB", + 10 + ], + [ + "b", + "bCabBB", + 10 + ], + [ + "b", + "bCbBbcA", + 12 + ], + [ + "b", + "bCcbAb", + 10 + ], + [ + "b", + "baBACBaaB", + 16 + ], + [ + "b", + "baCCbBC", + 12 + ], + [ + "b", + "baabBABb", + 14 + ], + [ + "b", + "baabbaCBB", + 16 + ], + [ + "b", + "baaccc", + 10 + ], + [ + "b", + "babBAcb", + 12 + ], + [ + "b", + "bb", + 2 + ], + [ + "b", + "bcBACbaBb", + 16 + ], + [ + "b", + "bcCa", + 6 + ], + [ + "b", + "bcCcAcbc", + 14 + ], + [ + "b", + "c", + 2 + ], + [ + "b", + "cABCaB", + 11 + ], + [ + "b", + "cAC", + 6 + ], + [ + "b", + "cAbBbBcc", + 14 + ], + [ + "b", + "cAbaBABBc", + 16 + ], + [ + "b", + "cAbaCBAa", + 14 + ], + [ + "b", + "cBAAAcaA", + 15 + ], + [ + "b", + "cBBcbAabb", + 16 + ], + [ + "b", + "cBCCAcb", + 12 + ], + [ + "b", + "cBCCa", + 9 + ], + [ + "b", + "cBCaCAc", + 13 + ], + [ + "b", + "cBbaBbcB", + 14 + ], + [ + "b", + "cBbbBaAa", + 14 + ], + [ + "b", + "cCAACba", + 12 + ], + [ + "b", + "cCaccAaCb", + 16 + ], + [ + "b", + "cCcbA", + 8 + ], + [ + "b", + "caA", + 6 + ], + [ + "b", + "caAb", + 6 + ], + [ + "b", + "caAccaCbb", + 16 + ], + [ + "b", + "caB", + 5 + ], + [ + "b", + "cabBbcA", + 12 + ], + [ + "b", + "cacbbBAb", + 14 + ], + [ + "b", + "cb", + 2 + ], + [ + "b", + "cbAa", + 6 + ], + [ + "b", + "cbAaCa", + 10 + ], + [ + "b", + "cbcBAcCbA", + 16 + ], + [ + "b", + "ccCaacc", + 14 + ], + [ + "b", + "ccCbaaaa", + 14 + ], + [ + "b", + "ccaC", + 8 + ], + [ + "b", + "ccbbcb", + 10 + ], + [ + "bA", + "AAAcACAbA", + 14 + ], + [ + "bA", + "AAbB", + 6 + ], + [ + "bA", + "ABaC", + 6 + ], + [ + "bA", + "ACBbbA", + 8 + ], + [ + "bA", + "ACBbccB", + 12 + ], + [ + "bA", + "ACbbBB", + 10 + ], + [ + "bA", + "Accc", + 8 + ], + [ + "bA", + "BAcCabc", + 11 + ], + [ + "bA", + "BCCcccB", + 13 + ], + [ + "bA", + "BabcCBCaa", + 15 + ], + [ + "bA", + "BbCaCBca", + 13 + ], + [ + "bA", + "BbbcbCCB", + 14 + ], + [ + "bA", + "Bbca", + 5 + ], + [ + "bA", + "C", + 4 + ], + [ + "bA", + "CAbABbBC", + 12 + ], + [ + "bA", + "CB", + 4 + ], + [ + "bA", + "CBCBa", + 8 + ], + [ + "bA", + "CbAaAaB", + 10 + ], + [ + "bA", + "CbcAAc", + 8 + ], + [ + "bA", + "CcAAcbcBC", + 16 + ], + [ + "bA", + "aAc", + 4 + ], + [ + "bA", + "aBCCcAcb", + 13 + ], + [ + "bA", + "aCb", + 6 + ], + [ + "bA", + "aCcbbc", + 10 + ], + [ + "bA", + "bAbcaAA", + 10 + ], + [ + "bA", + "bAc", + 2 + ], + [ + "bA", + "ba", + 1 + ], + [ + "bA", + "bb", + 2 + ], + [ + "bA", + "cAcCABaAb", + 15 + ], + [ + "bA", + "cCAABbBb", + 14 + ], + [ + "bA", + "cCC", + 6 + ], + [ + "bA", + "cabc", + 6 + ], + [ + "bA", + "ccCbcC", + 10 + ], + [ + "bAA", + "AabBB", + 8 + ], + [ + "bAA", + "BBAAaBCbC", + 13 + ], + [ + "bAA", + "C", + 6 + ], + [ + "bAA", + "CBaBcBb", + 12 + ], + [ + "bAA", + "CCBAc", + 7 + ], + [ + "bAA", + "abBBBAA", + 8 + ], + [ + "bAA", + "baacAbb", + 9 + ], + [ + "bAA", + "bcbBccAb", + 12 + ], + [ + "bAAA", + "C", + 8 + ], + [ + "bAAA", + "bBAAC", + 4 + ], + [ + "bAAAA", + "c", + 10 + ], + [ + "bAAAAbaCa", + "abacbC", + 12 + ], + [ + "bAAACbbb", + "Aaa", + 12 + ], + [ + "bAAACccC", + "CC", + 12 + ], + [ + "bAAAacAc", + "caC", + 12 + ], + [ + "bAAAbABC", + "CBCbBa", + 12 + ], + [ + "bAAB", + "bC", + 6 + ], + [ + "bAABaCA", + "A", + 12 + ], + [ + "bAABb", + "CaBBB", + 6 + ], + [ + "bAABcbbB", + "CbACCB", + 11 + ], + [ + "bAAC", + "AabbbaBA", + 13 + ], + [ + "bAAC", + "Acb", + 6 + ], + [ + "bAAC", + "aaB", + 6 + ], + [ + "bAACcACbc", + "Aaa", + 14 + ], + [ + "bAAa", + "AaABbabC", + 11 + ], + [ + "bAAa", + "bCAbbaa", + 7 + ], + [ + "bAAaCba", + "bAca", + 7 + ], + [ + "bAAaaaa", + "BC", + 13 + ], + [ + "bAAbAab", + "CBcA", + 12 + ], + [ + "bAAbCa", + "C", + 10 + ], + [ + "bAAbb", + "A", + 8 + ], + [ + "bAAc", + "CCAbca", + 8 + ], + [ + "bAAc", + "cCBAba", + 9 + ], + [ + "bAAcA", + "bbc", + 6 + ], + [ + "bAAccABbb", + "aAc", + 13 + ], + [ + "bAAccaCC", + "A", + 14 + ], + [ + "bAB", + "ACBcB", + 7 + ], + [ + "bAB", + "CbAA", + 4 + ], + [ + "bAB", + "bbABC", + 4 + ], + [ + "bABAC", + "BCaabaCBC", + 12 + ], + [ + "bABACCCB", + "abB", + 12 + ], + [ + "bABAaB", + "cCCCBbc", + 13 + ], + [ + "bABAaCBBA", + "BAbA", + 11 + ], + [ + "bABAaba", + "A", + 12 + ], + [ + "bABAba", + "BBBAccBA", + 9 + ], + [ + "bABAbbCbB", + "bA", + 14 + ], + [ + "bABAcCCb", + "abCaB", + 11 + ], + [ + "bABBCCC", + "bbCbBc", + 10 + ], + [ + "bABBa", + "bA", + 6 + ], + [ + "bABBcAc", + "bAC", + 9 + ], + [ + "bABC", + "AbBca", + 7 + ], + [ + "bABCBcAc", + "cBCAA", + 10 + ], + [ + "bABCC", + "aBCa", + 5 + ], + [ + "bABCCbbbC", + "cABACBBa", + 10 + ], + [ + "bABCaBCa", + "CaBbB", + 10 + ], + [ + "bABCbaB", + "ACCaCBc", + 10 + ], + [ + "bABa", + "BA", + 5 + ], + [ + "bABa", + "BAB", + 3 + ], + [ + "bABaCBBAa", + "Aa", + 14 + ], + [ + "bABb", + "acA", + 7 + ], + [ + "bABb", + "ccCA", + 8 + ], + [ + "bABbAB", + "ABCBCACc", + 11 + ], + [ + "bABbAC", + "bcBaCcAb", + 10 + ], + [ + "bABbBCB", + "cb", + 12 + ], + [ + "bABbaB", + "cAcAbbCAb", + 11 + ], + [ + "bABbaBAA", + "C", + 16 + ], + [ + "bABbbABBB", + "cAcb", + 14 + ], + [ + "bABbbbC", + "a", + 13 + ], + [ + "bABbcCab", + "ccccaa", + 11 + ], + [ + "bAC", + "AcAbc", + 7 + ], + [ + "bAC", + "bCcbAabb", + 12 + ], + [ + "bACA", + "ACaAAAaC", + 12 + ], + [ + "bACA", + "CAc", + 5 + ], + [ + "bACA", + "c", + 7 + ], + [ + "bACACAAa", + "cbBbC", + 14 + ], + [ + "bACAb", + "Cbc", + 8 + ], + [ + "bACAcc", + "BacBcAB", + 9 + ], + [ + "bACB", + "cBccC", + 8 + ], + [ + "bACBAC", + "BCCABaC", + 6 + ], + [ + "bACBBaA", + "bBACB", + 8 + ], + [ + "bACBCbb", + "b", + 12 + ], + [ + "bACBa", + "BCC", + 7 + ], + [ + "bACBaAcAb", + "C", + 16 + ], + [ + "bACBabABB", + "aCA", + 13 + ], + [ + "bACBcB", + "accBbaCcC", + 13 + ], + [ + "bACCaCcBb", + "aBaBcb", + 11 + ], + [ + "bACaBC", + "bA", + 8 + ], + [ + "bACaCCBAB", + "aaBacb", + 13 + ], + [ + "bACaCcC", + "aBCac", + 8 + ], + [ + "bACab", + "aBcBcAB", + 10 + ], + [ + "bACac", + "Bc", + 7 + ], + [ + "bACac", + "cBAacCAcB", + 10 + ], + [ + "bACbAA", + "B", + 11 + ], + [ + "bACbBbc", + "CbcAcBcA", + 11 + ], + [ + "bACc", + "bcA", + 5 + ], + [ + "bACc", + "cCb", + 6 + ], + [ + "bACcABb", + "BaC", + 10 + ], + [ + "bACcCaaC", + "AAbAbb", + 13 + ], + [ + "bAa", + "AaaACbAcc", + 14 + ], + [ + "bAa", + "AcAabb", + 8 + ], + [ + "bAa", + "bCbBCABBA", + 13 + ], + [ + "bAaA", + "aACcbaB", + 10 + ], + [ + "bAaAA", + "BacbCbBaa", + 14 + ], + [ + "bAaAAAa", + "cabAbA", + 9 + ], + [ + "bAaABAAC", + "AB", + 12 + ], + [ + "bAaAcA", + "cbC", + 11 + ], + [ + "bAaB", + "B", + 6 + ], + [ + "bAaB", + "acCCbb", + 11 + ], + [ + "bAaBAA", + "a", + 10 + ], + [ + "bAaBAcac", + "AABcaa", + 7 + ], + [ + "bAaBC", + "CBcaaaBa", + 10 + ], + [ + "bAaBa", + "C", + 10 + ], + [ + "bAaBaCBAB", + "CCbCCC", + 15 + ], + [ + "bAaBb", + "bCAA", + 7 + ], + [ + "bAaBbBc", + "AC", + 11 + ], + [ + "bAaBbc", + "cbbcAaab", + 10 + ], + [ + "bAaBc", + "a", + 8 + ], + [ + "bAaBc", + "cbCCBBbcc", + 12 + ], + [ + "bAaC", + "ABA", + 6 + ], + [ + "bAaC", + "BAaACAB", + 7 + ], + [ + "bAaCCa", + "CbCBB", + 10 + ], + [ + "bAaCa", + "bCBaABcbB", + 13 + ], + [ + "bAaCab", + "caBC", + 9 + ], + [ + "bAaa", + "AAcCbAC", + 11 + ], + [ + "bAaa", + "bBAAb", + 5 + ], + [ + "bAaaA", + "AbA", + 6 + ], + [ + "bAaaB", + "CABBC", + 8 + ], + [ + "bAaaB", + "bABBaC", + 6 + ], + [ + "bAaabaAc", + "cBaa", + 12 + ], + [ + "bAab", + "CcC", + 8 + ], + [ + "bAab", + "bAc", + 4 + ], + [ + "bAabAbC", + "A", + 12 + ], + [ + "bAabBACA", + "cCca", + 14 + ], + [ + "bAabBBCb", + "CbaCbA", + 12 + ], + [ + "bAabCAB", + "aA", + 10 + ], + [ + "bAabb", + "AaacAAA", + 11 + ], + [ + "bAabbC", + "babAb", + 6 + ], + [ + "bAabcA", + "bA", + 8 + ], + [ + "bAabcbc", + "BaAabcAaa", + 9 + ], + [ + "bAabccAa", + "aCbaB", + 12 + ], + [ + "bAac", + "ccACbbAA", + 13 + ], + [ + "bAacA", + "BBaACC", + 8 + ], + [ + "bAacAb", + "bacccBCc", + 10 + ], + [ + "bAacAbBca", + "C", + 17 + ], + [ + "bAacC", + "bbaAb", + 6 + ], + [ + "bAaccCB", + "c", + 12 + ], + [ + "bAb", + "ABCCAACCA", + 15 + ], + [ + "bAb", + "CCBAA", + 7 + ], + [ + "bAbACaC", + "bABcCAb", + 6 + ], + [ + "bAbAaC", + "BAbbA", + 6 + ], + [ + "bAbAabcab", + "CAabcBa", + 10 + ], + [ + "bAbAbcA", + "CAABBca", + 8 + ], + [ + "bAbBC", + "AACcbCca", + 11 + ], + [ + "bAbBCbaB", + "acacab", + 11 + ], + [ + "bAbBaCBcb", + "BaA", + 14 + ], + [ + "bAbBbbBbb", + "cAaacAC", + 16 + ], + [ + "bAbCAABaB", + "ACcBAccB", + 11 + ], + [ + "bAbCbCcCA", + "aBB", + 15 + ], + [ + "bAbCcB", + "aCAbA", + 10 + ], + [ + "bAba", + "CaAAb", + 8 + ], + [ + "bAbaCC", + "Bba", + 7 + ], + [ + "bAbab", + "CbCAcBcB", + 10 + ], + [ + "bAbb", + "acAbCBb", + 8 + ], + [ + "bAbb", + "b", + 6 + ], + [ + "bAbb", + "bAaAcBBab", + 11 + ], + [ + "bAbbB", + "AaACcBacC", + 14 + ], + [ + "bAbbaa", + "cCBC", + 11 + ], + [ + "bAbbbbBc", + "cABcBBC", + 9 + ], + [ + "bAbbbc", + "aCA", + 11 + ], + [ + "bAbc", + "Accbacc", + 9 + ], + [ + "bAbcBB", + "A", + 10 + ], + [ + "bAbcCaA", + "bACaCAcbC", + 11 + ], + [ + "bAbcCab", + "ABC", + 9 + ], + [ + "bAbcCbAA", + "BcBb", + 11 + ], + [ + "bAbcbA", + "CBCBCac", + 11 + ], + [ + "bAc", + "aaC", + 4 + ], + [ + "bAcA", + "bb", + 6 + ], + [ + "bAcAABA", + "aAAbca", + 9 + ], + [ + "bAcAAbA", + "BABabc", + 8 + ], + [ + "bAcAAbb", + "aC", + 12 + ], + [ + "bAcAbc", + "CAAcaaBa", + 10 + ], + [ + "bAcAc", + "BaC", + 7 + ], + [ + "bAcB", + "bcBC", + 4 + ], + [ + "bAcB", + "bccaA", + 6 + ], + [ + "bAcBAaaCa", + "aABCccaBa", + 12 + ], + [ + "bAcBAbBcC", + "B", + 16 + ], + [ + "bAcBBBABa", + "caA", + 14 + ], + [ + "bAcBCCbac", + "accBBAB", + 12 + ], + [ + "bAcBabbC", + "ca", + 12 + ], + [ + "bAcBbAb", + "cbaBA", + 9 + ], + [ + "bAcBbaA", + "AaBaaA", + 6 + ], + [ + "bAcC", + "Acac", + 5 + ], + [ + "bAcC", + "bba", + 6 + ], + [ + "bAcCAa", + "C", + 10 + ], + [ + "bAcCaCc", + "abbCcb", + 11 + ], + [ + "bAcCb", + "Bbcacac", + 9 + ], + [ + "bAcCbACCB", + "aA", + 15 + ], + [ + "bAcCcACA", + "ABCAaBB", + 11 + ], + [ + "bAcaAbA", + "baCCbBca", + 10 + ], + [ + "bAcac", + "BBbAbCccA", + 11 + ], + [ + "bAcb", + "aa", + 7 + ], + [ + "bAcb", + "cAbbb", + 6 + ], + [ + "bAcbAbBAC", + "CbBc", + 12 + ], + [ + "bAcbBbcb", + "cCcBBCaa", + 11 + ], + [ + "bAcc", + "aCcABC", + 9 + ], + [ + "bAccA", + "ccBaaCA", + 9 + ], + [ + "bAccCabB", + "aABCAAaAA", + 13 + ], + [ + "bAccCbb", + "BaAAcB", + 10 + ], + [ + "bAcca", + "CBbcBBBba", + 13 + ], + [ + "bAccaACaa", + "CCcBCaA", + 10 + ], + [ + "bAccaCCA", + "aABAABBCb", + 13 + ], + [ + "bAcccAC", + "ABC", + 10 + ], + [ + "bAcccAbaA", + "CBcCAbcC", + 11 + ], + [ + "bAcccaB", + "BccACBBC", + 10 + ], + [ + "bB", + "ACaAbC", + 10 + ], + [ + "bB", + "BCbCb", + 7 + ], + [ + "bB", + "Baa", + 5 + ], + [ + "bB", + "BbbbBAb", + 10 + ], + [ + "bB", + "Bcba", + 6 + ], + [ + "bB", + "CAAcBb", + 10 + ], + [ + "bB", + "CbbC", + 5 + ], + [ + "bB", + "aACCab", + 11 + ], + [ + "bB", + "aBaccb", + 10 + ], + [ + "bB", + "aBbC", + 6 + ], + [ + "bB", + "aCACcaA", + 14 + ], + [ + "bB", + "aaAABaCCc", + 16 + ], + [ + "bB", + "ac", + 4 + ], + [ + "bB", + "acACccAac", + 18 + ], + [ + "bB", + "bAAacb", + 9 + ], + [ + "bB", + "bBCccbcC", + 12 + ], + [ + "bB", + "bBbbcb", + 8 + ], + [ + "bB", + "bCbBAAbCc", + 14 + ], + [ + "bB", + "ba", + 2 + ], + [ + "bB", + "baAbcC", + 9 + ], + [ + "bB", + "bcBbACaa", + 12 + ], + [ + "bB", + "c", + 4 + ], + [ + "bB", + "cBCcc", + 8 + ], + [ + "bB", + "cCBa", + 6 + ], + [ + "bB", + "caBc", + 6 + ], + [ + "bB", + "caCCACb", + 13 + ], + [ + "bBA", + "AB", + 4 + ], + [ + "bBA", + "B", + 4 + ], + [ + "bBA", + "abBCbccC", + 12 + ], + [ + "bBA", + "bCaaa", + 7 + ], + [ + "bBA", + "cBB", + 4 + ], + [ + "bBAA", + "cAb", + 6 + ], + [ + "bBAAba", + "C", + 12 + ], + [ + "bBAAcb", + "BCcBABB", + 10 + ], + [ + "bBAB", + "ccaa", + 7 + ], + [ + "bBABbBc", + "Bb", + 10 + ], + [ + "bBAC", + "aCBb", + 8 + ], + [ + "bBACA", + "bbcaBB", + 8 + ], + [ + "bBACBA", + "CA", + 8 + ], + [ + "bBACBABc", + "ca", + 14 + ], + [ + "bBACCbCB", + "B", + 14 + ], + [ + "bBACbaC", + "aabAbaCC", + 9 + ], + [ + "bBAa", + "CBBbBaa", + 7 + ], + [ + "bBAa", + "CabC", + 8 + ], + [ + "bBAa", + "cCcCCCA", + 13 + ], + [ + "bBAaBAcB", + "CbCaaAbAA", + 12 + ], + [ + "bBAaBcAaB", + "ACcb", + 13 + ], + [ + "bBAaC", + "acBaAcC", + 8 + ], + [ + "bBAaCB", + "bcBbCBBca", + 12 + ], + [ + "bBAaCc", + "Aca", + 9 + ], + [ + "bBAac", + "AcccCbBc", + 14 + ], + [ + "bBAacA", + "aBCbaAAA", + 10 + ], + [ + "bBAbCA", + "cBAaaCACb", + 10 + ], + [ + "bBAba", + "B", + 8 + ], + [ + "bBAbac", + "cBbAaccb", + 10 + ], + [ + "bBAc", + "Bc", + 4 + ], + [ + "bBAcAbca", + "baB", + 12 + ], + [ + "bBAcBA", + "aAa", + 9 + ], + [ + "bBAcC", + "abbBbCBc", + 10 + ], + [ + "bBAcC", + "c", + 8 + ], + [ + "bBAca", + "Ba", + 6 + ], + [ + "bBAca", + "b", + 8 + ], + [ + "bBAca", + "c", + 8 + ], + [ + "bBB", + "ABACC", + 8 + ], + [ + "bBB", + "AcaBacAc", + 14 + ], + [ + "bBB", + "BCCBCB", + 7 + ], + [ + "bBB", + "Cba", + 5 + ], + [ + "bBB", + "bACbcbAc", + 12 + ], + [ + "bBBABBb", + "Cbab", + 10 + ], + [ + "bBBAa", + "c", + 10 + ], + [ + "bBBBB", + "AacCA", + 10 + ], + [ + "bBBBBAa", + "AbbBAB", + 8 + ], + [ + "bBBBCb", + "B", + 10 + ], + [ + "bBBBabC", + "abBacCCBA", + 13 + ], + [ + "bBBBc", + "AB", + 8 + ], + [ + "bBBC", + "B", + 6 + ], + [ + "bBBC", + "abAbBBcab", + 11 + ], + [ + "bBBCABbB", + "caaCC", + 14 + ], + [ + "bBBCAbB", + "BcBCBCcBc", + 10 + ], + [ + "bBBa", + "abbCAA", + 8 + ], + [ + "bBBaB", + "cacCCbAA", + 14 + ], + [ + "bBBaC", + "Bcc", + 7 + ], + [ + "bBBaaBC", + "bcbcbBba", + 11 + ], + [ + "bBBaaBb", + "a", + 12 + ], + [ + "bBBaabc", + "caaBba", + 10 + ], + [ + "bBBabac", + "aaAA", + 11 + ], + [ + "bBBb", + "Accaab", + 10 + ], + [ + "bBBb", + "aAacAbca", + 14 + ], + [ + "bBBbAcBB", + "BBAbBAb", + 9 + ], + [ + "bBBbBbbbB", + "cc", + 18 + ], + [ + "bBBbCa", + "BcC", + 8 + ], + [ + "bBBbaB", + "caAaaC", + 10 + ], + [ + "bBBbaBbCa", + "a", + 16 + ], + [ + "bBBbacabB", + "Ba", + 14 + ], + [ + "bBBbcc", + "bcA", + 8 + ], + [ + "bBBc", + "ABBbACc", + 8 + ], + [ + "bBBc", + "BAAb", + 7 + ], + [ + "bBBcA", + "caB", + 8 + ], + [ + "bBBcaca", + "CBBBbABcb", + 10 + ], + [ + "bBC", + "AB", + 4 + ], + [ + "bBC", + "aaCaCAcBc", + 15 + ], + [ + "bBC", + "bcaBACB", + 8 + ], + [ + "bBC", + "cAB", + 6 + ], + [ + "bBC", + "cBaCcbca", + 12 + ], + [ + "bBCA", + "AAc", + 7 + ], + [ + "bBCA", + "bCCACBc", + 8 + ], + [ + "bBCA", + "babCCBAC", + 9 + ], + [ + "bBCA", + "cBaabcA", + 9 + ], + [ + "bBCAB", + "ACcBBBBab", + 13 + ], + [ + "bBCABBA", + "BCabbCAB", + 9 + ], + [ + "bBCAbAb", + "caAbA", + 8 + ], + [ + "bBCAbBba", + "CbbBbbC", + 10 + ], + [ + "bBCAcBcCA", + "B", + 16 + ], + [ + "bBCBa", + "cbAAB", + 8 + ], + [ + "bBCBaBCaa", + "bA", + 15 + ], + [ + "bBCBaC", + "aABCAca", + 10 + ], + [ + "bBCBabBC", + "cCAc", + 12 + ], + [ + "bBCC", + "baAbacaA", + 12 + ], + [ + "bBCCA", + "aa", + 9 + ], + [ + "bBCCCCABc", + "babacAA", + 13 + ], + [ + "bBCCCb", + "ACc", + 9 + ], + [ + "bBCCbAb", + "a", + 13 + ], + [ + "bBCaABB", + "CbACac", + 10 + ], + [ + "bBCaCCC", + "ABccBC", + 8 + ], + [ + "bBCaabcAA", + "CBABCC", + 13 + ], + [ + "bBCac", + "BA", + 7 + ], + [ + "bBCacbCA", + "BaCBcCBC", + 10 + ], + [ + "bBCb", + "bBcCA", + 4 + ], + [ + "bBCbAAaAC", + "CCbCCA", + 12 + ], + [ + "bBCbBa", + "AbBaACCB", + 10 + ], + [ + "bBCbb", + "aCcaC", + 9 + ], + [ + "bBCc", + "ccB", + 7 + ], + [ + "bBCcaAAa", + "caabAbC", + 13 + ], + [ + "bBa", + "Bba", + 2 + ], + [ + "bBa", + "b", + 4 + ], + [ + "bBa", + "bBcAca", + 6 + ], + [ + "bBa", + "bCA", + 3 + ], + [ + "bBa", + "cACaAbBa", + 10 + ], + [ + "bBa", + "ccBcbcAcc", + 15 + ], + [ + "bBaABCcC", + "ABA", + 12 + ], + [ + "bBaACBaB", + "BCBBABbb", + 10 + ], + [ + "bBaAaA", + "Bb", + 10 + ], + [ + "bBaAaBc", + "BAbcaACBc", + 8 + ], + [ + "bBaAaC", + "cCBACaaA", + 10 + ], + [ + "bBaAb", + "bACbbacAB", + 10 + ], + [ + "bBaBCAAaa", + "CACBAc", + 13 + ], + [ + "bBaBCCcA", + "bb", + 13 + ], + [ + "bBaBCaAaB", + "bCAbCbbB", + 10 + ], + [ + "bBaBCcBcB", + "cabcc", + 11 + ], + [ + "bBaBa", + "BC", + 8 + ], + [ + "bBaBbAbAB", + "aBAAbCCBA", + 12 + ], + [ + "bBaBbb", + "BaCAbbb", + 7 + ], + [ + "bBaC", + "BAaAcb", + 8 + ], + [ + "bBaCbcC", + "bA", + 11 + ], + [ + "bBaCcAA", + "cAbb", + 12 + ], + [ + "bBaaBb", + "Caa", + 8 + ], + [ + "bBaaBcBbb", + "cABAaA", + 15 + ], + [ + "bBaaCABa", + "bcbaBcbC", + 11 + ], + [ + "bBaaCa", + "bAAC", + 6 + ], + [ + "bBaabbbbc", + "cbA", + 16 + ], + [ + "bBaacaC", + "bccaBC", + 8 + ], + [ + "bBabAcBA", + "ccaAbA", + 9 + ], + [ + "bBabB", + "BabcBBB", + 8 + ], + [ + "bBabC", + "ABc", + 7 + ], + [ + "bBabaAC", + "ccaCb", + 12 + ], + [ + "bBac", + "AbaAcAaB", + 11 + ], + [ + "bBac", + "BBCc", + 3 + ], + [ + "bBacbBcb", + "bCbc", + 9 + ], + [ + "bBb", + "AA", + 6 + ], + [ + "bBb", + "AbCaacc", + 12 + ], + [ + "bBb", + "CaaCCCaA", + 16 + ], + [ + "bBb", + "Ccac", + 8 + ], + [ + "bBb", + "a", + 6 + ], + [ + "bBb", + "aCC", + 6 + ], + [ + "bBb", + "baAC", + 6 + ], + [ + "bBb", + "cBA", + 4 + ], + [ + "bBb", + "caBaCBa", + 11 + ], + [ + "bBbA", + "C", + 8 + ], + [ + "bBbA", + "CBcBAA", + 7 + ], + [ + "bBbA", + "caBBABaBa", + 13 + ], + [ + "bBbAAa", + "aabbb", + 10 + ], + [ + "bBbB", + "AcbAA", + 8 + ], + [ + "bBbB", + "a", + 8 + ], + [ + "bBbBBaBAc", + "c", + 16 + ], + [ + "bBbBBba", + "Bbc", + 10 + ], + [ + "bBbBb", + "B", + 8 + ], + [ + "bBbCA", + "abBBcBBbc", + 12 + ], + [ + "bBbCCca", + "aCaCBCB", + 11 + ], + [ + "bBba", + "aAA", + 7 + ], + [ + "bBba", + "abB", + 6 + ], + [ + "bBbaA", + "cBCBCcCCB", + 15 + ], + [ + "bBbaC", + "bc", + 7 + ], + [ + "bBbaCba", + "aBBccAaB", + 10 + ], + [ + "bBbabBAC", + "bCBa", + 11 + ], + [ + "bBbacbBCA", + "BA", + 14 + ], + [ + "bBbbCA", + "bACbBAa", + 8 + ], + [ + "bBbbbc", + "c", + 10 + ], + [ + "bBbcAAba", + "cC", + 14 + ], + [ + "bBbcBBCa", + "b", + 14 + ], + [ + "bBbcCC", + "aacCBb", + 10 + ], + [ + "bBbcCC", + "acabCCb", + 9 + ], + [ + "bBbcbA", + "BcBCabB", + 9 + ], + [ + "bBbcbA", + "cBaCcCbB", + 10 + ], + [ + "bBbcbBa", + "BbA", + 9 + ], + [ + "bBc", + "A", + 6 + ], + [ + "bBc", + "ACA", + 6 + ], + [ + "bBc", + "CC", + 5 + ], + [ + "bBc", + "bCbA", + 5 + ], + [ + "bBc", + "bbcA", + 3 + ], + [ + "bBcA", + "BaCba", + 7 + ], + [ + "bBcAACbB", + "bCba", + 10 + ], + [ + "bBcABCb", + "BAca", + 9 + ], + [ + "bBcAa", + "Ca", + 7 + ], + [ + "bBcAcBabB", + "ccaCAb", + 11 + ], + [ + "bBcAccBAc", + "cAc", + 12 + ], + [ + "bBcB", + "Ca", + 7 + ], + [ + "bBcBAbB", + "A", + 12 + ], + [ + "bBcBAca", + "BcbC", + 8 + ], + [ + "bBcBc", + "C", + 9 + ], + [ + "bBcCCbcb", + "CAAcacCaC", + 14 + ], + [ + "bBcCaAb", + "CbbbCa", + 9 + ], + [ + "bBcCbAAa", + "c", + 14 + ], + [ + "bBcaaaCAC", + "ACBbc", + 16 + ], + [ + "bBcb", + "bCCac", + 7 + ], + [ + "bBcba", + "bba", + 4 + ], + [ + "bBcbaB", + "BaCCbc", + 10 + ], + [ + "bBcbaBAbB", + "AAb", + 13 + ], + [ + "bBcbaBbAB", + "c", + 16 + ], + [ + "bBcc", + "CcBABA", + 10 + ], + [ + "bBcc", + "aAc", + 6 + ], + [ + "bBccACBbA", + "CaCCCB", + 12 + ], + [ + "bBccBc", + "Caac", + 9 + ], + [ + "bBccC", + "bAcc", + 4 + ], + [ + "bBccb", + "bccAbBbC", + 10 + ], + [ + "bBccb", + "caBAA", + 10 + ], + [ + "bBccbBbCb", + "AAAbbaBA", + 15 + ], + [ + "bBccbBccC", + "c", + 16 + ], + [ + "bBccbb", + "AaABa", + 11 + ], + [ + "bBcccB", + "bcCAca", + 7 + ], + [ + "bC", + "A", + 4 + ], + [ + "bC", + "ACBBaBa", + 12 + ], + [ + "bC", + "Abc", + 3 + ], + [ + "bC", + "BAAcb", + 8 + ], + [ + "bC", + "BAa", + 5 + ], + [ + "bC", + "BAcaBCAcc", + 15 + ], + [ + "bC", + "BCbcCA", + 8 + ], + [ + "bC", + "BacAcb", + 10 + ], + [ + "bC", + "CC", + 2 + ], + [ + "bC", + "CbBcAbcc", + 13 + ], + [ + "bC", + "aBaCA", + 7 + ], + [ + "bC", + "aCCbCABBB", + 14 + ], + [ + "bC", + "aaBBCAA", + 11 + ], + [ + "bC", + "aaCbaAcB", + 13 + ], + [ + "bC", + "acCcbcB", + 11 + ], + [ + "bC", + "b", + 2 + ], + [ + "bC", + "bBBBC", + 6 + ], + [ + "bC", + "bBb", + 4 + ], + [ + "bC", + "bC", + 0 + ], + [ + "bC", + "baAAcb", + 9 + ], + [ + "bC", + "bac", + 3 + ], + [ + "bC", + "bbBb", + 6 + ], + [ + "bC", + "c", + 3 + ], + [ + "bC", + "cABAac", + 10 + ], + [ + "bC", + "cABcACACa", + 15 + ], + [ + "bC", + "cAaCb", + 8 + ], + [ + "bC", + "cBbB", + 6 + ], + [ + "bC", + "cBcCbcc", + 11 + ], + [ + "bC", + "cBcCcAa", + 11 + ], + [ + "bC", + "cccCBcaba", + 16 + ], + [ + "bCA", + "BbCaCc", + 7 + ], + [ + "bCA", + "ac", + 5 + ], + [ + "bCA", + "bCB", + 2 + ], + [ + "bCA", + "ba", + 3 + ], + [ + "bCA", + "cbcbAc", + 7 + ], + [ + "bCAAA", + "Cc", + 8 + ], + [ + "bCAAA", + "cBabbA", + 9 + ], + [ + "bCAAABc", + "Aabab", + 11 + ], + [ + "bCAABaCbc", + "Cab", + 12 + ], + [ + "bCAABccA", + "AaacCBBcB", + 13 + ], + [ + "bCAAC", + "bBAaCcc", + 7 + ], + [ + "bCAACaCa", + "CcAACaC", + 5 + ], + [ + "bCAAaBbCA", + "CbaAcB", + 13 + ], + [ + "bCAB", + "bAAA", + 4 + ], + [ + "bCABB", + "bA", + 6 + ], + [ + "bCABBCAA", + "bBCbcCc", + 11 + ], + [ + "bCABBcB", + "bBbACbaBb", + 11 + ], + [ + "bCABa", + "AaAa", + 6 + ], + [ + "bCABaBAcc", + "CBbaCCba", + 13 + ], + [ + "bCAC", + "ABCcc", + 6 + ], + [ + "bCAC", + "caCa", + 6 + ], + [ + "bCAC", + "cbCcb", + 6 + ], + [ + "bCACBA", + "cbac", + 10 + ], + [ + "bCACBB", + "Bcb", + 9 + ], + [ + "bCACa", + "c", + 9 + ], + [ + "bCACaaC", + "Cacaaa", + 6 + ], + [ + "bCACaaa", + "cC", + 11 + ], + [ + "bCACb", + "B", + 9 + ], + [ + "bCACbA", + "Cb", + 8 + ], + [ + "bCAaCB", + "aCAbcCbB", + 8 + ], + [ + "bCAaCbac", + "a", + 14 + ], + [ + "bCAaccaCC", + "b", + 16 + ], + [ + "bCAbAAcA", + "bBBCAabAc", + 10 + ], + [ + "bCAbab", + "ca", + 9 + ], + [ + "bCAbb", + "CBAcBAcBB", + 12 + ], + [ + "bCAc", + "BaCAaaBa", + 11 + ], + [ + "bCAcBA", + "CBBcCCA", + 10 + ], + [ + "bCAcC", + "BbaccaCA", + 10 + ], + [ + "bCAcC", + "BcA", + 6 + ], + [ + "bCAcc", + "cbCAB", + 6 + ], + [ + "bCB", + "CCabaC", + 9 + ], + [ + "bCB", + "abaaAbbAC", + 15 + ], + [ + "bCB", + "bCAca", + 6 + ], + [ + "bCB", + "cBAB", + 5 + ], + [ + "bCBA", + "BccBbcAA", + 10 + ], + [ + "bCBAAa", + "c", + 11 + ], + [ + "bCBBBCbc", + "CAbbbB", + 10 + ], + [ + "bCBBBcB", + "BBaBCBbC", + 10 + ], + [ + "bCBBa", + "CccaaC", + 9 + ], + [ + "bCBBbCc", + "bBaAB", + 10 + ], + [ + "bCBC", + "AbaCcaCB", + 10 + ], + [ + "bCBC", + "CcbaCaA", + 10 + ], + [ + "bCBC", + "aCAbcbCC", + 10 + ], + [ + "bCBCAB", + "C", + 10 + ], + [ + "bCBCACBb", + "bBacBCaA", + 11 + ], + [ + "bCBCBcbc", + "bA", + 14 + ], + [ + "bCBCaAc", + "a", + 12 + ], + [ + "bCBCbC", + "A", + 12 + ], + [ + "bCBa", + "Ba", + 4 + ], + [ + "bCBaAb", + "CABCCcb", + 10 + ], + [ + "bCBaabC", + "ACb", + 10 + ], + [ + "bCBabCa", + "cAbaccCC", + 11 + ], + [ + "bCBacABab", + "ccAacAaCc", + 11 + ], + [ + "bCBacaAB", + "ACbABB", + 10 + ], + [ + "bCBb", + "aaAbAbbC", + 11 + ], + [ + "bCBb", + "cBabcA", + 9 + ], + [ + "bCBb", + "cBcccaA", + 12 + ], + [ + "bCBbAaAb", + "BabA", + 11 + ], + [ + "bCBbAac", + "CBcca", + 8 + ], + [ + "bCBbAcC", + "CBbBbb", + 8 + ], + [ + "bCBbC", + "CA", + 8 + ], + [ + "bCBbaCCA", + "BAAab", + 13 + ], + [ + "bCBbabb", + "BcCBA", + 10 + ], + [ + "bCBbbCb", + "ABcbAba", + 10 + ], + [ + "bCBc", + "bbBACc", + 6 + ], + [ + "bCBcB", + "bCAbccACb", + 10 + ], + [ + "bCBcBBc", + "b", + 12 + ], + [ + "bCBca", + "cAABaCCa", + 11 + ], + [ + "bCBcabA", + "CAcbbcBcB", + 14 + ], + [ + "bCBcba", + "ABAcbc", + 8 + ], + [ + "bCBcccbC", + "Cbbbc", + 10 + ], + [ + "bCC", + "A", + 6 + ], + [ + "bCC", + "ABBbCCC", + 8 + ], + [ + "bCC", + "AaC", + 4 + ], + [ + "bCC", + "BB", + 5 + ], + [ + "bCC", + "a", + 6 + ], + [ + "bCC", + "aCbBaaCB", + 12 + ], + [ + "bCC", + "b", + 4 + ], + [ + "bCC", + "bbBaCaCAc", + 12 + ], + [ + "bCC", + "cB", + 5 + ], + [ + "bCCAACA", + "bc", + 11 + ], + [ + "bCCAAbAa", + "aC", + 14 + ], + [ + "bCCACBb", + "BcAA", + 10 + ], + [ + "bCCAc", + "bcBCABabC", + 10 + ], + [ + "bCCBACAa", + "cCB", + 11 + ], + [ + "bCCBC", + "CbbbACC", + 10 + ], + [ + "bCCBaBa", + "BC", + 11 + ], + [ + "bCCBbBAA", + "ACBbbBc", + 9 + ], + [ + "bCCCABcb", + "BaBbbAb", + 12 + ], + [ + "bCCCa", + "aA", + 9 + ], + [ + "bCCCbccc", + "aCAA", + 14 + ], + [ + "bCCa", + "AabcB", + 9 + ], + [ + "bCCa", + "BccBa", + 5 + ], + [ + "bCCa", + "bCACAaBb", + 8 + ], + [ + "bCCaA", + "cbAbaAA", + 8 + ], + [ + "bCCaAbBB", + "CcC", + 13 + ], + [ + "bCCaBa", + "AcCabCAc", + 9 + ], + [ + "bCCaCc", + "abAcCA", + 9 + ], + [ + "bCCaa", + "cA", + 8 + ], + [ + "bCCaaCaa", + "cbcc", + 14 + ], + [ + "bCCab", + "B", + 9 + ], + [ + "bCCaccbbB", + "cC", + 15 + ], + [ + "bCCb", + "cBBaBB", + 10 + ], + [ + "bCCbA", + "bcBC", + 6 + ], + [ + "bCCbACBBB", + "CA", + 14 + ], + [ + "bCCbB", + "aaBcCbAA", + 10 + ], + [ + "bCCbCc", + "aACbC", + 6 + ], + [ + "bCCbcA", + "caACc", + 10 + ], + [ + "bCCcAcAB", + "aCAB", + 10 + ], + [ + "bCCcc", + "aACCcacB", + 8 + ], + [ + "bCCccC", + "aabAb", + 12 + ], + [ + "bCa", + "Cb", + 4 + ], + [ + "bCa", + "aBbb", + 7 + ], + [ + "bCa", + "bBACAbba", + 10 + ], + [ + "bCa", + "baba", + 4 + ], + [ + "bCa", + "cbacb", + 7 + ], + [ + "bCa", + "ccaCaCCc", + 12 + ], + [ + "bCaA", + "AABbbA", + 9 + ], + [ + "bCaA", + "CBc", + 6 + ], + [ + "bCaAC", + "ACaaABaCa", + 10 + ], + [ + "bCaBAc", + "bbbBcbcAc", + 10 + ], + [ + "bCaBBBA", + "caCcBBCcB", + 12 + ], + [ + "bCaBBC", + "cacbBC", + 6 + ], + [ + "bCaBbCAC", + "aaCAcCAbC", + 11 + ], + [ + "bCaCAabc", + "bBaB", + 11 + ], + [ + "bCaCAcaC", + "bcccaa", + 8 + ], + [ + "bCaCCC", + "cAbabbACA", + 14 + ], + [ + "bCaCcB", + "ABbbcCABC", + 12 + ], + [ + "bCaCcac", + "CBbCAA", + 10 + ], + [ + "bCaa", + "a", + 6 + ], + [ + "bCaa", + "aBC", + 7 + ], + [ + "bCaabBC", + "CCABcA", + 10 + ], + [ + "bCabAacbC", + "BAB", + 14 + ], + [ + "bCabCc", + "CA", + 9 + ], + [ + "bCabaAAB", + "A", + 14 + ], + [ + "bCabbAacb", + "Cba", + 12 + ], + [ + "bCabbC", + "CAacA", + 9 + ], + [ + "bCac", + "C", + 6 + ], + [ + "bCac", + "cC", + 6 + ], + [ + "bCacAbBa", + "a", + 14 + ], + [ + "bCacBA", + "abB", + 8 + ], + [ + "bCacCcB", + "aAabBBbC", + 13 + ], + [ + "bCaccBAa", + "CB", + 12 + ], + [ + "bCb", + "aCBc", + 5 + ], + [ + "bCb", + "ab", + 4 + ], + [ + "bCb", + "ccA", + 5 + ], + [ + "bCbA", + "ab", + 6 + ], + [ + "bCbAAAB", + "AccbcBaB", + 10 + ], + [ + "bCbAB", + "BcBB", + 5 + ], + [ + "bCbACcbc", + "b", + 14 + ], + [ + "bCbAa", + "acCBABB", + 9 + ], + [ + "bCbAbcBc", + "b", + 14 + ], + [ + "bCbB", + "b", + 6 + ], + [ + "bCbBabC", + "cbacBCaBc", + 10 + ], + [ + "bCbBacaA", + "aBAaBCaa", + 11 + ], + [ + "bCbBbbbC", + "a", + 16 + ], + [ + "bCbBbcAb", + "ba", + 13 + ], + [ + "bCbCAbB", + "CABBbb", + 9 + ], + [ + "bCbCCCAcb", + "a", + 17 + ], + [ + "bCbCbb", + "AAACCCB", + 11 + ], + [ + "bCbCccc", + "abbAbC", + 11 + ], + [ + "bCbaACBbb", + "bCCccaa", + 13 + ], + [ + "bCbaAc", + "BA", + 9 + ], + [ + "bCbaaBc", + "CbAAcaBc", + 7 + ], + [ + "bCbac", + "aAcBABbaA", + 13 + ], + [ + "bCbac", + "b", + 8 + ], + [ + "bCbacABa", + "cCaac", + 10 + ], + [ + "bCbb", + "bbCBabAC", + 9 + ], + [ + "bCbbb", + "AcBc", + 8 + ], + [ + "bCbbba", + "AaBbc", + 9 + ], + [ + "bCbc", + "ABb", + 6 + ], + [ + "bCbc", + "CCb", + 4 + ], + [ + "bCbcB", + "AbAab", + 9 + ], + [ + "bCbcCBA", + "BCbBacC", + 9 + ], + [ + "bCbcCC", + "BbbABA", + 9 + ], + [ + "bCbcCbAC", + "ccccC", + 10 + ], + [ + "bCbca", + "bcbBCBa", + 6 + ], + [ + "bCbcaAAAA", + "A", + 16 + ], + [ + "bCbcaca", + "bBBAcc", + 8 + ], + [ + "bCbcbbBbC", + "CaC", + 14 + ], + [ + "bCc", + "BabBBCb", + 10 + ], + [ + "bCc", + "CCBcAA", + 8 + ], + [ + "bCc", + "CCCcCBcC", + 12 + ], + [ + "bCc", + "aaAABCCaB", + 14 + ], + [ + "bCc", + "aabbbaaB", + 14 + ], + [ + "bCc", + "bccB", + 3 + ], + [ + "bCcABC", + "aAcBcCC", + 10 + ], + [ + "bCcACCBa", + "cac", + 12 + ], + [ + "bCcACCaC", + "AbcaC", + 9 + ], + [ + "bCcB", + "BBB", + 5 + ], + [ + "bCcBA", + "CcAbcCbaA", + 11 + ], + [ + "bCcBB", + "cBb", + 5 + ], + [ + "bCcC", + "ACBaB", + 8 + ], + [ + "bCcCb", + "ccbBac", + 10 + ], + [ + "bCcCcCCCB", + "BCAaAa", + 15 + ], + [ + "bCca", + "CCaaaBbc", + 12 + ], + [ + "bCcaA", + "cACB", + 9 + ], + [ + "bCcaBbac", + "bBa", + 10 + ], + [ + "bCcaCc", + "A", + 11 + ], + [ + "bCcaCcC", + "bcCB", + 8 + ], + [ + "bCcaaa", + "B", + 11 + ], + [ + "bCcaabCB", + "bbAbcaAA", + 13 + ], + [ + "bCcacBCA", + "aACBccC", + 11 + ], + [ + "bCcbAaBBc", + "c", + 16 + ], + [ + "bCcbCCbb", + "bBbacaC", + 11 + ], + [ + "bCcbbaCab", + "BC", + 15 + ], + [ + "bCcbbc", + "bBBCB", + 9 + ], + [ + "bCcbc", + "acBCAcc", + 9 + ], + [ + "bCcc", + "CAbacbA", + 10 + ], + [ + "bCccbbbc", + "bBABAaBAc", + 13 + ], + [ + "ba", + "ABbbC", + 8 + ], + [ + "ba", + "BA", + 2 + ], + [ + "ba", + "BAABBb", + 10 + ], + [ + "ba", + "BacAAbA", + 11 + ], + [ + "ba", + "BbAaaCACc", + 14 + ], + [ + "ba", + "BcCAAC", + 10 + ], + [ + "ba", + "Bcc", + 5 + ], + [ + "ba", + "CCccCCa", + 12 + ], + [ + "ba", + "CaAbAb", + 9 + ], + [ + "ba", + "Cba", + 2 + ], + [ + "ba", + "Cca", + 4 + ], + [ + "ba", + "Ccac", + 6 + ], + [ + "ba", + "a", + 2 + ], + [ + "ba", + "aBABA", + 8 + ], + [ + "ba", + "aBaABB", + 9 + ], + [ + "ba", + "aCcaCbAbB", + 15 + ], + [ + "ba", + "bBC", + 4 + ], + [ + "ba", + "bBCC", + 6 + ], + [ + "ba", + "baABc", + 6 + ], + [ + "ba", + "baCAbB", + 8 + ], + [ + "ba", + "cA", + 3 + ], + [ + "ba", + "cABA", + 6 + ], + [ + "ba", + "cBbCCaB", + 10 + ], + [ + "ba", + "cBc", + 5 + ], + [ + "ba", + "cCCBcC", + 11 + ], + [ + "ba", + "caBBCAca", + 13 + ], + [ + "ba", + "cbBbb", + 8 + ], + [ + "ba", + "ccb", + 6 + ], + [ + "baA", + "AbAAaCaa", + 11 + ], + [ + "baA", + "B", + 5 + ], + [ + "baA", + "BBB", + 5 + ], + [ + "baA", + "a", + 4 + ], + [ + "baA", + "aCaaB", + 7 + ], + [ + "baA", + "cAaBCBaCB", + 15 + ], + [ + "baA", + "cBBcccca", + 14 + ], + [ + "baA", + "ccABbC", + 10 + ], + [ + "baAA", + "BBAaCacBC", + 14 + ], + [ + "baAA", + "cbbbCcbac", + 15 + ], + [ + "baAAA", + "CCcC", + 10 + ], + [ + "baAAABbC", + "BcACCbBa", + 11 + ], + [ + "baAAAbAC", + "caBb", + 12 + ], + [ + "baAAa", + "cACaAB", + 8 + ], + [ + "baAAc", + "bC", + 7 + ], + [ + "baAAcCa", + "CCABACcBC", + 12 + ], + [ + "baABBcc", + "cbcaaABc", + 9 + ], + [ + "baABCaCA", + "CABCbCAC", + 8 + ], + [ + "baABaBaAA", + "CAabb", + 13 + ], + [ + "baABbAcC", + "BcCBCCC", + 10 + ], + [ + "baAC", + "bCbAbBCA", + 10 + ], + [ + "baACCCcaA", + "Cb", + 16 + ], + [ + "baACca", + "bBcB", + 8 + ], + [ + "baAa", + "AbAab", + 6 + ], + [ + "baAaCAcc", + "acAbB", + 11 + ], + [ + "baAbCAc", + "baAacAac", + 5 + ], + [ + "baAbaAaba", + "cBA", + 15 + ], + [ + "baAbabAb", + "CC", + 16 + ], + [ + "baAcABAC", + "aabCBbBcB", + 13 + ], + [ + "baAcB", + "bbcb", + 5 + ], + [ + "baAcCcaaa", + "ccAA", + 12 + ], + [ + "baAca", + "aaAcCc", + 6 + ], + [ + "baAcaA", + "C", + 11 + ], + [ + "baAcab", + "B", + 11 + ], + [ + "baAcc", + "AbacACCCb", + 10 + ], + [ + "baB", + "BbccbbBbC", + 14 + ], + [ + "baB", + "acbAB", + 5 + ], + [ + "baB", + "accCa", + 10 + ], + [ + "baB", + "cA", + 5 + ], + [ + "baB", + "ca", + 4 + ], + [ + "baB", + "ccBACC", + 10 + ], + [ + "baBA", + "aa", + 5 + ], + [ + "baBAC", + "aA", + 6 + ], + [ + "baBAbccc", + "BCBaC", + 11 + ], + [ + "baBB", + "bCCaAca", + 10 + ], + [ + "baBB", + "cacbb", + 6 + ], + [ + "baBBC", + "BbBAA", + 7 + ], + [ + "baBBCAAc", + "bBaabAccc", + 11 + ], + [ + "baBBCcBCa", + "ABbBca", + 9 + ], + [ + "baBBaa", + "BCABAa", + 6 + ], + [ + "baBBbAb", + "bACa", + 10 + ], + [ + "baBBbCbBC", + "cBABabC", + 11 + ], + [ + "baBBcaBcC", + "CCCb", + 16 + ], + [ + "baBBcb", + "BBCbCCb", + 9 + ], + [ + "baBCcbbA", + "BBacCC", + 11 + ], + [ + "baBa", + "aA", + 5 + ], + [ + "baBa", + "bBbcAAb", + 10 + ], + [ + "baBa", + "cCbbbcBC", + 12 + ], + [ + "baBaABBb", + "bBcB", + 10 + ], + [ + "baBaaC", + "A", + 11 + ], + [ + "baBaaC", + "bBbAcc", + 7 + ], + [ + "baBbC", + "ACAc", + 8 + ], + [ + "baBbcCbaC", + "C", + 16 + ], + [ + "baBc", + "BAAbCa", + 8 + ], + [ + "baBcAAC", + "aBAAbACa", + 8 + ], + [ + "baBcC", + "Abc", + 6 + ], + [ + "baBcCCBBA", + "bbacBaaaC", + 14 + ], + [ + "baBcCCBb", + "Bccacb", + 9 + ], + [ + "baBcaAc", + "bc", + 10 + ], + [ + "baBcbccA", + "bCCa", + 11 + ], + [ + "baBccBC", + "C", + 12 + ], + [ + "baBccccb", + "AAbbaBCb", + 11 + ], + [ + "baC", + "AABBAb", + 10 + ], + [ + "baC", + "AB", + 5 + ], + [ + "baC", + "BBa", + 5 + ], + [ + "baC", + "CAaCCcbb", + 12 + ], + [ + "baC", + "CC", + 4 + ], + [ + "baC", + "caBcB", + 7 + ], + [ + "baCA", + "Bc", + 6 + ], + [ + "baCACBCac", + "a", + 16 + ], + [ + "baCAaAaBa", + "bcBcCab", + 12 + ], + [ + "baCAbc", + "CCc", + 8 + ], + [ + "baCB", + "B", + 6 + ], + [ + "baCBACbBa", + "b", + 16 + ], + [ + "baCBC", + "CAAcaCaB", + 12 + ], + [ + "baCBbCB", + "abc", + 9 + ], + [ + "baCCCCBB", + "b", + 14 + ], + [ + "baCCCcC", + "bbcAcABac", + 13 + ], + [ + "baCCbAB", + "CbBAC", + 9 + ], + [ + "baCCc", + "BcACCa", + 6 + ], + [ + "baCCc", + "ab", + 8 + ], + [ + "baCa", + "BAabaACcC", + 12 + ], + [ + "baCa", + "CCAABc", + 11 + ], + [ + "baCaAAB", + "aCB", + 8 + ], + [ + "baCaCa", + "caC", + 7 + ], + [ + "baCaCcbAb", + "bCB", + 13 + ], + [ + "baCb", + "CAbA", + 7 + ], + [ + "baCbCAB", + "aCBccCcC", + 11 + ], + [ + "baCbCC", + "ACCbA", + 8 + ], + [ + "baCbbCb", + "bACAc", + 8 + ], + [ + "baCbc", + "aaAbAb", + 8 + ], + [ + "baCbcACBc", + "CACcBb", + 11 + ], + [ + "baCc", + "BbcaaB", + 8 + ], + [ + "baCcA", + "bbbBcB", + 8 + ], + [ + "baCcaaC", + "cCCA", + 10 + ], + [ + "baCcb", + "BaCacAa", + 7 + ], + [ + "baa", + "ACbBca", + 8 + ], + [ + "baa", + "BaC", + 3 + ], + [ + "baaABBcBb", + "ABcacAC", + 14 + ], + [ + "baaAC", + "aCAb", + 6 + ], + [ + "baaAaBB", + "ccABBac", + 12 + ], + [ + "baaAb", + "bAcBabC", + 8 + ], + [ + "baaAcA", + "B", + 11 + ], + [ + "baaBAA", + "CbabaCCAA", + 8 + ], + [ + "baaBAAabB", + "cCB", + 16 + ], + [ + "baaBBBb", + "aC", + 12 + ], + [ + "baaBabb", + "cAaB", + 9 + ], + [ + "baaBb", + "CBbaBAbC", + 9 + ], + [ + "baaBcaa", + "CcCCbb", + 13 + ], + [ + "baaCCcAB", + "cCA", + 11 + ], + [ + "baaCaac", + "aCAaCCbA", + 11 + ], + [ + "baaCbA", + "ccBAAcC", + 12 + ], + [ + "baaa", + "CaCbCb", + 10 + ], + [ + "baaa", + "bBbBAAC", + 10 + ], + [ + "baaaAc", + "CBBbBBB", + 13 + ], + [ + "baaaCA", + "aab", + 8 + ], + [ + "baaaaabB", + "BCbbccA", + 15 + ], + [ + "baaacac", + "ABa", + 11 + ], + [ + "baab", + "aABbABC", + 11 + ], + [ + "baabA", + "cACC", + 9 + ], + [ + "baabaBaab", + "aCcA", + 15 + ], + [ + "baac", + "ACBbca", + 10 + ], + [ + "baacACa", + "bccCB", + 8 + ], + [ + "baacBbA", + "AaaCCbaaA", + 9 + ], + [ + "baacCc", + "CACBAA", + 11 + ], + [ + "baacaCcb", + "BBbbbAaBA", + 16 + ], + [ + "baacabBAA", + "aaaaBaB", + 9 + ], + [ + "bab", + "Cc", + 6 + ], + [ + "bab", + "CcBC", + 7 + ], + [ + "bab", + "a", + 4 + ], + [ + "bab", + "aabbAaBca", + 13 + ], + [ + "babA", + "AB", + 6 + ], + [ + "babA", + "bCb", + 4 + ], + [ + "babA", + "cccABCc", + 12 + ], + [ + "babAAaBC", + "Cb", + 14 + ], + [ + "babAaAA", + "bc", + 12 + ], + [ + "babAaBA", + "BbcBAbC", + 10 + ], + [ + "babBBB", + "b", + 10 + ], + [ + "babBa", + "BB", + 7 + ], + [ + "babBbAbAC", + "CbabB", + 12 + ], + [ + "babC", + "BCB", + 6 + ], + [ + "babC", + "CABB", + 6 + ], + [ + "babCABaa", + "BbcCAab", + 9 + ], + [ + "babCB", + "bcCCaABBC", + 12 + ], + [ + "babCBb", + "AAcbb", + 7 + ], + [ + "babCCCc", + "cCAbbca", + 12 + ], + [ + "babCCa", + "c", + 11 + ], + [ + "babCabCab", + "caac", + 13 + ], + [ + "babCbcc", + "AaAAcA", + 10 + ], + [ + "baba", + "abBcbAc", + 9 + ], + [ + "babaBA", + "CbcBbBabB", + 11 + ], + [ + "babaC", + "CbAaAA", + 8 + ], + [ + "babaCBaa", + "BbCa", + 9 + ], + [ + "babaa", + "C", + 10 + ], + [ + "babaaCBCC", + "BbaaAc", + 10 + ], + [ + "babb", + "AcB", + 6 + ], + [ + "babbA", + "BabaAAaB", + 9 + ], + [ + "babbCaaCB", + "cCaAAaBc", + 15 + ], + [ + "babbCbC", + "AA", + 13 + ], + [ + "babbCc", + "acbACaB", + 10 + ], + [ + "babbbbA", + "acA", + 10 + ], + [ + "babbcccAA", + "bAA", + 12 + ], + [ + "babcacA", + "c", + 12 + ], + [ + "bac", + "CBC", + 5 + ], + [ + "bac", + "CcBc", + 6 + ], + [ + "bac", + "Ccbca", + 8 + ], + [ + "bac", + "aacAc", + 6 + ], + [ + "bac", + "ba", + 2 + ], + [ + "bacABcBc", + "ABccc", + 8 + ], + [ + "bacAbca", + "aBCACc", + 9 + ], + [ + "bacBCbBb", + "ccAbcABA", + 12 + ], + [ + "bacBCc", + "cBcBB", + 8 + ], + [ + "bacBaBc", + "AcbcAcA", + 10 + ], + [ + "bacC", + "bbAbaCAB", + 11 + ], + [ + "bacCACCA", + "b", + 14 + ], + [ + "bacCAa", + "b", + 10 + ], + [ + "bacCCCccC", + "CCBbcacA", + 13 + ], + [ + "bacCbaBcB", + "Cab", + 13 + ], + [ + "bacCcBC", + "aBcbcccB", + 10 + ], + [ + "bacaCC", + "BAaAbcAC", + 10 + ], + [ + "bacaCcA", + "BcBAc", + 9 + ], + [ + "bacabaAA", + "AAACCBaC", + 13 + ], + [ + "bacacBa", + "BCAAaAA", + 11 + ], + [ + "bacbABaB", + "bCABBAc", + 10 + ], + [ + "bacbCAbbb", + "BaA", + 13 + ], + [ + "bacc", + "aAcAA", + 7 + ], + [ + "baccAA", + "C", + 11 + ], + [ + "baccAa", + "abCCB", + 9 + ], + [ + "baccBAA", + "ccCCbcCC", + 13 + ], + [ + "baccBBc", + "CAb", + 12 + ], + [ + "baccBbBaa", + "AbcaCcbb", + 12 + ], + [ + "baccCaCA", + "CAccb", + 11 + ], + [ + "baccaBc", + "AccABCbCC", + 11 + ], + [ + "baccccCB", + "cC", + 12 + ], + [ + "bb", + "A", + 4 + ], + [ + "bb", + "AABcCbCB", + 13 + ], + [ + "bb", + "AC", + 4 + ], + [ + "bb", + "Aabc", + 6 + ], + [ + "bb", + "AbC", + 4 + ], + [ + "bb", + "AbCC", + 6 + ], + [ + "bb", + "AbCCbbB", + 10 + ], + [ + "bb", + "Acaa", + 8 + ], + [ + "bb", + "B", + 3 + ], + [ + "bb", + "BAbcaB", + 9 + ], + [ + "bb", + "BCAC", + 7 + ], + [ + "bb", + "Bbccc", + 7 + ], + [ + "bb", + "CC", + 4 + ], + [ + "bb", + "a", + 4 + ], + [ + "bb", + "aBcCcc", + 11 + ], + [ + "bb", + "aaBBCc", + 10 + ], + [ + "bb", + "acCc", + 8 + ], + [ + "bb", + "accBa", + 9 + ], + [ + "bb", + "bA", + 2 + ], + [ + "bb", + "bAc", + 4 + ], + [ + "bb", + "bCbAcbaC", + 12 + ], + [ + "bb", + "baAB", + 5 + ], + [ + "bb", + "cAbBAbC", + 10 + ], + [ + "bb", + "cB", + 3 + ], + [ + "bb", + "cBC", + 5 + ], + [ + "bb", + "cbAacCaca", + 16 + ], + [ + "bb", + "cbBbABC", + 10 + ], + [ + "bbA", + "ABC", + 5 + ], + [ + "bbA", + "BBCabAA", + 9 + ], + [ + "bbA", + "BcCC", + 7 + ], + [ + "bbA", + "CB", + 5 + ], + [ + "bbA", + "bBbaababa", + 13 + ], + [ + "bbA", + "cCabBCAc", + 11 + ], + [ + "bbAA", + "B", + 7 + ], + [ + "bbAA", + "CC", + 8 + ], + [ + "bbAAaBb", + "AcC", + 12 + ], + [ + "bbAAb", + "BBBaaACAb", + 10 + ], + [ + "bbAAc", + "bBaCb", + 6 + ], + [ + "bbAAcAca", + "CCbBaccCB", + 12 + ], + [ + "bbAAcBca", + "bcA", + 11 + ], + [ + "bbAAcbCb", + "bAabCBAAC", + 12 + ], + [ + "bbAB", + "AaABCCB", + 10 + ], + [ + "bbAB", + "AbabABcC", + 8 + ], + [ + "bbAB", + "cBb", + 6 + ], + [ + "bbABACAbC", + "Ccabbc", + 13 + ], + [ + "bbABBC", + "CaAA", + 10 + ], + [ + "bbABCBA", + "ACb", + 9 + ], + [ + "bbABCBCbc", + "b", + 16 + ], + [ + "bbABab", + "CAcaba", + 8 + ], + [ + "bbABc", + "Bac", + 6 + ], + [ + "bbABcBBc", + "Aa", + 14 + ], + [ + "bbABcb", + "c", + 10 + ], + [ + "bbACABB", + "acC", + 12 + ], + [ + "bbACCcCbb", + "CCcC", + 10 + ], + [ + "bbAa", + "CbCaC", + 6 + ], + [ + "bbAa", + "cBcBBC", + 10 + ], + [ + "bbAaC", + "bBcCcAB", + 10 + ], + [ + "bbAaCaBAB", + "aabBc", + 13 + ], + [ + "bbAabBcca", + "BbaabB", + 8 + ], + [ + "bbAaccbAb", + "aCbBAAc", + 14 + ], + [ + "bbAb", + "B", + 7 + ], + [ + "bbAb", + "baaCABAa", + 11 + ], + [ + "bbAb", + "caAABCaac", + 15 + ], + [ + "bbAbAcaCA", + "cacab", + 13 + ], + [ + "bbAbB", + "ccAaCc", + 10 + ], + [ + "bbAbBc", + "AbcAbaBa", + 8 + ], + [ + "bbAbC", + "BBa", + 7 + ], + [ + "bbAbC", + "BcAcaCaaa", + 13 + ], + [ + "bbAbcBA", + "cAbbcBC", + 8 + ], + [ + "bbAc", + "bB", + 5 + ], + [ + "bbAcBabb", + "b", + 14 + ], + [ + "bbAcCaAC", + "CccacCABB", + 12 + ], + [ + "bbAcaA", + "caCabBaAB", + 13 + ], + [ + "bbAcabA", + "bBcbCb", + 9 + ], + [ + "bbB", + "Ac", + 6 + ], + [ + "bbB", + "aCbba", + 6 + ], + [ + "bbB", + "cAcbbBb", + 8 + ], + [ + "bbBA", + "B", + 6 + ], + [ + "bbBACc", + "AcCCBa", + 12 + ], + [ + "bbBAab", + "caAaBCbCb", + 14 + ], + [ + "bbBAbaa", + "aa", + 10 + ], + [ + "bbBBA", + "A", + 8 + ], + [ + "bbBBaaC", + "aCB", + 12 + ], + [ + "bbBBbc", + "ab", + 10 + ], + [ + "bbBCCCAbA", + "aAcCBBc", + 14 + ], + [ + "bbBCCaa", + "AACaAbAA", + 14 + ], + [ + "bbBCaaAC", + "bBAc", + 9 + ], + [ + "bbBCcbcbc", + "BBBaCcbBc", + 7 + ], + [ + "bbBa", + "BBcbc", + 7 + ], + [ + "bbBa", + "Cc", + 8 + ], + [ + "bbBaAcBaC", + "Bcc", + 13 + ], + [ + "bbBaCacbC", + "BAAaBcCa", + 13 + ], + [ + "bbBbA", + "Bbca", + 6 + ], + [ + "bbBbB", + "bBCaCbABa", + 11 + ], + [ + "bbBbBc", + "ABbBbc", + 5 + ], + [ + "bbBbCcBa", + "ba", + 12 + ], + [ + "bbBbaaaBB", + "C", + 18 + ], + [ + "bbBbabc", + "ABACBBacC", + 11 + ], + [ + "bbBbbcCA", + "AaabaCabb", + 15 + ], + [ + "bbBbc", + "Bab", + 7 + ], + [ + "bbBc", + "AaCcBCbCb", + 15 + ], + [ + "bbBcBCA", + "acaba", + 11 + ], + [ + "bbBcCc", + "BAc", + 8 + ], + [ + "bbBcab", + "cAabaC", + 10 + ], + [ + "bbBcbAba", + "b", + 14 + ], + [ + "bbBccBaCB", + "AcbAaCc", + 12 + ], + [ + "bbC", + "A", + 6 + ], + [ + "bbC", + "AAccbCBAA", + 14 + ], + [ + "bbC", + "BCAC", + 5 + ], + [ + "bbC", + "BacBCA", + 8 + ], + [ + "bbC", + "acBbCB", + 7 + ], + [ + "bbCAAb", + "aBAAcAc", + 9 + ], + [ + "bbCABbc", + "aCa", + 11 + ], + [ + "bbCACA", + "cBc", + 10 + ], + [ + "bbCAaBb", + "babcacCA", + 10 + ], + [ + "bbCAaa", + "cBaBbCa", + 11 + ], + [ + "bbCBCca", + "bC", + 10 + ], + [ + "bbCBacAB", + "aC", + 13 + ], + [ + "bbCBcBBcb", + "bCCCaa", + 13 + ], + [ + "bbCC", + "cAbBccA", + 9 + ], + [ + "bbCCAA", + "b", + 10 + ], + [ + "bbCCCBc", + "CCBAcbab", + 14 + ], + [ + "bbCCaccaA", + "ba", + 14 + ], + [ + "bbCCbBA", + "A", + 12 + ], + [ + "bbCCcABa", + "CBBbC", + 13 + ], + [ + "bbCCcCc", + "BbaabbaCc", + 11 + ], + [ + "bbCa", + "BC", + 5 + ], + [ + "bbCa", + "abBbA", + 6 + ], + [ + "bbCaAB", + "CCACcabAC", + 12 + ], + [ + "bbCaBabbC", + "CaBABbacC", + 10 + ], + [ + "bbCaaC", + "BbaBCcbCA", + 11 + ], + [ + "bbCaaCA", + "BcBBB", + 12 + ], + [ + "bbCabA", + "BaBBA", + 8 + ], + [ + "bbCabcAA", + "bc", + 12 + ], + [ + "bbCbAaBaA", + "CbAaAAc", + 9 + ], + [ + "bbCbCB", + "AaBB", + 9 + ], + [ + "bbCbaACb", + "Abbc", + 11 + ], + [ + "bbCbcaBA", + "AB", + 13 + ], + [ + "bbCc", + "aBaC", + 6 + ], + [ + "bbCcAA", + "ccaBAabBA", + 14 + ], + [ + "bbCcBaA", + "aAbCCabAb", + 11 + ], + [ + "bbCcaABc", + "a", + 14 + ], + [ + "bbCcc", + "BBAAA", + 8 + ], + [ + "bbCccBCCa", + "cacaCc", + 12 + ], + [ + "bba", + "ABBcccabc", + 14 + ], + [ + "bba", + "Bb", + 3 + ], + [ + "bba", + "C", + 6 + ], + [ + "bba", + "CBACA", + 8 + ], + [ + "bba", + "aCCAABCcb", + 17 + ], + [ + "bba", + "bbba", + 2 + ], + [ + "bbaA", + "CaCcCbb", + 14 + ], + [ + "bbaACCB", + "bAcAccABC", + 10 + ], + [ + "bbaAaaacc", + "CbaACB", + 11 + ], + [ + "bbaAcBA", + "cBbcaa", + 10 + ], + [ + "bbaB", + "Acc", + 8 + ], + [ + "bbaBAccC", + "cBBAb", + 11 + ], + [ + "bbaBBCc", + "C", + 12 + ], + [ + "bbaBCaAb", + "cCbA", + 12 + ], + [ + "bbaBaAc", + "cABCaA", + 9 + ], + [ + "bbaBbCbCb", + "aBccbBC", + 11 + ], + [ + "bbaBbaAbC", + "acaccca", + 15 + ], + [ + "bbaBc", + "bAbbCc", + 6 + ], + [ + "bbaCbCB", + "CCCA", + 10 + ], + [ + "bbaCbbC", + "c", + 13 + ], + [ + "bbaCc", + "CbCaBAaC", + 11 + ], + [ + "bbaCcBccb", + "C", + 16 + ], + [ + "bbab", + "ACB", + 7 + ], + [ + "bbab", + "CbbCbCbcC", + 12 + ], + [ + "bbabAbca", + "cBbbAB", + 10 + ], + [ + "bbabBcc", + "CAa", + 12 + ], + [ + "bbabC", + "abBAaAba", + 9 + ], + [ + "bbabC", + "cBb", + 7 + ], + [ + "bbabc", + "AAccbABAc", + 12 + ], + [ + "bbacC", + "aabaacA", + 8 + ], + [ + "bbacacb", + "acbCBaAcC", + 12 + ], + [ + "bbacccaa", + "AbBABACaa", + 9 + ], + [ + "bbb", + "ABC", + 5 + ], + [ + "bbb", + "C", + 6 + ], + [ + "bbb", + "aCBc", + 7 + ], + [ + "bbbA", + "bccbbcCCB", + 12 + ], + [ + "bbbABA", + "a", + 11 + ], + [ + "bbbACCCa", + "CBbcC", + 10 + ], + [ + "bbbAaBB", + "B", + 12 + ], + [ + "bbbAaCac", + "cCc", + 12 + ], + [ + "bbbAcbcC", + "aBBACacb", + 9 + ], + [ + "bbbB", + "ABAc", + 7 + ], + [ + "bbbB", + "AbABcABAB", + 12 + ], + [ + "bbbB", + "BB", + 5 + ], + [ + "bbbB", + "aC", + 8 + ], + [ + "bbbB", + "cCCcBcbCb", + 14 + ], + [ + "bbbBBBBCb", + "BcaBa", + 14 + ], + [ + "bbbBbA", + "bbA", + 6 + ], + [ + "bbbBbCBcB", + "bbcBcCC", + 9 + ], + [ + "bbbCa", + "CCB", + 8 + ], + [ + "bbbCccAA", + "bBAa", + 10 + ], + [ + "bbbaABaac", + "abaCbCB", + 13 + ], + [ + "bbbaAa", + "b", + 10 + ], + [ + "bbbaB", + "AC", + 9 + ], + [ + "bbbaa", + "CBBccC", + 10 + ], + [ + "bbbaaBba", + "Baa", + 11 + ], + [ + "bbbaacbb", + "cBbaC", + 10 + ], + [ + "bbbacBbBc", + "bcbcbCCC", + 10 + ], + [ + "bbbb", + "AbaACaC", + 12 + ], + [ + "bbbbbAB", + "aaAaCb", + 13 + ], + [ + "bbbbc", + "BBbC", + 5 + ], + [ + "bbbcAB", + "aBAbBBa", + 11 + ], + [ + "bbbcAcCAC", + "AaBbcCCcb", + 12 + ], + [ + "bbbcB", + "bcCc", + 6 + ], + [ + "bbbcBa", + "CAAccB", + 10 + ], + [ + "bbbcCB", + "aAbBABa", + 10 + ], + [ + "bbbca", + "cBbcabCC", + 9 + ], + [ + "bbbcbBAbc", + "AAacbcc", + 12 + ], + [ + "bbbcbcbc", + "Cbbaac", + 10 + ], + [ + "bbc", + "ACBaABaCC", + 15 + ], + [ + "bbc", + "BcCBaBcCc", + 14 + ], + [ + "bbc", + "CcB", + 6 + ], + [ + "bbc", + "bCCcBAac", + 11 + ], + [ + "bbc", + "c", + 4 + ], + [ + "bbcA", + "AAC", + 7 + ], + [ + "bbcACCca", + "bAABA", + 11 + ], + [ + "bbcAbBa", + "CaaA", + 11 + ], + [ + "bbcAbca", + "CCCCc", + 11 + ], + [ + "bbcAcbBab", + "CBacCca", + 12 + ], + [ + "bbcB", + "BaAbbccBb", + 10 + ], + [ + "bbcBAa", + "baaacc", + 10 + ], + [ + "bbcBCa", + "CaBabc", + 11 + ], + [ + "bbcCA", + "CAb", + 8 + ], + [ + "bbcCBACB", + "bcBBCaBc", + 10 + ], + [ + "bbcCBbAA", + "CcAc", + 12 + ], + [ + "bbcCC", + "BcbCc", + 6 + ], + [ + "bbcCCcB", + "b", + 12 + ], + [ + "bbca", + "AbbcaAcCa", + 10 + ], + [ + "bbca", + "acaBbbB", + 11 + ], + [ + "bbcaACCab", + "aACBab", + 8 + ], + [ + "bbcaAb", + "b", + 10 + ], + [ + "bbcaCab", + "B", + 13 + ], + [ + "bbcaaBCA", + "BCaaC", + 8 + ], + [ + "bbcaacCC", + "bCCcBACB", + 11 + ], + [ + "bbcab", + "bABaa", + 6 + ], + [ + "bbcabAB", + "BcC", + 11 + ], + [ + "bbcb", + "abAA", + 6 + ], + [ + "bbcbB", + "bCbAab", + 7 + ], + [ + "bbcbBccAa", + "bA", + 14 + ], + [ + "bbcbCcAB", + "cacaCCaBA", + 10 + ], + [ + "bbcc", + "B", + 7 + ], + [ + "bbcc", + "CcBBaABa", + 14 + ], + [ + "bbccAcBCB", + "CbacCAaB", + 11 + ], + [ + "bbccC", + "bac", + 6 + ], + [ + "bbccCa", + "baacc", + 7 + ], + [ + "bbccCcA", + "CbbbC", + 10 + ], + [ + "bbccaca", + "bb", + 10 + ], + [ + "bbccb", + "ABCA", + 8 + ], + [ + "bbccbB", + "Cbccbcb", + 5 + ], + [ + "bbccbBB", + "cbCB", + 8 + ], + [ + "bc", + "ACcCb", + 8 + ], + [ + "bc", + "Aa", + 4 + ], + [ + "bc", + "Ac", + 2 + ], + [ + "bc", + "BBAA", + 7 + ], + [ + "bc", + "BcA", + 3 + ], + [ + "bc", + "BcbBaCaCB", + 15 + ], + [ + "bc", + "CACcCBc", + 11 + ], + [ + "bc", + "CBBaAccB", + 13 + ], + [ + "bc", + "CaBa", + 7 + ], + [ + "bc", + "CcCaaABa", + 14 + ], + [ + "bc", + "a", + 4 + ], + [ + "bc", + "aAA", + 6 + ], + [ + "bc", + "aACBcB", + 9 + ], + [ + "bc", + "aBacc", + 7 + ], + [ + "bc", + "aBbAa", + 8 + ], + [ + "bc", + "acb", + 4 + ], + [ + "bc", + "b", + 2 + ], + [ + "bc", + "bA", + 2 + ], + [ + "bc", + "bBCcbA", + 8 + ], + [ + "bc", + "c", + 2 + ], + [ + "bc", + "cBb", + 5 + ], + [ + "bc", + "caaabc", + 8 + ], + [ + "bc", + "ccAB", + 6 + ], + [ + "bcA", + "ABbA", + 5 + ], + [ + "bcA", + "BBB", + 5 + ], + [ + "bcA", + "aabaAAB", + 10 + ], + [ + "bcA", + "acacbc", + 9 + ], + [ + "bcA", + "cbaACAB", + 9 + ], + [ + "bcAA", + "BaCc", + 7 + ], + [ + "bcAABAab", + "CB", + 13 + ], + [ + "bcAABbbBa", + "ABcccc", + 14 + ], + [ + "bcAABcb", + "c", + 12 + ], + [ + "bcAAbc", + "B", + 11 + ], + [ + "bcAB", + "a", + 7 + ], + [ + "bcAB", + "bcB", + 2 + ], + [ + "bcABAABcB", + "Cc", + 15 + ], + [ + "bcABAbBC", + "c", + 14 + ], + [ + "bcABAcB", + "bcCBCAbCa", + 9 + ], + [ + "bcAC", + "AAaC", + 5 + ], + [ + "bcACABab", + "c", + 14 + ], + [ + "bcACBbBaC", + "baaAbBbB", + 10 + ], + [ + "bcACa", + "bbaAcCBB", + 10 + ], + [ + "bcACbCa", + "aaaBBAbC", + 13 + ], + [ + "bcAa", + "BC", + 6 + ], + [ + "bcAa", + "b", + 6 + ], + [ + "bcAaAabA", + "abBB", + 13 + ], + [ + "bcAaBABA", + "CABac", + 10 + ], + [ + "bcAaBAaC", + "AaC", + 10 + ], + [ + "bcAaBCc", + "ca", + 10 + ], + [ + "bcAaaC", + "cbA", + 9 + ], + [ + "bcAabc", + "BAABb", + 7 + ], + [ + "bcAb", + "BcbbbA", + 7 + ], + [ + "bcAbAAAAb", + "abCBaAABc", + 11 + ], + [ + "bcAbACaB", + "cCaCAC", + 10 + ], + [ + "bcAbacAbc", + "BccaBBCbb", + 12 + ], + [ + "bcAc", + "BCBcaBCaB", + 13 + ], + [ + "bcAca", + "A", + 8 + ], + [ + "bcAcba", + "CcAc", + 6 + ], + [ + "bcAcbccB", + "Abbac", + 10 + ], + [ + "bcAccA", + "bbabbAcC", + 11 + ], + [ + "bcAccab", + "CCACcbcC", + 10 + ], + [ + "bcB", + "AaCbCccbb", + 13 + ], + [ + "bcB", + "BaAACbA", + 11 + ], + [ + "bcB", + "CAAABA", + 10 + ], + [ + "bcB", + "aaAaBccC", + 13 + ], + [ + "bcB", + "bAAAACCA", + 13 + ], + [ + "bcB", + "cAbcb", + 5 + ], + [ + "bcBA", + "bBBAb", + 4 + ], + [ + "bcBAAc", + "BccA", + 7 + ], + [ + "bcBACabcB", + "abBA", + 14 + ], + [ + "bcBAab", + "baaaBbcc", + 11 + ], + [ + "bcBAcAC", + "aCCC", + 10 + ], + [ + "bcBBC", + "c", + 8 + ], + [ + "bcBBCbAbA", + "bcCCb", + 10 + ], + [ + "bcBBaA", + "ABCBb", + 9 + ], + [ + "bcBBabABb", + "BcbaBBBCa", + 11 + ], + [ + "bcBBbB", + "bbbCC", + 8 + ], + [ + "bcBCAaaaB", + "CC", + 15 + ], + [ + "bcBCBC", + "aCB", + 8 + ], + [ + "bcBCCAB", + "ABCbc", + 10 + ], + [ + "bcBCCB", + "cAb", + 9 + ], + [ + "bcBCCcbA", + "c", + 14 + ], + [ + "bcBCa", + "CBccAbA", + 10 + ], + [ + "bcBa", + "abaBbcaba", + 11 + ], + [ + "bcBaBB", + "CB", + 9 + ], + [ + "bcBaCc", + "aaCBa", + 9 + ], + [ + "bcBaa", + "BcBB", + 5 + ], + [ + "bcBabcbc", + "accAbcB", + 8 + ], + [ + "bcBac", + "BB", + 7 + ], + [ + "bcBbAB", + "aCAbA", + 7 + ], + [ + "bcBbACCB", + "BAbcCc", + 10 + ], + [ + "bcBbACCac", + "CB", + 15 + ], + [ + "bcBbBCB", + "BcCbb", + 8 + ], + [ + "bcBbbAcac", + "ACbccac", + 9 + ], + [ + "bcBbc", + "caC", + 7 + ], + [ + "bcBc", + "A", + 8 + ], + [ + "bcBcaa", + "BbbCAaBB", + 10 + ], + [ + "bcBccBCBA", + "ABaCCAba", + 13 + ], + [ + "bcBccbcC", + "aC", + 14 + ], + [ + "bcC", + "ACabb", + 9 + ], + [ + "bcC", + "Ac", + 4 + ], + [ + "bcC", + "CACac", + 8 + ], + [ + "bcC", + "CAaCbCbb", + 13 + ], + [ + "bcC", + "CacBAbbac", + 15 + ], + [ + "bcC", + "a", + 6 + ], + [ + "bcC", + "abBBcB", + 8 + ], + [ + "bcC", + "acaAAaCbb", + 14 + ], + [ + "bcC", + "bBCaBBC", + 9 + ], + [ + "bcC", + "bbbCCABb", + 11 + ], + [ + "bcC", + "cBBBBCac", + 13 + ], + [ + "bcC", + "cCAAb", + 8 + ], + [ + "bcC", + "ccBcB", + 7 + ], + [ + "bcCAAA", + "CCCBbBAC", + 11 + ], + [ + "bcCAaA", + "AbCabC", + 9 + ], + [ + "bcCAb", + "CbBccBC", + 9 + ], + [ + "bcCAcAa", + "cB", + 12 + ], + [ + "bcCAcbC", + "AcAAbc", + 7 + ], + [ + "bcCB", + "a", + 8 + ], + [ + "bcCBAB", + "AaBAcB", + 8 + ], + [ + "bcCBBcb", + "CaCbaa", + 11 + ], + [ + "bcCBC", + "cb", + 7 + ], + [ + "bcCBaCAAc", + "aBb", + 16 + ], + [ + "bcCBaCb", + "aaaacC", + 11 + ], + [ + "bcCCAbB", + "BBcCAcA", + 8 + ], + [ + "bcCCa", + "BACbBaAcC", + 13 + ], + [ + "bcCCaa", + "cBcC", + 9 + ], + [ + "bcCCcbA", + "AAaAcCCA", + 12 + ], + [ + "bcCa", + "bCCC", + 3 + ], + [ + "bcCaaAB", + "cAAc", + 9 + ], + [ + "bcCaacC", + "BbcaccCCB", + 10 + ], + [ + "bcCab", + "BcCABbCAC", + 10 + ], + [ + "bcCacAA", + "CcbB", + 10 + ], + [ + "bcCacCaa", + "ABc", + 14 + ], + [ + "bcCacba", + "Bc", + 11 + ], + [ + "bcCb", + "aCbcBbCc", + 10 + ], + [ + "bcCbB", + "bAbCc", + 8 + ], + [ + "bcCbBCbaB", + "BC", + 14 + ], + [ + "bcCbaa", + "BbAACBAaC", + 10 + ], + [ + "bcCbbc", + "baAA", + 10 + ], + [ + "bcCc", + "AAA", + 8 + ], + [ + "bcCcBB", + "BaAccBC", + 8 + ], + [ + "bcCcaCCca", + "AaCc", + 12 + ], + [ + "bcCcbAAc", + "Ca", + 13 + ], + [ + "bca", + "AB", + 6 + ], + [ + "bca", + "AcaaBC", + 8 + ], + [ + "bca", + "CACBbcC", + 10 + ], + [ + "bca", + "bccb", + 4 + ], + [ + "bcaA", + "aBaCBBAa", + 12 + ], + [ + "bcaAAbCbC", + "CCcAA", + 13 + ], + [ + "bcaABAa", + "Ac", + 12 + ], + [ + "bcaACb", + "bAbCaCB", + 8 + ], + [ + "bcaAa", + "BbCcc", + 9 + ], + [ + "bcaAaaAC", + "acaaABc", + 8 + ], + [ + "bcaAba", + "BabBAaccb", + 14 + ], + [ + "bcaB", + "bCBCBAA", + 9 + ], + [ + "bcaBBAC", + "Cb", + 12 + ], + [ + "bcaCA", + "ACA", + 5 + ], + [ + "bcaCA", + "aB", + 8 + ], + [ + "bcaCAABcB", + "bBAbCcbc", + 12 + ], + [ + "bcaCB", + "AbaACbaC", + 10 + ], + [ + "bcaCBa", + "BaAbAB", + 9 + ], + [ + "bcaCa", + "cCbccbA", + 9 + ], + [ + "bcaCbBA", + "bcBabAb", + 8 + ], + [ + "bcaCbCbaA", + "bbCBb", + 11 + ], + [ + "bcaCcB", + "cAab", + 8 + ], + [ + "bcaa", + "CC", + 7 + ], + [ + "bcaa", + "aaBA", + 7 + ], + [ + "bcaaA", + "BAAacaAba", + 11 + ], + [ + "bcaaABBA", + "baa", + 10 + ], + [ + "bcaaAcbC", + "aBACAcaab", + 13 + ], + [ + "bcaaBaAb", + "b", + 14 + ], + [ + "bcaacb", + "acCb", + 7 + ], + [ + "bcab", + "a", + 6 + ], + [ + "bcab", + "cCAabCBCb", + 13 + ], + [ + "bcabAA", + "BAAcca", + 9 + ], + [ + "bcabC", + "Aac", + 7 + ], + [ + "bcabb", + "aAaA", + 8 + ], + [ + "bcac", + "CCAAbCbC", + 12 + ], + [ + "bcb", + "A", + 6 + ], + [ + "bcb", + "aBabCcB", + 9 + ], + [ + "bcb", + "abACACc", + 11 + ], + [ + "bcbA", + "AcbAcbCaB", + 11 + ], + [ + "bcbAAA", + "a", + 11 + ], + [ + "bcbAAAB", + "a", + 13 + ], + [ + "bcbACB", + "CBbcbCca", + 9 + ], + [ + "bcbACCA", + "AabaACAcB", + 11 + ], + [ + "bcbACCC", + "c", + 12 + ], + [ + "bcbAbCbB", + "caA", + 12 + ], + [ + "bcbAc", + "BACCccbCb", + 13 + ], + [ + "bcbBA", + "baaaa", + 7 + ], + [ + "bcbBAABCa", + "cBAcaa", + 10 + ], + [ + "bcbCAaAC", + "bB", + 13 + ], + [ + "bcbCAc", + "caccbaABC", + 11 + ], + [ + "bcbCB", + "c", + 8 + ], + [ + "bcbCcCa", + "CCCbACb", + 11 + ], + [ + "bcbaAACb", + "aBAcA", + 11 + ], + [ + "bcbaBBB", + "AA", + 13 + ], + [ + "bcbaccb", + "ACACCB", + 9 + ], + [ + "bcbb", + "cBcACA", + 9 + ], + [ + "bcbb", + "cCCBaaA", + 12 + ], + [ + "bcbbABC", + "CAAaa", + 11 + ], + [ + "bcbbB", + "ABB", + 7 + ], + [ + "bcbbBc", + "cCc", + 8 + ], + [ + "bcbbCBabA", + "cCccbccBA", + 12 + ], + [ + "bcbc", + "AAA", + 8 + ], + [ + "bcbc", + "Ca", + 7 + ], + [ + "bcbcAC", + "bBAaaacb", + 12 + ], + [ + "bcc", + "C", + 5 + ], + [ + "bcc", + "CaACa", + 9 + ], + [ + "bcc", + "bACb", + 5 + ], + [ + "bcc", + "bbcCcAa", + 8 + ], + [ + "bccA", + "C", + 7 + ], + [ + "bccA", + "aAb", + 8 + ], + [ + "bccA", + "ab", + 8 + ], + [ + "bccABAba", + "acacC", + 13 + ], + [ + "bccAC", + "BbbBcA", + 8 + ], + [ + "bccAbaA", + "aAc", + 12 + ], + [ + "bccAbcbcb", + "CbbcbbA", + 11 + ], + [ + "bccB", + "BcacaCB", + 7 + ], + [ + "bccB", + "cAcb", + 5 + ], + [ + "bccBABc", + "bAacbb", + 10 + ], + [ + "bccBBB", + "aAbbbbC", + 11 + ], + [ + "bccBBCbBa", + "bbbaabCbB", + 11 + ], + [ + "bccBBc", + "cCcbac", + 6 + ], + [ + "bccBBccA", + "bB", + 12 + ], + [ + "bccBCCAC", + "bABBCAabC", + 9 + ], + [ + "bccBCCBc", + "ACBaa", + 13 + ], + [ + "bccBa", + "CAcbB", + 7 + ], + [ + "bccBbA", + "aBCcBBBC", + 9 + ], + [ + "bccCA", + "BaBAAba", + 11 + ], + [ + "bccCAbbB", + "ccC", + 10 + ], + [ + "bccCBab", + "c", + 12 + ], + [ + "bccCCAaBB", + "bBa", + 14 + ], + [ + "bccCaBCC", + "Bb", + 14 + ], + [ + "bcca", + "AaAaabA", + 12 + ], + [ + "bccaCBb", + "bAbcabA", + 9 + ], + [ + "bccaCCC", + "CCBCBbAAA", + 16 + ], + [ + "bccaa", + "C", + 9 + ], + [ + "bccaab", + "cAcc", + 9 + ], + [ + "bccbAbab", + "b", + 14 + ], + [ + "bccbBCcCA", + "B", + 16 + ], + [ + "bccbBb", + "ccba", + 6 + ], + [ + "bccbC", + "bBC", + 5 + ], + [ + "bccbbCC", + "bBccA", + 9 + ], + [ + "bccbbbCB", + "BbcABC", + 10 + ], + [ + "bccbccAc", + "bBC", + 12 + ], + [ + "bccc", + "ACcca", + 5 + ], + [ + "bcccAA", + "bCBAbca", + 10 + ], + [ + "bcccAaBca", + "BaC", + 14 + ], + [ + "bcccBBCaA", + "bcAcaCcb", + 10 + ], + [ + "bcccC", + "aAAaa", + 10 + ], + [ + "bcccCCCbc", + "Bac", + 15 + ], + [ + "c", + "A", + 2 + ], + [ + "c", + "AA", + 4 + ], + [ + "c", + "AABacBC", + 12 + ], + [ + "c", + "AAbBBaBB", + 16 + ], + [ + "c", + "AB", + 4 + ], + [ + "c", + "ABA", + 6 + ], + [ + "c", + "ABBaCCBBB", + 17 + ], + [ + "c", + "ABBbBBCBA", + 17 + ], + [ + "c", + "ABbCb", + 9 + ], + [ + "c", + "ABbaaba", + 14 + ], + [ + "c", + "AC", + 3 + ], + [ + "c", + "ACABa", + 9 + ], + [ + "c", + "ACCB", + 7 + ], + [ + "c", + "ACCcbCCbC", + 16 + ], + [ + "c", + "ACbBBC", + 11 + ], + [ + "c", + "Aa", + 4 + ], + [ + "c", + "AaABA", + 10 + ], + [ + "c", + "Aaa", + 6 + ], + [ + "c", + "AaaaBbBC", + 15 + ], + [ + "c", + "AaabCAb", + 13 + ], + [ + "c", + "Ab", + 4 + ], + [ + "c", + "AbaCAAA", + 13 + ], + [ + "c", + "AcCACaAA", + 14 + ], + [ + "c", + "AcCCBAcaB", + 16 + ], + [ + "c", + "Acb", + 4 + ], + [ + "c", + "AcccbCacB", + 16 + ], + [ + "c", + "B", + 2 + ], + [ + "c", + "BA", + 4 + ], + [ + "c", + "BAAAAbB", + 14 + ], + [ + "c", + "BACA", + 7 + ], + [ + "c", + "BACbAC", + 11 + ], + [ + "c", + "BAbBbAc", + 12 + ], + [ + "c", + "BAbb", + 8 + ], + [ + "c", + "BAcBb", + 8 + ], + [ + "c", + "BB", + 4 + ], + [ + "c", + "BBAACAb", + 13 + ], + [ + "c", + "BBABBC", + 11 + ], + [ + "c", + "BBBcBccc", + 14 + ], + [ + "c", + "BBbbc", + 8 + ], + [ + "c", + "BBbcbbac", + 14 + ], + [ + "c", + "BBcBc", + 8 + ], + [ + "c", + "BC", + 3 + ], + [ + "c", + "BCA", + 5 + ], + [ + "c", + "BCAAcBC", + 12 + ], + [ + "c", + "BCAbCb", + 11 + ], + [ + "c", + "BCBc", + 6 + ], + [ + "c", + "BCa", + 5 + ], + [ + "c", + "BCcbaB", + 10 + ], + [ + "c", + "Ba", + 4 + ], + [ + "c", + "BaAaaA", + 12 + ], + [ + "c", + "BaBacca", + 12 + ], + [ + "c", + "BaCCBaCAC", + 17 + ], + [ + "c", + "BaaBcAcBb", + 16 + ], + [ + "c", + "BaaccC", + 10 + ], + [ + "c", + "BabCcAAcA", + 16 + ], + [ + "c", + "BbABABaBC", + 17 + ], + [ + "c", + "BbCa", + 7 + ], + [ + "c", + "BbaAacbb", + 14 + ], + [ + "c", + "BbaCAAcBa", + 16 + ], + [ + "c", + "BbcBb", + 8 + ], + [ + "c", + "Bbcc", + 6 + ], + [ + "c", + "Bc", + 2 + ], + [ + "c", + "BcBa", + 6 + ], + [ + "c", + "Bcb", + 4 + ], + [ + "c", + "Bcccb", + 8 + ], + [ + "c", + "C", + 1 + ], + [ + "c", + "CB", + 3 + ], + [ + "c", + "CBABBC", + 11 + ], + [ + "c", + "CBAcCA", + 10 + ], + [ + "c", + "CBBAbbA", + 13 + ], + [ + "c", + "CBCBb", + 9 + ], + [ + "c", + "CBCaBa", + 11 + ], + [ + "c", + "CBb", + 5 + ], + [ + "c", + "CCCBaaCB", + 15 + ], + [ + "c", + "CCCCCC", + 11 + ], + [ + "c", + "Ca", + 3 + ], + [ + "c", + "CaAb", + 7 + ], + [ + "c", + "CaCa", + 7 + ], + [ + "c", + "Cab", + 5 + ], + [ + "c", + "CabC", + 7 + ], + [ + "c", + "CbAC", + 7 + ], + [ + "c", + "CbabCAaAc", + 16 + ], + [ + "c", + "CcAABA", + 10 + ], + [ + "c", + "CccaaAa", + 12 + ], + [ + "c", + "a", + 2 + ], + [ + "c", + "aAAa", + 8 + ], + [ + "c", + "aAAc", + 6 + ], + [ + "c", + "aACbcB", + 10 + ], + [ + "c", + "aAbACcCA", + 14 + ], + [ + "c", + "aAbab", + 10 + ], + [ + "c", + "aB", + 4 + ], + [ + "c", + "aBAC", + 7 + ], + [ + "c", + "aBBbbc", + 10 + ], + [ + "c", + "aBaaA", + 10 + ], + [ + "c", + "aBb", + 6 + ], + [ + "c", + "aBcABcCCb", + 16 + ], + [ + "c", + "aBcBBCBbc", + 16 + ], + [ + "c", + "aCa", + 5 + ], + [ + "c", + "aa", + 4 + ], + [ + "c", + "aaCBCbC", + 13 + ], + [ + "c", + "aabcBAAcc", + 16 + ], + [ + "c", + "aabcBcA", + 12 + ], + [ + "c", + "aacABB", + 10 + ], + [ + "c", + "aacb", + 6 + ], + [ + "c", + "aaccAca", + 12 + ], + [ + "c", + "ab", + 4 + ], + [ + "c", + "abAa", + 8 + ], + [ + "c", + "abCAcC", + 10 + ], + [ + "c", + "abCCAB", + 11 + ], + [ + "c", + "abCc", + 6 + ], + [ + "c", + "ac", + 2 + ], + [ + "c", + "accbaBBAB", + 16 + ], + [ + "c", + "b", + 2 + ], + [ + "c", + "bAAccBAa", + 14 + ], + [ + "c", + "bAaBAbcCc", + 16 + ], + [ + "c", + "bAcacAbb", + 14 + ], + [ + "c", + "bBAaCa", + 11 + ], + [ + "c", + "bBAcaCaca", + 16 + ], + [ + "c", + "bBBCbaB", + 13 + ], + [ + "c", + "bBBa", + 8 + ], + [ + "c", + "bBab", + 8 + ], + [ + "c", + "bBcCbcABC", + 16 + ], + [ + "c", + "bBcCca", + 10 + ], + [ + "c", + "bCBC", + 7 + ], + [ + "c", + "bCC", + 5 + ], + [ + "c", + "bCCAbcBBa", + 16 + ], + [ + "c", + "bCCa", + 7 + ], + [ + "c", + "bCabaBC", + 13 + ], + [ + "c", + "bCc", + 4 + ], + [ + "c", + "bCcA", + 6 + ], + [ + "c", + "baaAB", + 10 + ], + [ + "c", + "baaABBC", + 13 + ], + [ + "c", + "baaAccba", + 14 + ], + [ + "c", + "bbBbbBBa", + 16 + ], + [ + "c", + "bbCccAAC", + 14 + ], + [ + "c", + "bc", + 2 + ], + [ + "c", + "bcAbC", + 8 + ], + [ + "c", + "bcBAcAcB", + 14 + ], + [ + "c", + "bcbBbCcb", + 14 + ], + [ + "c", + "bccAAa", + 10 + ], + [ + "c", + "c", + 0 + ], + [ + "c", + "cAABBb", + 10 + ], + [ + "c", + "cAACa", + 8 + ], + [ + "c", + "cABc", + 6 + ], + [ + "c", + "cAaCBc", + 10 + ], + [ + "c", + "cAacbCCA", + 14 + ], + [ + "c", + "cBCCAbA", + 12 + ], + [ + "c", + "cBacAc", + 10 + ], + [ + "c", + "cBcCBb", + 10 + ], + [ + "c", + "cCAB", + 6 + ], + [ + "c", + "cCCbbBBcA", + 16 + ], + [ + "c", + "cCcaBbcba", + 16 + ], + [ + "c", + "ca", + 2 + ], + [ + "c", + "caC", + 4 + ], + [ + "c", + "caa", + 4 + ], + [ + "c", + "cabA", + 6 + ], + [ + "c", + "cb", + 2 + ], + [ + "c", + "cbCaBBab", + 14 + ], + [ + "c", + "cbCbAa", + 10 + ], + [ + "c", + "cbbBbCcC", + 14 + ], + [ + "c", + "cbcaAAC", + 12 + ], + [ + "c", + "cc", + 2 + ], + [ + "c", + "ccB", + 4 + ], + [ + "c", + "ccCBaBAC", + 14 + ], + [ + "c", + "ccc", + 4 + ], + [ + "cA", + "A", + 2 + ], + [ + "cA", + "AAbaCB", + 10 + ], + [ + "cA", + "AC", + 4 + ], + [ + "cA", + "Ac", + 4 + ], + [ + "cA", + "Acc", + 4 + ], + [ + "cA", + "BABCB", + 8 + ], + [ + "cA", + "BBc", + 6 + ], + [ + "cA", + "BaaBCbA", + 11 + ], + [ + "cA", + "Bbb", + 6 + ], + [ + "cA", + "BbbAAccB", + 14 + ], + [ + "cA", + "Bc", + 4 + ], + [ + "cA", + "C", + 3 + ], + [ + "cA", + "CAaCAABb", + 13 + ], + [ + "cA", + "CAaacAcc", + 12 + ], + [ + "cA", + "CbaAccc", + 11 + ], + [ + "cA", + "Cbbb", + 7 + ], + [ + "cA", + "CcC", + 4 + ], + [ + "cA", + "aB", + 4 + ], + [ + "cA", + "aC", + 4 + ], + [ + "cA", + "ab", + 4 + ], + [ + "cA", + "abAAcc", + 10 + ], + [ + "cA", + "abC", + 6 + ], + [ + "cA", + "bBCAbCa", + 11 + ], + [ + "cA", + "bCbbBCAC", + 13 + ], + [ + "cA", + "bCcCBcCA", + 12 + ], + [ + "cA", + "bcaCcbC", + 11 + ], + [ + "cA", + "cABaBCb", + 10 + ], + [ + "cA", + "cBaAB", + 6 + ], + [ + "cA", + "cCBababA", + 12 + ], + [ + "cA", + "ccCBbBab", + 13 + ], + [ + "cA", + "cca", + 3 + ], + [ + "cAA", + "AaaCaBcCb", + 16 + ], + [ + "cAA", + "AbBC", + 8 + ], + [ + "cAA", + "a", + 5 + ], + [ + "cAA", + "cb", + 4 + ], + [ + "cAAA", + "cBaC", + 5 + ], + [ + "cAAAA", + "bcA", + 8 + ], + [ + "cAAAC", + "aBAaCcCca", + 13 + ], + [ + "cAAAacbCB", + "BBaACbA", + 12 + ], + [ + "cAAAbabc", + "BCAacBCBc", + 10 + ], + [ + "cAAAbbc", + "AAbb", + 6 + ], + [ + "cAAAcB", + "bbAB", + 8 + ], + [ + "cAAB", + "ABCaCbCbC", + 15 + ], + [ + "cAAB", + "Aab", + 4 + ], + [ + "cAABaBAa", + "bAaBaBA", + 5 + ], + [ + "cAAC", + "CAB", + 5 + ], + [ + "cAACA", + "CaABCCbAb", + 10 + ], + [ + "cAACAC", + "BC", + 10 + ], + [ + "cAACaCc", + "AcabA", + 9 + ], + [ + "cAACb", + "BCAcca", + 8 + ], + [ + "cAACbABCc", + "CCbAB", + 9 + ], + [ + "cAACbb", + "aAaC", + 7 + ], + [ + "cAACcAA", + "bAaCcacb", + 8 + ], + [ + "cAAa", + "caABcbBAB", + 12 + ], + [ + "cAAaB", + "BBaAb", + 7 + ], + [ + "cAAaBAAA", + "aCb", + 14 + ], + [ + "cAAaCbCc", + "CC", + 12 + ], + [ + "cAAaba", + "bcb", + 10 + ], + [ + "cAAabcCCA", + "aAa", + 13 + ], + [ + "cAAbB", + "AAcaBaa", + 10 + ], + [ + "cAAbBA", + "caCcABAB", + 9 + ], + [ + "cAAbBBaCa", + "CabcB", + 12 + ], + [ + "cAAbC", + "BAbbb", + 6 + ], + [ + "cAAba", + "CCBAabaAB", + 10 + ], + [ + "cAAc", + "bCcCCB", + 10 + ], + [ + "cAAcABCcb", + "BCBB", + 13 + ], + [ + "cAAcB", + "ca", + 7 + ], + [ + "cAAcCCAc", + "Cb", + 14 + ], + [ + "cAAcaabB", + "A", + 14 + ], + [ + "cAAccaaB", + "BBbbAcBc", + 15 + ], + [ + "cAB", + "B", + 4 + ], + [ + "cAB", + "BCAAacb", + 10 + ], + [ + "cAB", + "CaCbCca", + 11 + ], + [ + "cAB", + "CbacbCcbB", + 14 + ], + [ + "cAB", + "b", + 5 + ], + [ + "cAB", + "baabbCA", + 12 + ], + [ + "cAB", + "cbbaBbCb", + 11 + ], + [ + "cAB", + "cccBBCBC", + 12 + ], + [ + "cAB", + "cccCCCCb", + 13 + ], + [ + "cABA", + "CA", + 5 + ], + [ + "cABAABc", + "acabCCb", + 11 + ], + [ + "cABABAACA", + "cBaBCcaa", + 10 + ], + [ + "cABAa", + "c", + 8 + ], + [ + "cABAcaBb", + "BCBaBCBc", + 11 + ], + [ + "cABBAaCac", + "aAacACCcc", + 10 + ], + [ + "cABBCaBbc", + "bBAaBcACC", + 13 + ], + [ + "cABBc", + "B", + 8 + ], + [ + "cABBcacb", + "bBcCcCAA", + 13 + ], + [ + "cABC", + "B", + 6 + ], + [ + "cABCAB", + "bAcb", + 8 + ], + [ + "cABCAc", + "cBCBa", + 6 + ], + [ + "cABCAca", + "ABaCCCbcc", + 12 + ], + [ + "cABCBbbCA", + "ABBccc", + 11 + ], + [ + "cABCa", + "CaA", + 7 + ], + [ + "cABaA", + "aAAbaBb", + 9 + ], + [ + "cABaAaA", + "BAB", + 10 + ], + [ + "cABaBAC", + "acCa", + 12 + ], + [ + "cABaCAbbA", + "A", + 16 + ], + [ + "cABac", + "BaCc", + 6 + ], + [ + "cABbACA", + "BbccCBCBc", + 15 + ], + [ + "cABba", + "AAC", + 8 + ], + [ + "cABc", + "AaccB", + 7 + ], + [ + "cABcABc", + "cAcBBca", + 6 + ], + [ + "cABcBcb", + "cbBCa", + 8 + ], + [ + "cABcb", + "Cac", + 6 + ], + [ + "cABcba", + "BAab", + 8 + ], + [ + "cAC", + "BCaCAbaCa", + 13 + ], + [ + "cAC", + "C", + 4 + ], + [ + "cAC", + "CABbA", + 7 + ], + [ + "cAC", + "CAcABbA", + 10 + ], + [ + "cAC", + "bAa", + 4 + ], + [ + "cAC", + "cBBac", + 6 + ], + [ + "cACAACCbc", + "CAcABb", + 10 + ], + [ + "cACABcACC", + "CAc", + 12 + ], + [ + "cACACbC", + "BbCcAa", + 11 + ], + [ + "cACAabC", + "BbcbBcAAa", + 14 + ], + [ + "cACBCaC", + "C", + 12 + ], + [ + "cACBCcCBb", + "bBaaBaCbC", + 14 + ], + [ + "cACBaaB", + "bccBcBaB", + 9 + ], + [ + "cACCBBcb", + "Ba", + 14 + ], + [ + "cACCaa", + "aBcCaab", + 7 + ], + [ + "cACCc", + "ccAa", + 7 + ], + [ + "cACa", + "aBBcB", + 9 + ], + [ + "cACa", + "cAbCCA", + 5 + ], + [ + "cACaB", + "cAbbaBB", + 6 + ], + [ + "cACac", + "cBCBbbbB", + 12 + ], + [ + "cACbCBB", + "bBbAC", + 12 + ], + [ + "cACbaCc", + "AacCACBaB", + 11 + ], + [ + "cACbaba", + "acAACBcCC", + 11 + ], + [ + "cACbbC", + "Cba", + 8 + ], + [ + "cACbbb", + "ccacBccbA", + 11 + ], + [ + "cACbcb", + "b", + 10 + ], + [ + "cACc", + "Cc", + 4 + ], + [ + "cACc", + "bAba", + 6 + ], + [ + "cACcA", + "Caccc", + 5 + ], + [ + "cACcAcc", + "bbB", + 14 + ], + [ + "cACca", + "acabb", + 9 + ], + [ + "cACcaA", + "bB", + 12 + ], + [ + "cACccAacA", + "bcCBabCc", + 14 + ], + [ + "cAa", + "BacbCAbcA", + 13 + ], + [ + "cAa", + "Bbcb", + 8 + ], + [ + "cAa", + "C", + 5 + ], + [ + "cAa", + "aCBcCAcc", + 12 + ], + [ + "cAa", + "aCacc", + 8 + ], + [ + "cAa", + "caBcA", + 6 + ], + [ + "cAa", + "cacAbaAb", + 10 + ], + [ + "cAa", + "ccccAcaBC", + 12 + ], + [ + "cAaA", + "CbbaAaba", + 10 + ], + [ + "cAaAA", + "CaCbcbab", + 13 + ], + [ + "cAaAA", + "acAc", + 7 + ], + [ + "cAaAABAcb", + "bAba", + 14 + ], + [ + "cAaACBaa", + "cbBabcaac", + 11 + ], + [ + "cAaACc", + "ccbBB", + 10 + ], + [ + "cAaAaaB", + "CBCbBccBa", + 15 + ], + [ + "cAaAc", + "ABCACcb", + 10 + ], + [ + "cAaB", + "C", + 7 + ], + [ + "cAaB", + "aBaBA", + 6 + ], + [ + "cAaBCBbAA", + "aAc", + 14 + ], + [ + "cAaBaA", + "a", + 10 + ], + [ + "cAaC", + "BcbAbbCb", + 10 + ], + [ + "cAaC", + "CbB", + 7 + ], + [ + "cAaCAc", + "ac", + 8 + ], + [ + "cAaCaAc", + "bBBBbaC", + 12 + ], + [ + "cAaCaC", + "ABBa", + 8 + ], + [ + "cAaCc", + "c", + 8 + ], + [ + "cAaaAAA", + "BBCAa", + 11 + ], + [ + "cAaaaBCA", + "AcABc", + 10 + ], + [ + "cAaaacAB", + "aAbCB", + 10 + ], + [ + "cAaaacaa", + "ABB", + 14 + ], + [ + "cAaacB", + "AaCBbACB", + 10 + ], + [ + "cAaaca", + "bAbbc", + 8 + ], + [ + "cAabACa", + "bcaabaaAb", + 9 + ], + [ + "cAabCA", + "CbACAAcb", + 11 + ], + [ + "cAaba", + "a", + 8 + ], + [ + "cAabcacaa", + "aA", + 15 + ], + [ + "cAacAaBBC", + "bBaBAbcaC", + 12 + ], + [ + "cAaca", + "AcacAA", + 7 + ], + [ + "cAaca", + "BcCcBBBA", + 13 + ], + [ + "cAacc", + "BBCaCA", + 9 + ], + [ + "cAacc", + "a", + 8 + ], + [ + "cAacccAb", + "ccbbBACA", + 13 + ], + [ + "cAb", + "B", + 5 + ], + [ + "cAb", + "BAbABAC", + 10 + ], + [ + "cAb", + "BBAAc", + 8 + ], + [ + "cAb", + "CBABCa", + 8 + ], + [ + "cAb", + "CbBBaA", + 10 + ], + [ + "cAb", + "caBACCa", + 10 + ], + [ + "cAbA", + "Cacc", + 6 + ], + [ + "cAbA", + "aAAACA", + 8 + ], + [ + "cAbABbab", + "aCA", + 13 + ], + [ + "cAbAC", + "BAAc", + 5 + ], + [ + "cAbACB", + "bAcCC", + 8 + ], + [ + "cAbACcCaa", + "cBa", + 13 + ], + [ + "cAbAb", + "acBC", + 9 + ], + [ + "cAbAbA", + "bACaC", + 9 + ], + [ + "cAbAbAAAa", + "A", + 16 + ], + [ + "cAbBB", + "AbaaC", + 8 + ], + [ + "cAbBaAAAA", + "BabaaBAa", + 9 + ], + [ + "cAbBaB", + "AcB", + 8 + ], + [ + "cAbaBbBC", + "a", + 14 + ], + [ + "cAbab", + "Ba", + 7 + ], + [ + "cAbabb", + "bC", + 10 + ], + [ + "cAbbB", + "aBBcaAA", + 13 + ], + [ + "cAbbBCAcB", + "aabbaC", + 11 + ], + [ + "cAbbBaca", + "CbCAcBaC", + 12 + ], + [ + "cAbbBbcC", + "CB", + 13 + ], + [ + "cAbbb", + "cCbaBAAAc", + 13 + ], + [ + "cAbcAcBA", + "AcA", + 10 + ], + [ + "cAbcaCccC", + "ABbAbbcB", + 12 + ], + [ + "cAbcbB", + "AAABaac", + 11 + ], + [ + "cAbccBCBc", + "AAACAcbAc", + 12 + ], + [ + "cAc", + "AbBCcaBB", + 13 + ], + [ + "cAc", + "BCCcCaBac", + 13 + ], + [ + "cAc", + "CB", + 5 + ], + [ + "cAc", + "bBb", + 6 + ], + [ + "cAc", + "bCaCaCb", + 11 + ], + [ + "cAc", + "bcb", + 6 + ], + [ + "cAc", + "cAAcaa", + 6 + ], + [ + "cAcA", + "CaaB", + 6 + ], + [ + "cAcAA", + "cbAcBbB", + 8 + ], + [ + "cAcABAAc", + "aABaBBc", + 9 + ], + [ + "cAcACcBb", + "cacbCccC", + 7 + ], + [ + "cAcAb", + "aBbAA", + 8 + ], + [ + "cAcAcAcCc", + "caaAAcbc", + 7 + ], + [ + "cAcAcCB", + "ccbcbBbC", + 10 + ], + [ + "cAcBBaBCb", + "C", + 16 + ], + [ + "cAcBCb", + "abCbAAB", + 11 + ], + [ + "cAcBCcBba", + "A", + 16 + ], + [ + "cAcBbA", + "aBabBACbB", + 13 + ], + [ + "cAcBbB", + "ABBcacBBA", + 10 + ], + [ + "cAcCAB", + "CBBbc", + 11 + ], + [ + "cAcCBCa", + "CCA", + 9 + ], + [ + "cAcCBcBBa", + "CacACBBBB", + 8 + ], + [ + "cAcCCBCBA", + "ccCcbcbc", + 8 + ], + [ + "cAcCbCcAB", + "caC", + 13 + ], + [ + "cAcCcbaaA", + "CcBaa", + 9 + ], + [ + "cAca", + "BAcbCbC", + 10 + ], + [ + "cAcaAa", + "caAAaab", + 7 + ], + [ + "cAcaBAAC", + "BBB", + 14 + ], + [ + "cAcaaa", + "BaBaBC", + 9 + ], + [ + "cAcaaca", + "aaCBA", + 10 + ], + [ + "cAcabCbCB", + "BacBcbABb", + 11 + ], + [ + "cAcabaB", + "Cc", + 11 + ], + [ + "cAcac", + "acbA", + 7 + ], + [ + "cAcbABCBB", + "aABc", + 12 + ], + [ + "cAcbBCBac", + "bCbAAacB", + 13 + ], + [ + "cAcbbccAc", + "AABAaBbCb", + 16 + ], + [ + "cAcc", + "aCa", + 6 + ], + [ + "cAcc", + "bCAAcaCC", + 10 + ], + [ + "cAcc", + "cc", + 4 + ], + [ + "cAccCB", + "aAABca", + 9 + ], + [ + "cAccaBCAb", + "BBcBCCAbb", + 12 + ], + [ + "cAccaaABa", + "bCAcB", + 13 + ], + [ + "cAcccAA", + "bCAb", + 11 + ], + [ + "cAcccaCaA", + "abaB", + 14 + ], + [ + "cAcccacab", + "BbCCbaB", + 13 + ], + [ + "cB", + "AbAB", + 6 + ], + [ + "cB", + "AbBbCA", + 10 + ], + [ + "cB", + "B", + 2 + ], + [ + "cB", + "BACbBc", + 9 + ], + [ + "cB", + "BAcB", + 4 + ], + [ + "cB", + "BBaBaaccC", + 16 + ], + [ + "cB", + "BcAaA", + 8 + ], + [ + "cB", + "C", + 3 + ], + [ + "cB", + "CAA", + 5 + ], + [ + "cB", + "CAAA", + 7 + ], + [ + "cB", + "CAacabCCC", + 15 + ], + [ + "cB", + "CBBB", + 5 + ], + [ + "cB", + "CCBCABaaA", + 15 + ], + [ + "cB", + "Cc", + 3 + ], + [ + "cB", + "CcBAc", + 6 + ], + [ + "cB", + "a", + 4 + ], + [ + "cB", + "aACCba", + 10 + ], + [ + "cB", + "aacbcC", + 9 + ], + [ + "cB", + "acaaAABB", + 12 + ], + [ + "cB", + "b", + 3 + ], + [ + "cB", + "ba", + 4 + ], + [ + "cB", + "baacB", + 6 + ], + [ + "cB", + "bc", + 4 + ], + [ + "cB", + "cABAbCBc", + 12 + ], + [ + "cB", + "cCAB", + 4 + ], + [ + "cB", + "caAAbbBC", + 12 + ], + [ + "cB", + "caBAAa", + 8 + ], + [ + "cBA", + "Ac", + 6 + ], + [ + "cBA", + "CB", + 3 + ], + [ + "cBA", + "a", + 5 + ], + [ + "cBA", + "ac", + 6 + ], + [ + "cBA", + "b", + 5 + ], + [ + "cBA", + "bbaBac", + 9 + ], + [ + "cBA", + "cAaabbab", + 12 + ], + [ + "cBAA", + "AAB", + 6 + ], + [ + "cBAA", + "aCabbA", + 8 + ], + [ + "cBAAB", + "CCa", + 8 + ], + [ + "cBAABa", + "bA", + 9 + ], + [ + "cBAABccc", + "caBcbAAa", + 13 + ], + [ + "cBAAbCcC", + "Bcc", + 11 + ], + [ + "cBAAcAbAC", + "bBaacb", + 10 + ], + [ + "cBAB", + "cBBcaCCb", + 10 + ], + [ + "cBABaBCc", + "BAABc", + 7 + ], + [ + "cBABaac", + "baCbbb", + 12 + ], + [ + "cBABbBAaA", + "c", + 16 + ], + [ + "cBABba", + "AaAccABac", + 12 + ], + [ + "cBABca", + "aBcB", + 7 + ], + [ + "cBACBAAcA", + "BBCbCCBb", + 13 + ], + [ + "cBACa", + "cbaabBBcA", + 12 + ], + [ + "cBACc", + "cBbBaCb", + 7 + ], + [ + "cBACcBBC", + "AbaaBbcC", + 11 + ], + [ + "cBACcbCaa", + "ab", + 15 + ], + [ + "cBAa", + "cCCBaAc", + 8 + ], + [ + "cBAaBcaB", + "b", + 15 + ], + [ + "cBAacbBa", + "aaBb", + 11 + ], + [ + "cBAbCaBA", + "ccaB", + 9 + ], + [ + "cBAba", + "B", + 8 + ], + [ + "cBAbaa", + "CaccCBA", + 12 + ], + [ + "cBAbb", + "ca", + 7 + ], + [ + "cBAbbCaCc", + "aaCA", + 13 + ], + [ + "cBAbca", + "aaACbA", + 9 + ], + [ + "cBAc", + "BA", + 4 + ], + [ + "cBAc", + "aCCcbbbcC", + 13 + ], + [ + "cBAcAb", + "BCabCbcc", + 13 + ], + [ + "cBAcAbaa", + "AAC", + 12 + ], + [ + "cBAcBBc", + "cCcaaa", + 10 + ], + [ + "cBAcCCb", + "cCcAc", + 9 + ], + [ + "cBAcb", + "CaAAACba", + 10 + ], + [ + "cBB", + "BacacBcCA", + 14 + ], + [ + "cBB", + "Bc", + 4 + ], + [ + "cBB", + "bAACA", + 10 + ], + [ + "cBB", + "bCbBBC", + 7 + ], + [ + "cBBA", + "AcAAcABa", + 11 + ], + [ + "cBBA", + "Cca", + 6 + ], + [ + "cBBABC", + "bCcbaAB", + 9 + ], + [ + "cBBABC", + "cCCcBcBc", + 9 + ], + [ + "cBBAac", + "CbbbcB", + 9 + ], + [ + "cBBBABBA", + "AAAbAAAB", + 13 + ], + [ + "cBBBCA", + "caacccAbA", + 13 + ], + [ + "cBBBCacAB", + "Accab", + 13 + ], + [ + "cBBBcbA", + "cB", + 10 + ], + [ + "cBBC", + "acaC", + 6 + ], + [ + "cBBCBaCbA", + "CBcBaAc", + 10 + ], + [ + "cBBCCAca", + "ABCcCa", + 8 + ], + [ + "cBBCb", + "cBBbaaC", + 8 + ], + [ + "cBBCbB", + "aCbBaCaB", + 8 + ], + [ + "cBBaBaAac", + "C", + 17 + ], + [ + "cBBaaCbBb", + "baCCBa", + 11 + ], + [ + "cBBabaAc", + "b", + 14 + ], + [ + "cBBac", + "ba", + 7 + ], + [ + "cBBacC", + "aBcCAC", + 8 + ], + [ + "cBBbAaabA", + "aaA", + 12 + ], + [ + "cBBbB", + "BCcAACb", + 11 + ], + [ + "cBBbBaBcA", + "bbCCCc", + 13 + ], + [ + "cBBbCbc", + "ACccCBaCB", + 13 + ], + [ + "cBBbbaBcb", + "Cc", + 15 + ], + [ + "cBBbbbb", + "acBbaBca", + 10 + ], + [ + "cBBbbcAC", + "bCaBbbcbB", + 9 + ], + [ + "cBBbbcacb", + "BcCcaaBA", + 13 + ], + [ + "cBBbca", + "BbA", + 7 + ], + [ + "cBBcAccA", + "AcbbAC", + 11 + ], + [ + "cBBcBb", + "BaCb", + 7 + ], + [ + "cBBcaBcB", + "Aa", + 14 + ], + [ + "cBBcbC", + "bcCBacb", + 8 + ], + [ + "cBC", + "cACacBc", + 9 + ], + [ + "cBC", + "cCa", + 4 + ], + [ + "cBCA", + "C", + 6 + ], + [ + "cBCACaCaC", + "ccBBBCaac", + 9 + ], + [ + "cBCAaac", + "cB", + 10 + ], + [ + "cBCAacA", + "aaAcA", + 8 + ], + [ + "cBCAcCccC", + "cbB", + 15 + ], + [ + "cBCAcbC", + "CcAbCbbaA", + 13 + ], + [ + "cBCB", + "bbabCAAbB", + 13 + ], + [ + "cBCBCbCa", + "bcCAaCCa", + 10 + ], + [ + "cBCBacA", + "AcbBaA", + 7 + ], + [ + "cBCBbCBa", + "c", + 14 + ], + [ + "cBCCABcC", + "Baa", + 13 + ], + [ + "cBCCB", + "a", + 10 + ], + [ + "cBCCBcaBa", + "AcAAba", + 13 + ], + [ + "cBCCC", + "A", + 10 + ], + [ + "cBCCcBc", + "ccaBCB", + 9 + ], + [ + "cBCaB", + "BBbAA", + 7 + ], + [ + "cBCab", + "aaABbC", + 10 + ], + [ + "cBCacA", + "abcbAbAa", + 11 + ], + [ + "cBCb", + "aCbCc", + 6 + ], + [ + "cBCb", + "b", + 6 + ], + [ + "cBCb", + "cAA", + 6 + ], + [ + "cBCbCAc", + "ACacAB", + 9 + ], + [ + "cBCbCca", + "aaB", + 13 + ], + [ + "cBCbabA", + "bbBbABB", + 9 + ], + [ + "cBCbbBBbc", + "aCaBBbbb", + 10 + ], + [ + "cBCbcCC", + "ACBbBBc", + 10 + ], + [ + "cBCc", + "AcaCBCb", + 8 + ], + [ + "cBCcAbcac", + "aBcac", + 10 + ], + [ + "cBCcbccaa", + "bBbCaBB", + 13 + ], + [ + "cBa", + "b", + 5 + ], + [ + "cBa", + "bAAaA", + 8 + ], + [ + "cBaAA", + "baaCbca", + 11 + ], + [ + "cBaAAB", + "BcbB", + 8 + ], + [ + "cBaAACacA", + "bBa", + 14 + ], + [ + "cBaABacb", + "ACb", + 11 + ], + [ + "cBaB", + "BabB", + 4 + ], + [ + "cBaB", + "CBBBC", + 5 + ], + [ + "cBaBBAB", + "B", + 12 + ], + [ + "cBaBBCc", + "BacCACa", + 10 + ], + [ + "cBaBaABBB", + "bcc", + 17 + ], + [ + "cBaBbCBC", + "cAAB", + 11 + ], + [ + "cBaBc", + "bbC", + 7 + ], + [ + "cBaC", + "BacB", + 5 + ], + [ + "cBaC", + "bA", + 6 + ], + [ + "cBaCA", + "CAcabbb", + 11 + ], + [ + "cBaCAbCC", + "B", + 14 + ], + [ + "cBaCAccbc", + "bbccAcCBB", + 10 + ], + [ + "cBaCCC", + "ab", + 10 + ], + [ + "cBaCaBC", + "Cb", + 11 + ], + [ + "cBaCab", + "BC", + 8 + ], + [ + "cBaa", + "BAab", + 5 + ], + [ + "cBaaA", + "Bb", + 8 + ], + [ + "cBaaCabBb", + "aCACcCbbb", + 11 + ], + [ + "cBaaaBBac", + "bcaAbBcC", + 10 + ], + [ + "cBaab", + "acAacAbCc", + 11 + ], + [ + "cBab", + "ACCAB", + 7 + ], + [ + "cBabB", + "C", + 9 + ], + [ + "cBabBCaca", + "C", + 16 + ], + [ + "cBabBcab", + "CbcAAAa", + 12 + ], + [ + "cBabCaA", + "aaAbAaac", + 10 + ], + [ + "cBabbBCBb", + "C", + 16 + ], + [ + "cBac", + "A", + 7 + ], + [ + "cBacCAB", + "B", + 12 + ], + [ + "cBacabC", + "aAAaB", + 10 + ], + [ + "cBacac", + "c", + 10 + ], + [ + "cBb", + "BbbA", + 5 + ], + [ + "cBb", + "CAbcC", + 7 + ], + [ + "cBb", + "acAB", + 5 + ], + [ + "cBbACBB", + "bCCCAbbC", + 12 + ], + [ + "cBbACC", + "ACa", + 8 + ], + [ + "cBbAcabB", + "aA", + 14 + ], + [ + "cBbC", + "abAabbbc", + 12 + ], + [ + "cBbCAACc", + "bBB", + 13 + ], + [ + "cBbCAB", + "cbCb", + 5 + ], + [ + "cBbCAa", + "cacaBBAb", + 11 + ], + [ + "cBbCAaA", + "AB", + 12 + ], + [ + "cBbCAb", + "bC", + 8 + ], + [ + "cBbCBAAA", + "AbBbc", + 12 + ], + [ + "cBbCCC", + "BCba", + 8 + ], + [ + "cBbCc", + "ccaCBA", + 8 + ], + [ + "cBbCccaC", + "bA", + 13 + ], + [ + "cBba", + "cb", + 4 + ], + [ + "cBbaACaa", + "cC", + 12 + ], + [ + "cBbaCbc", + "ccaaca", + 9 + ], + [ + "cBbaaac", + "b", + 12 + ], + [ + "cBbaab", + "BbbBcC", + 9 + ], + [ + "cBbaccBA", + "c", + 14 + ], + [ + "cBbb", + "CCcCaa", + 10 + ], + [ + "cBbb", + "abCb", + 5 + ], + [ + "cBbbA", + "A", + 8 + ], + [ + "cBbbA", + "B", + 8 + ], + [ + "cBbbBAAb", + "AAaa", + 13 + ], + [ + "cBbbBBacb", + "cCaCCcAac", + 14 + ], + [ + "cBbbBCaa", + "AaBc", + 13 + ], + [ + "cBbbCa", + "CB", + 9 + ], + [ + "cBbbcBB", + "bAACBBb", + 10 + ], + [ + "cBbcBaCBC", + "abA", + 15 + ], + [ + "cBbcCAC", + "b", + 12 + ], + [ + "cBbcCb", + "caBBbb", + 7 + ], + [ + "cBbcaBAAc", + "bB", + 14 + ], + [ + "cBbcbAAb", + "aba", + 13 + ], + [ + "cBbcbcBB", + "AccaA", + 12 + ], + [ + "cBbccCcc", + "aaCBabcBB", + 15 + ], + [ + "cBbccb", + "caaABcBb", + 9 + ], + [ + "cBc", + "BCaAAAbB", + 14 + ], + [ + "cBc", + "CAAC", + 6 + ], + [ + "cBc", + "aAc", + 4 + ], + [ + "cBc", + "aBaAAc", + 8 + ], + [ + "cBc", + "aabbAc", + 9 + ], + [ + "cBc", + "aac", + 4 + ], + [ + "cBc", + "c", + 4 + ], + [ + "cBcA", + "bC", + 6 + ], + [ + "cBcAAbbcb", + "BAbb", + 10 + ], + [ + "cBcACAA", + "a", + 13 + ], + [ + "cBcACb", + "Bc", + 8 + ], + [ + "cBcAaACbc", + "abbB", + 14 + ], + [ + "cBcBaaC", + "AbC", + 11 + ], + [ + "cBcBbCC", + "aBbCaba", + 11 + ], + [ + "cBcBbCbbA", + "cBa", + 13 + ], + [ + "cBcBbb", + "Acb", + 8 + ], + [ + "cBcCaaAcb", + "baccACCCc", + 13 + ], + [ + "cBcCbcCa", + "aCa", + 12 + ], + [ + "cBcCccaAa", + "BCaCCabbA", + 12 + ], + [ + "cBcaAaC", + "bACBCAB", + 12 + ], + [ + "cBcaAbBCb", + "baCbbaa", + 12 + ], + [ + "cBcaAbc", + "aa", + 11 + ], + [ + "cBcaAcaaA", + "CACbcC", + 14 + ], + [ + "cBcaBcBc", + "aBbBCACc", + 11 + ], + [ + "cBcaCcCA", + "Bcc", + 10 + ], + [ + "cBcabC", + "bAAAabb", + 10 + ], + [ + "cBcbACbBB", + "ACBc", + 12 + ], + [ + "cBcbBAbAC", + "A", + 16 + ], + [ + "cBcbC", + "AAbBcCa", + 10 + ], + [ + "cBcbcaCb", + "cCbcCB", + 6 + ], + [ + "cBcc", + "bAcAcaaba", + 14 + ], + [ + "cBcc", + "cacc", + 2 + ], + [ + "cBccaAac", + "aab", + 12 + ], + [ + "cBccaBCB", + "Caa", + 13 + ], + [ + "cBccacbCA", + "bBCBAca", + 11 + ], + [ + "cBccbc", + "CAbA", + 9 + ], + [ + "cBcccCAC", + "BA", + 12 + ], + [ + "cC", + "A", + 4 + ], + [ + "cC", + "ABCCCa", + 9 + ], + [ + "cC", + "AbAacCAc", + 12 + ], + [ + "cC", + "AccAAABc", + 13 + ], + [ + "cC", + "BBAabcC", + 10 + ], + [ + "cC", + "BBc", + 5 + ], + [ + "cC", + "BBcaACaA", + 12 + ], + [ + "cC", + "BCABBCAaC", + 15 + ], + [ + "cC", + "BaAbcaBc", + 13 + ], + [ + "cC", + "BaBaccb", + 11 + ], + [ + "cC", + "CBA", + 5 + ], + [ + "cC", + "CacCac", + 8 + ], + [ + "cC", + "CcACcacbB", + 14 + ], + [ + "cC", + "CcBbb", + 8 + ], + [ + "cC", + "aACbbCAB", + 13 + ], + [ + "cC", + "aBABCBbc", + 14 + ], + [ + "cC", + "aCCcAAca", + 13 + ], + [ + "cC", + "aaBaBbAA", + 16 + ], + [ + "cC", + "acAb", + 6 + ], + [ + "cC", + "b", + 4 + ], + [ + "cC", + "bA", + 4 + ], + [ + "cC", + "bACBaA", + 10 + ], + [ + "cC", + "bacAcbc", + 11 + ], + [ + "cC", + "bcaCBaB", + 10 + ], + [ + "cC", + "c", + 2 + ], + [ + "cC", + "cA", + 2 + ], + [ + "cC", + "cABAc", + 7 + ], + [ + "cC", + "cAbc", + 5 + ], + [ + "cC", + "cBA", + 4 + ], + [ + "cC", + "cBCAccaCb", + 14 + ], + [ + "cC", + "cabcBCB", + 10 + ], + [ + "cC", + "cccaBa", + 9 + ], + [ + "cCA", + "c", + 4 + ], + [ + "cCAABb", + "ACbaBC", + 7 + ], + [ + "cCAACb", + "bbC", + 10 + ], + [ + "cCAAacBb", + "a", + 14 + ], + [ + "cCAAc", + "ABbCcbBb", + 14 + ], + [ + "cCAAc", + "AC", + 7 + ], + [ + "cCAB", + "AAaCAABab", + 12 + ], + [ + "cCABbAb", + "Ab", + 10 + ], + [ + "cCABbaBaA", + "aacC", + 15 + ], + [ + "cCAC", + "bCbbbbAC", + 10 + ], + [ + "cCACAb", + "AbC", + 10 + ], + [ + "cCACCc", + "cccbAabc", + 9 + ], + [ + "cCACc", + "BbAcaB", + 9 + ], + [ + "cCAa", + "CBA", + 5 + ], + [ + "cCAaabBbA", + "bCCCcacb", + 13 + ], + [ + "cCAac", + "BBA", + 8 + ], + [ + "cCAacBCc", + "CCBBaA", + 11 + ], + [ + "cCAacCCbA", + "bCACCa", + 9 + ], + [ + "cCAbA", + "aBBcaccbA", + 11 + ], + [ + "cCAbABC", + "bbACCaACB", + 13 + ], + [ + "cCAbACcc", + "AbBAccbb", + 11 + ], + [ + "cCAbCacAA", + "BcABBAC", + 12 + ], + [ + "cCAbbaA", + "CcACabA", + 8 + ], + [ + "cCAbcA", + "BABABC", + 10 + ], + [ + "cCAcAcbaB", + "BccBaCC", + 13 + ], + [ + "cCAcCAB", + "bcccCbbab", + 11 + ], + [ + "cCAcaabBA", + "bBcbCCBa", + 13 + ], + [ + "cCAcbBBa", + "AaBca", + 10 + ], + [ + "cCAcbcB", + "c", + 12 + ], + [ + "cCB", + "BBCAbba", + 11 + ], + [ + "cCB", + "BCcab", + 7 + ], + [ + "cCB", + "CC", + 3 + ], + [ + "cCB", + "CbBa", + 5 + ], + [ + "cCB", + "a", + 6 + ], + [ + "cCB", + "aC", + 4 + ], + [ + "cCBA", + "abcA", + 6 + ], + [ + "cCBACb", + "abBccaC", + 11 + ], + [ + "cCBAbCCa", + "a", + 14 + ], + [ + "cCBAbaC", + "aAbaAa", + 10 + ], + [ + "cCBAcCB", + "CbaCB", + 6 + ], + [ + "cCBBAb", + "cBcaC", + 7 + ], + [ + "cCBBBc", + "Cc", + 8 + ], + [ + "cCBBaa", + "CBC", + 8 + ], + [ + "cCBCBAc", + "ABCBCBbCB", + 9 + ], + [ + "cCBCa", + "AcacaBCAc", + 10 + ], + [ + "cCBCbB", + "Cc", + 9 + ], + [ + "cCBCcbB", + "cCBaAaBc", + 8 + ], + [ + "cCBaAac", + "C", + 12 + ], + [ + "cCBaCc", + "CcbBBbB", + 10 + ], + [ + "cCBac", + "bb", + 9 + ], + [ + "cCBbAC", + "abAbC", + 8 + ], + [ + "cCBbAaabb", + "BCc", + 16 + ], + [ + "cCBbAcCAC", + "acBCCbA", + 12 + ], + [ + "cCBbAccB", + "abA", + 12 + ], + [ + "cCBbbB", + "bbaaCCBbB", + 11 + ], + [ + "cCBc", + "ABbacCc", + 10 + ], + [ + "cCBc", + "cAcBb", + 5 + ], + [ + "cCBcABc", + "ac", + 11 + ], + [ + "cCBcACBa", + "cACcB", + 10 + ], + [ + "cCBcACCa", + "BACAAaa", + 11 + ], + [ + "cCBca", + "cbCacC", + 6 + ], + [ + "cCBcb", + "BCbAABAba", + 12 + ], + [ + "cCBcbCaCb", + "cbBCa", + 10 + ], + [ + "cCC", + "BbacaAb", + 12 + ], + [ + "cCC", + "CB", + 4 + ], + [ + "cCC", + "accaCCCcb", + 12 + ], + [ + "cCC", + "bAbcCcbcb", + 13 + ], + [ + "cCC", + "bB", + 6 + ], + [ + "cCC", + "bCBbABBCc", + 14 + ], + [ + "cCC", + "baAAb", + 10 + ], + [ + "cCC", + "cABBc", + 7 + ], + [ + "cCC", + "cCCbaac", + 8 + ], + [ + "cCCAbbbaa", + "BccccA", + 15 + ], + [ + "cCCAc", + "ccAbbb", + 9 + ], + [ + "cCCBBaBC", + "bcaA", + 13 + ], + [ + "cCCBCAaA", + "baB", + 13 + ], + [ + "cCCBc", + "bAccaAcB", + 11 + ], + [ + "cCCCC", + "cBC", + 6 + ], + [ + "cCCCaA", + "cCbB", + 8 + ], + [ + "cCCCaac", + "BCAcCb", + 11 + ], + [ + "cCCCbA", + "CcBBBBb", + 11 + ], + [ + "cCCCbb", + "ABccCcA", + 10 + ], + [ + "cCCCbbbAa", + "cA", + 14 + ], + [ + "cCCa", + "AccBc", + 7 + ], + [ + "cCCaA", + "BcACCA", + 6 + ], + [ + "cCCaAAAC", + "aBbcC", + 12 + ], + [ + "cCCaCB", + "CaaAcbCAB", + 12 + ], + [ + "cCCaccA", + "bc", + 12 + ], + [ + "cCCaccAC", + "abAACcCa", + 12 + ], + [ + "cCCb", + "C", + 6 + ], + [ + "cCCb", + "cAcBa", + 6 + ], + [ + "cCCbBCBab", + "CCcaca", + 11 + ], + [ + "cCCbb", + "BCBbbcA", + 8 + ], + [ + "cCCbc", + "bCCC", + 5 + ], + [ + "cCCbcbabA", + "aaCCc", + 14 + ], + [ + "cCCcABBB", + "aBBbABcb", + 11 + ], + [ + "cCCcCCcAa", + "bBCab", + 15 + ], + [ + "cCCcaaC", + "aBC", + 10 + ], + [ + "cCa", + "BacAaCAcA", + 13 + ], + [ + "cCa", + "C", + 4 + ], + [ + "cCa", + "CAACAAaC", + 11 + ], + [ + "cCa", + "aBBcbc", + 10 + ], + [ + "cCa", + "aCBab", + 6 + ], + [ + "cCa", + "aaCCAAAb", + 12 + ], + [ + "cCa", + "bBAcCcB", + 10 + ], + [ + "cCa", + "cBBcaCB", + 9 + ], + [ + "cCaA", + "CCaca", + 4 + ], + [ + "cCaA", + "cBcccC", + 9 + ], + [ + "cCaAAACA", + "cBBbacc", + 12 + ], + [ + "cCaAAacCc", + "cbCaBcA", + 12 + ], + [ + "cCaABCAAA", + "A", + 16 + ], + [ + "cCaAb", + "aBaAB", + 5 + ], + [ + "cCaAbAABA", + "CCabcAAbb", + 8 + ], + [ + "cCaAc", + "ABAbbBBB", + 15 + ], + [ + "cCaAcACaa", + "caaBcBc", + 11 + ], + [ + "cCaAcCBca", + "ABcc", + 12 + ], + [ + "cCaAcbA", + "aBCBcCCba", + 12 + ], + [ + "cCaB", + "ABABAbBBc", + 15 + ], + [ + "cCaBBaAb", + "aA", + 12 + ], + [ + "cCaBBaCAC", + "bC", + 15 + ], + [ + "cCaBBba", + "aa", + 10 + ], + [ + "cCaBCbb", + "BcaCB", + 8 + ], + [ + "cCaBb", + "Ac", + 9 + ], + [ + "cCaC", + "AC", + 5 + ], + [ + "cCaCA", + "BBBbbCAC", + 12 + ], + [ + "cCaCBBBCb", + "B", + 16 + ], + [ + "cCaCCB", + "BcBac", + 9 + ], + [ + "cCaCaB", + "AbcA", + 10 + ], + [ + "cCaCaaaA", + "abcCcc", + 14 + ], + [ + "cCaCc", + "aA", + 8 + ], + [ + "cCaa", + "CcCbcbA", + 9 + ], + [ + "cCaaBCb", + "A", + 13 + ], + [ + "cCaab", + "a", + 8 + ], + [ + "cCabB", + "AbbA", + 8 + ], + [ + "cCabB", + "AcaaACCb", + 11 + ], + [ + "cCabC", + "aBcB", + 8 + ], + [ + "cCabaBC", + "aB", + 10 + ], + [ + "cCabc", + "cabcccAB", + 10 + ], + [ + "cCabcBa", + "abccAaAB", + 12 + ], + [ + "cCac", + "AacBAaA", + 10 + ], + [ + "cCacacaa", + "CACbAbcC", + 13 + ], + [ + "cCacba", + "aAbAbBAc", + 13 + ], + [ + "cCb", + "AccbcbcB", + 11 + ], + [ + "cCb", + "BaC", + 6 + ], + [ + "cCb", + "BabCcAA", + 12 + ], + [ + "cCb", + "aCaBbBbC", + 12 + ], + [ + "cCb", + "accCcBAbA", + 12 + ], + [ + "cCb", + "cC", + 2 + ], + [ + "cCbAB", + "bcaac", + 8 + ], + [ + "cCbAB", + "cca", + 6 + ], + [ + "cCbAc", + "baB", + 7 + ], + [ + "cCbAcaB", + "AaBB", + 10 + ], + [ + "cCbBAc", + "bbBBBCa", + 10 + ], + [ + "cCbBBAbC", + "BCa", + 13 + ], + [ + "cCbBa", + "AAcCCaAB", + 11 + ], + [ + "cCbBacc", + "aBAbCAc", + 11 + ], + [ + "cCbBb", + "aacaBa", + 9 + ], + [ + "cCbBb", + "baAAacaCA", + 17 + ], + [ + "cCbBbc", + "acaAbC", + 8 + ], + [ + "cCbC", + "B", + 7 + ], + [ + "cCbC", + "CcBaA", + 7 + ], + [ + "cCbC", + "aC", + 6 + ], + [ + "cCbCCbCaA", + "acBBbCcC", + 12 + ], + [ + "cCbCaCBa", + "aBBAAbaA", + 13 + ], + [ + "cCbCac", + "CBAB", + 8 + ], + [ + "cCbCcaCc", + "cAbbAab", + 10 + ], + [ + "cCbCcbcbA", + "cbb", + 12 + ], + [ + "cCbaACaB", + "AB", + 12 + ], + [ + "cCbaAcaa", + "BCcCcb", + 12 + ], + [ + "cCbaB", + "aCCbc", + 7 + ], + [ + "cCbbAaaba", + "CccBCA", + 14 + ], + [ + "cCbbAbBC", + "acaAcBC", + 9 + ], + [ + "cCbbBC", + "bca", + 10 + ], + [ + "cCbbCB", + "AaBb", + 9 + ], + [ + "cCbbCBc", + "aBBAbba", + 12 + ], + [ + "cCbbCaA", + "A", + 12 + ], + [ + "cCbbabAC", + "B", + 15 + ], + [ + "cCbbccCb", + "bAcCc", + 10 + ], + [ + "cCbcABAa", + "ABaACa", + 11 + ], + [ + "cCbcB", + "bBBcbbA", + 10 + ], + [ + "cCbcbc", + "Aa", + 12 + ], + [ + "cCbccbB", + "abaaBc", + 11 + ], + [ + "cCbccbbaC", + "aCBAcBB", + 11 + ], + [ + "cCc", + "ABcAcB", + 8 + ], + [ + "cCc", + "BbaaC", + 9 + ], + [ + "cCc", + "CAbAabcAc", + 14 + ], + [ + "cCc", + "CccC", + 4 + ], + [ + "cCcA", + "CBaCbc", + 9 + ], + [ + "cCcAAC", + "cCbaCa", + 7 + ], + [ + "cCcAAbbcB", + "A", + 16 + ], + [ + "cCcAB", + "BCCa", + 6 + ], + [ + "cCcACAaCB", + "cccb", + 12 + ], + [ + "cCcAbbBbc", + "CBbaAb", + 12 + ], + [ + "cCcAcAa", + "c", + 12 + ], + [ + "cCcBC", + "CBBAbBAcC", + 13 + ], + [ + "cCcBCcbcb", + "C", + 16 + ], + [ + "cCcC", + "aAcbBCb", + 10 + ], + [ + "cCcCAb", + "bAaCcaCCB", + 11 + ], + [ + "cCcCaCaCB", + "AC", + 15 + ], + [ + "cCcCcB", + "b", + 11 + ], + [ + "cCcaAbCC", + "cAAaCC", + 7 + ], + [ + "cCcaBA", + "C", + 10 + ], + [ + "cCcaBBB", + "BCaCCcB", + 10 + ], + [ + "cCcaC", + "CCAcbCcCc", + 11 + ], + [ + "cCcaCa", + "AAcb", + 10 + ], + [ + "cCcaabba", + "A", + 15 + ], + [ + "cCcabc", + "bc", + 8 + ], + [ + "cCcb", + "BBaAbbaAb", + 16 + ], + [ + "cCcbAbcb", + "AcCbcAAA", + 12 + ], + [ + "cCcbBCCBC", + "cC", + 14 + ], + [ + "cCcbCCB", + "BAbABC", + 12 + ], + [ + "cCcbCaaC", + "cbbcccbca", + 12 + ], + [ + "cCcbaCca", + "baBCABcC", + 13 + ], + [ + "cCcbaba", + "cCBBA", + 7 + ], + [ + "cCcc", + "a", + 8 + ], + [ + "cCccBaa", + "CBcBA", + 7 + ], + [ + "cCccCaCbA", + "caABbAcB", + 13 + ], + [ + "cCccaA", + "abb", + 12 + ], + [ + "cCccbA", + "BBabb", + 10 + ], + [ + "cCccbB", + "abAcB", + 8 + ], + [ + "cCcccAAb", + "aa", + 14 + ], + [ + "cCcccC", + "CBcBaAAc", + 12 + ], + [ + "cCcccCA", + "bcCACb", + 9 + ], + [ + "ca", + "AC", + 4 + ], + [ + "ca", + "ACA", + 4 + ], + [ + "ca", + "ACACb", + 8 + ], + [ + "ca", + "ACa", + 3 + ], + [ + "ca", + "Aaaa", + 6 + ], + [ + "ca", + "BAacabbab", + 14 + ], + [ + "ca", + "BB", + 4 + ], + [ + "ca", + "BBcaAbBcb", + 14 + ], + [ + "ca", + "BacCBC", + 10 + ], + [ + "ca", + "BbA", + 5 + ], + [ + "ca", + "BbBbBC", + 12 + ], + [ + "ca", + "BbCACC", + 10 + ], + [ + "ca", + "Bcbc", + 6 + ], + [ + "ca", + "BccA", + 5 + ], + [ + "ca", + "C", + 3 + ], + [ + "ca", + "CA", + 2 + ], + [ + "ca", + "CAC", + 4 + ], + [ + "ca", + "CCcbBaaab", + 14 + ], + [ + "ca", + "CbCaAaB", + 11 + ], + [ + "ca", + "a", + 2 + ], + [ + "ca", + "aBAA", + 7 + ], + [ + "ca", + "aC", + 4 + ], + [ + "ca", + "aaAbcACCc", + 15 + ], + [ + "ca", + "acccCcBc", + 14 + ], + [ + "ca", + "bAAaCCAc", + 14 + ], + [ + "ca", + "bBcAABbbB", + 15 + ], + [ + "ca", + "bbb", + 6 + ], + [ + "ca", + "cBC", + 4 + ], + [ + "ca", + "cCbba", + 6 + ], + [ + "ca", + "ccBBaba", + 10 + ], + [ + "caA", + "B", + 6 + ], + [ + "caA", + "CcCcAA", + 7 + ], + [ + "caA", + "aCAbCCCA", + 12 + ], + [ + "caA", + "aCcCbbAAC", + 13 + ], + [ + "caA", + "bBbac", + 8 + ], + [ + "caA", + "bCACCACC", + 12 + ], + [ + "caA", + "bbaA", + 4 + ], + [ + "caA", + "bbbBA", + 8 + ], + [ + "caA", + "cbAacAbbc", + 12 + ], + [ + "caAA", + "bAbaa", + 7 + ], + [ + "caAAAB", + "ab", + 9 + ], + [ + "caAAAcaA", + "CacaAcA", + 6 + ], + [ + "caAACbc", + "CBBCABbbb", + 13 + ], + [ + "caAB", + "A", + 6 + ], + [ + "caAB", + "BCAcbbB", + 10 + ], + [ + "caAB", + "CAaAab", + 6 + ], + [ + "caABabc", + "ACbbCCC", + 12 + ], + [ + "caABb", + "AaCaBC", + 7 + ], + [ + "caAC", + "CbCcB", + 8 + ], + [ + "caAC", + "bBBBCCBA", + 14 + ], + [ + "caACABAA", + "aa", + 13 + ], + [ + "caACBa", + "BbbBcAc", + 13 + ], + [ + "caACCBAaa", + "bbAcA", + 13 + ], + [ + "caACCac", + "a", + 12 + ], + [ + "caAa", + "abBcaB", + 10 + ], + [ + "caAa", + "acaCcBc", + 10 + ], + [ + "caAaBaBc", + "bcbCa", + 14 + ], + [ + "caAaa", + "ac", + 8 + ], + [ + "caAaaaaa", + "ccc", + 14 + ], + [ + "caAac", + "ACcACAbc", + 9 + ], + [ + "caAbAAcBb", + "c", + 16 + ], + [ + "caAbAcACB", + "CBCCaAaaB", + 13 + ], + [ + "caAbBBAbC", + "bacC", + 13 + ], + [ + "caAbBCb", + "bbaaaCc", + 11 + ], + [ + "caAbbBa", + "bAC", + 12 + ], + [ + "caAbbb", + "bbCACabaC", + 13 + ], + [ + "caAc", + "baCBB", + 8 + ], + [ + "caAcCc", + "ACc", + 6 + ], + [ + "caAcbbaCB", + "cbcBc", + 12 + ], + [ + "caAcc", + "BBbabc", + 9 + ], + [ + "caAcccaAb", + "Acab", + 10 + ], + [ + "caB", + "CbAcacAa", + 12 + ], + [ + "caB", + "ccBA", + 4 + ], + [ + "caBAA", + "aCbc", + 8 + ], + [ + "caBABbbC", + "CB", + 13 + ], + [ + "caBAabAcC", + "aCA", + 14 + ], + [ + "caBAbAAc", + "bcCBBa", + 12 + ], + [ + "caBAbaAb", + "ba", + 12 + ], + [ + "caBAcB", + "BaaaBA", + 9 + ], + [ + "caBBA", + "Bc", + 8 + ], + [ + "caBBA", + "CacB", + 5 + ], + [ + "caBBaBAB", + "acAbaa", + 11 + ], + [ + "caBBbaaA", + "bB", + 13 + ], + [ + "caBC", + "CBaaBaAa", + 11 + ], + [ + "caBCBaBC", + "aABaB", + 8 + ], + [ + "caBCac", + "b", + 11 + ], + [ + "caBCc", + "CBCabB", + 9 + ], + [ + "caBa", + "CaBabAC", + 7 + ], + [ + "caBa", + "CcbccA", + 9 + ], + [ + "caBaB", + "BcA", + 8 + ], + [ + "caBaCAb", + "AacCAA", + 8 + ], + [ + "caBaCc", + "cCCA", + 8 + ], + [ + "caBb", + "AaCbCAAa", + 12 + ], + [ + "caBb", + "BCBC", + 6 + ], + [ + "caBb", + "b", + 6 + ], + [ + "caBbCaa", + "caCCbb", + 8 + ], + [ + "caBbCbbBB", + "aBCBCabca", + 11 + ], + [ + "caBbCcBC", + "cccBaB", + 11 + ], + [ + "caBbac", + "bac", + 6 + ], + [ + "caBbbB", + "BcBBA", + 9 + ], + [ + "caBbbcBa", + "b", + 14 + ], + [ + "caBc", + "bA", + 7 + ], + [ + "caBc", + "bBA", + 6 + ], + [ + "caBc", + "cc", + 4 + ], + [ + "caBcAA", + "ccacac", + 7 + ], + [ + "caBcacCb", + "bBc", + 12 + ], + [ + "caC", + "BCbb", + 7 + ], + [ + "caC", + "BbBcA", + 9 + ], + [ + "caC", + "babCacB", + 10 + ], + [ + "caC", + "bb", + 6 + ], + [ + "caC", + "cCbAaa", + 8 + ], + [ + "caCAB", + "CBA", + 7 + ], + [ + "caCAC", + "AcaaCaacc", + 10 + ], + [ + "caCAb", + "BaC", + 6 + ], + [ + "caCAccca", + "bACc", + 11 + ], + [ + "caCBA", + "aBBBBcA", + 10 + ], + [ + "caCBC", + "BcBBabA", + 11 + ], + [ + "caCBC", + "ac", + 7 + ], + [ + "caCBba", + "cBA", + 7 + ], + [ + "caCBbaBB", + "a", + 14 + ], + [ + "caCBbc", + "A", + 11 + ], + [ + "caCC", + "CaBC", + 3 + ], + [ + "caCCAa", + "Baabb", + 10 + ], + [ + "caCCAcaa", + "aC", + 12 + ], + [ + "caCCC", + "bCBaAAbC", + 11 + ], + [ + "caCCaa", + "acabCacA", + 7 + ], + [ + "caCCbCc", + "aCBcC", + 7 + ], + [ + "caCCcc", + "cbaCAacc", + 6 + ], + [ + "caCaBB", + "ccbBaBA", + 8 + ], + [ + "caCaBbcAA", + "baCcAB", + 10 + ], + [ + "caCaCAaaC", + "ABB", + 16 + ], + [ + "caCabcBa", + "CAcCABcc", + 10 + ], + [ + "caCb", + "BcAcABAB", + 11 + ], + [ + "caCb", + "bAbBCb", + 7 + ], + [ + "caCbAAcb", + "aaBbAB", + 9 + ], + [ + "caCbCBBb", + "A", + 15 + ], + [ + "caCbbC", + "cCcc", + 7 + ], + [ + "caCbbcbC", + "CBAAbCC", + 10 + ], + [ + "caCbc", + "B", + 9 + ], + [ + "caCcCaaB", + "AacCbcca", + 11 + ], + [ + "caa", + "CCAcAcaab", + 12 + ], + [ + "caa", + "b", + 6 + ], + [ + "caa", + "bAB", + 5 + ], + [ + "caa", + "bacAa", + 5 + ], + [ + "caaA", + "BaCbcC", + 10 + ], + [ + "caaAABaac", + "AC", + 15 + ], + [ + "caaACA", + "cB", + 10 + ], + [ + "caaAa", + "CaBaAbcB", + 9 + ], + [ + "caaAa", + "bbC", + 10 + ], + [ + "caaAbbc", + "Aa", + 11 + ], + [ + "caaB", + "bAc", + 7 + ], + [ + "caaB", + "cB", + 4 + ], + [ + "caaBA", + "C", + 9 + ], + [ + "caaBAabC", + "BACB", + 11 + ], + [ + "caaBCC", + "Ab", + 10 + ], + [ + "caaBCc", + "CCb", + 9 + ], + [ + "caaCCAa", + "bCccbA", + 11 + ], + [ + "caaCaBcBb", + "aCabaa", + 11 + ], + [ + "caaCbaB", + "CCc", + 11 + ], + [ + "caaCc", + "b", + 10 + ], + [ + "caaCcc", + "cbA", + 9 + ], + [ + "caaa", + "AcCc", + 8 + ], + [ + "caaa", + "bCabaCaa", + 9 + ], + [ + "caaaCb", + "AabC", + 7 + ], + [ + "caaaaC", + "CaaBCCaC", + 7 + ], + [ + "caaab", + "BCC", + 10 + ], + [ + "caaac", + "AaBbACcBa", + 13 + ], + [ + "caab", + "C", + 7 + ], + [ + "caabACbb", + "bb", + 12 + ], + [ + "caabB", + "AbaCbac", + 10 + ], + [ + "caabaABA", + "cbacccaA", + 10 + ], + [ + "caabcbcBB", + "abaAAaC", + 14 + ], + [ + "caac", + "ABb", + 7 + ], + [ + "caacAABaB", + "CbBcbaB", + 10 + ], + [ + "caacaccC", + "BAaccaBA", + 11 + ], + [ + "caacbaAc", + "Abccbc", + 10 + ], + [ + "cab", + "CB", + 4 + ], + [ + "cab", + "a", + 4 + ], + [ + "cab", + "abCCb", + 7 + ], + [ + "cab", + "bAaaBBA", + 11 + ], + [ + "cab", + "bBbCABC", + 11 + ], + [ + "cabAA", + "c", + 8 + ], + [ + "cabACCCCb", + "b", + 16 + ], + [ + "cabACc", + "bBBAb", + 9 + ], + [ + "cabBAaaB", + "BbCCBaBc", + 12 + ], + [ + "cabBC", + "A", + 9 + ], + [ + "cabBCa", + "C", + 10 + ], + [ + "cabBCcBbA", + "BbCbAAaAb", + 16 + ], + [ + "cabBaA", + "cCa", + 8 + ], + [ + "cabC", + "BBCabBCa", + 9 + ], + [ + "cabC", + "BCBb", + 7 + ], + [ + "cabC", + "Baccb", + 7 + ], + [ + "cabCCAcC", + "cCcA", + 9 + ], + [ + "cabCCaBca", + "BCbBc", + 11 + ], + [ + "cabCaba", + "a", + 12 + ], + [ + "cabCb", + "cB", + 7 + ], + [ + "cabCcbB", + "BBbAcBaac", + 13 + ], + [ + "cabaBBb", + "AbC", + 11 + ], + [ + "cabaa", + "ccBCAbAB", + 10 + ], + [ + "cababBBaB", + "AcBCAC", + 14 + ], + [ + "cabac", + "BCa", + 8 + ], + [ + "cabb", + "CACcCcac", + 14 + ], + [ + "cabb", + "a", + 6 + ], + [ + "cabbBBA", + "CCab", + 11 + ], + [ + "cabbBc", + "aCccAAcc", + 12 + ], + [ + "cabbbACA", + "bcaCC", + 11 + ], + [ + "cabc", + "BCBcBca", + 10 + ], + [ + "cabc", + "CaaBBAABA", + 14 + ], + [ + "cabcBCc", + "BABAC", + 10 + ], + [ + "cabca", + "aAaC", + 8 + ], + [ + "cac", + "BBbaabba", + 14 + ], + [ + "cac", + "bb", + 6 + ], + [ + "cac", + "bcBa", + 6 + ], + [ + "cac", + "cBaaBa", + 8 + ], + [ + "cacABBaB", + "BaBAabBbA", + 11 + ], + [ + "cacAaA", + "bc", + 10 + ], + [ + "cacAaaaBb", + "Aba", + 14 + ], + [ + "cacAbbcCB", + "AcCcAaBC", + 11 + ], + [ + "cacAc", + "cAcaAB", + 5 + ], + [ + "cacB", + "BCcbAAcbB", + 11 + ], + [ + "cacB", + "c", + 6 + ], + [ + "cacBAA", + "BbbCCab", + 12 + ], + [ + "cacBAc", + "bbaBB", + 10 + ], + [ + "cacBaAa", + "aBBBCbbbA", + 15 + ], + [ + "cacBab", + "AC", + 10 + ], + [ + "cacCCaB", + "ABCc", + 10 + ], + [ + "caca", + "bCbbAa", + 9 + ], + [ + "cacaAbAAA", + "bc", + 16 + ], + [ + "cacaAcc", + "bc", + 12 + ], + [ + "cacaBc", + "BaabCbbB", + 12 + ], + [ + "cacaaBc", + "caAacCAAa", + 11 + ], + [ + "cacaabBCa", + "AACaccAc", + 13 + ], + [ + "cacacBAbC", + "C", + 16 + ], + [ + "cacaca", + "aB", + 10 + ], + [ + "cacbAAaCa", + "b", + 16 + ], + [ + "cacbB", + "AbBaCB", + 9 + ], + [ + "cacbCcbcB", + "cc", + 14 + ], + [ + "cacbc", + "BbAACAAC", + 13 + ], + [ + "cacc", + "CAccbBacC", + 11 + ], + [ + "caccA", + "ccc", + 4 + ], + [ + "caccbc", + "ab", + 8 + ], + [ + "cb", + "AAaBCAa", + 13 + ], + [ + "cb", + "AAaC", + 8 + ], + [ + "cb", + "ABAcbc", + 8 + ], + [ + "cb", + "ABccA", + 8 + ], + [ + "cb", + "ACABcb", + 8 + ], + [ + "cb", + "Aa", + 4 + ], + [ + "cb", + "AbBAaB", + 10 + ], + [ + "cb", + "BCcbbACB", + 12 + ], + [ + "cb", + "BabCaAAB", + 14 + ], + [ + "cb", + "BbBCACCBb", + 15 + ], + [ + "cb", + "C", + 3 + ], + [ + "cb", + "CAAbCCB", + 11 + ], + [ + "cb", + "CABBCa", + 10 + ], + [ + "cb", + "CCACAAB", + 12 + ], + [ + "cb", + "aBcA", + 6 + ], + [ + "cb", + "aCBAaabaa", + 15 + ], + [ + "cb", + "aCBaacAac", + 16 + ], + [ + "cb", + "aCC", + 5 + ], + [ + "cb", + "aaBcCC", + 10 + ], + [ + "cb", + "acBAC", + 7 + ], + [ + "cb", + "bCBcaCbA", + 12 + ], + [ + "cb", + "bcCCC", + 8 + ], + [ + "cb", + "cBCaBCC", + 11 + ], + [ + "cb", + "cCabBBabA", + 14 + ], + [ + "cb", + "cb", + 0 + ], + [ + "cb", + "cccCa", + 8 + ], + [ + "cbA", + "AaAaB", + 8 + ], + [ + "cbA", + "AcACCa", + 9 + ], + [ + "cbA", + "BbCBABAA", + 12 + ], + [ + "cbA", + "aBcCCAAca", + 14 + ], + [ + "cbA", + "aaab", + 7 + ], + [ + "cbAA", + "BAbBc", + 8 + ], + [ + "cbAAaBcc", + "cABABCbb", + 10 + ], + [ + "cbAAcB", + "a", + 11 + ], + [ + "cbAAcC", + "cacC", + 5 + ], + [ + "cbAB", + "CAABa", + 5 + ], + [ + "cbABBb", + "acBA", + 9 + ], + [ + "cbABc", + "cbcAaCb", + 7 + ], + [ + "cbAC", + "C", + 6 + ], + [ + "cbACAbc", + "aABCAbA", + 8 + ], + [ + "cbACcAC", + "bbcAcbB", + 10 + ], + [ + "cbACcBBC", + "cABbcbbaB", + 12 + ], + [ + "cbACcb", + "cabbaAC", + 10 + ], + [ + "cbAaB", + "babCC", + 9 + ], + [ + "cbAaBc", + "Acc", + 8 + ], + [ + "cbAaBcCA", + "C", + 14 + ], + [ + "cbAaCBbB", + "A", + 14 + ], + [ + "cbAabcC", + "BBBCAc", + 11 + ], + [ + "cbAbAaBbc", + "bC", + 15 + ], + [ + "cbAbBBAA", + "bcaBbAc", + 9 + ], + [ + "cbAbCBA", + "acABcaC", + 10 + ], + [ + "cbAbCBBB", + "AAaaa", + 14 + ], + [ + "cbAbCaA", + "cbAcBB", + 7 + ], + [ + "cbAbaCc", + "BACabcaa", + 11 + ], + [ + "cbAbcCA", + "ccC", + 8 + ], + [ + "cbAbcaB", + "cc", + 10 + ], + [ + "cbAbcbAbB", + "AccBbbcA", + 13 + ], + [ + "cbAbcbb", + "caCaAB", + 10 + ], + [ + "cbAc", + "BABcCB", + 9 + ], + [ + "cbAc", + "bacb", + 5 + ], + [ + "cbAcCBb", + "ABac", + 10 + ], + [ + "cbAcbcccB", + "CCC", + 15 + ], + [ + "cbB", + "Aaa", + 6 + ], + [ + "cbB", + "CbC", + 3 + ], + [ + "cbB", + "caCaB", + 6 + ], + [ + "cbBA", + "BcBBccBA", + 9 + ], + [ + "cbBA", + "aCcbB", + 6 + ], + [ + "cbBAAc", + "bcABA", + 8 + ], + [ + "cbBAB", + "AbcBc", + 8 + ], + [ + "cbBABc", + "Cbba", + 7 + ], + [ + "cbBACACa", + "aA", + 13 + ], + [ + "cbBACBccA", + "Ca", + 15 + ], + [ + "cbBAba", + "AcAca", + 8 + ], + [ + "cbBAbb", + "CbaaC", + 8 + ], + [ + "cbBB", + "cAb", + 5 + ], + [ + "cbBB", + "cAba", + 5 + ], + [ + "cbBBbB", + "BBBBcaA", + 9 + ], + [ + "cbBBbca", + "cACABCb", + 10 + ], + [ + "cbBBcACBb", + "AACbBbbb", + 13 + ], + [ + "cbBCCaA", + "AccCcBc", + 11 + ], + [ + "cbBCacA", + "cB", + 10 + ], + [ + "cbBCb", + "CAAbBA", + 9 + ], + [ + "cbBa", + "aaCC", + 8 + ], + [ + "cbBa", + "cBaB", + 4 + ], + [ + "cbBa", + "cccB", + 6 + ], + [ + "cbBaBcAc", + "Aab", + 13 + ], + [ + "cbBaCAC", + "CCcCCc", + 10 + ], + [ + "cbBac", + "c", + 8 + ], + [ + "cbBacA", + "bCaaaBaa", + 12 + ], + [ + "cbBb", + "AABA", + 6 + ], + [ + "cbBb", + "CCaa", + 7 + ], + [ + "cbBbAbB", + "cC", + 12 + ], + [ + "cbBbCACCC", + "Ccc", + 14 + ], + [ + "cbBba", + "ccb", + 6 + ], + [ + "cbBbbb", + "BccCbaAAB", + 13 + ], + [ + "cbBc", + "A", + 8 + ], + [ + "cbBcCAa", + "acab", + 11 + ], + [ + "cbBcCCbAA", + "caAbaCaBc", + 14 + ], + [ + "cbBcaCB", + "bA", + 11 + ], + [ + "cbBcbaccC", + "CaAACBAAA", + 16 + ], + [ + "cbBcbc", + "ABBBAAc", + 9 + ], + [ + "cbBcc", + "CACaBC", + 10 + ], + [ + "cbC", + "AcABa", + 7 + ], + [ + "cbC", + "bCCBBa", + 10 + ], + [ + "cbCAbaAa", + "ccBCaC", + 11 + ], + [ + "cbCB", + "AABCCaaA", + 13 + ], + [ + "cbCBABAAb", + "a", + 17 + ], + [ + "cbCBAcacb", + "CAa", + 12 + ], + [ + "cbCBC", + "cbcaCaaba", + 11 + ], + [ + "cbCBccbcc", + "BcCbA", + 11 + ], + [ + "cbCC", + "B", + 7 + ], + [ + "cbCCBBCB", + "baBaCbC", + 11 + ], + [ + "cbCCBccBb", + "BaAaC", + 16 + ], + [ + "cbCCC", + "AACACB", + 8 + ], + [ + "cbCCbABBB", + "CcaABC", + 11 + ], + [ + "cbCCbBac", + "CAaA", + 12 + ], + [ + "cbCa", + "CBA", + 5 + ], + [ + "cbCa", + "bbcacb", + 7 + ], + [ + "cbCaB", + "cbBaCb", + 5 + ], + [ + "cbCbAaCCa", + "ACAAb", + 13 + ], + [ + "cbCbaC", + "BACcBC", + 8 + ], + [ + "cbCbaCcaC", + "AaaaBC", + 14 + ], + [ + "cbCbb", + "A", + 10 + ], + [ + "cbCbbCAAc", + "caccc", + 12 + ], + [ + "cbCbcC", + "B", + 11 + ], + [ + "cbCcAAcA", + "AcaAaCcCa", + 13 + ], + [ + "cbCcCAc", + "babCC", + 9 + ], + [ + "cbCcCB", + "BCABA", + 9 + ], + [ + "cbCcCbA", + "cB", + 11 + ], + [ + "cbCcb", + "AacBB", + 8 + ], + [ + "cbCcbca", + "BCB", + 10 + ], + [ + "cbCccca", + "AAA", + 13 + ], + [ + "cba", + "A", + 5 + ], + [ + "cba", + "b", + 4 + ], + [ + "cba", + "bBCaaCc", + 11 + ], + [ + "cba", + "cAAbc", + 6 + ], + [ + "cba", + "caABABbab", + 12 + ], + [ + "cba", + "ccAB", + 5 + ], + [ + "cbaAa", + "cBbbcB", + 8 + ], + [ + "cbaAc", + "cAAc", + 3 + ], + [ + "cbaBACBAc", + "a", + 16 + ], + [ + "cbaBCAAC", + "BAAcCc", + 12 + ], + [ + "cbaBCbbcC", + "BcAaabac", + 12 + ], + [ + "cbaBbCa", + "BBACcA", + 10 + ], + [ + "cbaC", + "BBCaACabc", + 13 + ], + [ + "cbaC", + "aaA", + 6 + ], + [ + "cbaCABA", + "BbAaBccBC", + 11 + ], + [ + "cbaCCA", + "cbCABA", + 6 + ], + [ + "cbaCCCa", + "a", + 12 + ], + [ + "cbaCacac", + "AcBBbAA", + 13 + ], + [ + "cbaCcaA", + "C", + 12 + ], + [ + "cbaa", + "aaBcCBcBa", + 13 + ], + [ + "cbaaA", + "cBaa", + 3 + ], + [ + "cbaabCcC", + "bB", + 13 + ], + [ + "cbabAA", + "Bc", + 11 + ], + [ + "cbabBbc", + "AbcacAC", + 11 + ], + [ + "cbabC", + "CBbaAa", + 7 + ], + [ + "cbabbC", + "aCacAcBAC", + 13 + ], + [ + "cbac", + "cCbBcACa", + 10 + ], + [ + "cbacAAAA", + "BcAbcAbc", + 12 + ], + [ + "cbacAAacc", + "ab", + 16 + ], + [ + "cbacAC", + "BaaABAbC", + 10 + ], + [ + "cbacACa", + "AcBbcBaC", + 10 + ], + [ + "cbacB", + "CaBAa", + 9 + ], + [ + "cbacCCab", + "Acbc", + 12 + ], + [ + "cbacCabBB", + "CCcc", + 14 + ], + [ + "cbb", + "BBbB", + 5 + ], + [ + "cbb", + "CcAaAC", + 10 + ], + [ + "cbb", + "bBcABAcCC", + 15 + ], + [ + "cbb", + "cbccAbA", + 8 + ], + [ + "cbbABaCBa", + "Ca", + 14 + ], + [ + "cbbAa", + "aBBcAa", + 6 + ], + [ + "cbbAaC", + "cbc", + 7 + ], + [ + "cbbAbB", + "BABaBA", + 9 + ], + [ + "cbbAbaaB", + "CCababBa", + 10 + ], + [ + "cbbBAC", + "AacCcb", + 12 + ], + [ + "cbbBbA", + "AbCAACc", + 12 + ], + [ + "cbbBbb", + "b", + 10 + ], + [ + "cbbBbbbCA", + "bBB", + 13 + ], + [ + "cbbBcBbBb", + "BaABc", + 14 + ], + [ + "cbbBcC", + "C", + 10 + ], + [ + "cbbCAaB", + "A", + 12 + ], + [ + "cbbCbC", + "cBaCCABb", + 10 + ], + [ + "cbbCcbA", + "baCBaBab", + 12 + ], + [ + "cbbaCA", + "aCAbbbCcA", + 9 + ], + [ + "cbbaCb", + "ABaCaB", + 8 + ], + [ + "cbbaaC", + "BcAAbAba", + 11 + ], + [ + "cbbabc", + "BaAaacCAc", + 14 + ], + [ + "cbbacB", + "b", + 10 + ], + [ + "cbbb", + "CC", + 7 + ], + [ + "cbbb", + "bBcCaCAC", + 14 + ], + [ + "cbbbB", + "abacb", + 7 + ], + [ + "cbbbBBcb", + "cA", + 14 + ], + [ + "cbbbaBbC", + "CbAABAC", + 8 + ], + [ + "cbbbc", + "c", + 8 + ], + [ + "cbbc", + "aCBAcAc", + 10 + ], + [ + "cbbc", + "abBBCAB", + 10 + ], + [ + "cbbcBC", + "BAB", + 9 + ], + [ + "cbbcBcCCb", + "bc", + 14 + ], + [ + "cbc", + "AACAAbCCB", + 14 + ], + [ + "cbc", + "BcbaA", + 6 + ], + [ + "cbc", + "CbBbACB", + 10 + ], + [ + "cbc", + "b", + 4 + ], + [ + "cbc", + "cBCcBaC", + 9 + ], + [ + "cbcA", + "ABBAcC", + 9 + ], + [ + "cbcAA", + "c", + 8 + ], + [ + "cbcACAabb", + "bccBcbAaA", + 13 + ], + [ + "cbcAaAAb", + "BBccBbCA", + 13 + ], + [ + "cbcAb", + "CCCbbbcba", + 13 + ], + [ + "cbcB", + "Aba", + 6 + ], + [ + "cbcB", + "bCaaaAba", + 14 + ], + [ + "cbcBacB", + "acbB", + 9 + ], + [ + "cbcBbb", + "cBa", + 8 + ], + [ + "cbcBcc", + "bbCcA", + 7 + ], + [ + "cbcC", + "aABacCCC", + 11 + ], + [ + "cbcCA", + "bBAaba", + 10 + ], + [ + "cbcCBcbc", + "acBa", + 12 + ], + [ + "cbcCcBa", + "CbbACa", + 8 + ], + [ + "cbcaB", + "bCaAAc", + 9 + ], + [ + "cbcabBAac", + "bcBCbCBb", + 13 + ], + [ + "cbcb", + "bba", + 6 + ], + [ + "cbcbCCA", + "AaaCCabcc", + 15 + ], + [ + "cbcbaCBb", + "BccCAb", + 9 + ], + [ + "cbcbbC", + "BAaa", + 11 + ], + [ + "cbcbcaCC", + "BaBbbB", + 14 + ], + [ + "cbcccaCc", + "acAAAa", + 13 + ], + [ + "cc", + "AAAbBbC", + 13 + ], + [ + "cc", + "ABBaccbbB", + 14 + ], + [ + "cc", + "ABa", + 6 + ], + [ + "cc", + "ABaA", + 8 + ], + [ + "cc", + "BAbbAab", + 14 + ], + [ + "cc", + "BAbc", + 6 + ], + [ + "cc", + "BBacCb", + 9 + ], + [ + "cc", + "BCbaB", + 9 + ], + [ + "cc", + "BaBcBAAc", + 12 + ], + [ + "cc", + "BaC", + 5 + ], + [ + "cc", + "Bbca", + 6 + ], + [ + "cc", + "CAbbcb", + 9 + ], + [ + "cc", + "CCAcCb", + 9 + ], + [ + "cc", + "Ccb", + 3 + ], + [ + "cc", + "aAaBCaA", + 13 + ], + [ + "cc", + "aB", + 4 + ], + [ + "cc", + "aBA", + 6 + ], + [ + "cc", + "acCcCabA", + 12 + ], + [ + "cc", + "b", + 4 + ], + [ + "cc", + "bACABABA", + 15 + ], + [ + "cc", + "baCaAAAc", + 13 + ], + [ + "cc", + "bacAbacB", + 12 + ], + [ + "cc", + "bcbA", + 6 + ], + [ + "cc", + "cABcAA", + 8 + ], + [ + "cc", + "cACac", + 6 + ], + [ + "cc", + "cAbba", + 8 + ], + [ + "cc", + "cB", + 2 + ], + [ + "cc", + "cCac", + 4 + ], + [ + "cc", + "cCbbAcaA", + 12 + ], + [ + "cc", + "cb", + 2 + ], + [ + "cc", + "ccBc", + 4 + ], + [ + "cc", + "ccCab", + 6 + ], + [ + "ccA", + "AcCccAcc", + 10 + ], + [ + "ccA", + "CBAaC", + 7 + ], + [ + "ccA", + "b", + 6 + ], + [ + "ccAABB", + "ccCBBbC", + 7 + ], + [ + "ccAAb", + "BaABC", + 8 + ], + [ + "ccAAbaA", + "BaA", + 9 + ], + [ + "ccAAbbbaB", + "AABBCc", + 12 + ], + [ + "ccAB", + "BcA", + 4 + ], + [ + "ccABA", + "BcBBcbBA", + 8 + ], + [ + "ccABBAA", + "bCCac", + 12 + ], + [ + "ccABcAA", + "AABBaBaA", + 11 + ], + [ + "ccAC", + "CAACBCaCA", + 13 + ], + [ + "ccAC", + "bA", + 6 + ], + [ + "ccACAAcb", + "AbabCa", + 12 + ], + [ + "ccACABbAc", + "BCbAb", + 12 + ], + [ + "ccACB", + "CBbabcAC", + 11 + ], + [ + "ccACBAaBa", + "ca", + 14 + ], + [ + "ccACBca", + "Cb", + 11 + ], + [ + "ccACC", + "CcaAba", + 7 + ], + [ + "ccACC", + "aCc", + 6 + ], + [ + "ccACaABcb", + "CBBCCABCc", + 10 + ], + [ + "ccACaBbAC", + "cBaAaB", + 11 + ], + [ + "ccACcAAB", + "AbCbaCAbb", + 13 + ], + [ + "ccACcbb", + "abCcBCb", + 9 + ], + [ + "ccAa", + "bca", + 4 + ], + [ + "ccAa", + "c", + 6 + ], + [ + "ccAaACB", + "BCabaaA", + 11 + ], + [ + "ccAaAbccA", + "AAbAAb", + 12 + ], + [ + "ccAaC", + "bAaaACAB", + 11 + ], + [ + "ccAcAC", + "c", + 10 + ], + [ + "ccAcAb", + "AbABBCbBA", + 14 + ], + [ + "ccAcb", + "bcAb", + 4 + ], + [ + "ccAcccc", + "ccCca", + 7 + ], + [ + "ccB", + "B", + 4 + ], + [ + "ccB", + "CcBAB", + 5 + ], + [ + "ccB", + "aAa", + 6 + ], + [ + "ccB", + "b", + 5 + ], + [ + "ccB", + "cAaAbaa", + 11 + ], + [ + "ccB", + "cBbCACaAB", + 13 + ], + [ + "ccBA", + "B", + 6 + ], + [ + "ccBA", + "CAac", + 7 + ], + [ + "ccBACbca", + "Abb", + 12 + ], + [ + "ccBAc", + "baaaCaaB", + 14 + ], + [ + "ccBB", + "BcC", + 6 + ], + [ + "ccBBA", + "BbACCaA", + 11 + ], + [ + "ccBBbAa", + "b", + 12 + ], + [ + "ccBBbb", + "cBbBb", + 4 + ], + [ + "ccBBbcC", + "CAbacA", + 10 + ], + [ + "ccBC", + "AaBAA", + 8 + ], + [ + "ccBC", + "Baba", + 7 + ], + [ + "ccBC", + "b", + 7 + ], + [ + "ccBC", + "cbba", + 5 + ], + [ + "ccBCAaBc", + "bBCCCAA", + 12 + ], + [ + "ccBCAbC", + "abC", + 9 + ], + [ + "ccBCBBcac", + "BCabBA", + 12 + ], + [ + "ccBCC", + "AbbC", + 7 + ], + [ + "ccBCCCa", + "BaCaB", + 10 + ], + [ + "ccBCCaBcB", + "AcC", + 14 + ], + [ + "ccBCCc", + "aBb", + 10 + ], + [ + "ccBCbBcC", + "ca", + 14 + ], + [ + "ccBCcCaA", + "bcbBAcaBA", + 10 + ], + [ + "ccBa", + "ACCaABcCa", + 12 + ], + [ + "ccBaC", + "AC", + 7 + ], + [ + "ccBaaAa", + "Cc", + 11 + ], + [ + "ccBab", + "BACC", + 9 + ], + [ + "ccBabcaBA", + "CBbc", + 11 + ], + [ + "ccBacCAbB", + "cCCcA", + 11 + ], + [ + "ccBbAABB", + "ccb", + 10 + ], + [ + "ccBbAaB", + "Cc", + 11 + ], + [ + "ccBbaCAb", + "Bcc", + 13 + ], + [ + "ccBbab", + "cCbBc", + 7 + ], + [ + "ccBbbbcB", + "Aacaaa", + 16 + ], + [ + "ccBcb", + "bbcACCb", + 9 + ], + [ + "ccC", + "Ab", + 6 + ], + [ + "ccC", + "CBcCaAbAc", + 13 + ], + [ + "ccC", + "aaCB", + 6 + ], + [ + "ccC", + "bBBAA", + 10 + ], + [ + "ccCAA", + "aCC", + 7 + ], + [ + "ccCAcCB", + "baAAbBac", + 14 + ], + [ + "ccCBAa", + "AABbcA", + 10 + ], + [ + "ccCBCc", + "caBcB", + 7 + ], + [ + "ccCBbC", + "BbbA", + 9 + ], + [ + "ccCC", + "A", + 8 + ], + [ + "ccCC", + "CCaBcACBC", + 11 + ], + [ + "ccCC", + "aab", + 8 + ], + [ + "ccCCAaa", + "B", + 14 + ], + [ + "ccCCBAaaC", + "Bb", + 16 + ], + [ + "ccCCBbCaA", + "AcACCaB", + 10 + ], + [ + "ccCCCaaCb", + "BaAbBB", + 16 + ], + [ + "ccCCacA", + "ACAAa", + 10 + ], + [ + "ccCa", + "acbBa", + 6 + ], + [ + "ccCaa", + "aCBCa", + 7 + ], + [ + "ccCab", + "CCAb", + 4 + ], + [ + "ccCbBB", + "AAcabCa", + 10 + ], + [ + "ccCba", + "aacAbCBb", + 11 + ], + [ + "ccCbbCBA", + "AaCBcAb", + 12 + ], + [ + "ccCbc", + "aCbBCcb", + 10 + ], + [ + "ccCbcCcA", + "aAA", + 14 + ], + [ + "ccCbcaaAC", + "abB", + 16 + ], + [ + "ccCcAbCA", + "AB", + 13 + ], + [ + "ccCcAccA", + "CCABcCCbc", + 13 + ], + [ + "ccCcBaA", + "caC", + 10 + ], + [ + "ccCcBbc", + "aaacAca", + 12 + ], + [ + "ccCcBcC", + "CBCCCBAA", + 9 + ], + [ + "ccCcabcb", + "baAb", + 12 + ], + [ + "ccCccbABc", + "b", + 16 + ], + [ + "cca", + "ABc", + 6 + ], + [ + "cca", + "aa", + 4 + ], + [ + "cca", + "bACA", + 6 + ], + [ + "ccaA", + "AcBa", + 5 + ], + [ + "ccaA", + "Ca", + 5 + ], + [ + "ccaABaccb", + "AAaaCBb", + 10 + ], + [ + "ccaACAC", + "BAc", + 11 + ], + [ + "ccaAba", + "Ccb", + 7 + ], + [ + "ccaAc", + "B", + 10 + ], + [ + "ccaAcCB", + "ccBB", + 8 + ], + [ + "ccaB", + "BbcB", + 6 + ], + [ + "ccaBC", + "CbbbB", + 8 + ], + [ + "ccaCA", + "ABBbb", + 10 + ], + [ + "ccaCAB", + "cCbcb", + 7 + ], + [ + "ccaCAcAB", + "acbb", + 11 + ], + [ + "ccaCAcBb", + "ccCbb", + 7 + ], + [ + "ccaCCCcCC", + "AACAc", + 13 + ], + [ + "ccaCaABb", + "bA", + 14 + ], + [ + "ccaCc", + "babb", + 8 + ], + [ + "ccaCcAAaB", + "BcAAaB", + 8 + ], + [ + "ccaCcB", + "B", + 10 + ], + [ + "ccaaBCB", + "AAA", + 12 + ], + [ + "ccaaaa", + "Aa", + 9 + ], + [ + "ccaab", + "acbbC", + 8 + ], + [ + "ccaac", + "BCBBb", + 9 + ], + [ + "ccab", + "C", + 7 + ], + [ + "ccab", + "aabBBcABa", + 14 + ], + [ + "ccabaB", + "CACba", + 7 + ], + [ + "ccabaCa", + "ccAac", + 6 + ], + [ + "ccababcA", + "abc", + 10 + ], + [ + "ccacAbBBB", + "Cb", + 15 + ], + [ + "ccacb", + "cbCA", + 7 + ], + [ + "ccb", + "A", + 6 + ], + [ + "ccb", + "Aa", + 6 + ], + [ + "ccb", + "Aca", + 4 + ], + [ + "ccb", + "acBAcb", + 6 + ], + [ + "ccb", + "acBccbAcA", + 12 + ], + [ + "ccbA", + "ba", + 5 + ], + [ + "ccbAAA", + "BAaca", + 9 + ], + [ + "ccbAACAc", + "CaaCBcBAa", + 14 + ], + [ + "ccbABAA", + "BBaccbb", + 13 + ], + [ + "ccbACa", + "cabACc", + 4 + ], + [ + "ccbAaCA", + "cCccaCCA", + 7 + ], + [ + "ccbAb", + "bbbCaACa", + 12 + ], + [ + "ccbAbA", + "cbcaBb", + 8 + ], + [ + "ccbAbBB", + "cBcbA", + 8 + ], + [ + "ccbAcC", + "AbBCcaacB", + 12 + ], + [ + "ccbBbcb", + "bCbCAC", + 10 + ], + [ + "ccbC", + "ACccBAc", + 8 + ], + [ + "ccbC", + "CB", + 6 + ], + [ + "ccbC", + "aCAA", + 7 + ], + [ + "ccbCC", + "AcCcCcb", + 8 + ], + [ + "ccbCa", + "bcBBcb", + 8 + ], + [ + "ccbCaACca", + "BBcaA", + 12 + ], + [ + "ccbCbbB", + "b", + 12 + ], + [ + "ccba", + "CAbbBc", + 9 + ], + [ + "ccba", + "Caa", + 5 + ], + [ + "ccba", + "bA", + 5 + ], + [ + "ccba", + "cbc", + 4 + ], + [ + "ccbabbC", + "AB", + 12 + ], + [ + "ccbbBbAb", + "CBc", + 13 + ], + [ + "ccbbabB", + "bCcaCa", + 11 + ], + [ + "ccbbcB", + "ACbcaaA", + 11 + ], + [ + "ccbbccCAC", + "CcccBcBC", + 10 + ], + [ + "ccbcABBCb", + "aAcAacC", + 12 + ], + [ + "ccbcAbBbc", + "a", + 17 + ], + [ + "ccbcB", + "CBaCAAcBc", + 12 + ], + [ + "ccbcBBAbB", + "cBccCc", + 13 + ], + [ + "ccbcCaab", + "cCaAAB", + 10 + ], + [ + "ccbcCbcB", + "CCCa", + 12 + ], + [ + "ccbcba", + "CA", + 10 + ], + [ + "ccc", + "AcBcbBcb", + 10 + ], + [ + "ccc", + "BbcCbB", + 9 + ], + [ + "ccc", + "CACABCbb", + 13 + ], + [ + "ccc", + "ac", + 4 + ], + [ + "ccc", + "baAABCbcc", + 13 + ], + [ + "ccc", + "c", + 4 + ], + [ + "ccc", + "cabACBAbB", + 15 + ], + [ + "cccA", + "cbBAbbB", + 10 + ], + [ + "cccAAA", + "AcB", + 10 + ], + [ + "cccAABCcA", + "ba", + 16 + ], + [ + "cccAC", + "ABCaa", + 8 + ], + [ + "cccAaccc", + "bcCC", + 12 + ], + [ + "cccAbC", + "cBbCAb", + 7 + ], + [ + "cccB", + "bACBcb", + 8 + ], + [ + "cccB", + "c", + 6 + ], + [ + "cccBAA", + "cbB", + 8 + ], + [ + "cccBAbb", + "bCCacb", + 9 + ], + [ + "cccBBAC", + "bbbcB", + 12 + ], + [ + "cccBBCc", + "CAaaAb", + 13 + ], + [ + "cccC", + "ACbB", + 7 + ], + [ + "cccC", + "bbbA", + 8 + ], + [ + "cccCabBA", + "AaBc", + 12 + ], + [ + "cccCbbcc", + "CcC", + 11 + ], + [ + "cccCccaC", + "b", + 16 + ], + [ + "ccca", + "cCcCAa", + 5 + ], + [ + "cccaAb", + "Abb", + 9 + ], + [ + "cccaCbA", + "cBcCBBbaA", + 9 + ], + [ + "cccaaa", + "BaABcbcca", + 14 + ], + [ + "cccacB", + "abBB", + 10 + ], + [ + "cccb", + "AABc", + 8 + ], + [ + "cccb", + "CbBAAbA", + 11 + ], + [ + "cccbABcc", + "a", + 15 + ], + [ + "cccbB", + "bcCAcaaba", + 11 + ], + [ + "cccbaBC", + "cbACAac", + 10 + ], + [ + "cccbabBb", + "ACc", + 13 + ], + [ + "cccbbA", + "bbcAc", + 10 + ], + [ + "cccbcaCC", + "AbCACBcCb", + 13 + ], + [ + "cccbcaaaC", + "baCcCc", + 14 + ], + [ + "ccccBa", + "abcbaaCbA", + 13 + ], + [ + "ccccCBcCA", + "Cbbab", + 15 + ], + [ + "ccccCCc", + "aabB", + 14 + ], + [ + "ccccaCA", + "Cb", + 12 + ], + [ + "cccccb", + "a", + 12 + ], + [ + "ccccccAcc", + "AB", + 16 + ] +] \ No newline at end of file diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 123bed6198c6..03a0f8b576f6 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -1770,7 +1770,6 @@ class TestException(MemoryError): gc_collect() -global_for_suggestions = None class NameErrorTests(unittest.TestCase): def test_name_error_has_name(self): @@ -1779,272 +1778,6 @@ def test_name_error_has_name(self): except NameError as exc: self.assertEqual("bluch", exc.name) - def test_name_error_suggestions(self): - def Substitution(): - noise = more_noise = a = bc = None - blech = None - print(bluch) - - def Elimination(): - noise = more_noise = a = bc = None - blch = None - print(bluch) - - def Addition(): - noise = more_noise = a = bc = None - bluchin = None - print(bluch) - - def SubstitutionOverElimination(): - blach = None - bluc = None - print(bluch) - - def SubstitutionOverAddition(): - blach = None - bluchi = None - print(bluch) - - def EliminationOverAddition(): - blucha = None - bluc = None - print(bluch) - - for func, suggestion in [(Substitution, "'blech'?"), - (Elimination, "'blch'?"), - (Addition, "'bluchin'?"), - (EliminationOverAddition, "'blucha'?"), - (SubstitutionOverElimination, "'blach'?"), - (SubstitutionOverAddition, "'blach'?")]: - err = None - try: - func() - except NameError as exc: - with support.captured_stderr() as err: - sys.__excepthook__(*sys.exc_info()) - self.assertIn(suggestion, err.getvalue()) - - def test_name_error_suggestions_from_globals(self): - def func(): - print(global_for_suggestio) - try: - func() - except NameError as exc: - with support.captured_stderr() as err: - sys.__excepthook__(*sys.exc_info()) - self.assertIn("'global_for_suggestions'?", err.getvalue()) - - def test_name_error_suggestions_from_builtins(self): - def func(): - print(ZeroDivisionErrrrr) - try: - func() - except NameError as exc: - with support.captured_stderr() as err: - sys.__excepthook__(*sys.exc_info()) - self.assertIn("'ZeroDivisionError'?", err.getvalue()) - - def test_name_error_suggestions_do_not_trigger_for_long_names(self): - def f(): - somethingverywronghehehehehehe = None - print(somethingverywronghe) - - try: - f() - except NameError as exc: - with support.captured_stderr() as err: - sys.__excepthook__(*sys.exc_info()) - - self.assertNotIn("somethingverywronghehe", err.getvalue()) - - def test_name_error_bad_suggestions_do_not_trigger_for_small_names(self): - vvv = mom = w = id = pytho = None - - with self.subTest(name="b"): - try: - b - except NameError as exc: - with support.captured_stderr() as err: - sys.__excepthook__(*sys.exc_info()) - self.assertNotIn("you mean", err.getvalue()) - self.assertNotIn("vvv", err.getvalue()) - self.assertNotIn("mom", err.getvalue()) - self.assertNotIn("'id'", err.getvalue()) - self.assertNotIn("'w'", err.getvalue()) - self.assertNotIn("'pytho'", err.getvalue()) - - with self.subTest(name="v"): - try: - v - except NameError as exc: - with support.captured_stderr() as err: - sys.__excepthook__(*sys.exc_info()) - self.assertNotIn("you mean", err.getvalue()) - self.assertNotIn("vvv", err.getvalue()) - self.assertNotIn("mom", err.getvalue()) - self.assertNotIn("'id'", err.getvalue()) - self.assertNotIn("'w'", err.getvalue()) - self.assertNotIn("'pytho'", err.getvalue()) - - with self.subTest(name="m"): - try: - m - except NameError as exc: - with support.captured_stderr() as err: - sys.__excepthook__(*sys.exc_info()) - self.assertNotIn("you mean", err.getvalue()) - self.assertNotIn("vvv", err.getvalue()) - self.assertNotIn("mom", err.getvalue()) - self.assertNotIn("'id'", err.getvalue()) - self.assertNotIn("'w'", err.getvalue()) - self.assertNotIn("'pytho'", err.getvalue()) - - with self.subTest(name="py"): - try: - py - except NameError as exc: - with support.captured_stderr() as err: - sys.__excepthook__(*sys.exc_info()) - self.assertNotIn("you mean", err.getvalue()) - self.assertNotIn("vvv", err.getvalue()) - self.assertNotIn("mom", err.getvalue()) - self.assertNotIn("'id'", err.getvalue()) - self.assertNotIn("'w'", err.getvalue()) - self.assertNotIn("'pytho'", err.getvalue()) - - def test_name_error_suggestions_do_not_trigger_for_too_many_locals(self): - def f(): - # Mutating locals() is unreliable, so we need to do it by hand - a1 = a2 = a3 = a4 = a5 = a6 = a7 = a8 = a9 = a10 = \ - a11 = a12 = a13 = a14 = a15 = a16 = a17 = a18 = a19 = a20 = \ - a21 = a22 = a23 = a24 = a25 = a26 = a27 = a28 = a29 = a30 = \ - a31 = a32 = a33 = a34 = a35 = a36 = a37 = a38 = a39 = a40 = \ - a41 = a42 = a43 = a44 = a45 = a46 = a47 = a48 = a49 = a50 = \ - a51 = a52 = a53 = a54 = a55 = a56 = a57 = a58 = a59 = a60 = \ - a61 = a62 = a63 = a64 = a65 = a66 = a67 = a68 = a69 = a70 = \ - a71 = a72 = a73 = a74 = a75 = a76 = a77 = a78 = a79 = a80 = \ - a81 = a82 = a83 = a84 = a85 = a86 = a87 = a88 = a89 = a90 = \ - a91 = a92 = a93 = a94 = a95 = a96 = a97 = a98 = a99 = a100 = \ - a101 = a102 = a103 = a104 = a105 = a106 = a107 = a108 = a109 = a110 = \ - a111 = a112 = a113 = a114 = a115 = a116 = a117 = a118 = a119 = a120 = \ - a121 = a122 = a123 = a124 = a125 = a126 = a127 = a128 = a129 = a130 = \ - a131 = a132 = a133 = a134 = a135 = a136 = a137 = a138 = a139 = a140 = \ - a141 = a142 = a143 = a144 = a145 = a146 = a147 = a148 = a149 = a150 = \ - a151 = a152 = a153 = a154 = a155 = a156 = a157 = a158 = a159 = a160 = \ - a161 = a162 = a163 = a164 = a165 = a166 = a167 = a168 = a169 = a170 = \ - a171 = a172 = a173 = a174 = a175 = a176 = a177 = a178 = a179 = a180 = \ - a181 = a182 = a183 = a184 = a185 = a186 = a187 = a188 = a189 = a190 = \ - a191 = a192 = a193 = a194 = a195 = a196 = a197 = a198 = a199 = a200 = \ - a201 = a202 = a203 = a204 = a205 = a206 = a207 = a208 = a209 = a210 = \ - a211 = a212 = a213 = a214 = a215 = a216 = a217 = a218 = a219 = a220 = \ - a221 = a222 = a223 = a224 = a225 = a226 = a227 = a228 = a229 = a230 = \ - a231 = a232 = a233 = a234 = a235 = a236 = a237 = a238 = a239 = a240 = \ - a241 = a242 = a243 = a244 = a245 = a246 = a247 = a248 = a249 = a250 = \ - a251 = a252 = a253 = a254 = a255 = a256 = a257 = a258 = a259 = a260 = \ - a261 = a262 = a263 = a264 = a265 = a266 = a267 = a268 = a269 = a270 = \ - a271 = a272 = a273 = a274 = a275 = a276 = a277 = a278 = a279 = a280 = \ - a281 = a282 = a283 = a284 = a285 = a286 = a287 = a288 = a289 = a290 = \ - a291 = a292 = a293 = a294 = a295 = a296 = a297 = a298 = a299 = a300 = \ - a301 = a302 = a303 = a304 = a305 = a306 = a307 = a308 = a309 = a310 = \ - a311 = a312 = a313 = a314 = a315 = a316 = a317 = a318 = a319 = a320 = \ - a321 = a322 = a323 = a324 = a325 = a326 = a327 = a328 = a329 = a330 = \ - a331 = a332 = a333 = a334 = a335 = a336 = a337 = a338 = a339 = a340 = \ - a341 = a342 = a343 = a344 = a345 = a346 = a347 = a348 = a349 = a350 = \ - a351 = a352 = a353 = a354 = a355 = a356 = a357 = a358 = a359 = a360 = \ - a361 = a362 = a363 = a364 = a365 = a366 = a367 = a368 = a369 = a370 = \ - a371 = a372 = a373 = a374 = a375 = a376 = a377 = a378 = a379 = a380 = \ - a381 = a382 = a383 = a384 = a385 = a386 = a387 = a388 = a389 = a390 = \ - a391 = a392 = a393 = a394 = a395 = a396 = a397 = a398 = a399 = a400 = \ - a401 = a402 = a403 = a404 = a405 = a406 = a407 = a408 = a409 = a410 = \ - a411 = a412 = a413 = a414 = a415 = a416 = a417 = a418 = a419 = a420 = \ - a421 = a422 = a423 = a424 = a425 = a426 = a427 = a428 = a429 = a430 = \ - a431 = a432 = a433 = a434 = a435 = a436 = a437 = a438 = a439 = a440 = \ - a441 = a442 = a443 = a444 = a445 = a446 = a447 = a448 = a449 = a450 = \ - a451 = a452 = a453 = a454 = a455 = a456 = a457 = a458 = a459 = a460 = \ - a461 = a462 = a463 = a464 = a465 = a466 = a467 = a468 = a469 = a470 = \ - a471 = a472 = a473 = a474 = a475 = a476 = a477 = a478 = a479 = a480 = \ - a481 = a482 = a483 = a484 = a485 = a486 = a487 = a488 = a489 = a490 = \ - a491 = a492 = a493 = a494 = a495 = a496 = a497 = a498 = a499 = a500 = \ - a501 = a502 = a503 = a504 = a505 = a506 = a507 = a508 = a509 = a510 = \ - a511 = a512 = a513 = a514 = a515 = a516 = a517 = a518 = a519 = a520 = \ - a521 = a522 = a523 = a524 = a525 = a526 = a527 = a528 = a529 = a530 = \ - a531 = a532 = a533 = a534 = a535 = a536 = a537 = a538 = a539 = a540 = \ - a541 = a542 = a543 = a544 = a545 = a546 = a547 = a548 = a549 = a550 = \ - a551 = a552 = a553 = a554 = a555 = a556 = a557 = a558 = a559 = a560 = \ - a561 = a562 = a563 = a564 = a565 = a566 = a567 = a568 = a569 = a570 = \ - a571 = a572 = a573 = a574 = a575 = a576 = a577 = a578 = a579 = a580 = \ - a581 = a582 = a583 = a584 = a585 = a586 = a587 = a588 = a589 = a590 = \ - a591 = a592 = a593 = a594 = a595 = a596 = a597 = a598 = a599 = a600 = \ - a601 = a602 = a603 = a604 = a605 = a606 = a607 = a608 = a609 = a610 = \ - a611 = a612 = a613 = a614 = a615 = a616 = a617 = a618 = a619 = a620 = \ - a621 = a622 = a623 = a624 = a625 = a626 = a627 = a628 = a629 = a630 = \ - a631 = a632 = a633 = a634 = a635 = a636 = a637 = a638 = a639 = a640 = \ - a641 = a642 = a643 = a644 = a645 = a646 = a647 = a648 = a649 = a650 = \ - a651 = a652 = a653 = a654 = a655 = a656 = a657 = a658 = a659 = a660 = \ - a661 = a662 = a663 = a664 = a665 = a666 = a667 = a668 = a669 = a670 = \ - a671 = a672 = a673 = a674 = a675 = a676 = a677 = a678 = a679 = a680 = \ - a681 = a682 = a683 = a684 = a685 = a686 = a687 = a688 = a689 = a690 = \ - a691 = a692 = a693 = a694 = a695 = a696 = a697 = a698 = a699 = a700 = \ - a701 = a702 = a703 = a704 = a705 = a706 = a707 = a708 = a709 = a710 = \ - a711 = a712 = a713 = a714 = a715 = a716 = a717 = a718 = a719 = a720 = \ - a721 = a722 = a723 = a724 = a725 = a726 = a727 = a728 = a729 = a730 = \ - a731 = a732 = a733 = a734 = a735 = a736 = a737 = a738 = a739 = a740 = \ - a741 = a742 = a743 = a744 = a745 = a746 = a747 = a748 = a749 = a750 = \ - a751 = a752 = a753 = a754 = a755 = a756 = a757 = a758 = a759 = a760 = \ - a761 = a762 = a763 = a764 = a765 = a766 = a767 = a768 = a769 = a770 = \ - a771 = a772 = a773 = a774 = a775 = a776 = a777 = a778 = a779 = a780 = \ - a781 = a782 = a783 = a784 = a785 = a786 = a787 = a788 = a789 = a790 = \ - a791 = a792 = a793 = a794 = a795 = a796 = a797 = a798 = a799 = a800 \ - = None - print(a0) - - try: - f() - except NameError as exc: - with support.captured_stderr() as err: - sys.__excepthook__(*sys.exc_info()) - - self.assertNotRegex(err.getvalue(), r"NameError.*a1") - - def test_name_error_with_custom_exceptions(self): - def f(): - blech = None - raise NameError() - - try: - f() - except NameError as exc: - with support.captured_stderr() as err: - sys.__excepthook__(*sys.exc_info()) - - self.assertNotIn("blech", err.getvalue()) - - def f(): - blech = None - raise NameError - - try: - f() - except NameError as exc: - with support.captured_stderr() as err: - sys.__excepthook__(*sys.exc_info()) - - self.assertNotIn("blech", err.getvalue()) - - def test_unbound_local_error_doesn_not_match(self): - def foo(): - something = 3 - print(somethong) - somethong = 3 - - try: - foo() - except UnboundLocalError as exc: - with support.captured_stderr() as err: - sys.__excepthook__(*sys.exc_info()) - - self.assertNotIn("something", err.getvalue()) - def test_issue45826(self): # regression test for bpo-45826 def f(): @@ -2076,6 +1809,8 @@ def f(): self.assertIn("nonsense", err.getvalue()) self.assertIn("ZeroDivisionError", err.getvalue()) + # Note: name suggestion tests live in `test_traceback`. + class AttributeErrorTests(unittest.TestCase): def test_attributes(self): @@ -2117,239 +1852,7 @@ def blech(self): self.assertEqual("bluch", exc.name) self.assertEqual(obj, exc.obj) - def test_getattr_suggestions(self): - class Substitution: - noise = more_noise = a = bc = None - blech = None - - class Elimination: - noise = more_noise = a = bc = None - blch = None - - class Addition: - noise = more_noise = a = bc = None - bluchin = None - - class SubstitutionOverElimination: - blach = None - bluc = None - - class SubstitutionOverAddition: - blach = None - bluchi = None - - class EliminationOverAddition: - blucha = None - bluc = None - - for cls, suggestion in [(Substitution, "'blech'?"), - (Elimination, "'blch'?"), - (Addition, "'bluchin'?"), - (EliminationOverAddition, "'bluc'?"), - (SubstitutionOverElimination, "'blach'?"), - (SubstitutionOverAddition, "'blach'?")]: - try: - cls().bluch - except AttributeError as exc: - with support.captured_stderr() as err: - sys.__excepthook__(*sys.exc_info()) - - self.assertIn(suggestion, err.getvalue()) - - def test_getattr_suggestions_do_not_trigger_for_long_attributes(self): - class A: - blech = None - - try: - A().somethingverywrong - except AttributeError as exc: - with support.captured_stderr() as err: - sys.__excepthook__(*sys.exc_info()) - - self.assertNotIn("blech", err.getvalue()) - - def test_getattr_error_bad_suggestions_do_not_trigger_for_small_names(self): - class MyClass: - vvv = mom = w = id = pytho = None - - with self.subTest(name="b"): - try: - MyClass.b - except AttributeError as exc: - with support.captured_stderr() as err: - sys.__excepthook__(*sys.exc_info()) - self.assertNotIn("you mean", err.getvalue()) - self.assertNotIn("vvv", err.getvalue()) - self.assertNotIn("mom", err.getvalue()) - self.assertNotIn("'id'", err.getvalue()) - self.assertNotIn("'w'", err.getvalue()) - self.assertNotIn("'pytho'", err.getvalue()) - - with self.subTest(name="v"): - try: - MyClass.v - except AttributeError as exc: - with support.captured_stderr() as err: - sys.__excepthook__(*sys.exc_info()) - self.assertNotIn("you mean", err.getvalue()) - self.assertNotIn("vvv", err.getvalue()) - self.assertNotIn("mom", err.getvalue()) - self.assertNotIn("'id'", err.getvalue()) - self.assertNotIn("'w'", err.getvalue()) - self.assertNotIn("'pytho'", err.getvalue()) - - with self.subTest(name="m"): - try: - MyClass.m - except AttributeError as exc: - with support.captured_stderr() as err: - sys.__excepthook__(*sys.exc_info()) - self.assertNotIn("you mean", err.getvalue()) - self.assertNotIn("vvv", err.getvalue()) - self.assertNotIn("mom", err.getvalue()) - self.assertNotIn("'id'", err.getvalue()) - self.assertNotIn("'w'", err.getvalue()) - self.assertNotIn("'pytho'", err.getvalue()) - - with self.subTest(name="py"): - try: - MyClass.py - except AttributeError as exc: - with support.captured_stderr() as err: - sys.__excepthook__(*sys.exc_info()) - self.assertNotIn("you mean", err.getvalue()) - self.assertNotIn("vvv", err.getvalue()) - self.assertNotIn("mom", err.getvalue()) - self.assertNotIn("'id'", err.getvalue()) - self.assertNotIn("'w'", err.getvalue()) - self.assertNotIn("'pytho'", err.getvalue()) - - - def test_getattr_suggestions_do_not_trigger_for_big_dicts(self): - class A: - blech = None - # A class with a very big __dict__ will not be consider - # for suggestions. - for index in range(2000): - setattr(A, f"index_{index}", None) - - try: - A().bluch - except AttributeError as exc: - with support.captured_stderr() as err: - sys.__excepthook__(*sys.exc_info()) - - self.assertNotIn("blech", err.getvalue()) - - def test_getattr_suggestions_no_args(self): - class A: - blech = None - def __getattr__(self, attr): - raise AttributeError() - - try: - A().bluch - except AttributeError as exc: - with support.captured_stderr() as err: - sys.__excepthook__(*sys.exc_info()) - - self.assertIn("blech", err.getvalue()) - - class A: - blech = None - def __getattr__(self, attr): - raise AttributeError - - try: - A().bluch - except AttributeError as exc: - with support.captured_stderr() as err: - sys.__excepthook__(*sys.exc_info()) - - self.assertIn("blech", err.getvalue()) - - def test_getattr_suggestions_invalid_args(self): - class NonStringifyClass: - __str__ = None - __repr__ = None - - class A: - blech = None - def __getattr__(self, attr): - raise AttributeError(NonStringifyClass()) - - class B: - blech = None - def __getattr__(self, attr): - raise AttributeError("Error", 23) - - class C: - blech = None - def __getattr__(self, attr): - raise AttributeError(23) - - for cls in [A, B, C]: - try: - cls().bluch - except AttributeError as exc: - with support.captured_stderr() as err: - sys.__excepthook__(*sys.exc_info()) - - self.assertIn("blech", err.getvalue()) - - def test_getattr_suggestions_for_same_name(self): - class A: - def __dir__(self): - return ['blech'] - try: - A().blech - except AttributeError as exc: - with support.captured_stderr() as err: - sys.__excepthook__(*sys.exc_info()) - - self.assertNotIn("Did you mean", err.getvalue()) - - def test_attribute_error_with_failing_dict(self): - class T: - bluch = 1 - def __dir__(self): - raise AttributeError("oh no!") - - try: - T().blich - except AttributeError as exc: - with support.captured_stderr() as err: - sys.__excepthook__(*sys.exc_info()) - - self.assertNotIn("blech", err.getvalue()) - self.assertNotIn("oh no!", err.getvalue()) - - def test_attribute_error_with_bad_name(self): - try: - raise AttributeError(name=12, obj=23) - except AttributeError as exc: - with support.captured_stderr() as err: - sys.__excepthook__(*sys.exc_info()) - - self.assertNotIn("?", err.getvalue()) - - def test_attribute_error_inside_nested_getattr(self): - class A: - bluch = 1 - - class B: - def __getattribute__(self, attr): - a = A() - return a.blich - - try: - B().something - except AttributeError as exc: - with support.captured_stderr() as err: - sys.__excepthook__(*sys.exc_info()) - - self.assertIn("Did you mean", err.getvalue()) - self.assertIn("bluch", err.getvalue()) + # Note: name suggestion tests live in `test_traceback`. class ImportErrorTests(unittest.TestCase): diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 2089050cadfc..4864b5c10b01 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -15,9 +15,11 @@ from test.support.os_helper import TESTFN, unlink from test.support.script_helper import assert_python_ok, assert_python_failure +import json import textwrap import traceback from functools import partial +from pathlib import Path MODULE_PREFIX = f'{__name__}.' if __name__ == '__main__' else '' @@ -27,6 +29,9 @@ test_tb = namedtuple('tb', ['tb_frame', 'tb_lineno', 'tb_next', 'tb_lasti']) +LEVENSHTEIN_DATA_FILE = Path(__file__).parent / 'levenshtein_examples.json' + + class TracebackCases(unittest.TestCase): # For now, a very minimal set of tests. I want to be sure that # formatting of SyntaxErrors works based on changes for 2.1. @@ -371,20 +376,36 @@ def test_signatures(self): '(exc, /, value=)') - at requires_debug_ranges() -class TracebackErrorLocationCaretTests(unittest.TestCase): - """ - Tests for printing code error expressions as part of PEP 657 - """ - def get_exception(self, callable): +class PurePythonExceptionFormattingMixin: + def get_exception(self, callable, slice_start=0, slice_end=-1): try: callable() self.fail("No exception thrown.") except: - return traceback.format_exc().splitlines()[:-1] + return traceback.format_exc().splitlines()[slice_start:slice_end] callable_line = get_exception.__code__.co_firstlineno + 2 + +class CAPIExceptionFormattingMixin: + def get_exception(self, callable, slice_start=0, slice_end=-1): + from _testcapi import exception_print + try: + callable() + self.fail("No exception thrown.") + except Exception as e: + with captured_output("stderr") as tbstderr: + exception_print(e) + return tbstderr.getvalue().splitlines()[slice_start:slice_end] + + callable_line = get_exception.__code__.co_firstlineno + 3 + + + at requires_debug_ranges() +class TracebackErrorLocationCaretTestBase: + """ + Tests for printing code error expressions as part of PEP 657 + """ def test_basic_caret(self): # NOTE: In caret tests, "if True:" is used as a way to force indicator # display, since the raising expression spans only part of the line. @@ -777,23 +798,29 @@ def f(): ] self.assertEqual(actual, expected) + + at requires_debug_ranges() +class PurePythonTracebackErrorCaretTests( + PurePythonExceptionFormattingMixin, + TracebackErrorLocationCaretTestBase, + unittest.TestCase, +): + """ + Same set of tests as above using the pure Python implementation of + traceback printing in traceback.py. + """ + + @cpython_only @requires_debug_ranges() -class CPythonTracebackErrorCaretTests(TracebackErrorLocationCaretTests): +class CPythonTracebackErrorCaretTests( + CAPIExceptionFormattingMixin, + TracebackErrorLocationCaretTestBase, + unittest.TestCase, +): """ Same set of tests as above but with Python's internal traceback printing. """ - def get_exception(self, callable): - from _testcapi import exception_print - try: - callable() - self.fail("No exception thrown.") - except Exception as e: - with captured_output("stderr") as tbstderr: - exception_print(e) - return tbstderr.getvalue().splitlines()[:-1] - - callable_line = get_exception.__code__.co_firstlineno + 3 class TracebackFormatTests(unittest.TestCase): @@ -2787,6 +2814,400 @@ def test_comparison(self): self.assertEqual(exc, ALWAYS_EQ) +global_for_suggestions = None + + +class SuggestionFormattingTestBase: + def get_suggestion(self, obj, attr_name=None): + if attr_name is not None: + def callable(): + getattr(obj, attr_name) + else: + callable = obj + + result_lines = self.get_exception( + callable, slice_start=-1, slice_end=None + ) + return result_lines[0] + + def test_getattr_suggestions(self): + class Substitution: + noise = more_noise = a = bc = None + blech = None + + class Elimination: + noise = more_noise = a = bc = None + blch = None + + class Addition: + noise = more_noise = a = bc = None + bluchin = None + + class SubstitutionOverElimination: + blach = None + bluc = None + + class SubstitutionOverAddition: + blach = None + bluchi = None + + class EliminationOverAddition: + blucha = None + bluc = None + + class CaseChangeOverSubstitution: + Luch = None + fluch = None + BLuch = None + + for cls, suggestion in [ + (Addition, "'bluchin'?"), + (Substitution, "'blech'?"), + (Elimination, "'blch'?"), + (Addition, "'bluchin'?"), + (SubstitutionOverElimination, "'blach'?"), + (SubstitutionOverAddition, "'blach'?"), + (EliminationOverAddition, "'bluc'?"), + (CaseChangeOverSubstitution, "'BLuch'?"), + ]: + actual = self.get_suggestion(cls(), 'bluch') + self.assertIn(suggestion, actual) + + def test_getattr_suggestions_do_not_trigger_for_long_attributes(self): + class A: + blech = None + + actual = self.get_suggestion(A(), 'somethingverywrong') + self.assertNotIn("blech", actual) + + def test_getattr_error_bad_suggestions_do_not_trigger_for_small_names(self): + class MyClass: + vvv = mom = w = id = pytho = None + + for name in ("b", "v", "m", "py"): + with self.subTest(name=name): + actual = self.get_suggestion(MyClass, name) + self.assertNotIn("you mean", actual) + self.assertNotIn("vvv", actual) + self.assertNotIn("mom", actual) + self.assertNotIn("'id'", actual) + self.assertNotIn("'w'", actual) + self.assertNotIn("'pytho'", actual) + + def test_getattr_suggestions_do_not_trigger_for_big_dicts(self): + class A: + blech = None + # A class with a very big __dict__ will not be consider + # for suggestions. + for index in range(2000): + setattr(A, f"index_{index}", None) + + actual = self.get_suggestion(A(), 'bluch') + self.assertNotIn("blech", actual) + + def test_getattr_suggestions_no_args(self): + class A: + blech = None + def __getattr__(self, attr): + raise AttributeError() + + actual = self.get_suggestion(A(), 'bluch') + self.assertIn("blech", actual) + + class A: + blech = None + def __getattr__(self, attr): + raise AttributeError + + actual = self.get_suggestion(A(), 'bluch') + self.assertIn("blech", actual) + + def test_getattr_suggestions_invalid_args(self): + class NonStringifyClass: + __str__ = None + __repr__ = None + + class A: + blech = None + def __getattr__(self, attr): + raise AttributeError(NonStringifyClass()) + + class B: + blech = None + def __getattr__(self, attr): + raise AttributeError("Error", 23) + + class C: + blech = None + def __getattr__(self, attr): + raise AttributeError(23) + + for cls in [A, B, C]: + actual = self.get_suggestion(cls(), 'bluch') + self.assertIn("blech", actual) + + def test_getattr_suggestions_for_same_name(self): + class A: + def __dir__(self): + return ['blech'] + actual = self.get_suggestion(A(), 'blech') + self.assertNotIn("Did you mean", actual) + + def test_attribute_error_with_failing_dict(self): + class T: + bluch = 1 + def __dir__(self): + raise AttributeError("oh no!") + + actual = self.get_suggestion(T(), 'blich') + self.assertNotIn("blech", actual) + self.assertNotIn("oh no!", actual) + + def test_attribute_error_with_bad_name(self): + def raise_attribute_error_with_bad_name(): + raise AttributeError(name=12, obj=23) + + result_lines = self.get_exception( + raise_attribute_error_with_bad_name, slice_start=-1, slice_end=None + ) + self.assertNotIn("?", result_lines[-1]) + + def test_attribute_error_inside_nested_getattr(self): + class A: + bluch = 1 + + class B: + def __getattribute__(self, attr): + a = A() + return a.blich + + actual = self.get_suggestion(B(), 'something') + self.assertIn("Did you mean", actual) + self.assertIn("bluch", actual) + + def test_name_error_suggestions(self): + def Substitution(): + noise = more_noise = a = bc = None + blech = None + print(bluch) + + def Elimination(): + noise = more_noise = a = bc = None + blch = None + print(bluch) + + def Addition(): + noise = more_noise = a = bc = None + bluchin = None + print(bluch) + + def SubstitutionOverElimination(): + blach = None + bluc = None + print(bluch) + + def SubstitutionOverAddition(): + blach = None + bluchi = None + print(bluch) + + def EliminationOverAddition(): + blucha = None + bluc = None + print(bluch) + + for func, suggestion in [(Substitution, "'blech'?"), + (Elimination, "'blch'?"), + (Addition, "'bluchin'?"), + (EliminationOverAddition, "'blucha'?"), + (SubstitutionOverElimination, "'blach'?"), + (SubstitutionOverAddition, "'blach'?")]: + actual = self.get_suggestion(func) + self.assertIn(suggestion, actual) + + def test_name_error_suggestions_from_globals(self): + def func(): + print(global_for_suggestio) + actual = self.get_suggestion(func) + self.assertIn("'global_for_suggestions'?", actual) + + def test_name_error_suggestions_from_builtins(self): + def func(): + print(ZeroDivisionErrrrr) + actual = self.get_suggestion(func) + self.assertIn("'ZeroDivisionError'?", actual) + + def test_name_error_suggestions_do_not_trigger_for_long_names(self): + def func(): + somethingverywronghehehehehehe = None + print(somethingverywronghe) + actual = self.get_suggestion(func) + self.assertNotIn("somethingverywronghehe", actual) + + def test_name_error_bad_suggestions_do_not_trigger_for_small_names(self): + + def f_b(): + vvv = mom = w = id = pytho = None + b + + def f_v(): + vvv = mom = w = id = pytho = None + v + + def f_m(): + vvv = mom = w = id = pytho = None + m + + def f_py(): + vvv = mom = w = id = pytho = None + py + + for name, func in (("b", f_b), ("v", f_v), ("m", f_m), ("py", f_py)): + with self.subTest(name=name): + actual = self.get_suggestion(func) + self.assertNotIn("you mean", actual) + self.assertNotIn("vvv", actual) + self.assertNotIn("mom", actual) + self.assertNotIn("'id'", actual) + self.assertNotIn("'w'", actual) + self.assertNotIn("'pytho'", actual) + + def test_name_error_suggestions_do_not_trigger_for_too_many_locals(self): + def func(): + # Mutating locals() is unreliable, so we need to do it by hand + a1 = a2 = a3 = a4 = a5 = a6 = a7 = a8 = a9 = a10 = \ + a11 = a12 = a13 = a14 = a15 = a16 = a17 = a18 = a19 = a20 = \ + a21 = a22 = a23 = a24 = a25 = a26 = a27 = a28 = a29 = a30 = \ + a31 = a32 = a33 = a34 = a35 = a36 = a37 = a38 = a39 = a40 = \ + a41 = a42 = a43 = a44 = a45 = a46 = a47 = a48 = a49 = a50 = \ + a51 = a52 = a53 = a54 = a55 = a56 = a57 = a58 = a59 = a60 = \ + a61 = a62 = a63 = a64 = a65 = a66 = a67 = a68 = a69 = a70 = \ + a71 = a72 = a73 = a74 = a75 = a76 = a77 = a78 = a79 = a80 = \ + a81 = a82 = a83 = a84 = a85 = a86 = a87 = a88 = a89 = a90 = \ + a91 = a92 = a93 = a94 = a95 = a96 = a97 = a98 = a99 = a100 = \ + a101 = a102 = a103 = a104 = a105 = a106 = a107 = a108 = a109 = a110 = \ + a111 = a112 = a113 = a114 = a115 = a116 = a117 = a118 = a119 = a120 = \ + a121 = a122 = a123 = a124 = a125 = a126 = a127 = a128 = a129 = a130 = \ + a131 = a132 = a133 = a134 = a135 = a136 = a137 = a138 = a139 = a140 = \ + a141 = a142 = a143 = a144 = a145 = a146 = a147 = a148 = a149 = a150 = \ + a151 = a152 = a153 = a154 = a155 = a156 = a157 = a158 = a159 = a160 = \ + a161 = a162 = a163 = a164 = a165 = a166 = a167 = a168 = a169 = a170 = \ + a171 = a172 = a173 = a174 = a175 = a176 = a177 = a178 = a179 = a180 = \ + a181 = a182 = a183 = a184 = a185 = a186 = a187 = a188 = a189 = a190 = \ + a191 = a192 = a193 = a194 = a195 = a196 = a197 = a198 = a199 = a200 = \ + a201 = a202 = a203 = a204 = a205 = a206 = a207 = a208 = a209 = a210 = \ + a211 = a212 = a213 = a214 = a215 = a216 = a217 = a218 = a219 = a220 = \ + a221 = a222 = a223 = a224 = a225 = a226 = a227 = a228 = a229 = a230 = \ + a231 = a232 = a233 = a234 = a235 = a236 = a237 = a238 = a239 = a240 = \ + a241 = a242 = a243 = a244 = a245 = a246 = a247 = a248 = a249 = a250 = \ + a251 = a252 = a253 = a254 = a255 = a256 = a257 = a258 = a259 = a260 = \ + a261 = a262 = a263 = a264 = a265 = a266 = a267 = a268 = a269 = a270 = \ + a271 = a272 = a273 = a274 = a275 = a276 = a277 = a278 = a279 = a280 = \ + a281 = a282 = a283 = a284 = a285 = a286 = a287 = a288 = a289 = a290 = \ + a291 = a292 = a293 = a294 = a295 = a296 = a297 = a298 = a299 = a300 = \ + a301 = a302 = a303 = a304 = a305 = a306 = a307 = a308 = a309 = a310 = \ + a311 = a312 = a313 = a314 = a315 = a316 = a317 = a318 = a319 = a320 = \ + a321 = a322 = a323 = a324 = a325 = a326 = a327 = a328 = a329 = a330 = \ + a331 = a332 = a333 = a334 = a335 = a336 = a337 = a338 = a339 = a340 = \ + a341 = a342 = a343 = a344 = a345 = a346 = a347 = a348 = a349 = a350 = \ + a351 = a352 = a353 = a354 = a355 = a356 = a357 = a358 = a359 = a360 = \ + a361 = a362 = a363 = a364 = a365 = a366 = a367 = a368 = a369 = a370 = \ + a371 = a372 = a373 = a374 = a375 = a376 = a377 = a378 = a379 = a380 = \ + a381 = a382 = a383 = a384 = a385 = a386 = a387 = a388 = a389 = a390 = \ + a391 = a392 = a393 = a394 = a395 = a396 = a397 = a398 = a399 = a400 = \ + a401 = a402 = a403 = a404 = a405 = a406 = a407 = a408 = a409 = a410 = \ + a411 = a412 = a413 = a414 = a415 = a416 = a417 = a418 = a419 = a420 = \ + a421 = a422 = a423 = a424 = a425 = a426 = a427 = a428 = a429 = a430 = \ + a431 = a432 = a433 = a434 = a435 = a436 = a437 = a438 = a439 = a440 = \ + a441 = a442 = a443 = a444 = a445 = a446 = a447 = a448 = a449 = a450 = \ + a451 = a452 = a453 = a454 = a455 = a456 = a457 = a458 = a459 = a460 = \ + a461 = a462 = a463 = a464 = a465 = a466 = a467 = a468 = a469 = a470 = \ + a471 = a472 = a473 = a474 = a475 = a476 = a477 = a478 = a479 = a480 = \ + a481 = a482 = a483 = a484 = a485 = a486 = a487 = a488 = a489 = a490 = \ + a491 = a492 = a493 = a494 = a495 = a496 = a497 = a498 = a499 = a500 = \ + a501 = a502 = a503 = a504 = a505 = a506 = a507 = a508 = a509 = a510 = \ + a511 = a512 = a513 = a514 = a515 = a516 = a517 = a518 = a519 = a520 = \ + a521 = a522 = a523 = a524 = a525 = a526 = a527 = a528 = a529 = a530 = \ + a531 = a532 = a533 = a534 = a535 = a536 = a537 = a538 = a539 = a540 = \ + a541 = a542 = a543 = a544 = a545 = a546 = a547 = a548 = a549 = a550 = \ + a551 = a552 = a553 = a554 = a555 = a556 = a557 = a558 = a559 = a560 = \ + a561 = a562 = a563 = a564 = a565 = a566 = a567 = a568 = a569 = a570 = \ + a571 = a572 = a573 = a574 = a575 = a576 = a577 = a578 = a579 = a580 = \ + a581 = a582 = a583 = a584 = a585 = a586 = a587 = a588 = a589 = a590 = \ + a591 = a592 = a593 = a594 = a595 = a596 = a597 = a598 = a599 = a600 = \ + a601 = a602 = a603 = a604 = a605 = a606 = a607 = a608 = a609 = a610 = \ + a611 = a612 = a613 = a614 = a615 = a616 = a617 = a618 = a619 = a620 = \ + a621 = a622 = a623 = a624 = a625 = a626 = a627 = a628 = a629 = a630 = \ + a631 = a632 = a633 = a634 = a635 = a636 = a637 = a638 = a639 = a640 = \ + a641 = a642 = a643 = a644 = a645 = a646 = a647 = a648 = a649 = a650 = \ + a651 = a652 = a653 = a654 = a655 = a656 = a657 = a658 = a659 = a660 = \ + a661 = a662 = a663 = a664 = a665 = a666 = a667 = a668 = a669 = a670 = \ + a671 = a672 = a673 = a674 = a675 = a676 = a677 = a678 = a679 = a680 = \ + a681 = a682 = a683 = a684 = a685 = a686 = a687 = a688 = a689 = a690 = \ + a691 = a692 = a693 = a694 = a695 = a696 = a697 = a698 = a699 = a700 = \ + a701 = a702 = a703 = a704 = a705 = a706 = a707 = a708 = a709 = a710 = \ + a711 = a712 = a713 = a714 = a715 = a716 = a717 = a718 = a719 = a720 = \ + a721 = a722 = a723 = a724 = a725 = a726 = a727 = a728 = a729 = a730 = \ + a731 = a732 = a733 = a734 = a735 = a736 = a737 = a738 = a739 = a740 = \ + a741 = a742 = a743 = a744 = a745 = a746 = a747 = a748 = a749 = a750 = \ + a751 = a752 = a753 = a754 = a755 = a756 = a757 = a758 = a759 = a760 = \ + a761 = a762 = a763 = a764 = a765 = a766 = a767 = a768 = a769 = a770 = \ + a771 = a772 = a773 = a774 = a775 = a776 = a777 = a778 = a779 = a780 = \ + a781 = a782 = a783 = a784 = a785 = a786 = a787 = a788 = a789 = a790 = \ + a791 = a792 = a793 = a794 = a795 = a796 = a797 = a798 = a799 = a800 \ + = None + print(a0) + + actual = self.get_suggestion(func) + self.assertNotRegex(actual, r"NameError.*a1") + + def test_name_error_with_custom_exceptions(self): + def func(): + blech = None + raise NameError() + + actual = self.get_suggestion(func) + self.assertNotIn("blech", actual) + + def func(): + blech = None + raise NameError + + actual = self.get_suggestion(func) + self.assertNotIn("blech", actual) + + def test_unbound_local_error_does_not_match(self): + def func(): + something = 3 + print(somethong) + somethong = 3 + + actual = self.get_suggestion(func) + self.assertNotIn("something", actual) + + +class PurePythonSuggestionFormattingTests( + PurePythonExceptionFormattingMixin, + SuggestionFormattingTestBase, + unittest.TestCase, +): + """ + Same set of tests as above using the pure Python implementation of + traceback printing in traceback.py. + """ + + + at cpython_only +class CPythonSuggestionFormattingTests( + CAPIExceptionFormattingMixin, + SuggestionFormattingTestBase, + unittest.TestCase, +): + """ + Same set of tests as above but with Python's internal traceback printing. + """ + + class MiscTest(unittest.TestCase): def test_all(self): @@ -2800,6 +3221,59 @@ def test_all(self): expected.add(name) self.assertCountEqual(traceback.__all__, expected) + def test_levenshtein_distance(self): + # copied from _testinternalcapi.test_edit_cost + # to also exercise the Python implementation + + def CHECK(a, b, expected): + actual = traceback._levenshtein_distance(a, b, 4044) + self.assertEqual(actual, expected) + + CHECK("", "", 0) + CHECK("", "a", 2) + CHECK("a", "A", 1) + CHECK("Apple", "Aple", 2) + CHECK("Banana", "B at n@n@", 6) + CHECK("Cherry", "Cherry!", 2) + CHECK("---0---", "------", 2) + CHECK("abc", "y", 6) + CHECK("aa", "bb", 4) + CHECK("aaaaa", "AAAAA", 5) + CHECK("wxyz", "wXyZ", 2) + CHECK("wxyz", "wXyZ123", 8) + CHECK("Python", "Java", 12) + CHECK("Java", "C#", 8) + CHECK("AbstractFoobarManager", "abstract_foobar_manager", 3+2*2) + CHECK("CPython", "PyPy", 10) + CHECK("CPython", "pypy", 11) + CHECK("AttributeError", "AttributeErrop", 2) + CHECK("AttributeError", "AttributeErrorTests", 10) + CHECK("ABA", "AAB", 4) + + def test_levenshtein_distance_short_circuit(self): + if not LEVENSHTEIN_DATA_FILE.is_file(): + self.fail( + f"{LEVENSHTEIN_DATA_FILE} is missing." + f" Run `make regen-test-levenshtein`" + ) + + with LEVENSHTEIN_DATA_FILE.open("r") as f: + examples = json.load(f) + for a, b, expected in examples: + res1 = traceback._levenshtein_distance(a, b, 1000) + self.assertEqual(res1, expected, msg=(a, b)) + + for threshold in [expected, expected + 1, expected + 2]: + # big enough thresholds shouldn't change the result + res2 = traceback._levenshtein_distance(a, b, threshold) + self.assertEqual(res2, expected, msg=(a, b, threshold)) + + for threshold in range(expected): + # for small thresholds, the only piece of information + # we receive is "strings not close enough". + res3 = traceback._levenshtein_distance(a, b, threshold) + self.assertGreater(res3, threshold, msg=(a, b, threshold)) + if __name__ == "__main__": unittest.main() diff --git a/Lib/traceback.py b/Lib/traceback.py index b1a5fd0a26d4..c46ddaf51a00 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -707,6 +707,11 @@ def __init__(self, exc_type, exc_value, exc_traceback, *, limit=None, self.offset = exc_value.offset self.end_offset = exc_value.end_offset self.msg = exc_value.msg + elif exc_type and issubclass(exc_type, (NameError, AttributeError)) and \ + getattr(exc_value, "name", None) is not None: + suggestion = _compute_suggestion_error(exc_value, exc_traceback) + if suggestion: + self._str += f". Did you mean: '{suggestion}'?" if lookup_lines: self._load_lines() self.__suppress_context__ = \ @@ -977,3 +982,125 @@ def print(self, *, file=None, chain=True): file = sys.stderr for line in self.format(chain=chain): print(line, file=file, end="") + + +_MAX_CANDIDATE_ITEMS = 750 +_MAX_STRING_SIZE = 40 +_MOVE_COST = 2 +_CASE_COST = 1 + + +def _substitution_cost(ch_a, ch_b): + if ch_a == ch_b: + return 0 + if ch_a.lower() == ch_b.lower(): + return _CASE_COST + return _MOVE_COST + + +def _compute_suggestion_error(exc_value, tb): + wrong_name = getattr(exc_value, "name", None) + if wrong_name is None or not isinstance(wrong_name, str): + return None + if isinstance(exc_value, AttributeError): + obj = exc_value.obj + try: + d = dir(obj) + except Exception: + return None + else: + assert isinstance(exc_value, NameError) + # find most recent frame + if tb is None: + return None + while tb.tb_next is not None: + tb = tb.tb_next + frame = tb.tb_frame + d = ( + list(frame.f_locals) + + list(frame.f_globals) + + list(frame.f_globals['__builtins__']) + ) + if len(d) > _MAX_CANDIDATE_ITEMS: + return None + wrong_name_len = len(wrong_name) + if wrong_name_len > _MAX_STRING_SIZE: + return None + best_distance = wrong_name_len + suggestion = None + for possible_name in d: + if possible_name == wrong_name: + # A missing attribute is "found". Don't suggest it (see GH-88821). + continue + # No more than 1/3 of the involved characters should need changed. + max_distance = (len(possible_name) + wrong_name_len + 3) * _MOVE_COST // 6 + # Don't take matches we've already beaten. + max_distance = min(max_distance, best_distance - 1) + current_distance = _levenshtein_distance(wrong_name, possible_name, max_distance) + if current_distance > max_distance: + continue + if not suggestion or current_distance < best_distance: + suggestion = possible_name + best_distance = current_distance + return suggestion + + +def _levenshtein_distance(a, b, max_cost): + # A Python implementation of Python/suggestions.c:levenshtein_distance. + + # Both strings are the same + if a == b: + return 0 + + # Trim away common affixes + pre = 0 + while a[pre:] and b[pre:] and a[pre] == b[pre]: + pre += 1 + a = a[pre:] + b = b[pre:] + post = 0 + while a[:post or None] and b[:post or None] and a[post-1] == b[post-1]: + post -= 1 + a = a[:post or None] + b = b[:post or None] + if not a or not b: + return _MOVE_COST * (len(a) + len(b)) + if len(a) > _MAX_STRING_SIZE or len(b) > _MAX_STRING_SIZE: + return max_cost + 1 + + # Prefer shorter buffer + if len(b) < len(a): + a, b = b, a + + # Quick fail when a match is impossible + if (len(b) - len(a)) * _MOVE_COST > max_cost: + return max_cost + 1 + + # Instead of producing the whole traditional len(a)-by-len(b) + # matrix, we can update just one row in place. + # Initialize the buffer row + row = list(range(_MOVE_COST, _MOVE_COST * (len(a) + 1), _MOVE_COST)) + + result = 0 + for bindex in range(len(b)): + bchar = b[bindex] + distance = result = bindex * _MOVE_COST + minimum = sys.maxsize + for index in range(len(a)): + # 1) Previous distance in this row is cost(b[:b_index], a[:index]) + substitute = distance + _substitution_cost(bchar, a[index]) + # 2) cost(b[:b_index], a[:index+1]) from previous row + distance = row[index] + # 3) existing result is cost(b[:b_index+1], a[index]) + + insert_delete = min(result, distance) + _MOVE_COST + result = min(insert_delete, substitute) + + # cost(b[:b_index+1], a[:index+1]) + row[index] = result + if result < minimum: + minimum = result + if minimum > max_cost: + # Everything in this row is too big, so bail early. + return max_cost + 1 + return result diff --git a/Makefile.pre.in b/Makefile.pre.in index 01578306bd5f..11118354f15d 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -958,6 +958,11 @@ regen-test-frozenmain: $(BUILDPYTHON) # using Programs/freeze_test_frozenmain.py $(RUNSHARED) ./$(BUILDPYTHON) $(srcdir)/Programs/freeze_test_frozenmain.py Programs/test_frozenmain.h +.PHONY: regen-test-levenshtein +regen-test-levenshtein: + # Regenerate Lib/test/levenshtein_examples.json + $(PYTHON_FOR_REGEN) $(srcdir)/Tools/scripts/generate_levenshtein_examples.py Lib/test/levenshtein_examples.json + .PHONY: regen-re regen-re: $(BUILDPYTHON) # Regenerate Lib/re/_casefix.py @@ -1223,7 +1228,7 @@ regen-limited-abi: all regen-all: regen-opcode regen-opcode-targets regen-typeslots \ regen-token regen-ast regen-keyword regen-sre regen-frozen clinic \ regen-pegen-metaparser regen-pegen regen-test-frozenmain \ - regen-global-objects + regen-test-levenshtein regen-global-objects @echo @echo "Note: make regen-stdlib-module-names and make regen-configure should be run manually" diff --git a/Misc/NEWS.d/next/Library/2022-10-04-00-43-43.gh-issue-97008.3rjtt6.rst b/Misc/NEWS.d/next/Library/2022-10-04-00-43-43.gh-issue-97008.3rjtt6.rst new file mode 100644 index 000000000000..b41f88d07890 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-04-00-43-43.gh-issue-97008.3rjtt6.rst @@ -0,0 +1,5 @@ +:exc:`NameError` and :exc:`AttributeError` spelling suggestions provided +since :gh:`82711` are now also emitted by the pure Python +:mod:`traceback` module. Tests for those suggestions now exercise both +implementations to ensure they are equivalent. Patch by Carl Friedrich +Bolz-Tereick and ?ukasz Langa. diff --git a/Tools/scripts/generate_levenshtein_examples.py b/Tools/scripts/generate_levenshtein_examples.py new file mode 100644 index 000000000000..5a8360fff731 --- /dev/null +++ b/Tools/scripts/generate_levenshtein_examples.py @@ -0,0 +1,70 @@ +"""Generate 10,000 unique examples for the Levenshtein short-circuit tests.""" + +import argparse +from functools import cache +import json +import os.path +from random import choices, randrange + + +# This should be in sync with Lib/traceback.py. It's not importing those values +# because this script is being executed by PYTHON_FOR_REGEN and not by the in-tree +# build of Python. +_MOVE_COST = 2 +_CASE_COST = 1 + + +def _substitution_cost(ch_a, ch_b): + if ch_a == ch_b: + return 0 + if ch_a.lower() == ch_b.lower(): + return _CASE_COST + return _MOVE_COST + + + at cache +def levenshtein(a, b): + if not a or not b: + return (len(a) + len(b)) * _MOVE_COST + option1 = levenshtein(a[:-1], b[:-1]) + _substitution_cost(a[-1], b[-1]) + option2 = levenshtein(a[:-1], b) + _MOVE_COST + option3 = levenshtein(a, b[:-1]) + _MOVE_COST + return min(option1, option2, option3) + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('output_path', metavar='FILE', type=str) + parser.add_argument('--overwrite', dest='overwrite', action='store_const', + const=True, default=False, + help='overwrite an existing test file') + + args = parser.parse_args() + output_path = os.path.realpath(args.output_path) + if not args.overwrite and os.path.isfile(output_path): + print(f"{output_path} already exists, skipping regeneration.") + print( + "To force, add --overwrite to the invocation of this tool or" + " delete the existing file." + ) + return + + examples = set() + # Create a lot of non-empty examples, which should end up with a Gauss-like + # distribution for even costs (moves) and odd costs (case substitutions). + while len(examples) < 9990: + a = ''.join(choices("abcABC", k=randrange(1, 10))) + b = ''.join(choices("abcABC", k=randrange(1, 10))) + expected = levenshtein(a, b) + examples.add((a, b, expected)) + # Create one empty case each for strings between 0 and 9 in length. + for i in range(10): + b = ''.join(choices("abcABC", k=i)) + expected = levenshtein("", b) + examples.add(("", b, expected)) + with open(output_path, "w") as f: + json.dump(sorted(examples), f, indent=2) + + +if __name__ == "__main__": + main() From webhook-mailer at python.org Tue Oct 4 18:37:41 2022 From: webhook-mailer at python.org (zooba) Date: Tue, 04 Oct 2022 22:37:41 -0000 Subject: [Python-checkins] gh-58451: Add optional delete_on_close parameter to NamedTemporaryFile (GH-97015) Message-ID: https://github.com/python/cpython/commit/743453a5541d3a6f19046459d22a7991ecb88223 commit: 743453a5541d3a6f19046459d22a7991ecb88223 branch: main author: Ev2geny committer: zooba date: 2022-10-04T23:37:33+01:00 summary: gh-58451: Add optional delete_on_close parameter to NamedTemporaryFile (GH-97015) files: A Misc/NEWS.d/next/Library/2020-09-28-04-56-04.bpo-14243.YECnxv.rst M Doc/library/tempfile.rst M Doc/whatsnew/3.12.rst M Lib/tempfile.py M Lib/test/test_tempfile.py diff --git a/Doc/library/tempfile.rst b/Doc/library/tempfile.rst index b7e604c1b70a..b6d4f5dd05bb 100644 --- a/Doc/library/tempfile.rst +++ b/Doc/library/tempfile.rst @@ -75,20 +75,61 @@ The module defines the following user-callable items: Added *errors* parameter. -.. function:: NamedTemporaryFile(mode='w+b', buffering=-1, encoding=None, newline=None, suffix=None, prefix=None, dir=None, delete=True, *, errors=None) - - This function operates exactly as :func:`TemporaryFile` does, except that - the file is guaranteed to have a visible name in the file system (on - Unix, the directory entry is not unlinked). That name can be retrieved - from the :attr:`name` attribute of the returned - file-like object. Whether the name can be - used to open the file a second time, while the named temporary file is - still open, varies across platforms (it can be so used on Unix; it cannot - on Windows). If *delete* is true (the default), the file is - deleted as soon as it is closed. - The returned object is always a file-like object whose :attr:`!file` - attribute is the underlying true file object. This file-like object can - be used in a :keyword:`with` statement, just like a normal file. +.. function:: NamedTemporaryFile(mode='w+b', buffering=-1, encoding=None, newline=None, suffix=None, prefix=None, dir=None, delete=True, *, errors=None, delete_on_close=True) + + This function operates exactly as :func:`TemporaryFile` does, except the + following differences: + + * This function returns a file that is guaranteed to have a visible name in + the file system. + * To manage the named file, it extends the parameters of + :func:`TemporaryFile` with *delete* and *delete_on_close* parameters that + determine whether and how the named file should be automatically deleted. + + The returned object is always a :term:`file-like object` whose :attr:`!file` + attribute is the underlying true file object. This :term:`file-like object` + can be used in a :keyword:`with` statement, just like a normal file. The + name of the temporary file can be retrieved from the :attr:`name` attribute + of the returned file-like object. On Unix, unlike with the + :func:`TemporaryFile`, the directory entry does not get unlinked immediately + after the file creation. + + If *delete* is true (the default) and *delete_on_close* is true (the + default), the file is deleted as soon as it is closed. If *delete* is true + and *delete_on_close* is false, the file is deleted on context manager exit + only, or else when the :term:`file-like object` is finalized. Deletion is not + always guaranteed in this case (see :meth:`object.__del__`). If *delete* is + false, the value of *delete_on_close* is ignored. + + Therefore to use the name of the temporary file to reopen the file after + closing it, either make sure not to delete the file upon closure (set the + *delete* parameter to be false) or, in case the temporary file is created in + a :keyword:`with` statement, set the *delete_on_close* parameter to be false. + The latter approach is recommended as it provides assistance in automatic + cleaning of the temporary file upon the context manager exit. + + Opening the temporary file again by its name while it is still open works as + follows: + + * On POSIX the file can always be opened again. + * On Windows, make sure that at least one of the following conditions are + fulfilled: + + * *delete* is false + * additional open shares delete access (e.g. by calling :func:`os.open` + with the flag ``O_TEMPORARY``) + * *delete* is true but *delete_on_close* is false. Note, that in this + case the additional opens that do not share delete access (e.g. + created via builtin :func:`open`) must be closed before exiting the + context manager, else the :func:`os.unlink` call on context manager + exit will fail with a :exc:`PermissionError`. + + On Windows, if *delete_on_close* is false, and the file is created in a + directory for which the user lacks delete access, then the :func:`os.unlink` + call on exit of the context manager will fail with a :exc:`PermissionError`. + This cannot happen when *delete_on_close* is true because delete access is + requested by the open, which fails immediately if the requested access is not + granted. On POSIX (only), a process that is terminated abruptly with SIGKILL cannot automatically delete any NamedTemporaryFiles it created. @@ -98,6 +139,9 @@ The module defines the following user-callable items: .. versionchanged:: 3.8 Added *errors* parameter. + .. versionchanged:: 3.12 + Added *delete_on_close* parameter. + .. class:: SpooledTemporaryFile(max_size=0, mode='w+b', buffering=-1, encoding=None, newline=None, suffix=None, prefix=None, dir=None, *, errors=None) @@ -346,6 +390,19 @@ Here are some examples of typical usage of the :mod:`tempfile` module:: >>> # file is now closed and removed + # create a temporary file using a context manager + # close the file, use the name to open the file again + >>> with tempfile.TemporaryFile(delete_on_close=False) as fp: + ... fp.write(b'Hello world!') + ... fp.close() + # the file is closed, but not removed + # open the file again by using its name + ... with open(fp.name) as f + ... f.read() + b'Hello world!' + >>> + # file is now removed + # create a temporary directory using the context manager >>> with tempfile.TemporaryDirectory() as tmpdirname: ... print('created temporary directory', tmpdirname) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 39ae2518bbdd..052507a4873f 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -148,6 +148,11 @@ unicodedata * The Unicode database has been updated to version 15.0.0. (Contributed by Benjamin Peterson in :gh:`96734`). +tempfile +-------- + +The :class:`tempfile.NamedTemporaryFile` function has a new optional parameter +*delete_on_close* (Contributed by Evgeny Zorin in :gh:`58451`.) Optimizations ============= diff --git a/Lib/tempfile.py b/Lib/tempfile.py index 480c17232e9f..bb18d60db0d9 100644 --- a/Lib/tempfile.py +++ b/Lib/tempfile.py @@ -418,42 +418,42 @@ class _TemporaryFileCloser: underlying file object, without adding a __del__ method to the temporary file.""" - file = None # Set here since __del__ checks it + cleanup_called = False close_called = False - def __init__(self, file, name, delete=True): + def __init__(self, file, name, delete=True, delete_on_close=True): self.file = file self.name = name self.delete = delete + self.delete_on_close = delete_on_close - # NT provides delete-on-close as a primitive, so we don't need - # the wrapper to do anything special. We still use it so that - # file.name is useful (i.e. not "(fdopen)") with NamedTemporaryFile. - if _os.name != 'nt': - # Cache the unlinker so we don't get spurious errors at - # shutdown when the module-level "os" is None'd out. Note - # that this must be referenced as self.unlink, because the - # name TemporaryFileWrapper may also get None'd out before - # __del__ is called. - - def close(self, unlink=_os.unlink): - if not self.close_called and self.file is not None: - self.close_called = True - try: + def cleanup(self, windows=(_os.name == 'nt'), unlink=_os.unlink): + if not self.cleanup_called: + self.cleanup_called = True + try: + if not self.close_called: + self.close_called = True self.file.close() - finally: - if self.delete: + finally: + # Windows provides delete-on-close as a primitive, in which + # case the file was deleted by self.file.close(). + if self.delete and not (windows and self.delete_on_close): + try: unlink(self.name) + except FileNotFoundError: + pass - # Need to ensure the file is deleted on __del__ - def __del__(self): - self.close() - - else: - def close(self): - if not self.close_called: - self.close_called = True + def close(self): + if not self.close_called: + self.close_called = True + try: self.file.close() + finally: + if self.delete and self.delete_on_close: + self.cleanup() + + def __del__(self): + self.cleanup() class _TemporaryFileWrapper: @@ -464,11 +464,11 @@ class _TemporaryFileWrapper: remove the file when it is no longer needed. """ - def __init__(self, file, name, delete=True): + def __init__(self, file, name, delete=True, delete_on_close=True): self.file = file self.name = name - self.delete = delete - self._closer = _TemporaryFileCloser(file, name, delete) + self._closer = _TemporaryFileCloser(file, name, delete, + delete_on_close) def __getattr__(self, name): # Attribute lookups are delegated to the underlying file @@ -499,7 +499,7 @@ def __enter__(self): # deleted when used in a with statement def __exit__(self, exc, value, tb): result = self.file.__exit__(exc, value, tb) - self.close() + self._closer.cleanup() return result def close(self): @@ -518,10 +518,10 @@ def __iter__(self): for line in self.file: yield line - def NamedTemporaryFile(mode='w+b', buffering=-1, encoding=None, newline=None, suffix=None, prefix=None, - dir=None, delete=True, *, errors=None): + dir=None, delete=True, *, errors=None, + delete_on_close=True): """Create and return a temporary file. Arguments: 'prefix', 'suffix', 'dir' -- as for mkstemp. @@ -529,7 +529,10 @@ def NamedTemporaryFile(mode='w+b', buffering=-1, encoding=None, 'buffering' -- the buffer size argument to io.open (default -1). 'encoding' -- the encoding argument to io.open (default None) 'newline' -- the newline argument to io.open (default None) - 'delete' -- whether the file is deleted on close (default True). + 'delete' -- whether the file is automatically deleted (default True). + 'delete_on_close' -- if 'delete', whether the file is deleted on close + (default True) or otherwise either on context manager exit + (if context manager was used) or on object finalization. . 'errors' -- the errors argument to io.open (default None) The file is created as mkstemp() would do it. @@ -548,7 +551,7 @@ def NamedTemporaryFile(mode='w+b', buffering=-1, encoding=None, # Setting O_TEMPORARY in the flags causes the OS to delete # the file when it is closed. This is only supported by Windows. - if _os.name == 'nt' and delete: + if _os.name == 'nt' and delete and delete_on_close: flags |= _os.O_TEMPORARY if "b" not in mode: @@ -567,12 +570,13 @@ def opener(*args): raw = getattr(file, 'buffer', file) raw = getattr(raw, 'raw', raw) raw.name = name - return _TemporaryFileWrapper(file, name, delete) + return _TemporaryFileWrapper(file, name, delete, delete_on_close) except: file.close() raise except: - if name is not None and not (_os.name == 'nt' and delete): + if name is not None and not ( + _os.name == 'nt' and delete and delete_on_close): _os.unlink(name) raise diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py index ccf7ea072de2..7c2c8de7a2e6 100644 --- a/Lib/test/test_tempfile.py +++ b/Lib/test/test_tempfile.py @@ -11,6 +11,7 @@ import stat import types import weakref +import gc from unittest import mock import unittest @@ -1013,6 +1014,102 @@ def use_closed(): pass self.assertRaises(ValueError, use_closed) + def test_context_man_not_del_on_close_if_delete_on_close_false(self): + # Issue gh-58451: tempfile.NamedTemporaryFile is not particulary useful + # on Windows + # A NamedTemporaryFile is NOT deleted when closed if + # delete_on_close=False, but is deleted on context manager exit + dir = tempfile.mkdtemp() + try: + with tempfile.NamedTemporaryFile(dir=dir, + delete=True, + delete_on_close=False) as f: + f.write(b'blat') + f_name = f.name + f.close() + with self.subTest(): + # Testing that file is not deleted on close + self.assertTrue(os.path.exists(f.name), + f"NamedTemporaryFile {f.name!r} is incorrectly " + f"deleted on closure when delete_on_close=False") + + with self.subTest(): + # Testing that file is deleted on context manager exit + self.assertFalse(os.path.exists(f.name), + f"NamedTemporaryFile {f.name!r} exists " + f"after context manager exit") + + finally: + os.rmdir(dir) + + def test_context_man_ok_to_delete_manually(self): + # In the case of delete=True, a NamedTemporaryFile can be manually + # deleted in a with-statement context without causing an error. + dir = tempfile.mkdtemp() + try: + with tempfile.NamedTemporaryFile(dir=dir, + delete=True, + delete_on_close=False) as f: + f.write(b'blat') + f.close() + os.unlink(f.name) + + finally: + os.rmdir(dir) + + def test_context_man_not_del_if_delete_false(self): + # A NamedTemporaryFile is not deleted if delete = False + dir = tempfile.mkdtemp() + f_name = "" + try: + # Test that delete_on_close=True has no effect if delete=False. + with tempfile.NamedTemporaryFile(dir=dir, delete=False, + delete_on_close=True) as f: + f.write(b'blat') + f_name = f.name + self.assertTrue(os.path.exists(f.name), + f"NamedTemporaryFile {f.name!r} exists after close") + finally: + os.unlink(f_name) + os.rmdir(dir) + + def test_del_by_finalizer(self): + # A NamedTemporaryFile is deleted when finalized in the case of + # delete=True, delete_on_close=False, and no with-statement is used. + def my_func(dir): + f = tempfile.NamedTemporaryFile(dir=dir, delete=True, + delete_on_close=False) + tmp_name = f.name + f.write(b'blat') + # Testing extreme case, where the file is not explicitly closed + # f.close() + return tmp_name + # Make sure that the garbage collector has finalized the file object. + gc.collect() + dir = tempfile.mkdtemp() + try: + tmp_name = my_func(dir) + self.assertFalse(os.path.exists(tmp_name), + f"NamedTemporaryFile {tmp_name!r} " + f"exists after finalizer ") + finally: + os.rmdir(dir) + + def test_correct_finalizer_work_if_already_deleted(self): + # There should be no error in the case of delete=True, + # delete_on_close=False, no with-statement is used, and the file is + # deleted manually. + def my_func(dir)->str: + f = tempfile.NamedTemporaryFile(dir=dir, delete=True, + delete_on_close=False) + tmp_name = f.name + f.write(b'blat') + f.close() + os.unlink(tmp_name) + return tmp_name + # Make sure that the garbage collector has finalized the file object. + gc.collect() + def test_bad_mode(self): dir = tempfile.mkdtemp() self.addCleanup(os_helper.rmtree, dir) @@ -1081,7 +1178,8 @@ def test_iobase_interface(self): missing_attrs = iobase_attrs - spooledtempfile_attrs self.assertFalse( missing_attrs, - 'SpooledTemporaryFile missing attributes from IOBase/BufferedIOBase/TextIOBase' + 'SpooledTemporaryFile missing attributes from ' + 'IOBase/BufferedIOBase/TextIOBase' ) def test_del_on_close(self): diff --git a/Misc/NEWS.d/next/Library/2020-09-28-04-56-04.bpo-14243.YECnxv.rst b/Misc/NEWS.d/next/Library/2020-09-28-04-56-04.bpo-14243.YECnxv.rst new file mode 100644 index 000000000000..267535452ef1 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-09-28-04-56-04.bpo-14243.YECnxv.rst @@ -0,0 +1 @@ +The :class:`tempfile.NamedTemporaryFile` function has a new optional parameter *delete_on_close* From webhook-mailer at python.org Tue Oct 4 18:50:47 2022 From: webhook-mailer at python.org (ezio-melotti) Date: Tue, 04 Oct 2022 22:50:47 -0000 Subject: [Python-checkins] gh-95913: Move py.exe to appropriate What's New section & refine text (#97718) Message-ID: https://github.com/python/cpython/commit/985958187d578cfa311e404588950b29fda95db7 commit: 985958187d578cfa311e404588950b29fda95db7 branch: main author: C.A.M. Gerlach committer: ezio-melotti date: 2022-10-05T00:50:34+02:00 summary: gh-95913: Move py.exe to appropriate What's New section & refine text (#97718) * Move Windows py.exe improvements from Typing section to New Features * Add ref target label and use literal for py.exe * Be clearer/explict about what legacy version arg components reprisent * Apply other minor clarity and textual fixes to py.exe launcher text * Refine phrasing of legacy sentence of py.exe desc Co-authored-by: Ezio Melotti Co-authored-by: Ezio Melotti files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 0d38abfc0005..c7233aab71e6 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -207,6 +207,32 @@ See :pep:`678` for more details. PEP written by Zac Hatfield-Dodds.) +.. _whatsnew311-windows-launcher: + +Windows ``py.exe`` launcher improvements +---------------------------------------- + +The copy of the :ref:`launcher` included with Python 3.11 has been significantly +updated. It now supports company/tag syntax as defined in :pep:`514` using the +``-V:/`` argument instead of the limited ``-.``. +This allows launching distributions other than ``PythonCore``, +the one hosted on `python.org `_. + +When using ``-V:`` selectors, either company or tag can be omitted, but all +installs will be searched. For example, ``-V:OtherPython/`` will select the +"best" tag registered for ``OtherPython``, while ``-V:3.11`` or ``-V:/3.11`` +will select the "best" distribution with tag ``3.11``. + +When using the legacy ``-``, ``-.``, +``--`` or ``-.-`` arguments, +all existing behaviour should be preserved from past versions, +and only releases from ``PythonCore`` will be selected. +However, the ``-64`` suffix now implies "not 32-bit" (not necessarily x86-64), +as there are multiple supported 64-bit platforms. +32-bit runtimes are detected by checking the runtime's tag for a ``-32`` suffix. +All releases of Python since 3.5 have included this in their 32-bit builds. + + .. _new-feat-related-type-hints-311: .. _whatsnew311-typing-features: @@ -401,28 +427,6 @@ See `this message from the Steering Council /`` argument instead of the limited ``-x.y`` argument. This -allows launching distributions other than ``PythonCore``, which is the one -obtained from `python.org `_. - -When using ``-V:`` selectors, either company or tag can be omitted, but all -installs will be searched. For example, ``-V:OtherPython/`` will select the -"best" tag registered for ``OtherPython``, while ``-V:3.11`` or ``-V:/3.11`` -will select the "best" distribution with tag ``3.11``. - -When using legacy ``-x``, ``-x.y``, ``-x-ZZ`` or ``-x.y-ZZ`` arguments, all -existing behaviour should be preserved from past versions. Only releases from -``PythonCore`` will be selected. However, the ``-64`` suffix now implies "not -32-bit", as there are multiple supported 64-bit platforms. 32-bit runtimes are -detected by checking its tag for a ``-32`` suffix. All releases of Python -since 3.5 have included this in their 32-bit builds. - - Other Language Changes ====================== From webhook-mailer at python.org Tue Oct 4 18:54:34 2022 From: webhook-mailer at python.org (orsenthil) Date: Tue, 04 Oct 2022 22:54:34 -0000 Subject: [Python-checkins] gh-88355: Fix backslashes in AF_PIPE (#96543) Message-ID: https://github.com/python/cpython/commit/ff28d8926de92d809e3b7f71d3e44672178ed11e commit: ff28d8926de92d809e3b7f71d3e44672178ed11e branch: main author: cousteau committer: orsenthil date: 2022-10-04T15:54:03-07:00 summary: gh-88355: Fix backslashes in AF_PIPE (#96543) Fix backslashes in AF_PIPE (#88355) The correct syntax for AF_PIPE addresses is `\\.\pipe\blahblah`, not `\.\pipe{blahblah}`, but the syntax markup messed up the backslashes. files: M Doc/library/multiprocessing.rst diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst index 6f6e7881598b..dab115acdc20 100644 --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -2629,9 +2629,9 @@ Address Formats filesystem. * An ``'AF_PIPE'`` address is a string of the form - :samp:`r'\\\\.\\pipe\\{PipeName}'`. To use :func:`Client` to connect to a named + :samp:`r'\\\\\\.\\pipe\\\\{PipeName}'`. To use :func:`Client` to connect to a named pipe on a remote computer called *ServerName* one should use an address of the - form :samp:`r'\\\\{ServerName}\\pipe\\{PipeName}'` instead. + form :samp:`r'\\\\\\\\{ServerName}\\pipe\\\\{PipeName}'` instead. Note that any string beginning with two backslashes is assumed by default to be an ``'AF_PIPE'`` address rather than an ``'AF_UNIX'`` address. From webhook-mailer at python.org Tue Oct 4 18:55:40 2022 From: webhook-mailer at python.org (orsenthil) Date: Tue, 04 Oct 2022 22:55:40 -0000 Subject: [Python-checkins] [3.11] gh-88355: Fix backslashes in AF_PIPE (GH-96543) (#97854) Message-ID: https://github.com/python/cpython/commit/5fdce5d009eddb1aa83b494bb51468312e004f46 commit: 5fdce5d009eddb1aa83b494bb51468312e004f46 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: orsenthil date: 2022-10-04T15:55:34-07:00 summary: [3.11] gh-88355: Fix backslashes in AF_PIPE (GH-96543) (#97854) gh-88355: Fix backslashes in AF_PIPE (GH-96543) Fix backslashes in AF_PIPE (GH-88355) The correct syntax for AF_PIPE addresses is `\\.\pipe\blahblah`, not `\.\pipe{blahblah}`, but the syntax markup messed up the backslashes. (cherry picked from commit ff28d8926de92d809e3b7f71d3e44672178ed11e) Co-authored-by: cousteau Co-authored-by: cousteau files: M Doc/library/multiprocessing.rst diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst index 6f6e7881598b..dab115acdc20 100644 --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -2629,9 +2629,9 @@ Address Formats filesystem. * An ``'AF_PIPE'`` address is a string of the form - :samp:`r'\\\\.\\pipe\\{PipeName}'`. To use :func:`Client` to connect to a named + :samp:`r'\\\\\\.\\pipe\\\\{PipeName}'`. To use :func:`Client` to connect to a named pipe on a remote computer called *ServerName* one should use an address of the - form :samp:`r'\\\\{ServerName}\\pipe\\{PipeName}'` instead. + form :samp:`r'\\\\\\\\{ServerName}\\pipe\\\\{PipeName}'` instead. Note that any string beginning with two backslashes is assumed by default to be an ``'AF_PIPE'`` address rather than an ``'AF_UNIX'`` address. From webhook-mailer at python.org Tue Oct 4 18:55:44 2022 From: webhook-mailer at python.org (orsenthil) Date: Tue, 04 Oct 2022 22:55:44 -0000 Subject: [Python-checkins] [3.10] gh-88355: Fix backslashes in AF_PIPE (GH-96543) (#97855) Message-ID: https://github.com/python/cpython/commit/a980dafd2cd414d17a4f94fc662c448bd8226964 commit: a980dafd2cd414d17a4f94fc662c448bd8226964 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: orsenthil date: 2022-10-04T15:55:39-07:00 summary: [3.10] gh-88355: Fix backslashes in AF_PIPE (GH-96543) (#97855) gh-88355: Fix backslashes in AF_PIPE (GH-96543) Fix backslashes in AF_PIPE (GH-88355) The correct syntax for AF_PIPE addresses is `\\.\pipe\blahblah`, not `\.\pipe{blahblah}`, but the syntax markup messed up the backslashes. (cherry picked from commit ff28d8926de92d809e3b7f71d3e44672178ed11e) Co-authored-by: cousteau Co-authored-by: cousteau files: M Doc/library/multiprocessing.rst diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst index 48bccabe6a31..95e74b9b93d6 100644 --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -2595,9 +2595,9 @@ Address Formats filesystem. * An ``'AF_PIPE'`` address is a string of the form - :samp:`r'\\\\.\\pipe\\{PipeName}'`. To use :func:`Client` to connect to a named + :samp:`r'\\\\\\.\\pipe\\\\{PipeName}'`. To use :func:`Client` to connect to a named pipe on a remote computer called *ServerName* one should use an address of the - form :samp:`r'\\\\{ServerName}\\pipe\\{PipeName}'` instead. + form :samp:`r'\\\\\\\\{ServerName}\\pipe\\\\{PipeName}'` instead. Note that any string beginning with two backslashes is assumed by default to be an ``'AF_PIPE'`` address rather than an ``'AF_UNIX'`` address. From webhook-mailer at python.org Tue Oct 4 18:59:05 2022 From: webhook-mailer at python.org (miss-islington) Date: Tue, 04 Oct 2022 22:59:05 -0000 Subject: [Python-checkins] gh-95913: Move py.exe to appropriate What's New section & refine text (GH-97718) Message-ID: https://github.com/python/cpython/commit/a685cc0a5e74106a671841caf27b8d729e695053 commit: a685cc0a5e74106a671841caf27b8d729e695053 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-04T15:58:59-07:00 summary: gh-95913: Move py.exe to appropriate What's New section & refine text (GH-97718) * Move Windows py.exe improvements from Typing section to New Features * Add ref target label and use literal for py.exe * Be clearer/explict about what legacy version arg components reprisent * Apply other minor clarity and textual fixes to py.exe launcher text * Refine phrasing of legacy sentence of py.exe desc Co-authored-by: Ezio Melotti Co-authored-by: Ezio Melotti (cherry picked from commit 985958187d578cfa311e404588950b29fda95db7) Co-authored-by: C.A.M. Gerlach files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index fe36f99f5382..f3202f0c6d79 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -207,6 +207,32 @@ See :pep:`678` for more details. PEP written by Zac Hatfield-Dodds.) +.. _whatsnew311-windows-launcher: + +Windows ``py.exe`` launcher improvements +---------------------------------------- + +The copy of the :ref:`launcher` included with Python 3.11 has been significantly +updated. It now supports company/tag syntax as defined in :pep:`514` using the +``-V:/`` argument instead of the limited ``-.``. +This allows launching distributions other than ``PythonCore``, +the one hosted on `python.org `_. + +When using ``-V:`` selectors, either company or tag can be omitted, but all +installs will be searched. For example, ``-V:OtherPython/`` will select the +"best" tag registered for ``OtherPython``, while ``-V:3.11`` or ``-V:/3.11`` +will select the "best" distribution with tag ``3.11``. + +When using the legacy ``-``, ``-.``, +``--`` or ``-.-`` arguments, +all existing behaviour should be preserved from past versions, +and only releases from ``PythonCore`` will be selected. +However, the ``-64`` suffix now implies "not 32-bit" (not necessarily x86-64), +as there are multiple supported 64-bit platforms. +32-bit runtimes are detected by checking the runtime's tag for a ``-32`` suffix. +All releases of Python since 3.5 have included this in their 32-bit builds. + + .. _new-feat-related-type-hints-311: .. _whatsnew311-typing-features: @@ -401,28 +427,6 @@ See `this message from the Steering Council /`` argument instead of the limited ``-x.y`` argument. This -allows launching distributions other than ``PythonCore``, which is the one -obtained from `python.org `_. - -When using ``-V:`` selectors, either company or tag can be omitted, but all -installs will be searched. For example, ``-V:OtherPython/`` will select the -"best" tag registered for ``OtherPython``, while ``-V:3.11`` or ``-V:/3.11`` -will select the "best" distribution with tag ``3.11``. - -When using legacy ``-x``, ``-x.y``, ``-x-ZZ`` or ``-x.y-ZZ`` arguments, all -existing behaviour should be preserved from past versions. Only releases from -``PythonCore`` will be selected. However, the ``-64`` suffix now implies "not -32-bit", as there are multiple supported 64-bit platforms. 32-bit runtimes are -detected by checking its tag for a ``-32`` suffix. All releases of Python -since 3.5 have included this in their 32-bit builds. - - Other Language Changes ====================== From webhook-mailer at python.org Tue Oct 4 19:11:05 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 04 Oct 2022 23:11:05 -0000 Subject: [Python-checkins] gh-93738: Documentation C syntax (:c:type:`Py_UNICODE*` -> :c:expr:`Py_UNICODE*`) (#97784) Message-ID: https://github.com/python/cpython/commit/a081cae2a2cd1248ad067c3f7dc218ea7e3d203a commit: a081cae2a2cd1248ad067c3f7dc218ea7e3d203a branch: main author: Adam Turner <9087854+AA-Turner at users.noreply.github.com> committer: ambv date: 2022-10-04T16:10:57-07:00 summary: gh-93738: Documentation C syntax (:c:type:`Py_UNICODE*` -> :c:expr:`Py_UNICODE*`) (#97784) :c:type:`Py_UNICODE*` -> :c:expr:`Py_UNICODE*` files: M Doc/whatsnew/3.3.rst diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst index 2d78f81798f2..609370bad274 100644 --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -2267,7 +2267,7 @@ The :c:type:`Py_UNICODE` has been deprecated by :pep:`393` and will be removed in Python 4. All functions using this type are deprecated: Unicode functions and methods using :c:type:`Py_UNICODE` and -:c:type:`Py_UNICODE*` types: +:c:expr:`Py_UNICODE*` types: * :c:macro:`PyUnicode_FromUnicode`: use :c:func:`PyUnicode_FromWideChar` or :c:func:`PyUnicode_FromKindAndData` From webhook-mailer at python.org Tue Oct 4 19:11:28 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 04 Oct 2022 23:11:28 -0000 Subject: [Python-checkins] gh-93738: Documentation C syntax (:c:type:`PyUnicodeObject*` -> :c:expr:`PyUnicodeObject*`) (#97783) Message-ID: https://github.com/python/cpython/commit/898834e27b82bd1f3532b6448a862a7a9cdeff66 commit: 898834e27b82bd1f3532b6448a862a7a9cdeff66 branch: main author: Adam Turner <9087854+AA-Turner at users.noreply.github.com> committer: ambv date: 2022-10-04T16:11:20-07:00 summary: gh-93738: Documentation C syntax (:c:type:`PyUnicodeObject*` -> :c:expr:`PyUnicodeObject*`) (#97783) :c:type:`PyUnicodeObject*` -> :c:expr:`PyUnicodeObject*` files: M Doc/c-api/unicode.rst diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst index 99afebd762a4..f8b6fef33215 100644 --- a/Doc/c-api/unicode.rst +++ b/Doc/c-api/unicode.rst @@ -728,7 +728,7 @@ conversion function: ParseTuple converter: decode :class:`bytes` objects -- obtained either directly or indirectly through the :class:`os.PathLike` interface -- to :class:`str` using :c:func:`PyUnicode_DecodeFSDefaultAndSize`; :class:`str` - objects are output as-is. *result* must be a :c:type:`PyUnicodeObject*` which + objects are output as-is. *result* must be a :c:expr:`PyUnicodeObject*` which must be released when it is no longer used. .. versionadded:: 3.2 From webhook-mailer at python.org Tue Oct 4 19:11:42 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 04 Oct 2022 23:11:42 -0000 Subject: [Python-checkins] gh-93738: Documentation C syntax (:c:type:`PyBytesObject*` -> :c:expr:`PyBytesObject*`) (#97782) Message-ID: https://github.com/python/cpython/commit/9ebc50866b58a0ee2985c6540a67fee8a4a49e4d commit: 9ebc50866b58a0ee2985c6540a67fee8a4a49e4d branch: main author: Adam Turner <9087854+AA-Turner at users.noreply.github.com> committer: ambv date: 2022-10-04T16:11:34-07:00 summary: gh-93738: Documentation C syntax (:c:type:`PyBytesObject*` -> :c:expr:`PyBytesObject*`) (#97782) :c:type:`PyBytesObject*` -> :c:expr:`PyBytesObject*` files: M Doc/c-api/unicode.rst diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst index f8b6fef33215..ec9c5d089c57 100644 --- a/Doc/c-api/unicode.rst +++ b/Doc/c-api/unicode.rst @@ -711,7 +711,7 @@ conversion function: ParseTuple converter: encode :class:`str` objects -- obtained directly or through the :class:`os.PathLike` interface -- to :class:`bytes` using :c:func:`PyUnicode_EncodeFSDefault`; :class:`bytes` objects are output as-is. - *result* must be a :c:type:`PyBytesObject*` which must be released when it is + *result* must be a :c:expr:`PyBytesObject*` which must be released when it is no longer used. .. versionadded:: 3.1 From webhook-mailer at python.org Tue Oct 4 19:12:02 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 04 Oct 2022 23:12:02 -0000 Subject: [Python-checkins] gh-93738: Documentation C syntax (:c:type:`PyTupleObject*` -> :c:expr:`PyTupleObject*`) (#97780) Message-ID: https://github.com/python/cpython/commit/510baa429affb832d7b4ed68182e59daa2815d2e commit: 510baa429affb832d7b4ed68182e59daa2815d2e branch: main author: Adam Turner <9087854+AA-Turner at users.noreply.github.com> committer: ambv date: 2022-10-04T16:11:54-07:00 summary: gh-93738: Documentation C syntax (:c:type:`PyTupleObject*` -> :c:expr:`PyTupleObject*`) (#97780) :c:type:`PyTupleObject*` -> :c:expr:`PyTupleObject*` files: M Doc/c-api/typehints.rst diff --git a/Doc/c-api/typehints.rst b/Doc/c-api/typehints.rst index 8b0b9b651e80..88554a346c0d 100644 --- a/Doc/c-api/typehints.rst +++ b/Doc/c-api/typehints.rst @@ -16,7 +16,7 @@ two types exist -- :ref:`GenericAlias ` and :class:`types.GenericAlias`. The *origin* and *args* arguments set the ``GenericAlias``\ 's ``__origin__`` and ``__args__`` attributes respectively. *origin* should be a :c:type:`PyTypeObject*`, and *args* can be a - :c:type:`PyTupleObject*` or any ``PyObject*``. If *args* passed is + :c:expr:`PyTupleObject*` or any ``PyObject*``. If *args* passed is not a tuple, a 1-tuple is automatically constructed and ``__args__`` is set to ``(args,)``. Minimal checking is done for the arguments, so the function will succeed even From webhook-mailer at python.org Tue Oct 4 19:12:30 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 04 Oct 2022 23:12:30 -0000 Subject: [Python-checkins] gh-93738: Documentation C syntax (:c:type:`PyInterpreterState *` -> :c:expr:`PyInterpreterState *`) (#97777) Message-ID: https://github.com/python/cpython/commit/4ebb0250314b57637d213cd5bc5f5ce5dd911d94 commit: 4ebb0250314b57637d213cd5bc5f5ce5dd911d94 branch: main author: Adam Turner <9087854+AA-Turner at users.noreply.github.com> committer: ambv date: 2022-10-04T16:12:22-07:00 summary: gh-93738: Documentation C syntax (:c:type:`PyInterpreterState *` -> :c:expr:`PyInterpreterState *`) (#97777) :c:type:`PyInterpreterState *` -> :c:expr:`PyInterpreterState *` files: M Doc/c-api/init.rst diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index 2a9cf0ea7022..ec3034893b90 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -1023,7 +1023,7 @@ code, or when embedding the Python interpreter: .. c:type:: PyThreadState This data structure represents the state of a single thread. The only public - data member is :attr:`interp` (:c:type:`PyInterpreterState *`), which points to + data member is :attr:`interp` (:c:expr:`PyInterpreterState *`), which points to this thread's interpreter state. From webhook-mailer at python.org Tue Oct 4 19:13:11 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 04 Oct 2022 23:13:11 -0000 Subject: [Python-checkins] gh-93738: Documentation C syntax (:c:type:`PyObject` -> :c:expr:`PyObject`) (#97776) Message-ID: https://github.com/python/cpython/commit/0bf6a617ed1832bc4803e532c8d6b3427cf48b13 commit: 0bf6a617ed1832bc4803e532c8d6b3427cf48b13 branch: main author: Adam Turner <9087854+AA-Turner at users.noreply.github.com> committer: ambv date: 2022-10-04T16:13:03-07:00 summary: gh-93738: Documentation C syntax (:c:type:`PyObject` -> :c:expr:`PyObject`) (#97776) :c:type:`PyObject` -> :c:expr:`PyObject` files: M Doc/c-api/arg.rst M Doc/c-api/call.rst M Doc/c-api/dict.rst M Doc/c-api/exceptions.rst M Doc/c-api/init.rst M Doc/c-api/intro.rst M Doc/c-api/structures.rst M Doc/c-api/tuple.rst M Doc/c-api/typeobj.rst M Doc/library/ctypes.rst diff --git a/Doc/c-api/arg.rst b/Doc/c-api/arg.rst index 2e63e4d4563d..c9dcf746ef2f 100644 --- a/Doc/c-api/arg.rst +++ b/Doc/c-api/arg.rst @@ -129,17 +129,17 @@ which disallows mutable objects such as :class:`bytearray`. ``S`` (:class:`bytes`) [PyBytesObject \*] Requires that the Python object is a :class:`bytes` object, without attempting any conversion. Raises :exc:`TypeError` if the object is not - a bytes object. The C variable may also be declared as :c:type:`PyObject*`. + a bytes object. The C variable may also be declared as :c:expr:`PyObject*`. ``Y`` (:class:`bytearray`) [PyByteArrayObject \*] Requires that the Python object is a :class:`bytearray` object, without attempting any conversion. Raises :exc:`TypeError` if the object is not - a :class:`bytearray` object. The C variable may also be declared as :c:type:`PyObject*`. + a :class:`bytearray` object. The C variable may also be declared as :c:expr:`PyObject*`. ``U`` (:class:`str`) [PyObject \*] Requires that the Python object is a Unicode object, without attempting any conversion. Raises :exc:`TypeError` if the object is not a Unicode - object. The C variable may also be declared as :c:type:`PyObject*`. + object. The C variable may also be declared as :c:expr:`PyObject*`. ``w*`` (read-write :term:`bytes-like object`) [Py_buffer] This format accepts any object which implements the read-write buffer @@ -283,7 +283,7 @@ Other objects ``O!`` (object) [*typeobject*, PyObject \*] Store a Python object in a C object pointer. This is similar to ``O``, but takes two C arguments: the first is the address of a Python type object, the - second is the address of the C variable (of type :c:type:`PyObject*`) into which + second is the address of the C variable (of type :c:expr:`PyObject*`) into which the object pointer is stored. If the Python object does not have the required type, :exc:`TypeError` is raised. @@ -444,7 +444,7 @@ API Functions *args*; it must actually be a tuple. The length of the tuple must be at least *min* and no more than *max*; *min* and *max* may be equal. Additional arguments must be passed to the function, each of which should be a pointer to a - :c:type:`PyObject*` variable; these will be filled in with the values from + :c:expr:`PyObject*` variable; these will be filled in with the values from *args*; they will contain :term:`borrowed references `. The variables which correspond to optional parameters not given by *args* will not be filled in; these should diff --git a/Doc/c-api/call.rst b/Doc/c-api/call.rst index 11d5c33a2d15..6fb2e1519610 100644 --- a/Doc/c-api/call.rst +++ b/Doc/c-api/call.rst @@ -284,7 +284,7 @@ please see individual documentation for details. This is the equivalent of the Python expression: ``callable(*args)``. - Note that if you only pass :c:type:`PyObject *` args, + Note that if you only pass :c:expr:`PyObject *` args, :c:func:`PyObject_CallFunctionObjArgs` is a faster alternative. .. versionchanged:: 3.4 @@ -305,7 +305,7 @@ please see individual documentation for details. This is the equivalent of the Python expression: ``obj.name(arg1, arg2, ...)``. - Note that if you only pass :c:type:`PyObject *` args, + Note that if you only pass :c:expr:`PyObject *` args, :c:func:`PyObject_CallMethodObjArgs` is a faster alternative. .. versionchanged:: 3.4 @@ -315,7 +315,7 @@ please see individual documentation for details. .. c:function:: PyObject* PyObject_CallFunctionObjArgs(PyObject *callable, ...) Call a callable Python object *callable*, with a variable number of - :c:type:`PyObject *` arguments. The arguments are provided as a variable number + :c:expr:`PyObject *` arguments. The arguments are provided as a variable number of parameters followed by *NULL*. Return the result of the call on success, or raise an exception and return @@ -329,7 +329,7 @@ please see individual documentation for details. Call a method of the Python object *obj*, where the name of the method is given as a Python string object in *name*. It is called with a variable number of - :c:type:`PyObject *` arguments. The arguments are provided as a variable number + :c:expr:`PyObject *` arguments. The arguments are provided as a variable number of parameters followed by *NULL*. Return the result of the call on success, or raise an exception and return diff --git a/Doc/c-api/dict.rst b/Doc/c-api/dict.rst index d257c9b5f763..67c2026baa14 100644 --- a/Doc/c-api/dict.rst +++ b/Doc/c-api/dict.rst @@ -118,7 +118,7 @@ Dictionary Objects .. c:function:: PyObject* PyDict_GetItemString(PyObject *p, const char *key) This is the same as :c:func:`PyDict_GetItem`, but *key* is specified as a - :c:type:`const char*`, rather than a :c:type:`PyObject*`. + :c:type:`const char*`, rather than a :c:expr:`PyObject*`. Note that exceptions which occur while calling :meth:`__hash__` and :meth:`__eq__` methods and creating a temporary string object @@ -167,7 +167,7 @@ Dictionary Objects prior to the first call to this function to start the iteration; the function returns true for each pair in the dictionary, and false once all pairs have been reported. The parameters *pkey* and *pvalue* should either - point to :c:type:`PyObject*` variables that will be filled in with each key + point to :c:expr:`PyObject*` variables that will be filled in with each key and value, respectively, or may be ``NULL``. Any references returned through them are borrowed. *ppos* should not be altered during iteration. Its value represents offsets within the internal dictionary structure, and diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index df73f23d2de2..7221957fe1db 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -848,7 +848,7 @@ Standard Exceptions All standard Python exceptions are available as global variables whose names are ``PyExc_`` followed by the Python exception name. These have the type -:c:type:`PyObject*`; they are all class objects. For completeness, here are all +:c:expr:`PyObject*`; they are all class objects. For completeness, here are all the variables: .. index:: @@ -1068,7 +1068,7 @@ Standard Warning Categories All standard Python warning categories are available as global variables whose names are ``PyExc_`` followed by the Python exception name. These have the type -:c:type:`PyObject*`; they are all class objects. For completeness, here are all +:c:expr:`PyObject*`; they are all class objects. For completeness, here are all the variables: .. index:: diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index ec3034893b90..cb3bfedc97e8 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -1875,7 +1875,7 @@ you need to include :file:`pythread.h` to use thread-local storage. .. note:: None of these API functions handle memory management on behalf of the :c:type:`void*` values. You need to allocate and deallocate them yourself. - If the :c:type:`void*` values happen to be :c:type:`PyObject*`, these + If the :c:type:`void*` values happen to be :c:expr:`PyObject*`, these functions don't do refcount operations on them either. .. _thread-specific-storage-api: diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst index 557ccfc05234..991bc3b09fd8 100644 --- a/Doc/c-api/intro.rst +++ b/Doc/c-api/intro.rst @@ -264,13 +264,13 @@ Objects, Types and Reference Counts .. index:: object: type Most Python/C API functions have one or more arguments as well as a return value -of type :c:type:`PyObject*`. This type is a pointer to an opaque data type +of type :c:expr:`PyObject*`. This type is a pointer to an opaque data type representing an arbitrary Python object. Since all Python object types are treated the same way by the Python language in most situations (e.g., assignments, scope rules, and argument passing), it is only fitting that they should be represented by a single C type. Almost all Python objects live on the heap: you never declare an automatic or static variable of type -:c:type:`PyObject`, only pointer variables of type :c:type:`PyObject*` can be +:c:type:`PyObject`, only pointer variables of type :c:expr:`PyObject*` can be declared. The sole exception are the type objects; since these must never be deallocated, they are typically static :c:type:`PyTypeObject` objects. diff --git a/Doc/c-api/structures.rst b/Doc/c-api/structures.rst index f1eb09bb5691..1cc5c4647120 100644 --- a/Doc/c-api/structures.rst +++ b/Doc/c-api/structures.rst @@ -27,7 +27,7 @@ the definition of all other Python objects. object. In a normal "release" build, it contains only the object's reference count and a pointer to the corresponding type object. Nothing is actually declared to be a :c:type:`PyObject`, but every pointer - to a Python object can be cast to a :c:type:`PyObject*`. Access to the + to a Python object can be cast to a :c:expr:`PyObject*`. Access to the members must be done by using the macros :c:macro:`Py_REFCNT` and :c:macro:`Py_TYPE`. @@ -184,7 +184,7 @@ Implementing functions and methods .. c:type:: PyCFunction Type of the functions used to implement most Python callables in C. - Functions of this type take two :c:type:`PyObject*` parameters and return + Functions of this type take two :c:expr:`PyObject*` parameters and return one such value. If the return value is ``NULL``, an exception shall have been set. If not ``NULL``, the return value is interpreted as the return value of the function as exposed in Python. The function must return a new @@ -263,10 +263,10 @@ Implementing functions and methods +------------------+---------------+-------------------------------+ The :attr:`ml_meth` is a C function pointer. The functions may be of different -types, but they always return :c:type:`PyObject*`. If the function is not of +types, but they always return :c:expr:`PyObject*`. If the function is not of the :c:type:`PyCFunction`, the compiler will require a cast in the method table. Even though :c:type:`PyCFunction` defines the first parameter as -:c:type:`PyObject*`, it is common that the method implementation uses the +:c:expr:`PyObject*`, it is common that the method implementation uses the specific C type of the *self* object. The :attr:`ml_flags` field is a bitfield which can include the following flags. @@ -278,7 +278,7 @@ There are these calling conventions: .. data:: METH_VARARGS This is the typical calling convention, where the methods have the type - :c:type:`PyCFunction`. The function expects two :c:type:`PyObject*` values. + :c:type:`PyCFunction`. The function expects two :c:expr:`PyObject*` values. The first one is the *self* object for methods; for module functions, it is the module object. The second parameter (often called *args*) is a tuple object representing all arguments. This parameter is typically processed @@ -299,7 +299,7 @@ There are these calling conventions: Fast calling convention supporting only positional arguments. The methods have the type :c:type:`_PyCFunctionFast`. The first parameter is *self*, the second parameter is a C array - of :c:type:`PyObject*` values indicating the arguments and the third + of :c:expr:`PyObject*` values indicating the arguments and the third parameter is the number of arguments (the length of the array). .. versionadded:: 3.7 @@ -315,7 +315,7 @@ There are these calling conventions: with methods of type :c:type:`_PyCFunctionFastWithKeywords`. Keyword arguments are passed the same way as in the :ref:`vectorcall protocol `: - there is an additional fourth :c:type:`PyObject*` parameter + there is an additional fourth :c:expr:`PyObject*` parameter which is a tuple representing the names of the keyword arguments (which are guaranteed to be strings) or possibly ``NULL`` if there are no keywords. The values of the keyword @@ -354,7 +354,7 @@ There are these calling conventions: Methods with a single object argument can be listed with the :const:`METH_O` flag, instead of invoking :c:func:`PyArg_ParseTuple` with a ``"O"`` argument. They have the type :c:type:`PyCFunction`, with the *self* parameter, and a - :c:type:`PyObject*` parameter representing the single argument. + :c:expr:`PyObject*` parameter representing the single argument. These two constants are not used to indicate the calling convention but the @@ -522,7 +522,7 @@ Accessing attributes of extension types | | | getter and setter | +-------------+------------------+-----------------------------------+ - The ``get`` function takes one :c:type:`PyObject*` parameter (the + The ``get`` function takes one :c:expr:`PyObject*` parameter (the instance) and a function pointer (the associated ``closure``):: typedef PyObject *(*getter)(PyObject *, void *); @@ -530,7 +530,7 @@ Accessing attributes of extension types It should return a new reference on success or ``NULL`` with a set exception on failure. - ``set`` functions take two :c:type:`PyObject*` parameters (the instance and + ``set`` functions take two :c:expr:`PyObject*` parameters (the instance and the value to be set) and a function pointer (the associated ``closure``):: typedef int (*setter)(PyObject *, PyObject *, void *); diff --git a/Doc/c-api/tuple.rst b/Doc/c-api/tuple.rst index 9b85522600d4..0bfd4b308d93 100644 --- a/Doc/c-api/tuple.rst +++ b/Doc/c-api/tuple.rst @@ -161,7 +161,7 @@ type. .. c:type:: PyStructSequence_Field Describes a field of a struct sequence. As a struct sequence is modeled as a - tuple, all fields are typed as :c:type:`PyObject*`. The index in the + tuple, all fields are typed as :c:expr:`PyObject*`. The index in the :attr:`fields` array of the :c:type:`PyStructSequence_Desc` determines which field of the struct sequence is described. diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index 2439f7c41b56..32ecc111d9df 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -1520,7 +1520,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) than zero and contains the offset in the instance structure of the weak reference list head (ignoring the GC header, if present); this offset is used by :c:func:`PyObject_ClearWeakRefs` and the :c:func:`PyWeakref_\*` functions. The - instance structure needs to include a field of type :c:type:`PyObject*` which is + instance structure needs to include a field of type :c:expr:`PyObject*` which is initialized to ``NULL``. Do not confuse this field with :c:member:`~PyTypeObject.tp_weaklist`; that is the list head for diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index 9546696e1c3d..685ff835346f 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -2387,8 +2387,8 @@ These are the fundamental ctypes data types: .. class:: py_object - Represents the C :c:type:`PyObject *` datatype. Calling this without an - argument creates a ``NULL`` :c:type:`PyObject *` pointer. + Represents the C :c:expr:`PyObject *` datatype. Calling this without an + argument creates a ``NULL`` :c:expr:`PyObject *` pointer. The :mod:`ctypes.wintypes` module provides quite some other Windows specific data types, for example :c:type:`HWND`, :c:type:`WPARAM`, or :c:type:`DWORD`. Some From webhook-mailer at python.org Tue Oct 4 19:16:45 2022 From: webhook-mailer at python.org (ezio-melotti) Date: Tue, 04 Oct 2022 23:16:45 -0000 Subject: [Python-checkins] gh-95913: Copyedit/improve Other Language Changes What's New section (#97719) Message-ID: https://github.com/python/cpython/commit/a77d9dedcd0d52c2663e9de4417dec9d1c5199f4 commit: a77d9dedcd0d52c2663e9de4417dec9d1c5199f4 branch: main author: C.A.M. Gerlach committer: ezio-melotti date: 2022-10-05T01:16:37+02:00 summary: gh-95913: Copyedit/improve Other Language Changes What's New section (#97719) * Add/refine cross references to items in other lang changes section * Unify context manager exception changes into single non-repetitive item * More clearly describe the intent and consequences of the -P option * Apply minor clarifications & copyedits to rest of section * Tweak the formatting of module references Co-authored-by: Ezio Melotti Co-authored-by: Ezio Melotti files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index c7233aab71e6..173580d58941 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -427,52 +427,57 @@ See `this message from the Steering Council `. (See - :issue:`46725` for more details.) - -* Asynchronous comprehensions are now allowed inside comprehensions in - asynchronous functions. Outer comprehensions implicitly become - asynchronous. (Contributed by Serhiy Storchaka in :issue:`33346`.) +* Starred unpacking expressions can now be used in :keyword:`for` statements. + (See :issue:`46725` for more details.) -* A :exc:`TypeError` is now raised instead of an :exc:`AttributeError` in - :meth:`contextlib.ExitStack.enter_context` and - :meth:`contextlib.AsyncExitStack.enter_async_context` for objects which do not - support the :term:`context manager` or :term:`asynchronous context manager` - protocols correspondingly. - (Contributed by Serhiy Storchaka in :issue:`44471`.) +* Asynchronous :ref:`comprehensions ` are now allowed + inside comprehensions in :ref:`asynchronous functions `. + Outer comprehensions implicitly become asynchronous in this case. + (Contributed by Serhiy Storchaka in :issue:`33346`.) * A :exc:`TypeError` is now raised instead of an :exc:`AttributeError` in - :keyword:`with` and :keyword:`async with` statements for objects which do not - support the :term:`context manager` or :term:`asynchronous context manager` - protocols correspondingly. - (Contributed by Serhiy Storchaka in :issue:`12022`.) - -* Added :meth:`object.__getstate__` which provides the default - implementation of the ``__getstate__()`` method. :mod:`Copying ` - and :mod:`pickling ` instances of subclasses of builtin types + :keyword:`with` statements and :meth:`contextlib.ExitStack.enter_context` + for objects that do not support the :term:`context manager` protocol, + and in :keyword:`async with` statements and + :meth:`contextlib.AsyncExitStack.enter_async_context` + for objects not supporting the :term:`asynchronous context manager` protocol. + (Contributed by Serhiy Storchaka in :issue:`12022` and :issue:`44471`.) + +* Added :meth:`object.__getstate__`, which provides the default + implementation of the :meth:`!__getstate__` method. :mod:`copy`\ing + and :mod:`pickle`\ing instances of subclasses of builtin types :class:`bytearray`, :class:`set`, :class:`frozenset`, :class:`collections.OrderedDict`, :class:`collections.deque`, :class:`weakref.WeakSet`, and :class:`datetime.tzinfo` now copies and pickles instance attributes implemented as :term:`slots <__slots__>`. (Contributed by Serhiy Storchaka in :issue:`26579`.) -* Add :option:`-P` command line option and :envvar:`PYTHONSAFEPATH` environment - variable to not prepend a potentially unsafe path to :data:`sys.path` such as - the current directory, the script's directory or an empty string. +* Added a :option:`-P` command line option + and a :envvar:`PYTHONSAFEPATH` environment variable, + which disable the automatic prepending to :data:`sys.path` + of the script's directory when running a script, + or the current directory when using :option:`-c` and :option:`-m`. + This ensures only stdlib and installed modules + are picked up by :keyword:`import`, + and avoids unintentionally or maliciously shadowing modules + with those in a local (and typically user-writable) directory. (Contributed by Victor Stinner in :gh:`57684`.) -* A ``"z"`` option was added to the format specification mini-language that - coerces negative zero to zero after rounding to the format precision. See - :pep:`682` for more details. (Contributed by John Belmonte in :gh:`90153`.) +* A ``"z"`` option was added to the :ref:`formatspec` that + coerces negative to positive zero after rounding to the format precision. + See :pep:`682` for more details. + (Contributed by John Belmonte in :gh:`90153`.) -* Bytes are no longer accepted on :attr:`sys.path`. Support broke sometime - between Python 3.2 and 3.6 with no one noticing until after Python 3.10.0 - was released. Bringing back support would also be problematic due to - interactions between :option:`-b` and :attr:`sys.path_importer_cache` when - there is a mixture of strings and bytes keys. +* Bytes are no longer accepted on :data:`sys.path`. Support broke sometime + between Python 3.2 and 3.6, with no one noticing until after Python 3.10.0 + was released. In addition, bringing back support would be problematic due to + interactions between :option:`-b` and :data:`sys.path_importer_cache` when + there is a mixture of :class:`str` and :class:`bytes` keys. (Contributed by Thomas Grainger in :gh:`91181`.) Other CPython Implementation Changes From webhook-mailer at python.org Tue Oct 4 19:18:18 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 04 Oct 2022 23:18:18 -0000 Subject: [Python-checkins] gh-93738: Documentation C syntax (:c:data:`view->obj` -> :c:expr:`view->obj`) (#97773) Message-ID: https://github.com/python/cpython/commit/fa59bda8d30ea0b6c19007205b57c800c944304c commit: fa59bda8d30ea0b6c19007205b57c800c944304c branch: main author: Adam Turner <9087854+AA-Turner at users.noreply.github.com> committer: ambv date: 2022-10-04T16:18:09-07:00 summary: gh-93738: Documentation C syntax (:c:data:`view->obj` -> :c:expr:`view->obj`) (#97773) :c:data:`view->obj` -> :c:expr:`view->obj` files: M Doc/c-api/typeobj.rst diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index 32ecc111d9df..86c0830e7a9c 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -2356,13 +2356,13 @@ Buffer Object Structures steps: (1) Check if the request can be met. If not, raise :c:data:`PyExc_BufferError`, - set :c:data:`view->obj` to ``NULL`` and return ``-1``. + set :c:expr:`view->obj` to ``NULL`` and return ``-1``. (2) Fill in the requested fields. (3) Increment an internal counter for the number of exports. - (4) Set :c:data:`view->obj` to *exporter* and increment :c:data:`view->obj`. + (4) Set :c:expr:`view->obj` to *exporter* and increment :c:expr:`view->obj`. (5) Return ``0``. @@ -2370,10 +2370,10 @@ Buffer Object Structures schemes can be used: * Re-export: Each member of the tree acts as the exporting object and - sets :c:data:`view->obj` to a new reference to itself. + sets :c:expr:`view->obj` to a new reference to itself. * Redirect: The buffer request is redirected to the root object of the - tree. Here, :c:data:`view->obj` will be a new reference to the root + tree. Here, :c:expr:`view->obj` will be a new reference to the root object. The individual fields of *view* are described in section @@ -2415,7 +2415,7 @@ Buffer Object Structures *view* argument. - This function MUST NOT decrement :c:data:`view->obj`, since that is + This function MUST NOT decrement :c:expr:`view->obj`, since that is done automatically in :c:func:`PyBuffer_Release` (this scheme is useful for breaking reference cycles). From webhook-mailer at python.org Tue Oct 4 19:24:56 2022 From: webhook-mailer at python.org (miss-islington) Date: Tue, 04 Oct 2022 23:24:56 -0000 Subject: [Python-checkins] gh-95913: Copyedit/improve Other Language Changes What's New section (GH-97719) Message-ID: https://github.com/python/cpython/commit/a13b4e8ca67d612386def140093ba024d410a811 commit: a13b4e8ca67d612386def140093ba024d410a811 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-04T16:24:50-07:00 summary: gh-95913: Copyedit/improve Other Language Changes What's New section (GH-97719) * Add/refine cross references to items in other lang changes section * Unify context manager exception changes into single non-repetitive item * More clearly describe the intent and consequences of the -P option * Apply minor clarifications & copyedits to rest of section * Tweak the formatting of module references Co-authored-by: Ezio Melotti Co-authored-by: Ezio Melotti (cherry picked from commit a77d9dedcd0d52c2663e9de4417dec9d1c5199f4) Co-authored-by: C.A.M. Gerlach files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index f3202f0c6d79..8906be1eccda 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -427,52 +427,57 @@ See `this message from the Steering Council `. (See - :issue:`46725` for more details.) - -* Asynchronous comprehensions are now allowed inside comprehensions in - asynchronous functions. Outer comprehensions implicitly become - asynchronous. (Contributed by Serhiy Storchaka in :issue:`33346`.) +* Starred unpacking expressions can now be used in :keyword:`for` statements. + (See :issue:`46725` for more details.) -* A :exc:`TypeError` is now raised instead of an :exc:`AttributeError` in - :meth:`contextlib.ExitStack.enter_context` and - :meth:`contextlib.AsyncExitStack.enter_async_context` for objects which do not - support the :term:`context manager` or :term:`asynchronous context manager` - protocols correspondingly. - (Contributed by Serhiy Storchaka in :issue:`44471`.) +* Asynchronous :ref:`comprehensions ` are now allowed + inside comprehensions in :ref:`asynchronous functions `. + Outer comprehensions implicitly become asynchronous in this case. + (Contributed by Serhiy Storchaka in :issue:`33346`.) * A :exc:`TypeError` is now raised instead of an :exc:`AttributeError` in - :keyword:`with` and :keyword:`async with` statements for objects which do not - support the :term:`context manager` or :term:`asynchronous context manager` - protocols correspondingly. - (Contributed by Serhiy Storchaka in :issue:`12022`.) - -* Added :meth:`object.__getstate__` which provides the default - implementation of the ``__getstate__()`` method. :mod:`Copying ` - and :mod:`pickling ` instances of subclasses of builtin types + :keyword:`with` statements and :meth:`contextlib.ExitStack.enter_context` + for objects that do not support the :term:`context manager` protocol, + and in :keyword:`async with` statements and + :meth:`contextlib.AsyncExitStack.enter_async_context` + for objects not supporting the :term:`asynchronous context manager` protocol. + (Contributed by Serhiy Storchaka in :issue:`12022` and :issue:`44471`.) + +* Added :meth:`object.__getstate__`, which provides the default + implementation of the :meth:`!__getstate__` method. :mod:`copy`\ing + and :mod:`pickle`\ing instances of subclasses of builtin types :class:`bytearray`, :class:`set`, :class:`frozenset`, :class:`collections.OrderedDict`, :class:`collections.deque`, :class:`weakref.WeakSet`, and :class:`datetime.tzinfo` now copies and pickles instance attributes implemented as :term:`slots <__slots__>`. (Contributed by Serhiy Storchaka in :issue:`26579`.) -* Add :option:`-P` command line option and :envvar:`PYTHONSAFEPATH` environment - variable to not prepend a potentially unsafe path to :data:`sys.path` such as - the current directory, the script's directory or an empty string. +* Added a :option:`-P` command line option + and a :envvar:`PYTHONSAFEPATH` environment variable, + which disable the automatic prepending to :data:`sys.path` + of the script's directory when running a script, + or the current directory when using :option:`-c` and :option:`-m`. + This ensures only stdlib and installed modules + are picked up by :keyword:`import`, + and avoids unintentionally or maliciously shadowing modules + with those in a local (and typically user-writable) directory. (Contributed by Victor Stinner in :gh:`57684`.) -* A ``"z"`` option was added to the format specification mini-language that - coerces negative zero to zero after rounding to the format precision. See - :pep:`682` for more details. (Contributed by John Belmonte in :gh:`90153`.) +* A ``"z"`` option was added to the :ref:`formatspec` that + coerces negative to positive zero after rounding to the format precision. + See :pep:`682` for more details. + (Contributed by John Belmonte in :gh:`90153`.) -* Bytes are no longer accepted on :attr:`sys.path`. Support broke sometime - between Python 3.2 and 3.6 with no one noticing until after Python 3.10.0 - was released. Bringing back support would also be problematic due to - interactions between :option:`-b` and :attr:`sys.path_importer_cache` when - there is a mixture of strings and bytes keys. +* Bytes are no longer accepted on :data:`sys.path`. Support broke sometime + between Python 3.2 and 3.6, with no one noticing until after Python 3.10.0 + was released. In addition, bringing back support would be problematic due to + interactions between :option:`-b` and :data:`sys.path_importer_cache` when + there is a mixture of :class:`str` and :class:`bytes` keys. (Contributed by Thomas Grainger in :gh:`91181`.) Other CPython Implementation Changes From webhook-mailer at python.org Tue Oct 4 19:26:22 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 04 Oct 2022 23:26:22 -0000 Subject: [Python-checkins] gh-93738: Documentation C syntax (Use `c:struct`) (#97772) Message-ID: https://github.com/python/cpython/commit/a0f5599aac2037da715d09733e0a83a9cba7c37a commit: a0f5599aac2037da715d09733e0a83a9cba7c37a branch: main author: Adam Turner <9087854+AA-Turner at users.noreply.github.com> committer: ambv date: 2022-10-04T16:26:14-07:00 summary: gh-93738: Documentation C syntax (Use `c:struct`) (#97772) Use `c:struct` files: M Doc/c-api/import.rst M Doc/c-api/veryhigh.rst M Doc/library/ctypes.rst M Doc/library/socket.rst M Doc/whatsnew/3.11.rst M Doc/whatsnew/3.8.rst diff --git a/Doc/c-api/import.rst b/Doc/c-api/import.rst index 5e2333a74ce6..0922956c607b 100644 --- a/Doc/c-api/import.rst +++ b/Doc/c-api/import.rst @@ -243,7 +243,7 @@ Importing Modules UTF-8 encoded string instead of a Unicode object. -.. c:type:: struct _frozen +.. c:struct:: _frozen .. index:: single: freeze utility @@ -265,7 +265,7 @@ Importing Modules .. c:var:: const struct _frozen* PyImport_FrozenModules - This pointer is initialized to point to an array of :c:type:`struct _frozen` + This pointer is initialized to point to an array of :c:struct:`_frozen` records, terminated by one whose members are all ``NULL`` or zero. When a frozen module is imported, it is searched in this table. Third-party code could play tricks with this to provide a dynamically created collection of frozen modules. @@ -281,7 +281,7 @@ Importing Modules :c:func:`Py_Initialize`. -.. c:type:: struct _inittab +.. c:struct:: _inittab Structure describing a single entry in the list of built-in modules. Each of these structures gives the name and initialization function for a module built diff --git a/Doc/c-api/veryhigh.rst b/Doc/c-api/veryhigh.rst index b17818e35ed9..e3752bdccb66 100644 --- a/Doc/c-api/veryhigh.rst +++ b/Doc/c-api/veryhigh.rst @@ -82,7 +82,7 @@ the same library that the Python runtime is using. .. c:function:: int PyRun_SimpleString(const char *command) This is a simplified interface to :c:func:`PyRun_SimpleStringFlags` below, - leaving the :c:type:`PyCompilerFlags`\* argument set to ``NULL``. + leaving the :c:struct:`PyCompilerFlags`\* argument set to ``NULL``. .. c:function:: int PyRun_SimpleStringFlags(const char *command, PyCompilerFlags *flags) @@ -338,7 +338,7 @@ the same library that the Python runtime is using. interpreter loop. -.. c:type:: struct PyCompilerFlags +.. c:struct:: PyCompilerFlags This is the structure used to hold compiler flags. In cases where code is only being compiled, it is passed as ``int flags``, and in cases where code is being diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index 685ff835346f..d4c52a27592a 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -1088,7 +1088,7 @@ An extended example which also demonstrates the use of pointers accesses the Quoting the docs for that value: - This pointer is initialized to point to an array of :c:type:`struct _frozen` + This pointer is initialized to point to an array of :c:struct:`_frozen` records, terminated by one whose members are all ``NULL`` or zero. When a frozen module is imported, it is searched in this table. Third-party code could play tricks with this to provide a dynamically created collection of frozen modules. @@ -1107,7 +1107,7 @@ size, we show only how this table can be read with :mod:`ctypes`:: ... >>> -We have defined the :c:type:`struct _frozen` data type, so we can get the pointer +We have defined the :c:struct:`_frozen` data type, so we can get the pointer to the table:: >>> FrozenTable = POINTER(struct_frozen) diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst index f97c4f670016..1a9e5fee77b7 100644 --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -1059,7 +1059,7 @@ The :mod:`socket` module also offers various network-related services: Convert an IPv4 address from dotted-quad string format (for example, '123.45.67.89') to 32-bit packed binary format, as a bytes object four characters in length. This is useful when conversing with a program that uses the standard C - library and needs objects of type :c:type:`struct in_addr`, which is the C type + library and needs objects of type :c:struct:`in_addr`, which is the C type for the 32-bit packed binary this function returns. :func:`inet_aton` also accepts strings with less than three dots; see the @@ -1078,7 +1078,7 @@ The :mod:`socket` module also offers various network-related services: Convert a 32-bit packed IPv4 address (a :term:`bytes-like object` four bytes in length) to its standard dotted-quad string representation (for example, '123.45.67.89'). This is useful when conversing with a program that uses the - standard C library and needs objects of type :c:type:`struct in_addr`, which + standard C library and needs objects of type :c:struct:`in_addr`, which is the C type for the 32-bit packed binary data this function takes as an argument. @@ -1095,8 +1095,8 @@ The :mod:`socket` module also offers various network-related services: Convert an IP address from its family-specific string format to a packed, binary format. :func:`inet_pton` is useful when a library or network protocol - calls for an object of type :c:type:`struct in_addr` (similar to - :func:`inet_aton`) or :c:type:`struct in6_addr`. + calls for an object of type :c:struct:`in_addr` (similar to + :func:`inet_aton`) or :c:struct:`in6_addr`. Supported values for *address_family* are currently :const:`AF_INET` and :const:`AF_INET6`. If the IP address string *ip_string* is invalid, @@ -1116,8 +1116,8 @@ The :mod:`socket` module also offers various network-related services: bytes) to its standard, family-specific string representation (for example, ``'7.10.0.5'`` or ``'5aef:2b::8'``). :func:`inet_ntop` is useful when a library or network protocol returns an - object of type :c:type:`struct in_addr` (similar to :func:`inet_ntoa`) or - :c:type:`struct in6_addr`. + object of type :c:struct:`in_addr` (similar to :func:`inet_ntoa`) or + :c:struct:`in6_addr`. Supported values for *address_family* are currently :const:`AF_INET` and :const:`AF_INET6`. If the bytes object *packed_ip* is not the correct diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 173580d58941..f7e63ec8b0f5 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1880,7 +1880,7 @@ Porting to Python 3.11 fields of the result from the exception instance (the ``value`` field). (Contributed by Irit Katriel in :issue:`45711`.) -* :c:type:`_frozen` has a new ``is_package`` field to indicate whether +* :c:struct:`_frozen` has a new ``is_package`` field to indicate whether or not the frozen module is a package. Previously, a negative value in the ``size`` field was the indicator. Now only non-negative values be used for ``size``. diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst index 1ab741ff95b7..95aa6f7a8582 100644 --- a/Doc/whatsnew/3.8.rst +++ b/Doc/whatsnew/3.8.rst @@ -2015,7 +2015,7 @@ Changes in the Python API Changes in the C API -------------------- -* The :c:type:`PyCompilerFlags` structure got a new *cf_feature_version* +* The :c:struct:`PyCompilerFlags` structure got a new *cf_feature_version* field. It should be initialized to ``PY_MINOR_VERSION``. The field is ignored by default, and is used if and only if ``PyCF_ONLY_AST`` flag is set in *cf_flags*. From webhook-mailer at python.org Tue Oct 4 19:26:44 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 04 Oct 2022 23:26:44 -0000 Subject: [Python-checkins] gh-93738: Documentation C syntax (:c:type:`TYPE` -> :c:expr:`TYPE`) (#97770) Message-ID: https://github.com/python/cpython/commit/8b211b4cdbcddecfcc4d1682864795b5f1438c59 commit: 8b211b4cdbcddecfcc4d1682864795b5f1438c59 branch: main author: Adam Turner <9087854+AA-Turner at users.noreply.github.com> committer: ambv date: 2022-10-04T16:26:36-07:00 summary: gh-93738: Documentation C syntax (:c:type:`TYPE` -> :c:expr:`TYPE`) (#97770) :c:type:`TYPE` -> :c:expr:`TYPE` files: M Doc/c-api/memory.rst diff --git a/Doc/c-api/memory.rst b/Doc/c-api/memory.rst index 335ea00cff7c..4abbf340c5f4 100644 --- a/Doc/c-api/memory.rst +++ b/Doc/c-api/memory.rst @@ -265,14 +265,14 @@ The following type-oriented macros are provided for convenience. Note that .. c:function:: TYPE* PyMem_New(TYPE, size_t n) Same as :c:func:`PyMem_Malloc`, but allocates ``(n * sizeof(TYPE))`` bytes of - memory. Returns a pointer cast to :c:type:`TYPE*`. The memory will not have + memory. Returns a pointer cast to :c:expr:`TYPE*`. The memory will not have been initialized in any way. .. c:function:: TYPE* PyMem_Resize(void *p, TYPE, size_t n) Same as :c:func:`PyMem_Realloc`, but the memory block is resized to ``(n * - sizeof(TYPE))`` bytes. Returns a pointer cast to :c:type:`TYPE*`. On return, + sizeof(TYPE))`` bytes. Returns a pointer cast to :c:expr:`TYPE*`. On return, *p* will be a pointer to the new memory area, or ``NULL`` in the event of failure. From webhook-mailer at python.org Tue Oct 4 19:27:38 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 04 Oct 2022 23:27:38 -0000 Subject: [Python-checkins] gh-93738: Documentation C syntax (:c:type:`FILE` -> :c:expr:`FILE`) (#97769) Message-ID: https://github.com/python/cpython/commit/192d401ba53224020f5f9ca6e1ff2c9f89511ac4 commit: 192d401ba53224020f5f9ca6e1ff2c9f89511ac4 branch: main author: Adam Turner <9087854+AA-Turner at users.noreply.github.com> committer: ambv date: 2022-10-04T16:27:29-07:00 summary: gh-93738: Documentation C syntax (:c:type:`FILE` -> :c:expr:`FILE`) (#97769) :c:type:`FILE` -> :c:expr:`FILE` files: M Doc/c-api/file.rst M Doc/c-api/marshal.rst M Doc/c-api/veryhigh.rst diff --git a/Doc/c-api/file.rst b/Doc/c-api/file.rst index ed3735aa8360..145dfe4962ac 100644 --- a/Doc/c-api/file.rst +++ b/Doc/c-api/file.rst @@ -8,7 +8,7 @@ File Objects .. index:: object: file These APIs are a minimal emulation of the Python 2 C API for built-in file -objects, which used to rely on the buffered I/O (:c:type:`FILE*`) support +objects, which used to rely on the buffered I/O (:c:expr:`FILE*`) support from the C standard library. In Python 3, files and streams use the new :mod:`io` module, which defines several layers over the low-level unbuffered I/O of the operating system. The functions described below are diff --git a/Doc/c-api/marshal.rst b/Doc/c-api/marshal.rst index 7bb0dad2b6b6..1ba18beb3ea0 100644 --- a/Doc/c-api/marshal.rst +++ b/Doc/c-api/marshal.rst @@ -43,7 +43,7 @@ The following functions allow marshalled values to be read back in. .. c:function:: long PyMarshal_ReadLongFromFile(FILE *file) - Return a C :c:type:`long` from the data stream in a :c:type:`FILE*` opened + Return a C :c:type:`long` from the data stream in a :c:expr:`FILE*` opened for reading. Only a 32-bit value can be read in using this function, regardless of the native size of :c:type:`long`. @@ -53,7 +53,7 @@ The following functions allow marshalled values to be read back in. .. c:function:: int PyMarshal_ReadShortFromFile(FILE *file) - Return a C :c:type:`short` from the data stream in a :c:type:`FILE*` opened + Return a C :c:type:`short` from the data stream in a :c:expr:`FILE*` opened for reading. Only a 16-bit value can be read in using this function, regardless of the native size of :c:type:`short`. @@ -63,7 +63,7 @@ The following functions allow marshalled values to be read back in. .. c:function:: PyObject* PyMarshal_ReadObjectFromFile(FILE *file) - Return a Python object from the data stream in a :c:type:`FILE*` opened for + Return a Python object from the data stream in a :c:expr:`FILE*` opened for reading. On error, sets the appropriate exception (:exc:`EOFError`, :exc:`ValueError` @@ -72,7 +72,7 @@ The following functions allow marshalled values to be read back in. .. c:function:: PyObject* PyMarshal_ReadLastObjectFromFile(FILE *file) - Return a Python object from the data stream in a :c:type:`FILE*` opened for + Return a Python object from the data stream in a :c:expr:`FILE*` opened for reading. Unlike :c:func:`PyMarshal_ReadObjectFromFile`, this function assumes that no further objects will be read from the file, allowing it to aggressively load file data into memory so that the de-serialization can diff --git a/Doc/c-api/veryhigh.rst b/Doc/c-api/veryhigh.rst index e3752bdccb66..513856d8a48d 100644 --- a/Doc/c-api/veryhigh.rst +++ b/Doc/c-api/veryhigh.rst @@ -16,11 +16,11 @@ parameter. The available start symbols are :const:`Py_eval_input`, :const:`Py_file_input`, and :const:`Py_single_input`. These are described following the functions which accept them as parameters. -Note also that several of these functions take :c:type:`FILE*` parameters. One -particular issue which needs to be handled carefully is that the :c:type:`FILE` +Note also that several of these functions take :c:expr:`FILE*` parameters. One +particular issue which needs to be handled carefully is that the :c:expr:`FILE` structure for different C libraries can be different and incompatible. Under Windows (at least), it is possible for dynamically linked extensions to actually -use different libraries, so care should be taken that :c:type:`FILE*` parameters +use different libraries, so care should be taken that :c:expr:`FILE*` parameters are only passed to these functions if it is certain that they were created by the same library that the Python runtime is using. From webhook-mailer at python.org Tue Oct 4 19:32:35 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 04 Oct 2022 23:32:35 -0000 Subject: [Python-checkins] gh-93738: Documentation C syntax (:c:type: to :c:expr:, misc. cases) (#97775) Message-ID: https://github.com/python/cpython/commit/6b3d4db02edc5883a7e7cbe088711edaef0d9853 commit: 6b3d4db02edc5883a7e7cbe088711edaef0d9853 branch: main author: Adam Turner <9087854+AA-Turner at users.noreply.github.com> committer: ambv date: 2022-10-04T16:32:27-07:00 summary: gh-93738: Documentation C syntax (:c:type: to :c:expr:, misc. cases) (#97775) * :c:type: to :c:expr: * Update Doc/whatsnew/2.4.rst files: M Doc/c-api/file.rst M Doc/c-api/structures.rst M Doc/whatsnew/2.4.rst M Misc/NEWS.d/3.8.0a4.rst diff --git a/Doc/c-api/file.rst b/Doc/c-api/file.rst index 145dfe4962ac..745d892be7ea 100644 --- a/Doc/c-api/file.rst +++ b/Doc/c-api/file.rst @@ -65,7 +65,7 @@ the :mod:`io` APIs instead. Overrides the normal behavior of :func:`io.open_code` to pass its parameter through the provided handler. - The handler is a function of type :c:type:`PyObject *(\*)(PyObject *path, + The handler is a function of type :c:expr:`PyObject *(\*)(PyObject *path, void *userData)`, where *path* is guaranteed to be :c:type:`PyUnicodeObject`. The *userData* pointer is passed into the hook function. Since hook diff --git a/Doc/c-api/structures.rst b/Doc/c-api/structures.rst index 1cc5c4647120..76803a093353 100644 --- a/Doc/c-api/structures.rst +++ b/Doc/c-api/structures.rst @@ -103,7 +103,7 @@ the definition of all other Python objects. .. versionchanged:: 3.11 :c:func:`Py_TYPE()` is changed to an inline static function. - The parameter type is no longer :c:type:`const PyObject*`. + The parameter type is no longer :c:expr:`const PyObject*`. .. c:function:: int Py_IS_TYPE(PyObject *o, PyTypeObject *type) @@ -128,7 +128,7 @@ the definition of all other Python objects. Use the :c:func:`Py_SET_REFCNT()` function to set an object reference count. .. versionchanged:: 3.11 - The parameter type is no longer :c:type:`const PyObject*`. + The parameter type is no longer :c:expr:`const PyObject*`. .. versionchanged:: 3.10 :c:func:`Py_REFCNT()` is changed to the inline static function. @@ -149,7 +149,7 @@ the definition of all other Python objects. .. versionchanged:: 3.11 :c:func:`Py_SIZE()` is changed to an inline static function. - The parameter type is no longer :c:type:`const PyVarObject*`. + The parameter type is no longer :c:expr:`const PyVarObject*`. .. c:function:: void Py_SET_SIZE(PyVarObject *o, Py_ssize_t size) diff --git a/Doc/whatsnew/2.4.rst b/Doc/whatsnew/2.4.rst index ddfac1a3f4e6..61f9eb43243c 100644 --- a/Doc/whatsnew/2.4.rst +++ b/Doc/whatsnew/2.4.rst @@ -1453,7 +1453,7 @@ Some of the changes to Python's build process and to the C API are: extension functions: :c:macro:`Py_RETURN_NONE`, :c:macro:`Py_RETURN_TRUE`, and :c:macro:`Py_RETURN_FALSE`. (Contributed by Brett Cannon.) -* Another new macro, :c:macro:`Py_CLEAR(obj)`, decreases the reference count of +* Another new macro, :c:macro:`Py_CLEAR`, decreases the reference count of *obj* and sets *obj* to the null pointer. (Contributed by Jim Fulton.) * A new function, ``PyTuple_Pack(N, obj1, obj2, ..., objN)``, constructs @@ -1464,7 +1464,7 @@ Some of the changes to Python's build process and to the C API are: lookups without masking exceptions raised during the look-up process. (Contributed by Raymond Hettinger.) -* The :c:macro:`Py_IS_NAN(X)` macro returns 1 if its float or double argument +* The :c:expr:`Py_IS_NAN(X)` macro returns 1 if its float or double argument *X* is a NaN. (Contributed by Tim Peters.) * C code can avoid unnecessary locking by using the new diff --git a/Misc/NEWS.d/3.8.0a4.rst b/Misc/NEWS.d/3.8.0a4.rst index a21de196aa96..9841195210c9 100644 --- a/Misc/NEWS.d/3.8.0a4.rst +++ b/Misc/NEWS.d/3.8.0a4.rst @@ -1354,7 +1354,7 @@ the function is called twice. .. nonce: pz-DIR .. section: C API -:c:macro:`PyDoc_VAR(name)` and :c:macro:`PyDoc_STRVAR(name,str)` now create +:c:expr:`PyDoc_VAR(name)` and :c:expr:`PyDoc_STRVAR(name,str)` now create ``static const char name[]`` instead of ``static char name[]``. Patch by Inada Naoki. From webhook-mailer at python.org Tue Oct 4 19:38:29 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 04 Oct 2022 23:38:29 -0000 Subject: [Python-checkins] [3.11] gh-93738: Documentation C syntax (:c:type:`Py_UNICODE*` -> :c:expr:`Py_UNICODE*`) (GH-97784) (#97857) Message-ID: https://github.com/python/cpython/commit/1657c837f321eaae264f945941be7a49b8103fa0 commit: 1657c837f321eaae264f945941be7a49b8103fa0 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-04T16:38:24-07:00 summary: [3.11] gh-93738: Documentation C syntax (:c:type:`Py_UNICODE*` -> :c:expr:`Py_UNICODE*`) (GH-97784) (#97857) :c:type:`Py_UNICODE*` -> :c:expr:`Py_UNICODE*` (cherry picked from commit a081cae2a2cd1248ad067c3f7dc218ea7e3d203a) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> files: M Doc/whatsnew/3.3.rst diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst index 2d78f81798f2..609370bad274 100644 --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -2267,7 +2267,7 @@ The :c:type:`Py_UNICODE` has been deprecated by :pep:`393` and will be removed in Python 4. All functions using this type are deprecated: Unicode functions and methods using :c:type:`Py_UNICODE` and -:c:type:`Py_UNICODE*` types: +:c:expr:`Py_UNICODE*` types: * :c:macro:`PyUnicode_FromUnicode`: use :c:func:`PyUnicode_FromWideChar` or :c:func:`PyUnicode_FromKindAndData` From webhook-mailer at python.org Tue Oct 4 19:38:44 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 04 Oct 2022 23:38:44 -0000 Subject: [Python-checkins] [3.10] gh-93738: Documentation C syntax (:c:type:`Py_UNICODE*` -> :c:expr:`Py_UNICODE*`) (GH-97784) (#97858) Message-ID: https://github.com/python/cpython/commit/f879297b862ff8a566f732c337b711f0a31aa96b commit: f879297b862ff8a566f732c337b711f0a31aa96b branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-04T16:38:39-07:00 summary: [3.10] gh-93738: Documentation C syntax (:c:type:`Py_UNICODE*` -> :c:expr:`Py_UNICODE*`) (GH-97784) (#97858) :c:type:`Py_UNICODE*` -> :c:expr:`Py_UNICODE*` (cherry picked from commit a081cae2a2cd1248ad067c3f7dc218ea7e3d203a) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> files: M Doc/whatsnew/3.3.rst diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst index 2d78f81798f2..609370bad274 100644 --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -2267,7 +2267,7 @@ The :c:type:`Py_UNICODE` has been deprecated by :pep:`393` and will be removed in Python 4. All functions using this type are deprecated: Unicode functions and methods using :c:type:`Py_UNICODE` and -:c:type:`Py_UNICODE*` types: +:c:expr:`Py_UNICODE*` types: * :c:macro:`PyUnicode_FromUnicode`: use :c:func:`PyUnicode_FromWideChar` or :c:func:`PyUnicode_FromKindAndData` From webhook-mailer at python.org Tue Oct 4 19:39:04 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 04 Oct 2022 23:39:04 -0000 Subject: [Python-checkins] [3.11] gh-93738: Documentation C syntax (:c:type:`PyUnicodeObject*` -> :c:expr:`PyUnicodeObject*`) (GH-97783) (#97859) Message-ID: https://github.com/python/cpython/commit/9749c6029ed85aa08dfe4a06566b38e03f3932c4 commit: 9749c6029ed85aa08dfe4a06566b38e03f3932c4 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-04T16:38:58-07:00 summary: [3.11] gh-93738: Documentation C syntax (:c:type:`PyUnicodeObject*` -> :c:expr:`PyUnicodeObject*`) (GH-97783) (#97859) :c:type:`PyUnicodeObject*` -> :c:expr:`PyUnicodeObject*` (cherry picked from commit 898834e27b82bd1f3532b6448a862a7a9cdeff66) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> files: M Doc/c-api/unicode.rst diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst index eb9901339536..d86e99ffbbfa 100644 --- a/Doc/c-api/unicode.rst +++ b/Doc/c-api/unicode.rst @@ -866,7 +866,7 @@ conversion function: ParseTuple converter: decode :class:`bytes` objects -- obtained either directly or indirectly through the :class:`os.PathLike` interface -- to :class:`str` using :c:func:`PyUnicode_DecodeFSDefaultAndSize`; :class:`str` - objects are output as-is. *result* must be a :c:type:`PyUnicodeObject*` which + objects are output as-is. *result* must be a :c:expr:`PyUnicodeObject*` which must be released when it is no longer used. .. versionadded:: 3.2 From webhook-mailer at python.org Tue Oct 4 19:40:03 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 04 Oct 2022 23:40:03 -0000 Subject: [Python-checkins] [3.10] gh-93738: Documentation C syntax (:c:type:`PyUnicodeObject*` -> :c:expr:`PyUnicodeObject*`) (GH-97783) (#97860) Message-ID: https://github.com/python/cpython/commit/20ddf1c17aa6d74d0c89f9cf9c085a9e804c0ead commit: 20ddf1c17aa6d74d0c89f9cf9c085a9e804c0ead branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-04T16:39:57-07:00 summary: [3.10] gh-93738: Documentation C syntax (:c:type:`PyUnicodeObject*` -> :c:expr:`PyUnicodeObject*`) (GH-97783) (#97860) :c:type:`PyUnicodeObject*` -> :c:expr:`PyUnicodeObject*` (cherry picked from commit 898834e27b82bd1f3532b6448a862a7a9cdeff66) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> files: M Doc/c-api/unicode.rst diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst index 09ded4c32db0..a7abe555a740 100644 --- a/Doc/c-api/unicode.rst +++ b/Doc/c-api/unicode.rst @@ -870,7 +870,7 @@ conversion function: ParseTuple converter: decode :class:`bytes` objects -- obtained either directly or indirectly through the :class:`os.PathLike` interface -- to :class:`str` using :c:func:`PyUnicode_DecodeFSDefaultAndSize`; :class:`str` - objects are output as-is. *result* must be a :c:type:`PyUnicodeObject*` which + objects are output as-is. *result* must be a :c:expr:`PyUnicodeObject*` which must be released when it is no longer used. .. versionadded:: 3.2 From webhook-mailer at python.org Tue Oct 4 19:40:52 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 04 Oct 2022 23:40:52 -0000 Subject: [Python-checkins] [3.11] gh-93738: Documentation C syntax (:c:type:`PyBytesObject*` -> :c:expr:`PyBytesObject*`) (GH-97782) (#97861) Message-ID: https://github.com/python/cpython/commit/df133f54ef3bb21215d3b3481d64bb31d89c3c33 commit: df133f54ef3bb21215d3b3481d64bb31d89c3c33 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-04T16:40:47-07:00 summary: [3.11] gh-93738: Documentation C syntax (:c:type:`PyBytesObject*` -> :c:expr:`PyBytesObject*`) (GH-97782) (#97861) :c:type:`PyBytesObject*` -> :c:expr:`PyBytesObject*` (cherry picked from commit 9ebc50866b58a0ee2985c6540a67fee8a4a49e4d) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> files: M Doc/c-api/unicode.rst diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst index d86e99ffbbfa..d26bac83ec6d 100644 --- a/Doc/c-api/unicode.rst +++ b/Doc/c-api/unicode.rst @@ -849,7 +849,7 @@ argument parsing, the ``"O&"`` converter should be used, passing ParseTuple converter: encode :class:`str` objects -- obtained directly or through the :class:`os.PathLike` interface -- to :class:`bytes` using :c:func:`PyUnicode_EncodeFSDefault`; :class:`bytes` objects are output as-is. - *result* must be a :c:type:`PyBytesObject*` which must be released when it is + *result* must be a :c:expr:`PyBytesObject*` which must be released when it is no longer used. .. versionadded:: 3.1 From webhook-mailer at python.org Tue Oct 4 19:41:10 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 04 Oct 2022 23:41:10 -0000 Subject: [Python-checkins] [3.10] gh-93738: Documentation C syntax (:c:type:`PyBytesObject*` -> :c:expr:`PyBytesObject*`) (GH-97782) (#97862) Message-ID: https://github.com/python/cpython/commit/5aa108b9e045849bbbf5b2aedc207356198ee840 commit: 5aa108b9e045849bbbf5b2aedc207356198ee840 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-04T16:41:05-07:00 summary: [3.10] gh-93738: Documentation C syntax (:c:type:`PyBytesObject*` -> :c:expr:`PyBytesObject*`) (GH-97782) (#97862) :c:type:`PyBytesObject*` -> :c:expr:`PyBytesObject*` (cherry picked from commit 9ebc50866b58a0ee2985c6540a67fee8a4a49e4d) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> files: M Doc/c-api/unicode.rst diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst index a7abe555a740..fbf51d31d56e 100644 --- a/Doc/c-api/unicode.rst +++ b/Doc/c-api/unicode.rst @@ -853,7 +853,7 @@ argument parsing, the ``"O&"`` converter should be used, passing ParseTuple converter: encode :class:`str` objects -- obtained directly or through the :class:`os.PathLike` interface -- to :class:`bytes` using :c:func:`PyUnicode_EncodeFSDefault`; :class:`bytes` objects are output as-is. - *result* must be a :c:type:`PyBytesObject*` which must be released when it is + *result* must be a :c:expr:`PyBytesObject*` which must be released when it is no longer used. .. versionadded:: 3.1 From webhook-mailer at python.org Tue Oct 4 19:46:18 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 04 Oct 2022 23:46:18 -0000 Subject: [Python-checkins] [3.11] gh-93738: Documentation C syntax (:c:type:`PyTupleObject*` -> :c:expr:`PyTupleObject*`) (GH-97780) (#97863) Message-ID: https://github.com/python/cpython/commit/a51124729a78f4f8e5f36ae53f0e83468c128c0b commit: a51124729a78f4f8e5f36ae53f0e83468c128c0b branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-04T16:46:13-07:00 summary: [3.11] gh-93738: Documentation C syntax (:c:type:`PyTupleObject*` -> :c:expr:`PyTupleObject*`) (GH-97780) (#97863) :c:type:`PyTupleObject*` -> :c:expr:`PyTupleObject*` (cherry picked from commit 510baa429affb832d7b4ed68182e59daa2815d2e) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> files: M Doc/c-api/typehints.rst diff --git a/Doc/c-api/typehints.rst b/Doc/c-api/typehints.rst index 8b0b9b651e80..88554a346c0d 100644 --- a/Doc/c-api/typehints.rst +++ b/Doc/c-api/typehints.rst @@ -16,7 +16,7 @@ two types exist -- :ref:`GenericAlias ` and :class:`types.GenericAlias`. The *origin* and *args* arguments set the ``GenericAlias``\ 's ``__origin__`` and ``__args__`` attributes respectively. *origin* should be a :c:type:`PyTypeObject*`, and *args* can be a - :c:type:`PyTupleObject*` or any ``PyObject*``. If *args* passed is + :c:expr:`PyTupleObject*` or any ``PyObject*``. If *args* passed is not a tuple, a 1-tuple is automatically constructed and ``__args__`` is set to ``(args,)``. Minimal checking is done for the arguments, so the function will succeed even From webhook-mailer at python.org Tue Oct 4 19:46:35 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 04 Oct 2022 23:46:35 -0000 Subject: [Python-checkins] [3.10] gh-93738: Documentation C syntax (:c:type:`PyTupleObject*` -> :c:expr:`PyTupleObject*`) (GH-97780) (#97864) Message-ID: https://github.com/python/cpython/commit/9c755d7d6b77b0f9e98dea94b035459990ab19be commit: 9c755d7d6b77b0f9e98dea94b035459990ab19be branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-04T16:46:30-07:00 summary: [3.10] gh-93738: Documentation C syntax (:c:type:`PyTupleObject*` -> :c:expr:`PyTupleObject*`) (GH-97780) (#97864) :c:type:`PyTupleObject*` -> :c:expr:`PyTupleObject*` (cherry picked from commit 510baa429affb832d7b4ed68182e59daa2815d2e) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> files: M Doc/c-api/typehints.rst diff --git a/Doc/c-api/typehints.rst b/Doc/c-api/typehints.rst index dfda96a47243..79f29acc2e1e 100644 --- a/Doc/c-api/typehints.rst +++ b/Doc/c-api/typehints.rst @@ -16,7 +16,7 @@ two types exist -- :ref:`GenericAlias ` and :class:`types.GenericAlias`. The *origin* and *args* arguments set the ``GenericAlias``\ 's ``__origin__`` and ``__args__`` attributes respectively. *origin* should be a :c:type:`PyTypeObject*`, and *args* can be a - :c:type:`PyTupleObject*` or any ``PyObject*``. If *args* passed is + :c:expr:`PyTupleObject*` or any ``PyObject*``. If *args* passed is not a tuple, a 1-tuple is automatically constructed and ``__args__`` is set to ``(args,)``. Minimal checking is done for the arguments, so the function will succeed even From webhook-mailer at python.org Tue Oct 4 20:04:06 2022 From: webhook-mailer at python.org (ezio-melotti) Date: Wed, 05 Oct 2022 00:04:06 -0000 Subject: [Python-checkins] gh-95913: Copyedit/improve Implementation Changes What's New section (#97720) Message-ID: https://github.com/python/cpython/commit/4e731814d781dae3419e981c0acc3ef833e26e8a commit: 4e731814d781dae3419e981c0acc3ef833e26e8a branch: main author: C.A.M. Gerlach committer: ezio-melotti date: 2022-10-05T02:03:58+02:00 summary: gh-95913: Copyedit/improve Implementation Changes What's New section (#97720) * Add and refine reST/Sphinx syntax for implementation changes section * Clarify and refine wording in the Implementation Changes section * Elide unnecessary comma Co-authored-by: Ezio Melotti Co-authored-by: Ezio Melotti files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index f7e63ec8b0f5..dafbbb673f0e 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -480,17 +480,24 @@ Other Language Changes there is a mixture of :class:`str` and :class:`bytes` keys. (Contributed by Thomas Grainger in :gh:`91181`.) + +.. _whatsnew311-other-implementation-changes: + Other CPython Implementation Changes ==================================== -* Special methods :meth:`complex.__complex__` and :meth:`bytes.__bytes__` are implemented to - support :class:`typing.SupportsComplex` and :class:`typing.SupportsBytes` protocols. +* The special methods :meth:`~object.__complex__` for :class:`complex` + and :meth:`~object.__bytes__` for :class:`bytes` are implemented to support + the :class:`typing.SupportsComplex` and :class:`typing.SupportsBytes` protocols. (Contributed by Mark Dickinson and Dong-hee Na in :issue:`24234`.) -* ``siphash13`` is added as a new internal hashing algorithms. It has similar security - properties as ``siphash24`` but it is slightly faster for long inputs. ``str``, ``bytes``, - and some other types now use it as default algorithm for :func:`hash`. :pep:`552` - hash-based pyc files now use ``siphash13``, too. +* ``siphash13`` is added as a new internal hashing algorithm. + It has similar security properties as ``siphash24``, + but it is slightly faster for long inputs. + :class:`str`, :class:`bytes`, and some other types + now use it as the default algorithm for :func:`hash`. + :pep:`552` :ref:`hash-based .pyc files ` + now use ``siphash13`` too. (Contributed by Inada Naoki in :issue:`29410`.) * When an active exception is re-raised by a :keyword:`raise` statement with no parameters, @@ -499,25 +506,28 @@ Other CPython Implementation Changes reflected in the re-raised exception. (Contributed by Irit Katriel in :issue:`45711`.) -* The interpreter state's representation of handled exceptions (a.k.a exc_info, or - _PyErr_StackItem) now has only the ``exc_value`` field, ``exc_type`` and ``exc_traceback`` - have been removed as their values can be derived from ``exc_value``. +* The interpreter state's representation of handled exceptions + (aka ``exc_info`` or ``_PyErr_StackItem``) + now only has the ``exc_value`` field; ``exc_type`` and ``exc_traceback`` + have been removed, as they can be derived from ``exc_value``. (Contributed by Irit Katriel in :issue:`45711`.) -* A new command line option for the Windows installer ``AppendPath`` has been added. - It behaves similiar to ``PrependPath`` but appends the install and scripts directories - instead of prepending them. +* A new :ref:`command line option `, ``AppendPath``, + has been added for the Windows installer. + It behaves similarly to ``PrependPath``, + but appends the install and scripts directories instead of prepending them. (Contributed by Bastian Neuburger in :issue:`44934`.) -* The :c:member:`PyConfig.module_search_paths_set` field must now be set to 1 for +* The :c:member:`PyConfig.module_search_paths_set` field must now be set to ``1`` for initialization to use :c:member:`PyConfig.module_search_paths` to initialize :data:`sys.path`. Otherwise, initialization will recalculate the path and replace any values added to ``module_search_paths``. -* The output of the :option:`--help` option is changed to fit inside 50 lines and 80 - columns. Information about :ref:`Python environment variables ` - and :option:`-X options <-X>` is available with the new :option:`--help-env` or - :option:`--help-xoptions` flags, and with :option:`--help-all`. +* The output of the :option:`--help` option now fits in 50 lines/80 columns. + Information about :ref:`Python environment variables ` + and :option:`-X` options is now available using the respective + :option:`--help-env` and :option:`--help-xoptions` flags, + and with the new :option:`--help-all`. (Contributed by ?ric Araujo in :issue:`46142`.) From webhook-mailer at python.org Tue Oct 4 20:29:32 2022 From: webhook-mailer at python.org (orsenthil) Date: Wed, 05 Oct 2022 00:29:32 -0000 Subject: [Python-checkins] gh-97837: Change deprecation warning message in `unittest` (#97838) Message-ID: https://github.com/python/cpython/commit/c3648f4e4a12ec6efe65684facfcd08996e550ca commit: c3648f4e4a12ec6efe65684facfcd08996e550ca branch: main author: Nikita Sobolev committer: orsenthil date: 2022-10-04T17:29:18-07:00 summary: gh-97837: Change deprecation warning message in `unittest` (#97838) files: A Misc/NEWS.d/next/Library/2022-10-04-21-21-41.gh-issue-97837.19q-eg.rst M Lib/test/test_unittest/test_async_case.py M Lib/test/test_unittest/test_case.py M Lib/unittest/async_case.py M Lib/unittest/case.py diff --git a/Lib/test/test_unittest/test_async_case.py b/Lib/test/test_unittest/test_async_case.py index d7d4dc91316c..fab8270ea33a 100644 --- a/Lib/test/test_unittest/test_async_case.py +++ b/Lib/test/test_unittest/test_async_case.py @@ -277,25 +277,36 @@ async def on_cleanup2(self): self.assertEqual(events, ['asyncSetUp', 'test', 'asyncTearDown', 'cleanup2', 'cleanup1']) def test_deprecation_of_return_val_from_test(self): - # Issue 41322 - deprecate return of value!=None from a test + # Issue 41322 - deprecate return of value that is not None from a test + class Nothing: + def __eq__(self, o): + return o is None class Test(unittest.IsolatedAsyncioTestCase): async def test1(self): return 1 async def test2(self): yield 1 + async def test3(self): + return Nothing() with self.assertWarns(DeprecationWarning) as w: Test('test1').run() - self.assertIn('It is deprecated to return a value!=None', str(w.warning)) + self.assertIn('It is deprecated to return a value that is not None', str(w.warning)) self.assertIn('test1', str(w.warning)) self.assertEqual(w.filename, __file__) with self.assertWarns(DeprecationWarning) as w: Test('test2').run() - self.assertIn('It is deprecated to return a value!=None', str(w.warning)) + self.assertIn('It is deprecated to return a value that is not None', str(w.warning)) self.assertIn('test2', str(w.warning)) self.assertEqual(w.filename, __file__) + with self.assertWarns(DeprecationWarning) as w: + Test('test3').run() + self.assertIn('It is deprecated to return a value that is not None', str(w.warning)) + self.assertIn('test3', str(w.warning)) + self.assertEqual(w.filename, __file__) + def test_cleanups_interleave_order(self): events = [] diff --git a/Lib/test/test_unittest/test_case.py b/Lib/test/test_unittest/test_case.py index fae0d1076da9..05d60a8ad3cf 100644 --- a/Lib/test/test_unittest/test_case.py +++ b/Lib/test/test_unittest/test_case.py @@ -307,25 +307,36 @@ def test(self): Foo('test').run() def test_deprecation_of_return_val_from_test(self): - # Issue 41322 - deprecate return of value!=None from a test + # Issue 41322 - deprecate return of value that is not None from a test + class Nothing: + def __eq__(self, o): + return o is None class Foo(unittest.TestCase): def test1(self): return 1 def test2(self): yield 1 + def test3(self): + return Nothing() with self.assertWarns(DeprecationWarning) as w: Foo('test1').run() - self.assertIn('It is deprecated to return a value!=None', str(w.warning)) + self.assertIn('It is deprecated to return a value that is not None', str(w.warning)) self.assertIn('test1', str(w.warning)) self.assertEqual(w.filename, __file__) with self.assertWarns(DeprecationWarning) as w: Foo('test2').run() - self.assertIn('It is deprecated to return a value!=None', str(w.warning)) + self.assertIn('It is deprecated to return a value that is not None', str(w.warning)) self.assertIn('test2', str(w.warning)) self.assertEqual(w.filename, __file__) + with self.assertWarns(DeprecationWarning) as w: + Foo('test3').run() + self.assertIn('It is deprecated to return a value that is not None', str(w.warning)) + self.assertIn('test3', str(w.warning)) + self.assertEqual(w.filename, __file__) + def _check_call_order__subtests(self, result, events, expected_events): class Foo(Test.LoggingTestCase): def test(self): diff --git a/Lib/unittest/async_case.py b/Lib/unittest/async_case.py index 3457e92e5da2..bd2a47115606 100644 --- a/Lib/unittest/async_case.py +++ b/Lib/unittest/async_case.py @@ -88,7 +88,7 @@ def _callSetUp(self): def _callTestMethod(self, method): if self._callMaybeAsync(method) is not None: - warnings.warn(f'It is deprecated to return a value!=None from a ' + warnings.warn(f'It is deprecated to return a value that is not None from a ' f'test case ({method})', DeprecationWarning, stacklevel=4) def _callTearDown(self): diff --git a/Lib/unittest/case.py b/Lib/unittest/case.py index af8303333d40..b01f6605e23e 100644 --- a/Lib/unittest/case.py +++ b/Lib/unittest/case.py @@ -577,7 +577,7 @@ def _callSetUp(self): def _callTestMethod(self, method): if method() is not None: - warnings.warn(f'It is deprecated to return a value!=None from a ' + warnings.warn(f'It is deprecated to return a value that is not None from a ' f'test case ({method})', DeprecationWarning, stacklevel=3) def _callTearDown(self): diff --git a/Misc/NEWS.d/next/Library/2022-10-04-21-21-41.gh-issue-97837.19q-eg.rst b/Misc/NEWS.d/next/Library/2022-10-04-21-21-41.gh-issue-97837.19q-eg.rst new file mode 100644 index 000000000000..b1350c959e2b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-04-21-21-41.gh-issue-97837.19q-eg.rst @@ -0,0 +1,7 @@ +Change deprecate warning message in :mod:`unittest` from + +``It is deprecated to return a value!=None`` + +to + +``It is deprecated to return a value that is not None from a test case`` From webhook-mailer at python.org Tue Oct 4 20:30:12 2022 From: webhook-mailer at python.org (brandtbucher) Date: Wed, 05 Oct 2022 00:30:12 -0000 Subject: [Python-checkins] GH-97779: Ensure that *all* frame objects are backed by "complete" frames (GH-97845) Message-ID: https://github.com/python/cpython/commit/0ff8fd65838f9f9ed90d7a055d26a2ce9fc0ce85 commit: 0ff8fd65838f9f9ed90d7a055d26a2ce9fc0ce85 branch: main author: Brandt Bucher committer: brandtbucher date: 2022-10-04T17:30:03-07:00 summary: GH-97779: Ensure that *all* frame objects are backed by "complete" frames (GH-97845) files: A Misc/NEWS.d/next/Core and Builtins/2022-10-04-02-00-10.gh-issue-97779.f3N1hI.rst M Lib/test/test_code.py M Objects/codeobject.c M Objects/frameobject.c M Python/frame.c diff --git a/Lib/test/test_code.py b/Lib/test/test_code.py index 2fdfdd0d309c..4e4d82314a9f 100644 --- a/Lib/test/test_code.py +++ b/Lib/test/test_code.py @@ -132,6 +132,7 @@ import unittest import textwrap import weakref +import dis try: import ctypes @@ -682,6 +683,38 @@ def test_lines(self): self.check_lines(misshappen) self.check_lines(bug93662) + @cpython_only + def test_code_new_empty(self): + # If this test fails, it means that the construction of PyCode_NewEmpty + # needs to be modified! Please update this test *and* PyCode_NewEmpty, + # so that they both stay in sync. + def f(): + pass + PY_CODE_LOCATION_INFO_NO_COLUMNS = 13 + f.__code__ = f.__code__.replace( + co_firstlineno=42, + co_code=bytes( + [ + dis.opmap["RESUME"], 0, + dis.opmap["LOAD_ASSERTION_ERROR"], 0, + dis.opmap["RAISE_VARARGS"], 1, + ] + ), + co_linetable=bytes( + [ + (1 << 7) + | (PY_CODE_LOCATION_INFO_NO_COLUMNS << 3) + | (3 - 1), + 0, + ] + ), + ) + self.assertRaises(AssertionError, f) + self.assertEqual( + list(f.__code__.co_positions()), + 3 * [(42, 42, None, None)], + ) + if check_impl_detail(cpython=True) and ctypes is not None: py = ctypes.pythonapi diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-04-02-00-10.gh-issue-97779.f3N1hI.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-04-02-00-10.gh-issue-97779.f3N1hI.rst new file mode 100644 index 000000000000..611521808865 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-04-02-00-10.gh-issue-97779.f3N1hI.rst @@ -0,0 +1 @@ +Ensure that all Python frame objects are backed by "complete" frames. diff --git a/Objects/codeobject.c b/Objects/codeobject.c index 7d0d038f489a..14d1d00684ae 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -638,12 +638,22 @@ PyCode_New(int argcount, int kwonlyargcount, exceptiontable); } -static const char assert0[6] = { +// NOTE: When modifying the construction of PyCode_NewEmpty, please also change +// test.test_code.CodeLocationTest.test_code_new_empty to keep it in sync! + +static const uint8_t assert0[6] = { RESUME, 0, LOAD_ASSERTION_ERROR, 0, RAISE_VARARGS, 1 }; +static const uint8_t linetable[2] = { + (1 << 7) // New entry. + | (PY_CODE_LOCATION_INFO_NO_COLUMNS << 3) + | (3 - 1), // Three code units. + 0, // Offset from co_firstlineno. +}; + PyCodeObject * PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno) { @@ -651,6 +661,7 @@ PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno) PyObject *filename_ob = NULL; PyObject *funcname_ob = NULL; PyObject *code_ob = NULL; + PyObject *linetable_ob = NULL; PyCodeObject *result = NULL; nulltuple = PyTuple_New(0); @@ -665,10 +676,14 @@ PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno) if (filename_ob == NULL) { goto failed; } - code_ob = PyBytes_FromStringAndSize(assert0, 6); + code_ob = PyBytes_FromStringAndSize((const char *)assert0, 6); if (code_ob == NULL) { goto failed; } + linetable_ob = PyBytes_FromStringAndSize((const char *)linetable, 2); + if (linetable_ob == NULL) { + goto failed; + } #define emptystring (PyObject *)&_Py_SINGLETON(bytes_empty) struct _PyCodeConstructor con = { @@ -677,7 +692,7 @@ PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno) .qualname = funcname_ob, .code = code_ob, .firstlineno = firstlineno, - .linetable = emptystring, + .linetable = linetable_ob, .consts = nulltuple, .names = nulltuple, .localsplusnames = nulltuple, @@ -692,6 +707,7 @@ PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno) Py_XDECREF(funcname_ob); Py_XDECREF(filename_ob); Py_XDECREF(code_ob); + Py_XDECREF(linetable_ob); return result; } diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 2e3777943126..6a51a946ef35 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -588,6 +588,7 @@ first_line_not_before(int *lines, int len, int line) static PyFrameState _PyFrame_GetState(PyFrameObject *frame) { + assert(!_PyFrame_IsIncomplete(frame->f_frame)); if (frame->f_frame->stacktop == 0) { return FRAME_CLEARED; } @@ -1094,6 +1095,9 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code, init_frame((_PyInterpreterFrame *)f->_f_frame_data, func, locals); f->f_frame = (_PyInterpreterFrame *)f->_f_frame_data; f->f_frame->owner = FRAME_OWNED_BY_FRAME_OBJECT; + // This frame needs to be "complete", so pretend that the first RESUME ran: + f->f_frame->prev_instr = _PyCode_CODE(code) + code->_co_firsttraceable; + assert(!_PyFrame_IsIncomplete(f->f_frame)); Py_DECREF(func); _PyObject_GC_TRACK(f); return f; @@ -1222,6 +1226,7 @@ _PyFrame_FastToLocalsWithError(_PyInterpreterFrame *frame) { int PyFrame_FastToLocalsWithError(PyFrameObject *f) { + assert(!_PyFrame_IsIncomplete(f->f_frame)); if (f == NULL) { PyErr_BadInternalCall(); return -1; @@ -1237,7 +1242,7 @@ void PyFrame_FastToLocals(PyFrameObject *f) { int res; - + assert(!_PyFrame_IsIncomplete(f->f_frame)); assert(!PyErr_Occurred()); res = PyFrame_FastToLocalsWithError(f); @@ -1320,6 +1325,7 @@ _PyFrame_LocalsToFast(_PyInterpreterFrame *frame, int clear) void PyFrame_LocalsToFast(PyFrameObject *f, int clear) { + assert(!_PyFrame_IsIncomplete(f->f_frame)); if (f && f->f_fast_as_locals && _PyFrame_GetState(f) != FRAME_CLEARED) { _PyFrame_LocalsToFast(f->f_frame, clear); f->f_fast_as_locals = 0; @@ -1330,6 +1336,7 @@ PyFrame_LocalsToFast(PyFrameObject *f, int clear) int _PyFrame_IsEntryFrame(PyFrameObject *frame) { assert(frame != NULL); + assert(!_PyFrame_IsIncomplete(frame->f_frame)); return frame->f_frame->is_entry; } @@ -1338,6 +1345,7 @@ PyCodeObject * PyFrame_GetCode(PyFrameObject *frame) { assert(frame != NULL); + assert(!_PyFrame_IsIncomplete(frame->f_frame)); PyCodeObject *code = frame->f_frame->f_code; assert(code != NULL); Py_INCREF(code); @@ -1349,6 +1357,7 @@ PyFrameObject* PyFrame_GetBack(PyFrameObject *frame) { assert(frame != NULL); + assert(!_PyFrame_IsIncomplete(frame->f_frame)); PyFrameObject *back = frame->f_back; if (back == NULL) { _PyInterpreterFrame *prev = frame->f_frame->previous; @@ -1366,24 +1375,28 @@ PyFrame_GetBack(PyFrameObject *frame) PyObject* PyFrame_GetLocals(PyFrameObject *frame) { + assert(!_PyFrame_IsIncomplete(frame->f_frame)); return frame_getlocals(frame, NULL); } PyObject* PyFrame_GetGlobals(PyFrameObject *frame) { + assert(!_PyFrame_IsIncomplete(frame->f_frame)); return frame_getglobals(frame, NULL); } PyObject* PyFrame_GetBuiltins(PyFrameObject *frame) { + assert(!_PyFrame_IsIncomplete(frame->f_frame)); return frame_getbuiltins(frame, NULL); } int PyFrame_GetLasti(PyFrameObject *frame) { + assert(!_PyFrame_IsIncomplete(frame->f_frame)); int lasti = _PyInterpreterFrame_LASTI(frame->f_frame); if (lasti < 0) { return -1; @@ -1394,6 +1407,7 @@ PyFrame_GetLasti(PyFrameObject *frame) PyObject * PyFrame_GetGenerator(PyFrameObject *frame) { + assert(!_PyFrame_IsIncomplete(frame->f_frame)); if (frame->f_frame->owner != FRAME_OWNED_BY_GENERATOR) { return NULL; } diff --git a/Python/frame.c b/Python/frame.c index 05a8cffcb8a7..96566de63a78 100644 --- a/Python/frame.c +++ b/Python/frame.c @@ -70,6 +70,13 @@ take_ownership(PyFrameObject *f, _PyInterpreterFrame *frame) frame = (_PyInterpreterFrame *)f->_f_frame_data; f->f_frame = frame; frame->owner = FRAME_OWNED_BY_FRAME_OBJECT; + if (_PyFrame_IsIncomplete(frame)) { + // This may be a newly-created generator or coroutine frame. Since it's + // dead anyways, just pretend that the first RESUME ran: + PyCodeObject *code = frame->f_code; + frame->prev_instr = _PyCode_CODE(code) + code->_co_firsttraceable; + } + assert(!_PyFrame_IsIncomplete(frame)); assert(f->f_back == NULL); _PyInterpreterFrame *prev = frame->previous; while (prev && _PyFrame_IsIncomplete(prev)) { From webhook-mailer at python.org Tue Oct 4 20:34:11 2022 From: webhook-mailer at python.org (markshannon) Date: Wed, 05 Oct 2022 00:34:11 -0000 Subject: [Python-checkins] GH-91079: Decouple C stack overflow checks from Python recursion checks. (GH-96510) Message-ID: https://github.com/python/cpython/commit/76449350b3467b85bcb565f9e2bf945bd150a66e commit: 76449350b3467b85bcb565f9e2bf945bd150a66e branch: main author: Mark Shannon committer: markshannon date: 2022-10-05T01:34:03+01:00 summary: GH-91079: Decouple C stack overflow checks from Python recursion checks. (GH-96510) files: A Misc/NEWS.d/next/Core and Builtins/2022-09-05-09-56-32.gh-issue-91079.H4-DdU.rst M Include/cpython/pystate.h M Include/internal/pycore_ceval.h M Include/internal/pycore_runtime_init.h M Lib/test/support/__init__.py M Lib/test/test_ast.py M Lib/test/test_call.py M Lib/test/test_collections.py M Lib/test/test_compile.py M Lib/test/test_dynamic.py M Lib/test/test_exceptions.py M Lib/test/test_isinstance.py M Lib/test/test_marshal.py M Modules/_testinternalcapi.c M Parser/asdl_c.py M Python/Python-ast.c M Python/ast.c M Python/ast_opt.c M Python/ceval.c M Python/pystate.c M Python/symtable.c M Python/sysmodule.c diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h index cc3c3eae9419..7722a384cbfa 100644 --- a/Include/cpython/pystate.h +++ b/Include/cpython/pystate.h @@ -95,8 +95,10 @@ struct _ts { /* Was this thread state statically allocated? */ int _static; - int recursion_remaining; - int recursion_limit; + int py_recursion_remaining; + int py_recursion_limit; + + int c_recursion_remaining; int recursion_headroom; /* Allow 50 more calls to handle any errors. */ /* 'tracing' keeps track of the execution depth when tracing/profiling. @@ -202,6 +204,16 @@ struct _ts { _PyCFrame root_cframe; }; +/* WASI has limited call stack. Python's recursion limit depends on code + layout, optimization, and WASI runtime. Wasmtime can handle about 700 + recursions, sometimes less. 500 is a more conservative limit. */ +#ifndef C_RECURSION_LIMIT +# ifdef __wasi__ +# define C_RECURSION_LIMIT 500 +# else +# define C_RECURSION_LIMIT 800 +# endif +#endif /* other API */ diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h index 4914948c6ca7..deda070a6dea 100644 --- a/Include/internal/pycore_ceval.h +++ b/Include/internal/pycore_ceval.h @@ -12,15 +12,8 @@ extern "C" { struct pyruntimestate; struct _ceval_runtime_state; -/* WASI has limited call stack. Python's recursion limit depends on code - layout, optimization, and WASI runtime. Wasmtime can handle about 700-750 - recursions, sometimes less. 600 is a more conservative limit. */ #ifndef Py_DEFAULT_RECURSION_LIMIT -# ifdef __wasi__ -# define Py_DEFAULT_RECURSION_LIMIT 600 -# else -# define Py_DEFAULT_RECURSION_LIMIT 1000 -# endif +# define Py_DEFAULT_RECURSION_LIMIT 1000 #endif #include "pycore_interp.h" // PyInterpreterState.eval_frame @@ -118,12 +111,12 @@ extern void _PyEval_DeactivateOpCache(void); /* With USE_STACKCHECK macro defined, trigger stack checks in _Py_CheckRecursiveCall() on every 64th call to _Py_EnterRecursiveCall. */ static inline int _Py_MakeRecCheck(PyThreadState *tstate) { - return (tstate->recursion_remaining-- <= 0 - || (tstate->recursion_remaining & 63) == 0); + return (tstate->c_recursion_remaining-- <= 0 + || (tstate->c_recursion_remaining & 63) == 0); } #else static inline int _Py_MakeRecCheck(PyThreadState *tstate) { - return tstate->recursion_remaining-- <= 0; + return tstate->c_recursion_remaining-- <= 0; } #endif @@ -131,6 +124,9 @@ PyAPI_FUNC(int) _Py_CheckRecursiveCall( PyThreadState *tstate, const char *where); +int _Py_CheckRecursiveCallPy( + PyThreadState *tstate); + static inline int _Py_EnterRecursiveCallTstate(PyThreadState *tstate, const char *where) { return (_Py_MakeRecCheck(tstate) && _Py_CheckRecursiveCall(tstate, where)); @@ -142,7 +138,7 @@ static inline int _Py_EnterRecursiveCall(const char *where) { } static inline void _Py_LeaveRecursiveCallTstate(PyThreadState *tstate) { - tstate->recursion_remaining++; + tstate->c_recursion_remaining++; } static inline void _Py_LeaveRecursiveCall(void) { @@ -157,6 +153,7 @@ extern PyObject* _Py_MakeCoro(PyFunctionObject *func); extern int _Py_HandlePending(PyThreadState *tstate); + #ifdef __cplusplus } #endif diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h index 621d5cc86425..8dd7a3128c66 100644 --- a/Include/internal/pycore_runtime_init.h +++ b/Include/internal/pycore_runtime_init.h @@ -68,7 +68,7 @@ extern "C" { #define _PyThreadState_INIT \ { \ ._static = 1, \ - .recursion_limit = Py_DEFAULT_RECURSION_LIMIT, \ + .py_recursion_limit = Py_DEFAULT_RECURSION_LIMIT, \ .context_ver = 1, \ } diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 573dce52ca47..9fdad641232c 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -60,7 +60,7 @@ "run_with_tz", "PGO", "missing_compiler_executable", "ALWAYS_EQ", "NEVER_EQ", "LARGEST", "SMALLEST", "LOOPBACK_TIMEOUT", "INTERNET_TIMEOUT", "SHORT_TIMEOUT", "LONG_TIMEOUT", - "Py_DEBUG", + "Py_DEBUG", "EXCEEDS_RECURSION_LIMIT", ] @@ -2352,3 +2352,6 @@ def adjust_int_max_str_digits(max_digits): yield finally: sys.set_int_max_str_digits(current) + +#For recursion tests, easily exceeds default recursion limit +EXCEEDS_RECURSION_LIMIT = 5000 diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py index 9a7df28e22c4..b34644118d28 100644 --- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -825,9 +825,9 @@ def next(self): @support.cpython_only def test_ast_recursion_limit(self): - fail_depth = sys.getrecursionlimit() * 3 - crash_depth = sys.getrecursionlimit() * 300 - success_depth = int(fail_depth * 0.75) + fail_depth = support.EXCEEDS_RECURSION_LIMIT + crash_depth = 100_000 + success_depth = 1200 def check_limit(prefix, repeated): expect_ok = prefix + repeated * success_depth diff --git a/Lib/test/test_call.py b/Lib/test/test_call.py index c1a386228ff0..1f3307f822a5 100644 --- a/Lib/test/test_call.py +++ b/Lib/test/test_call.py @@ -864,6 +864,44 @@ def test_multiple_values(self): with self.check_raises_type_error(msg): A().method_two_args("x", "y", x="oops") + at cpython_only +class TestRecursion(unittest.TestCase): + + def test_super_deep(self): + + def recurse(n): + if n: + recurse(n-1) + + def py_recurse(n, m): + if n: + py_recurse(n-1, m) + else: + c_py_recurse(m-1) + + def c_recurse(n): + if n: + _testcapi.pyobject_fastcall(c_recurse, (n-1,)) + + def c_py_recurse(m): + if m: + _testcapi.pyobject_fastcall(py_recurse, (1000, m)) + + depth = sys.getrecursionlimit() + sys.setrecursionlimit(100_000) + try: + recurse(90_000) + with self.assertRaises(RecursionError): + recurse(101_000) + c_recurse(100) + with self.assertRaises(RecursionError): + c_recurse(90_000) + c_py_recurse(90) + with self.assertRaises(RecursionError): + c_py_recurse(100_000) + finally: + sys.setrecursionlimit(depth) + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py index 59b3f2ec7bfc..1e398d6c3c7a 100644 --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -545,7 +545,7 @@ def test_odd_sizes(self): self.assertEqual(Dot(1)._replace(d=999), (999,)) self.assertEqual(Dot(1)._fields, ('d',)) - n = 5000 + n = support.EXCEEDS_RECURSION_LIMIT names = list(set(''.join([choice(string.ascii_letters) for j in range(10)]) for i in range(n))) n = len(names) diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index 7c55c7148aec..21dcc1a719cc 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -111,8 +111,7 @@ def __getitem__(self, key): @unittest.skipIf(support.is_wasi, "exhausts limited stack on WASI") def test_extended_arg(self): - # default: 1000 * 2.5 = 2500 repetitions - repeat = int(sys.getrecursionlimit() * 2.5) + repeat = 2000 longexpr = 'x = x or ' + '-x' * repeat g = {} code = ''' diff --git a/Lib/test/test_dynamic.py b/Lib/test/test_dynamic.py index 25544dea14df..7e12d428e0fd 100644 --- a/Lib/test/test_dynamic.py +++ b/Lib/test/test_dynamic.py @@ -140,11 +140,11 @@ class MyGlobals(dict): def __missing__(self, key): return int(key.removeprefix("_number_")) - # 1,000 on most systems - limit = sys.getrecursionlimit() - code = "lambda: " + "+".join(f"_number_{i}" for i in range(limit)) + # Need more than 256 variables to use EXTENDED_ARGS + variables = 400 + code = "lambda: " + "+".join(f"_number_{i}" for i in range(variables)) sum_func = eval(code, MyGlobals()) - expected = sum(range(limit)) + expected = sum(range(variables)) # Warm up the the function for quickening (PEP 659) for _ in range(30): self.assertEqual(sum_func(), expected) diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 03a0f8b576f6..65a3a8a48a88 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -1372,6 +1372,7 @@ def test_recursion_normalizing_exception(self): code = """if 1: import sys from _testinternalcapi import get_recursion_depth + from test import support class MyException(Exception): pass @@ -1399,13 +1400,8 @@ def gen(): generator = gen() next(generator) recursionlimit = sys.getrecursionlimit() - depth = get_recursion_depth() try: - # Upon the last recursive invocation of recurse(), - # tstate->recursion_depth is equal to (recursion_limit - 1) - # and is equal to recursion_limit when _gen_throw() calls - # PyErr_NormalizeException(). - recurse(setrecursionlimit(depth + 2) - depth) + recurse(support.EXCEEDS_RECURSION_LIMIT) finally: sys.setrecursionlimit(recursionlimit) print('Done.') diff --git a/Lib/test/test_isinstance.py b/Lib/test/test_isinstance.py index a0974640bc11..2fcf6ebbee7e 100644 --- a/Lib/test/test_isinstance.py +++ b/Lib/test/test_isinstance.py @@ -8,7 +8,7 @@ from test import support - + class TestIsInstanceExceptions(unittest.TestCase): # Test to make sure that an AttributeError when accessing the instance's # class's bases is masked. This was actually a bug in Python 2.2 and @@ -97,7 +97,7 @@ def getclass(self): class D: pass self.assertRaises(RuntimeError, isinstance, c, D) - + # These tests are similar to above, but tickle certain code paths in # issubclass() instead of isinstance() -- really PyObject_IsSubclass() # vs. PyObject_IsInstance(). @@ -147,7 +147,7 @@ def getbases(self): self.assertRaises(TypeError, issubclass, B, C()) - + # meta classes for creating abstract classes and instances class AbstractClass(object): def __init__(self, bases): @@ -179,7 +179,7 @@ class Super: class Child(Super): pass - + class TestIsInstanceIsSubclass(unittest.TestCase): # Tests to ensure that isinstance and issubclass work on abstract # classes and instances. Before the 2.2 release, TypeErrors were @@ -353,10 +353,10 @@ def blowstack(fxn, arg, compare_to): # Make sure that calling isinstance with a deeply nested tuple for its # argument will raise RecursionError eventually. tuple_arg = (compare_to,) - for cnt in range(sys.getrecursionlimit()+5): + for cnt in range(support.EXCEEDS_RECURSION_LIMIT): tuple_arg = (tuple_arg,) fxn(arg, tuple_arg) - + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py index 882a819ca809..fe4f368bed42 100644 --- a/Lib/test/test_marshal.py +++ b/Lib/test/test_marshal.py @@ -117,7 +117,8 @@ def test_code(self): def test_many_codeobjects(self): # Issue2957: bad recursion count on code objects - count = 5000 # more than MAX_MARSHAL_STACK_DEPTH + # more than MAX_MARSHAL_STACK_DEPTH + count = support.EXCEEDS_RECURSION_LIMIT codes = (ExceptionTestCase.test_exceptions.__code__,) * count marshal.loads(marshal.dumps(codes)) diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-05-09-56-32.gh-issue-91079.H4-DdU.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-05-09-56-32.gh-issue-91079.H4-DdU.rst new file mode 100644 index 000000000000..64606ac74a49 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-09-05-09-56-32.gh-issue-91079.H4-DdU.rst @@ -0,0 +1,3 @@ +Separate Python recursion checking from C recursion checking which reduces +the chance of C stack overflow and allows the recursion limit to be +increased safely. diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 02a061b84f85..5724bd5f200f 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -44,9 +44,7 @@ get_recursion_depth(PyObject *self, PyObject *Py_UNUSED(args)) { PyThreadState *tstate = _PyThreadState_GET(); - /* subtract one to ignore the frame of the get_recursion_depth() call */ - - return PyLong_FromLong(tstate->recursion_limit - tstate->recursion_remaining - 1); + return PyLong_FromLong(tstate->py_recursion_limit - tstate->py_recursion_remaining); } diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py index 13dd44ca0cdc..6bd2e66c804d 100755 --- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -1380,7 +1380,6 @@ class PartingShots(StaticVisitor): return NULL; } - int recursion_limit = Py_GetRecursionLimit(); int starting_recursion_depth; /* Be careful here to prevent overflow. */ int COMPILER_STACK_FRAME_SCALE = 3; @@ -1388,11 +1387,9 @@ class PartingShots(StaticVisitor): if (!tstate) { return 0; } - state->recursion_limit = (recursion_limit < INT_MAX / COMPILER_STACK_FRAME_SCALE) ? - recursion_limit * COMPILER_STACK_FRAME_SCALE : recursion_limit; - int recursion_depth = tstate->recursion_limit - tstate->recursion_remaining; - starting_recursion_depth = (recursion_depth < INT_MAX / COMPILER_STACK_FRAME_SCALE) ? - recursion_depth * COMPILER_STACK_FRAME_SCALE : recursion_depth; + state->recursion_limit = C_RECURSION_LIMIT * COMPILER_STACK_FRAME_SCALE; + int recursion_depth = C_RECURSION_LIMIT - tstate->c_recursion_remaining; + starting_recursion_depth = recursion_depth * COMPILER_STACK_FRAME_SCALE; state->recursion_depth = starting_recursion_depth; PyObject *result = ast2obj_mod(state, t); diff --git a/Python/Python-ast.c b/Python/Python-ast.c index f485af675ccf..2571e28bc169 100644 --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -12315,7 +12315,6 @@ PyObject* PyAST_mod2obj(mod_ty t) return NULL; } - int recursion_limit = Py_GetRecursionLimit(); int starting_recursion_depth; /* Be careful here to prevent overflow. */ int COMPILER_STACK_FRAME_SCALE = 3; @@ -12323,11 +12322,9 @@ PyObject* PyAST_mod2obj(mod_ty t) if (!tstate) { return 0; } - state->recursion_limit = (recursion_limit < INT_MAX / COMPILER_STACK_FRAME_SCALE) ? - recursion_limit * COMPILER_STACK_FRAME_SCALE : recursion_limit; - int recursion_depth = tstate->recursion_limit - tstate->recursion_remaining; - starting_recursion_depth = (recursion_depth < INT_MAX / COMPILER_STACK_FRAME_SCALE) ? - recursion_depth * COMPILER_STACK_FRAME_SCALE : recursion_depth; + state->recursion_limit = C_RECURSION_LIMIT * COMPILER_STACK_FRAME_SCALE; + int recursion_depth = C_RECURSION_LIMIT - tstate->c_recursion_remaining; + starting_recursion_depth = recursion_depth * COMPILER_STACK_FRAME_SCALE; state->recursion_depth = starting_recursion_depth; PyObject *result = ast2obj_mod(state, t); diff --git a/Python/ast.c b/Python/ast.c index a0321b58ba8c..50fc8e01fb3f 100644 --- a/Python/ast.c +++ b/Python/ast.c @@ -975,7 +975,6 @@ _PyAST_Validate(mod_ty mod) int res = -1; struct validator state; PyThreadState *tstate; - int recursion_limit = Py_GetRecursionLimit(); int starting_recursion_depth; /* Setup recursion depth check counters */ @@ -984,12 +983,10 @@ _PyAST_Validate(mod_ty mod) return 0; } /* Be careful here to prevent overflow. */ - int recursion_depth = tstate->recursion_limit - tstate->recursion_remaining; - starting_recursion_depth = (recursion_depth< INT_MAX / COMPILER_STACK_FRAME_SCALE) ? - recursion_depth * COMPILER_STACK_FRAME_SCALE : recursion_depth; + int recursion_depth = C_RECURSION_LIMIT - tstate->c_recursion_remaining; + starting_recursion_depth = recursion_depth * COMPILER_STACK_FRAME_SCALE; state.recursion_depth = starting_recursion_depth; - state.recursion_limit = (recursion_limit < INT_MAX / COMPILER_STACK_FRAME_SCALE) ? - recursion_limit * COMPILER_STACK_FRAME_SCALE : recursion_limit; + state.recursion_limit = C_RECURSION_LIMIT * COMPILER_STACK_FRAME_SCALE; switch (mod->kind) { case Module_kind: diff --git a/Python/ast_opt.c b/Python/ast_opt.c index b1d807bcf10a..426c5341b56f 100644 --- a/Python/ast_opt.c +++ b/Python/ast_opt.c @@ -1080,7 +1080,6 @@ int _PyAST_Optimize(mod_ty mod, PyArena *arena, _PyASTOptimizeState *state) { PyThreadState *tstate; - int recursion_limit = Py_GetRecursionLimit(); int starting_recursion_depth; /* Setup recursion depth check counters */ @@ -1089,12 +1088,10 @@ _PyAST_Optimize(mod_ty mod, PyArena *arena, _PyASTOptimizeState *state) return 0; } /* Be careful here to prevent overflow. */ - int recursion_depth = tstate->recursion_limit - tstate->recursion_remaining; - starting_recursion_depth = (recursion_depth < INT_MAX / COMPILER_STACK_FRAME_SCALE) ? - recursion_depth * COMPILER_STACK_FRAME_SCALE : recursion_depth; + int recursion_depth = C_RECURSION_LIMIT - tstate->c_recursion_remaining; + starting_recursion_depth = recursion_depth * COMPILER_STACK_FRAME_SCALE; state->recursion_depth = starting_recursion_depth; - state->recursion_limit = (recursion_limit < INT_MAX / COMPILER_STACK_FRAME_SCALE) ? - recursion_limit * COMPILER_STACK_FRAME_SCALE : recursion_limit; + state->recursion_limit = C_RECURSION_LIMIT * COMPILER_STACK_FRAME_SCALE; int ret = astfold_mod(mod, arena, state); assert(ret || PyErr_Occurred()); diff --git a/Python/ceval.c b/Python/ceval.c index 82b5422c188e..c08c794005d1 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -257,9 +257,9 @@ Py_SetRecursionLimit(int new_limit) PyInterpreterState *interp = _PyInterpreterState_GET(); interp->ceval.recursion_limit = new_limit; for (PyThreadState *p = interp->threads.head; p != NULL; p = p->next) { - int depth = p->recursion_limit - p->recursion_remaining; - p->recursion_limit = new_limit; - p->recursion_remaining = new_limit - depth; + int depth = p->py_recursion_limit - p->py_recursion_remaining; + p->py_recursion_limit = new_limit; + p->py_recursion_remaining = new_limit - depth; } } @@ -268,35 +268,27 @@ Py_SetRecursionLimit(int new_limit) int _Py_CheckRecursiveCall(PyThreadState *tstate, const char *where) { - /* Check against global limit first. */ - int depth = tstate->recursion_limit - tstate->recursion_remaining; - if (depth < tstate->interp->ceval.recursion_limit) { - tstate->recursion_limit = tstate->interp->ceval.recursion_limit; - tstate->recursion_remaining = tstate->recursion_limit - depth; - assert(tstate->recursion_remaining > 0); - return 0; - } #ifdef USE_STACKCHECK if (PyOS_CheckStack()) { - ++tstate->recursion_remaining; + ++tstate->c_recursion_remaining; _PyErr_SetString(tstate, PyExc_MemoryError, "Stack overflow"); return -1; } #endif if (tstate->recursion_headroom) { - if (tstate->recursion_remaining < -50) { + if (tstate->c_recursion_remaining < -50) { /* Overflowing while handling an overflow. Give up. */ Py_FatalError("Cannot recover from stack overflow."); } } else { - if (tstate->recursion_remaining <= 0) { + if (tstate->c_recursion_remaining <= 0) { tstate->recursion_headroom++; _PyErr_Format(tstate, PyExc_RecursionError, "maximum recursion depth exceeded%s", where); tstate->recursion_headroom--; - ++tstate->recursion_remaining; + ++tstate->c_recursion_remaining; return -1; } } @@ -983,6 +975,39 @@ pop_frame(PyThreadState *tstate, _PyInterpreterFrame *frame) return prev_frame; } + +int _Py_CheckRecursiveCallPy( + PyThreadState *tstate) +{ + if (tstate->recursion_headroom) { + if (tstate->py_recursion_remaining < -50) { + /* Overflowing while handling an overflow. Give up. */ + Py_FatalError("Cannot recover from Python stack overflow."); + } + } + else { + if (tstate->py_recursion_remaining <= 0) { + tstate->recursion_headroom++; + _PyErr_Format(tstate, PyExc_RecursionError, + "maximum recursion depth exceeded"); + tstate->recursion_headroom--; + return -1; + } + } + return 0; +} + +static inline int _Py_EnterRecursivePy(PyThreadState *tstate) { + return (tstate->py_recursion_remaining-- <= 0) && + _Py_CheckRecursiveCallPy(tstate); +} + + +static inline void _Py_LeaveRecursiveCallPy(PyThreadState *tstate) { + tstate->py_recursion_remaining++; +} + + /* It is only between the KW_NAMES instruction and the following CALL, * that this has any meaning. */ @@ -1037,10 +1062,15 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int frame->previous = prev_cframe->current_frame; cframe.current_frame = frame; + if (_Py_EnterRecursiveCallTstate(tstate, "")) { + tstate->c_recursion_remaining--; + tstate->py_recursion_remaining--; + goto exit_unwind; + } + /* support for generator.throw() */ if (throwflag) { - if (_Py_EnterRecursiveCallTstate(tstate, "")) { - tstate->recursion_remaining--; + if (_Py_EnterRecursivePy(tstate)) { goto exit_unwind; } TRACE_FUNCTION_THROW_ENTRY(); @@ -1079,8 +1109,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int start_frame: - if (_Py_EnterRecursiveCallTstate(tstate, "")) { - tstate->recursion_remaining--; + if (_Py_EnterRecursivePy(tstate)) { goto exit_unwind; } @@ -1830,12 +1859,13 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int _PyFrame_SetStackPointer(frame, stack_pointer); TRACE_FUNCTION_EXIT(); DTRACE_FUNCTION_EXIT(); - _Py_LeaveRecursiveCallTstate(tstate); + _Py_LeaveRecursiveCallPy(tstate); if (!frame->is_entry) { frame = cframe.current_frame = pop_frame(tstate, frame); _PyFrame_StackPush(frame, retval); goto resume_frame; } + _Py_LeaveRecursiveCallTstate(tstate); /* Restore previous cframe and return. */ tstate->cframe = cframe.previous; tstate->cframe->use_tracing = cframe.use_tracing; @@ -2046,6 +2076,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int _PyFrame_SetStackPointer(frame, stack_pointer); TRACE_FUNCTION_EXIT(); DTRACE_FUNCTION_EXIT(); + _Py_LeaveRecursiveCallPy(tstate); _Py_LeaveRecursiveCallTstate(tstate); /* Restore previous cframe and return. */ tstate->cframe = cframe.previous; @@ -4800,7 +4831,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int assert(frame->frame_obj == NULL); gen->gi_frame_state = FRAME_CREATED; gen_frame->owner = FRAME_OWNED_BY_GENERATOR; - _Py_LeaveRecursiveCallTstate(tstate); + _Py_LeaveRecursiveCallPy(tstate); if (!frame->is_entry) { _PyInterpreterFrame *prev = frame->previous; _PyThreadState_PopFrame(tstate, frame); @@ -4808,6 +4839,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; } + _Py_LeaveRecursiveCallTstate(tstate); /* Make sure that frame is in a valid state */ frame->stacktop = 0; frame->f_locals = NULL; @@ -5178,12 +5210,13 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int exit_unwind: assert(_PyErr_Occurred(tstate)); - _Py_LeaveRecursiveCallTstate(tstate); + _Py_LeaveRecursiveCallPy(tstate); if (frame->is_entry) { /* Restore previous cframe and exit */ tstate->cframe = cframe.previous; tstate->cframe->use_tracing = cframe.use_tracing; assert(tstate->cframe->current_frame == frame->previous); + _Py_LeaveRecursiveCallTstate(tstate); return NULL; } frame = cframe.current_frame = pop_frame(tstate, frame); @@ -5755,11 +5788,11 @@ _PyEvalFrameClearAndPop(PyThreadState *tstate, _PyInterpreterFrame * frame) // _PyThreadState_PopFrame, since f_code is already cleared at that point: assert((PyObject **)frame + frame->f_code->co_framesize == tstate->datastack_top); - tstate->recursion_remaining--; + tstate->c_recursion_remaining--; assert(frame->frame_obj == NULL || frame->frame_obj->f_frame == frame); assert(frame->owner == FRAME_OWNED_BY_THREAD); _PyFrame_Clear(frame); - tstate->recursion_remaining++; + tstate->c_recursion_remaining++; _PyThreadState_PopFrame(tstate, frame); } diff --git a/Python/pystate.c b/Python/pystate.c index 23e9d24c591b..50ae0ce68217 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -792,8 +792,9 @@ init_threadstate(PyThreadState *tstate, tstate->native_thread_id = PyThread_get_thread_native_id(); #endif - tstate->recursion_limit = interp->ceval.recursion_limit, - tstate->recursion_remaining = interp->ceval.recursion_limit, + tstate->py_recursion_limit = interp->ceval.recursion_limit, + tstate->py_recursion_remaining = interp->ceval.recursion_limit, + tstate->c_recursion_remaining = C_RECURSION_LIMIT; tstate->exc_info = &tstate->exc_state; diff --git a/Python/symtable.c b/Python/symtable.c index 0b259b08b61f..342f5a080d3d 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -278,7 +278,6 @@ _PySymtable_Build(mod_ty mod, PyObject *filename, PyFutureFeatures *future) asdl_stmt_seq *seq; int i; PyThreadState *tstate; - int recursion_limit = Py_GetRecursionLimit(); int starting_recursion_depth; if (st == NULL) @@ -298,12 +297,10 @@ _PySymtable_Build(mod_ty mod, PyObject *filename, PyFutureFeatures *future) return NULL; } /* Be careful here to prevent overflow. */ - int recursion_depth = tstate->recursion_limit - tstate->recursion_remaining; - starting_recursion_depth = (recursion_depth < INT_MAX / COMPILER_STACK_FRAME_SCALE) ? - recursion_depth * COMPILER_STACK_FRAME_SCALE : recursion_depth; + int recursion_depth = C_RECURSION_LIMIT - tstate->c_recursion_remaining; + starting_recursion_depth = recursion_depth * COMPILER_STACK_FRAME_SCALE; st->recursion_depth = starting_recursion_depth; - st->recursion_limit = (recursion_limit < INT_MAX / COMPILER_STACK_FRAME_SCALE) ? - recursion_limit * COMPILER_STACK_FRAME_SCALE : recursion_limit; + st->recursion_limit = C_RECURSION_LIMIT * COMPILER_STACK_FRAME_SCALE; /* Make the initial symbol information gathering pass */ if (!symtable_enter_block(st, &_Py_ID(top), ModuleBlock, (void *)mod, 0, 0, 0, 0)) { diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 1ecf6a2dd39f..2c66415ee3d3 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1218,7 +1218,7 @@ sys_setrecursionlimit_impl(PyObject *module, int new_limit) /* Reject too low new limit if the current recursion depth is higher than the new low-water mark. */ - int depth = tstate->recursion_limit - tstate->recursion_remaining; + int depth = tstate->py_recursion_limit - tstate->py_recursion_remaining; if (depth >= new_limit) { _PyErr_Format(tstate, PyExc_RecursionError, "cannot set the recursion limit to %i at " From webhook-mailer at python.org Tue Oct 4 20:36:12 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Wed, 05 Oct 2022 00:36:12 -0000 Subject: [Python-checkins] gh-97654: Add auto exception chaining example to tutorial (#97703) Message-ID: https://github.com/python/cpython/commit/395b66a0ae5237eec195ca97daaaf8563706ed34 commit: 395b66a0ae5237eec195ca97daaaf8563706ed34 branch: main author: Shahriar Heidrich committer: JelleZijlstra date: 2022-10-04T17:36:04-07:00 summary: gh-97654: Add auto exception chaining example to tutorial (#97703) Add auto exception chaining example to tutorial files: M Doc/tutorial/errors.rst diff --git a/Doc/tutorial/errors.rst b/Doc/tutorial/errors.rst index 57919e3bad13..67bb19556681 100644 --- a/Doc/tutorial/errors.rst +++ b/Doc/tutorial/errors.rst @@ -284,8 +284,27 @@ re-raise the exception:: Exception Chaining ================== -The :keyword:`raise` statement allows an optional :keyword:`from` which enables -chaining exceptions. For example:: +If an unhandled exception occurs inside an :keyword:`except` section, it will +have the exception being handled attached to it and included in the error +message:: + + >>> try: + ... open("database.sqlite") + ... except OSError: + ... raise RuntimeError("unable to handle error") + ... + Traceback (most recent call last): + File "", line 2, in + FileNotFoundError: [Errno 2] No such file or directory: 'database.sqlite' + + During handling of the above exception, another exception occurred: + + Traceback (most recent call last): + File "", line 4, in + RuntimeError: unable to handle error + +To indicate that an exception is a direct consequence of another, the +:keyword:`raise` statement allows an optional :keyword:`from` clause:: # exc must be exception instance or None. raise RuntimeError from exc @@ -311,9 +330,8 @@ This can be useful when you are transforming exceptions. For example:: File "", line 4, in RuntimeError: Failed to open database -Exception chaining happens automatically when an exception is raised inside an -:keyword:`except` or :keyword:`finally` section. This can be -disabled by using ``from None`` idiom: +It also allows disabling automatic exception chaining using the ``from None`` +idiom:: >>> try: ... open('database.sqlite') From webhook-mailer at python.org Tue Oct 4 20:39:50 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Wed, 05 Oct 2022 00:39:50 -0000 Subject: [Python-checkins] Add re.VERBOSE flag documentation example (#97678) Message-ID: https://github.com/python/cpython/commit/0ceafa7fa408b64377ea31dd5386152da19ef38a commit: 0ceafa7fa408b64377ea31dd5386152da19ef38a branch: main author: Athos Ribeiro committer: JelleZijlstra date: 2022-10-04T17:39:42-07:00 summary: Add re.VERBOSE flag documentation example (#97678) The current re.VERBOSE documentation example leaves space for ambiguous interpretation. One may read that spaces within the `(?:` token are spaces inside the non-capturing group (such as `(?: )`). This patch removes the ambiguity by including examples after the statement. files: M Doc/library/re.rst diff --git a/Doc/library/re.rst b/Doc/library/re.rst index 1b9a7b63ef5e..5b304f717b07 100644 --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -783,7 +783,8 @@ Flags more readable by allowing you to visually separate logical sections of the pattern and add comments. Whitespace within the pattern is ignored, except when in a character class, or when preceded by an unescaped backslash, - or within tokens like ``*?``, ``(?:`` or ``(?P<...>``. + or within tokens like ``*?``, ``(?:`` or ``(?P<...>``. For example, ``(? :`` + and ``* ?`` are not allowed. When a line contains a ``#`` that is not in a character class and is not preceded by an unescaped backslash, all characters from the leftmost such ``#`` through the end of the line are ignored. From webhook-mailer at python.org Tue Oct 4 20:47:07 2022 From: webhook-mailer at python.org (ambv) Date: Wed, 05 Oct 2022 00:47:07 -0000 Subject: [Python-checkins] [3.11] gh-93738: Documentation C syntax (:c:type:`FILE` -> :c:expr:`FILE`) (GH-97769) (#97871) Message-ID: https://github.com/python/cpython/commit/1b7da7f0886ff6ba3bbbd664d3eb5e485ff8b3c2 commit: 1b7da7f0886ff6ba3bbbd664d3eb5e485ff8b3c2 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-04T17:47:02-07:00 summary: [3.11] gh-93738: Documentation C syntax (:c:type:`FILE` -> :c:expr:`FILE`) (GH-97769) (#97871) :c:type:`FILE` -> :c:expr:`FILE` (cherry picked from commit 192d401ba53224020f5f9ca6e1ff2c9f89511ac4) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> files: M Doc/c-api/file.rst M Doc/c-api/marshal.rst M Doc/c-api/veryhigh.rst diff --git a/Doc/c-api/file.rst b/Doc/c-api/file.rst index ed3735aa8360..145dfe4962ac 100644 --- a/Doc/c-api/file.rst +++ b/Doc/c-api/file.rst @@ -8,7 +8,7 @@ File Objects .. index:: object: file These APIs are a minimal emulation of the Python 2 C API for built-in file -objects, which used to rely on the buffered I/O (:c:type:`FILE*`) support +objects, which used to rely on the buffered I/O (:c:expr:`FILE*`) support from the C standard library. In Python 3, files and streams use the new :mod:`io` module, which defines several layers over the low-level unbuffered I/O of the operating system. The functions described below are diff --git a/Doc/c-api/marshal.rst b/Doc/c-api/marshal.rst index 7bb0dad2b6b6..1ba18beb3ea0 100644 --- a/Doc/c-api/marshal.rst +++ b/Doc/c-api/marshal.rst @@ -43,7 +43,7 @@ The following functions allow marshalled values to be read back in. .. c:function:: long PyMarshal_ReadLongFromFile(FILE *file) - Return a C :c:type:`long` from the data stream in a :c:type:`FILE*` opened + Return a C :c:type:`long` from the data stream in a :c:expr:`FILE*` opened for reading. Only a 32-bit value can be read in using this function, regardless of the native size of :c:type:`long`. @@ -53,7 +53,7 @@ The following functions allow marshalled values to be read back in. .. c:function:: int PyMarshal_ReadShortFromFile(FILE *file) - Return a C :c:type:`short` from the data stream in a :c:type:`FILE*` opened + Return a C :c:type:`short` from the data stream in a :c:expr:`FILE*` opened for reading. Only a 16-bit value can be read in using this function, regardless of the native size of :c:type:`short`. @@ -63,7 +63,7 @@ The following functions allow marshalled values to be read back in. .. c:function:: PyObject* PyMarshal_ReadObjectFromFile(FILE *file) - Return a Python object from the data stream in a :c:type:`FILE*` opened for + Return a Python object from the data stream in a :c:expr:`FILE*` opened for reading. On error, sets the appropriate exception (:exc:`EOFError`, :exc:`ValueError` @@ -72,7 +72,7 @@ The following functions allow marshalled values to be read back in. .. c:function:: PyObject* PyMarshal_ReadLastObjectFromFile(FILE *file) - Return a Python object from the data stream in a :c:type:`FILE*` opened for + Return a Python object from the data stream in a :c:expr:`FILE*` opened for reading. Unlike :c:func:`PyMarshal_ReadObjectFromFile`, this function assumes that no further objects will be read from the file, allowing it to aggressively load file data into memory so that the de-serialization can diff --git a/Doc/c-api/veryhigh.rst b/Doc/c-api/veryhigh.rst index 7bd47bb9c660..d15adad3dfe6 100644 --- a/Doc/c-api/veryhigh.rst +++ b/Doc/c-api/veryhigh.rst @@ -16,11 +16,11 @@ parameter. The available start symbols are :const:`Py_eval_input`, :const:`Py_file_input`, and :const:`Py_single_input`. These are described following the functions which accept them as parameters. -Note also that several of these functions take :c:type:`FILE*` parameters. One -particular issue which needs to be handled carefully is that the :c:type:`FILE` +Note also that several of these functions take :c:expr:`FILE*` parameters. One +particular issue which needs to be handled carefully is that the :c:expr:`FILE` structure for different C libraries can be different and incompatible. Under Windows (at least), it is possible for dynamically linked extensions to actually -use different libraries, so care should be taken that :c:type:`FILE*` parameters +use different libraries, so care should be taken that :c:expr:`FILE*` parameters are only passed to these functions if it is certain that they were created by the same library that the Python runtime is using. From webhook-mailer at python.org Tue Oct 4 20:47:25 2022 From: webhook-mailer at python.org (ambv) Date: Wed, 05 Oct 2022 00:47:25 -0000 Subject: [Python-checkins] [3.10] gh-93738: Documentation C syntax (:c:type:`FILE` -> :c:expr:`FILE`) (GH-97769) (#97872) Message-ID: https://github.com/python/cpython/commit/5eedf1d8636da4faa1ced9c02cf59d35ac2f00a6 commit: 5eedf1d8636da4faa1ced9c02cf59d35ac2f00a6 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-04T17:47:20-07:00 summary: [3.10] gh-93738: Documentation C syntax (:c:type:`FILE` -> :c:expr:`FILE`) (GH-97769) (#97872) :c:type:`FILE` -> :c:expr:`FILE` (cherry picked from commit 192d401ba53224020f5f9ca6e1ff2c9f89511ac4) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> files: M Doc/c-api/file.rst M Doc/c-api/marshal.rst M Doc/c-api/veryhigh.rst diff --git a/Doc/c-api/file.rst b/Doc/c-api/file.rst index ed3735aa8360..145dfe4962ac 100644 --- a/Doc/c-api/file.rst +++ b/Doc/c-api/file.rst @@ -8,7 +8,7 @@ File Objects .. index:: object: file These APIs are a minimal emulation of the Python 2 C API for built-in file -objects, which used to rely on the buffered I/O (:c:type:`FILE*`) support +objects, which used to rely on the buffered I/O (:c:expr:`FILE*`) support from the C standard library. In Python 3, files and streams use the new :mod:`io` module, which defines several layers over the low-level unbuffered I/O of the operating system. The functions described below are diff --git a/Doc/c-api/marshal.rst b/Doc/c-api/marshal.rst index 7bb0dad2b6b6..1ba18beb3ea0 100644 --- a/Doc/c-api/marshal.rst +++ b/Doc/c-api/marshal.rst @@ -43,7 +43,7 @@ The following functions allow marshalled values to be read back in. .. c:function:: long PyMarshal_ReadLongFromFile(FILE *file) - Return a C :c:type:`long` from the data stream in a :c:type:`FILE*` opened + Return a C :c:type:`long` from the data stream in a :c:expr:`FILE*` opened for reading. Only a 32-bit value can be read in using this function, regardless of the native size of :c:type:`long`. @@ -53,7 +53,7 @@ The following functions allow marshalled values to be read back in. .. c:function:: int PyMarshal_ReadShortFromFile(FILE *file) - Return a C :c:type:`short` from the data stream in a :c:type:`FILE*` opened + Return a C :c:type:`short` from the data stream in a :c:expr:`FILE*` opened for reading. Only a 16-bit value can be read in using this function, regardless of the native size of :c:type:`short`. @@ -63,7 +63,7 @@ The following functions allow marshalled values to be read back in. .. c:function:: PyObject* PyMarshal_ReadObjectFromFile(FILE *file) - Return a Python object from the data stream in a :c:type:`FILE*` opened for + Return a Python object from the data stream in a :c:expr:`FILE*` opened for reading. On error, sets the appropriate exception (:exc:`EOFError`, :exc:`ValueError` @@ -72,7 +72,7 @@ The following functions allow marshalled values to be read back in. .. c:function:: PyObject* PyMarshal_ReadLastObjectFromFile(FILE *file) - Return a Python object from the data stream in a :c:type:`FILE*` opened for + Return a Python object from the data stream in a :c:expr:`FILE*` opened for reading. Unlike :c:func:`PyMarshal_ReadObjectFromFile`, this function assumes that no further objects will be read from the file, allowing it to aggressively load file data into memory so that the de-serialization can diff --git a/Doc/c-api/veryhigh.rst b/Doc/c-api/veryhigh.rst index 5b8735de75e9..68d6604ace9e 100644 --- a/Doc/c-api/veryhigh.rst +++ b/Doc/c-api/veryhigh.rst @@ -16,11 +16,11 @@ parameter. The available start symbols are :const:`Py_eval_input`, :const:`Py_file_input`, and :const:`Py_single_input`. These are described following the functions which accept them as parameters. -Note also that several of these functions take :c:type:`FILE*` parameters. One -particular issue which needs to be handled carefully is that the :c:type:`FILE` +Note also that several of these functions take :c:expr:`FILE*` parameters. One +particular issue which needs to be handled carefully is that the :c:expr:`FILE` structure for different C libraries can be different and incompatible. Under Windows (at least), it is possible for dynamically linked extensions to actually -use different libraries, so care should be taken that :c:type:`FILE*` parameters +use different libraries, so care should be taken that :c:expr:`FILE*` parameters are only passed to these functions if it is certain that they were created by the same library that the Python runtime is using. From webhook-mailer at python.org Tue Oct 4 20:47:57 2022 From: webhook-mailer at python.org (gpshead) Date: Wed, 05 Oct 2022 00:47:57 -0000 Subject: [Python-checkins] gh-97825: fix AttributeError when calling subprocess.check_output(input=None) with encoding or errors args (#97826) Message-ID: https://github.com/python/cpython/commit/db64fb9bbe92b212db7dd173f787ea3607ae971a commit: db64fb9bbe92b212db7dd173f787ea3607ae971a branch: main author: andrei kulakov committer: gpshead date: 2022-10-04T17:47:49-07:00 summary: gh-97825: fix AttributeError when calling subprocess.check_output(input=None) with encoding or errors args (#97826) * fix AttributeError, add unit test files: A Misc/NEWS.d/next/Library/2022-10-04-07-55-19.gh-issue-97825.mNdv1l.rst M Lib/subprocess.py M Lib/test/test_subprocess.py diff --git a/Lib/subprocess.py b/Lib/subprocess.py index 7ae8df154b48..760b93b47ebb 100644 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -456,7 +456,8 @@ def check_output(*popenargs, timeout=None, **kwargs): if 'input' in kwargs and kwargs['input'] is None: # Explicitly passing input=None was previously equivalent to passing an # empty string. That is maintained here for backwards compatibility. - if kwargs.get('universal_newlines') or kwargs.get('text'): + if kwargs.get('universal_newlines') or kwargs.get('text') or kwargs.get('encoding') \ + or kwargs.get('errors'): empty = '' else: empty = b'' diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index f6854922a5b8..424a4a93b6f9 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -238,6 +238,12 @@ def test_check_output_input_none_universal_newlines(self): input=None, universal_newlines=True) self.assertNotIn('XX', output) + def test_check_output_input_none_encoding_errors(self): + output = subprocess.check_output( + [sys.executable, "-c", "print('foo')"], + input=None, encoding='utf-8', errors='ignore') + self.assertIn('foo', output) + def test_check_output_stdout_arg(self): # check_output() refuses to accept 'stdout' argument with self.assertRaises(ValueError) as c: diff --git a/Misc/NEWS.d/next/Library/2022-10-04-07-55-19.gh-issue-97825.mNdv1l.rst b/Misc/NEWS.d/next/Library/2022-10-04-07-55-19.gh-issue-97825.mNdv1l.rst new file mode 100644 index 000000000000..4633dce7b663 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-04-07-55-19.gh-issue-97825.mNdv1l.rst @@ -0,0 +1 @@ +Fixes :exc:`AttributeError` when :meth:`subprocess.check_output` is used with argument ``input=None`` and either of the arguments *encoding* or *errors* are used. From webhook-mailer at python.org Tue Oct 4 20:48:05 2022 From: webhook-mailer at python.org (ambv) Date: Wed, 05 Oct 2022 00:48:05 -0000 Subject: [Python-checkins] [3.10] gh-93738: Documentation C syntax (:c:type:`TYPE` -> :c:expr:`TYPE`) (GH-97770) (#97870) Message-ID: https://github.com/python/cpython/commit/994eaa3a6f8f3f3b7fae649cc51dcdcc98bfac48 commit: 994eaa3a6f8f3f3b7fae649cc51dcdcc98bfac48 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-04T17:47:56-07:00 summary: [3.10] gh-93738: Documentation C syntax (:c:type:`TYPE` -> :c:expr:`TYPE`) (GH-97770) (#97870) :c:type:`TYPE` -> :c:expr:`TYPE` (cherry picked from commit 8b211b4cdbcddecfcc4d1682864795b5f1438c59) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> files: M Doc/c-api/memory.rst diff --git a/Doc/c-api/memory.rst b/Doc/c-api/memory.rst index 1bdb6a801e4c..419efb758991 100644 --- a/Doc/c-api/memory.rst +++ b/Doc/c-api/memory.rst @@ -265,14 +265,14 @@ The following type-oriented macros are provided for convenience. Note that .. c:function:: TYPE* PyMem_New(TYPE, size_t n) Same as :c:func:`PyMem_Malloc`, but allocates ``(n * sizeof(TYPE))`` bytes of - memory. Returns a pointer cast to :c:type:`TYPE*`. The memory will not have + memory. Returns a pointer cast to :c:expr:`TYPE*`. The memory will not have been initialized in any way. .. c:function:: TYPE* PyMem_Resize(void *p, TYPE, size_t n) Same as :c:func:`PyMem_Realloc`, but the memory block is resized to ``(n * - sizeof(TYPE))`` bytes. Returns a pointer cast to :c:type:`TYPE*`. On return, + sizeof(TYPE))`` bytes. Returns a pointer cast to :c:expr:`TYPE*`. On return, *p* will be a pointer to the new memory area, or ``NULL`` in the event of failure. From webhook-mailer at python.org Tue Oct 4 20:48:30 2022 From: webhook-mailer at python.org (ambv) Date: Wed, 05 Oct 2022 00:48:30 -0000 Subject: [Python-checkins] [3.11] gh-93738: Documentation C syntax (:c:type:`TYPE` -> :c:expr:`TYPE`) (GH-97770) (#97874) Message-ID: https://github.com/python/cpython/commit/3ec11d92fd5db72ae27083fa2933a8d1c93c7c82 commit: 3ec11d92fd5db72ae27083fa2933a8d1c93c7c82 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-04T17:48:24-07:00 summary: [3.11] gh-93738: Documentation C syntax (:c:type:`TYPE` -> :c:expr:`TYPE`) (GH-97770) (#97874) :c:type:`TYPE` -> :c:expr:`TYPE` (cherry picked from commit 8b211b4cdbcddecfcc4d1682864795b5f1438c59) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> files: M Doc/c-api/memory.rst diff --git a/Doc/c-api/memory.rst b/Doc/c-api/memory.rst index 335ea00cff7c..4abbf340c5f4 100644 --- a/Doc/c-api/memory.rst +++ b/Doc/c-api/memory.rst @@ -265,14 +265,14 @@ The following type-oriented macros are provided for convenience. Note that .. c:function:: TYPE* PyMem_New(TYPE, size_t n) Same as :c:func:`PyMem_Malloc`, but allocates ``(n * sizeof(TYPE))`` bytes of - memory. Returns a pointer cast to :c:type:`TYPE*`. The memory will not have + memory. Returns a pointer cast to :c:expr:`TYPE*`. The memory will not have been initialized in any way. .. c:function:: TYPE* PyMem_Resize(void *p, TYPE, size_t n) Same as :c:func:`PyMem_Realloc`, but the memory block is resized to ``(n * - sizeof(TYPE))`` bytes. Returns a pointer cast to :c:type:`TYPE*`. On return, + sizeof(TYPE))`` bytes. Returns a pointer cast to :c:expr:`TYPE*`. On return, *p* will be a pointer to the new memory area, or ``NULL`` in the event of failure. From webhook-mailer at python.org Tue Oct 4 20:53:54 2022 From: webhook-mailer at python.org (ambv) Date: Wed, 05 Oct 2022 00:53:54 -0000 Subject: [Python-checkins] [3.11] gh-93738: Documentation C syntax (:c:type:`PyInterpreterState *` -> :c:expr:`PyInterpreterState *`) (GH-97777) (#97865) Message-ID: https://github.com/python/cpython/commit/76c50d784f791c717bad086f51939640bebf67ab commit: 76c50d784f791c717bad086f51939640bebf67ab branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-04T17:53:48-07:00 summary: [3.11] gh-93738: Documentation C syntax (:c:type:`PyInterpreterState *` -> :c:expr:`PyInterpreterState *`) (GH-97777) (#97865) :c:type:`PyInterpreterState *` -> :c:expr:`PyInterpreterState *` (cherry picked from commit 4ebb0250314b57637d213cd5bc5f5ce5dd911d94) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> files: M Doc/c-api/init.rst diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index d4954958f855..d573ef131280 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -914,7 +914,7 @@ code, or when embedding the Python interpreter: .. c:type:: PyThreadState This data structure represents the state of a single thread. The only public - data member is :attr:`interp` (:c:type:`PyInterpreterState *`), which points to + data member is :attr:`interp` (:c:expr:`PyInterpreterState *`), which points to this thread's interpreter state. From webhook-mailer at python.org Tue Oct 4 20:55:23 2022 From: webhook-mailer at python.org (ambv) Date: Wed, 05 Oct 2022 00:55:23 -0000 Subject: [Python-checkins] [3.11] gh-93738: Documentation C syntax (:c:data:`view->obj` -> :c:expr:`view->obj`) (GH-97773) (#97867) Message-ID: https://github.com/python/cpython/commit/98e250bed101d0ffba266f72aeab4c0ff602797a commit: 98e250bed101d0ffba266f72aeab4c0ff602797a branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-04T17:55:17-07:00 summary: [3.11] gh-93738: Documentation C syntax (:c:data:`view->obj` -> :c:expr:`view->obj`) (GH-97773) (#97867) :c:data:`view->obj` -> :c:expr:`view->obj` (cherry picked from commit fa59bda8d30ea0b6c19007205b57c800c944304c) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> files: M Doc/c-api/typeobj.rst diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index 8be489ad1efc..7fa8fcecb68f 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -2321,13 +2321,13 @@ Buffer Object Structures steps: (1) Check if the request can be met. If not, raise :c:data:`PyExc_BufferError`, - set :c:data:`view->obj` to ``NULL`` and return ``-1``. + set :c:expr:`view->obj` to ``NULL`` and return ``-1``. (2) Fill in the requested fields. (3) Increment an internal counter for the number of exports. - (4) Set :c:data:`view->obj` to *exporter* and increment :c:data:`view->obj`. + (4) Set :c:expr:`view->obj` to *exporter* and increment :c:expr:`view->obj`. (5) Return ``0``. @@ -2335,10 +2335,10 @@ Buffer Object Structures schemes can be used: * Re-export: Each member of the tree acts as the exporting object and - sets :c:data:`view->obj` to a new reference to itself. + sets :c:expr:`view->obj` to a new reference to itself. * Redirect: The buffer request is redirected to the root object of the - tree. Here, :c:data:`view->obj` will be a new reference to the root + tree. Here, :c:expr:`view->obj` will be a new reference to the root object. The individual fields of *view* are described in section @@ -2380,7 +2380,7 @@ Buffer Object Structures *view* argument. - This function MUST NOT decrement :c:data:`view->obj`, since that is + This function MUST NOT decrement :c:expr:`view->obj`, since that is done automatically in :c:func:`PyBuffer_Release` (this scheme is useful for breaking reference cycles). From webhook-mailer at python.org Tue Oct 4 20:55:36 2022 From: webhook-mailer at python.org (ambv) Date: Wed, 05 Oct 2022 00:55:36 -0000 Subject: [Python-checkins] [3.10] gh-93738: Documentation C syntax (:c:data:`view->obj` -> :c:expr:`view->obj`) (GH-97773) (#97868) Message-ID: https://github.com/python/cpython/commit/95289bf98369c3f2b782d89f8ab591569f636be7 commit: 95289bf98369c3f2b782d89f8ab591569f636be7 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-04T17:55:31-07:00 summary: [3.10] gh-93738: Documentation C syntax (:c:data:`view->obj` -> :c:expr:`view->obj`) (GH-97773) (#97868) :c:data:`view->obj` -> :c:expr:`view->obj` (cherry picked from commit fa59bda8d30ea0b6c19007205b57c800c944304c) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> files: M Doc/c-api/typeobj.rst diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index b939d930b18c..13de82f3700b 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -2327,13 +2327,13 @@ Buffer Object Structures steps: (1) Check if the request can be met. If not, raise :c:data:`PyExc_BufferError`, - set :c:data:`view->obj` to ``NULL`` and return ``-1``. + set :c:expr:`view->obj` to ``NULL`` and return ``-1``. (2) Fill in the requested fields. (3) Increment an internal counter for the number of exports. - (4) Set :c:data:`view->obj` to *exporter* and increment :c:data:`view->obj`. + (4) Set :c:expr:`view->obj` to *exporter* and increment :c:expr:`view->obj`. (5) Return ``0``. @@ -2341,10 +2341,10 @@ Buffer Object Structures schemes can be used: * Re-export: Each member of the tree acts as the exporting object and - sets :c:data:`view->obj` to a new reference to itself. + sets :c:expr:`view->obj` to a new reference to itself. * Redirect: The buffer request is redirected to the root object of the - tree. Here, :c:data:`view->obj` will be a new reference to the root + tree. Here, :c:expr:`view->obj` will be a new reference to the root object. The individual fields of *view* are described in section @@ -2386,7 +2386,7 @@ Buffer Object Structures *view* argument. - This function MUST NOT decrement :c:data:`view->obj`, since that is + This function MUST NOT decrement :c:expr:`view->obj`, since that is done automatically in :c:func:`PyBuffer_Release` (this scheme is useful for breaking reference cycles). From webhook-mailer at python.org Tue Oct 4 20:56:28 2022 From: webhook-mailer at python.org (ambv) Date: Wed, 05 Oct 2022 00:56:28 -0000 Subject: [Python-checkins] gh-93738: Documentation C syntax (:c:type:`PyTypeObject*` -> :c:expr:`PyTypeObject*`) (#97778) Message-ID: https://github.com/python/cpython/commit/c70c8b69762f720377adaf22f2e5ec6496a7be53 commit: c70c8b69762f720377adaf22f2e5ec6496a7be53 branch: main author: Adam Turner <9087854+AA-Turner at users.noreply.github.com> committer: ambv date: 2022-10-04T17:56:20-07:00 summary: gh-93738: Documentation C syntax (:c:type:`PyTypeObject*` -> :c:expr:`PyTypeObject*`) (#97778) Co-authored-by: Ezio Melotti files: M Doc/c-api/object.rst M Doc/c-api/typehints.rst diff --git a/Doc/c-api/object.rst b/Doc/c-api/object.rst index fb03366056b0..5a25a2b6c9d3 100644 --- a/Doc/c-api/object.rst +++ b/Doc/c-api/object.rst @@ -310,7 +310,7 @@ Object Protocol is equivalent to the Python expression ``type(o)``. This function increments the reference count of the return value. There's really no reason to use this function instead of the :c:func:`Py_TYPE()` function, which returns a - pointer of type :c:type:`PyTypeObject*`, except when the incremented reference + pointer of type :c:expr:`PyTypeObject*`, except when the incremented reference count is needed. diff --git a/Doc/c-api/typehints.rst b/Doc/c-api/typehints.rst index 88554a346c0d..4c1957a2a1db 100644 --- a/Doc/c-api/typehints.rst +++ b/Doc/c-api/typehints.rst @@ -15,7 +15,7 @@ two types exist -- :ref:`GenericAlias ` and Equivalent to calling the Python class :class:`types.GenericAlias`. The *origin* and *args* arguments set the ``GenericAlias``\ 's ``__origin__`` and ``__args__`` attributes respectively. - *origin* should be a :c:type:`PyTypeObject*`, and *args* can be a + *origin* should be a :c:expr:`PyTypeObject*`, and *args* can be a :c:expr:`PyTupleObject*` or any ``PyObject*``. If *args* passed is not a tuple, a 1-tuple is automatically constructed and ``__args__`` is set to ``(args,)``. From webhook-mailer at python.org Tue Oct 4 20:56:51 2022 From: webhook-mailer at python.org (ambv) Date: Wed, 05 Oct 2022 00:56:51 -0000 Subject: [Python-checkins] [3.10] gh-93738: Documentation C syntax (:c:type:`PyInterpreterState *` -> :c:expr:`PyInterpreterState *`) (GH-97777) (#97877) Message-ID: https://github.com/python/cpython/commit/09e5029aca36c21157516bb44269644084fdf9ad commit: 09e5029aca36c21157516bb44269644084fdf9ad branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-04T17:56:46-07:00 summary: [3.10] gh-93738: Documentation C syntax (:c:type:`PyInterpreterState *` -> :c:expr:`PyInterpreterState *`) (GH-97777) (#97877) :c:type:`PyInterpreterState *` -> :c:expr:`PyInterpreterState *` (cherry picked from commit 4ebb0250314b57637d213cd5bc5f5ce5dd911d94) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> files: M Doc/c-api/init.rst diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index a44442a50155..45efa8949878 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -867,7 +867,7 @@ code, or when embedding the Python interpreter: .. c:type:: PyThreadState This data structure represents the state of a single thread. The only public - data member is :attr:`interp` (:c:type:`PyInterpreterState *`), which points to + data member is :attr:`interp` (:c:expr:`PyInterpreterState *`), which points to this thread's interpreter state. From webhook-mailer at python.org Tue Oct 4 21:09:05 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 05 Oct 2022 01:09:05 -0000 Subject: [Python-checkins] gh-95913: Copyedit/improve Implementation Changes What's New section (GH-97720) Message-ID: https://github.com/python/cpython/commit/d03f45203b4abf8095d5c5c692c9c9c2f8083eec commit: d03f45203b4abf8095d5c5c692c9c9c2f8083eec branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-04T18:08:59-07:00 summary: gh-95913: Copyedit/improve Implementation Changes What's New section (GH-97720) * Add and refine reST/Sphinx syntax for implementation changes section * Clarify and refine wording in the Implementation Changes section * Elide unnecessary comma Co-authored-by: Ezio Melotti Co-authored-by: Ezio Melotti (cherry picked from commit 4e731814d781dae3419e981c0acc3ef833e26e8a) Co-authored-by: C.A.M. Gerlach files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 8906be1eccda..553261dbd4cc 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -480,17 +480,24 @@ Other Language Changes there is a mixture of :class:`str` and :class:`bytes` keys. (Contributed by Thomas Grainger in :gh:`91181`.) + +.. _whatsnew311-other-implementation-changes: + Other CPython Implementation Changes ==================================== -* Special methods :meth:`complex.__complex__` and :meth:`bytes.__bytes__` are implemented to - support :class:`typing.SupportsComplex` and :class:`typing.SupportsBytes` protocols. +* The special methods :meth:`~object.__complex__` for :class:`complex` + and :meth:`~object.__bytes__` for :class:`bytes` are implemented to support + the :class:`typing.SupportsComplex` and :class:`typing.SupportsBytes` protocols. (Contributed by Mark Dickinson and Dong-hee Na in :issue:`24234`.) -* ``siphash13`` is added as a new internal hashing algorithms. It has similar security - properties as ``siphash24`` but it is slightly faster for long inputs. ``str``, ``bytes``, - and some other types now use it as default algorithm for :func:`hash`. :pep:`552` - hash-based pyc files now use ``siphash13``, too. +* ``siphash13`` is added as a new internal hashing algorithm. + It has similar security properties as ``siphash24``, + but it is slightly faster for long inputs. + :class:`str`, :class:`bytes`, and some other types + now use it as the default algorithm for :func:`hash`. + :pep:`552` :ref:`hash-based .pyc files ` + now use ``siphash13`` too. (Contributed by Inada Naoki in :issue:`29410`.) * When an active exception is re-raised by a :keyword:`raise` statement with no parameters, @@ -499,25 +506,28 @@ Other CPython Implementation Changes reflected in the re-raised exception. (Contributed by Irit Katriel in :issue:`45711`.) -* The interpreter state's representation of handled exceptions (a.k.a exc_info, or - _PyErr_StackItem) now has only the ``exc_value`` field, ``exc_type`` and ``exc_traceback`` - have been removed as their values can be derived from ``exc_value``. +* The interpreter state's representation of handled exceptions + (aka ``exc_info`` or ``_PyErr_StackItem``) + now only has the ``exc_value`` field; ``exc_type`` and ``exc_traceback`` + have been removed, as they can be derived from ``exc_value``. (Contributed by Irit Katriel in :issue:`45711`.) -* A new command line option for the Windows installer ``AppendPath`` has been added. - It behaves similiar to ``PrependPath`` but appends the install and scripts directories - instead of prepending them. +* A new :ref:`command line option `, ``AppendPath``, + has been added for the Windows installer. + It behaves similarly to ``PrependPath``, + but appends the install and scripts directories instead of prepending them. (Contributed by Bastian Neuburger in :issue:`44934`.) -* The :c:member:`PyConfig.module_search_paths_set` field must now be set to 1 for +* The :c:member:`PyConfig.module_search_paths_set` field must now be set to ``1`` for initialization to use :c:member:`PyConfig.module_search_paths` to initialize :data:`sys.path`. Otherwise, initialization will recalculate the path and replace any values added to ``module_search_paths``. -* The output of the :option:`--help` option is changed to fit inside 50 lines and 80 - columns. Information about :ref:`Python environment variables ` - and :option:`-X options <-X>` is available with the new :option:`--help-env` or - :option:`--help-xoptions` flags, and with :option:`--help-all`. +* The output of the :option:`--help` option now fits in 50 lines/80 columns. + Information about :ref:`Python environment variables ` + and :option:`-X` options is now available using the respective + :option:`--help-env` and :option:`--help-xoptions` flags, + and with the new :option:`--help-all`. (Contributed by ?ric Araujo in :issue:`46142`.) * Converting between :class:`int` and :class:`str` in bases other than 2 From webhook-mailer at python.org Tue Oct 4 21:29:59 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 05 Oct 2022 01:29:59 -0000 Subject: [Python-checkins] Add re.VERBOSE flag documentation example (GH-97678) Message-ID: https://github.com/python/cpython/commit/01513758298ae8fb956ce18c01d748d2986cfef3 commit: 01513758298ae8fb956ce18c01d748d2986cfef3 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-04T18:29:54-07:00 summary: Add re.VERBOSE flag documentation example (GH-97678) The current re.VERBOSE documentation example leaves space for ambiguous interpretation. One may read that spaces within the `(?:` token are spaces inside the non-capturing group (such as `(?: )`). This patch removes the ambiguity by including examples after the statement. (cherry picked from commit 0ceafa7fa408b64377ea31dd5386152da19ef38a) Co-authored-by: Athos Ribeiro files: M Doc/library/re.rst diff --git a/Doc/library/re.rst b/Doc/library/re.rst index 2392785d6c46..3a6e2e7f8908 100644 --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -781,7 +781,8 @@ Flags more readable by allowing you to visually separate logical sections of the pattern and add comments. Whitespace within the pattern is ignored, except when in a character class, or when preceded by an unescaped backslash, - or within tokens like ``*?``, ``(?:`` or ``(?P<...>``. + or within tokens like ``*?``, ``(?:`` or ``(?P<...>``. For example, ``(? :`` + and ``* ?`` are not allowed. When a line contains a ``#`` that is not in a character class and is not preceded by an unescaped backslash, all characters from the leftmost such ``#`` through the end of the line are ignored. From webhook-mailer at python.org Tue Oct 4 21:37:06 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 05 Oct 2022 01:37:06 -0000 Subject: [Python-checkins] Add re.VERBOSE flag documentation example (GH-97678) Message-ID: https://github.com/python/cpython/commit/24908f1f207f4642fc57ae79c69a3dcb0770a96a commit: 24908f1f207f4642fc57ae79c69a3dcb0770a96a branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-04T18:37:01-07:00 summary: Add re.VERBOSE flag documentation example (GH-97678) The current re.VERBOSE documentation example leaves space for ambiguous interpretation. One may read that spaces within the `(?:` token are spaces inside the non-capturing group (such as `(?: )`). This patch removes the ambiguity by including examples after the statement. (cherry picked from commit 0ceafa7fa408b64377ea31dd5386152da19ef38a) Co-authored-by: Athos Ribeiro files: M Doc/library/re.rst diff --git a/Doc/library/re.rst b/Doc/library/re.rst index fd1224131221..e7d1f0560b2a 100644 --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -702,7 +702,8 @@ Flags more readable by allowing you to visually separate logical sections of the pattern and add comments. Whitespace within the pattern is ignored, except when in a character class, or when preceded by an unescaped backslash, - or within tokens like ``*?``, ``(?:`` or ``(?P<...>``. + or within tokens like ``*?``, ``(?:`` or ``(?P<...>``. For example, ``(? :`` + and ``* ?`` are not allowed. When a line contains a ``#`` that is not in a character class and is not preceded by an unescaped backslash, all characters from the leftmost such ``#`` through the end of the line are ignored. From webhook-mailer at python.org Tue Oct 4 23:30:14 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 05 Oct 2022 03:30:14 -0000 Subject: [Python-checkins] gh-97825: fix AttributeError when calling subprocess.check_output(input=None) with encoding or errors args (GH-97826) Message-ID: https://github.com/python/cpython/commit/9133aabc708de881c06458b4e316489178475c3c commit: 9133aabc708de881c06458b4e316489178475c3c branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-04T20:29:40-07:00 summary: gh-97825: fix AttributeError when calling subprocess.check_output(input=None) with encoding or errors args (GH-97826) * fix AttributeError, add unit test (cherry picked from commit db64fb9bbe92b212db7dd173f787ea3607ae971a) Co-authored-by: andrei kulakov files: A Misc/NEWS.d/next/Library/2022-10-04-07-55-19.gh-issue-97825.mNdv1l.rst M Lib/subprocess.py M Lib/test/test_subprocess.py diff --git a/Lib/subprocess.py b/Lib/subprocess.py index 7ae8df154b48..760b93b47ebb 100644 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -456,7 +456,8 @@ def check_output(*popenargs, timeout=None, **kwargs): if 'input' in kwargs and kwargs['input'] is None: # Explicitly passing input=None was previously equivalent to passing an # empty string. That is maintained here for backwards compatibility. - if kwargs.get('universal_newlines') or kwargs.get('text'): + if kwargs.get('universal_newlines') or kwargs.get('text') or kwargs.get('encoding') \ + or kwargs.get('errors'): empty = '' else: empty = b'' diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index f6854922a5b8..424a4a93b6f9 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -238,6 +238,12 @@ def test_check_output_input_none_universal_newlines(self): input=None, universal_newlines=True) self.assertNotIn('XX', output) + def test_check_output_input_none_encoding_errors(self): + output = subprocess.check_output( + [sys.executable, "-c", "print('foo')"], + input=None, encoding='utf-8', errors='ignore') + self.assertIn('foo', output) + def test_check_output_stdout_arg(self): # check_output() refuses to accept 'stdout' argument with self.assertRaises(ValueError) as c: diff --git a/Misc/NEWS.d/next/Library/2022-10-04-07-55-19.gh-issue-97825.mNdv1l.rst b/Misc/NEWS.d/next/Library/2022-10-04-07-55-19.gh-issue-97825.mNdv1l.rst new file mode 100644 index 000000000000..4633dce7b663 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-04-07-55-19.gh-issue-97825.mNdv1l.rst @@ -0,0 +1 @@ +Fixes :exc:`AttributeError` when :meth:`subprocess.check_output` is used with argument ``input=None`` and either of the arguments *encoding* or *errors* are used. From webhook-mailer at python.org Tue Oct 4 23:35:58 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 05 Oct 2022 03:35:58 -0000 Subject: [Python-checkins] gh-97825: fix AttributeError when calling subprocess.check_output(input=None) with encoding or errors args (GH-97826) Message-ID: https://github.com/python/cpython/commit/ece5f7e04600150712d88b928b76d0f2de5f5011 commit: ece5f7e04600150712d88b928b76d0f2de5f5011 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-04T20:35:53-07:00 summary: gh-97825: fix AttributeError when calling subprocess.check_output(input=None) with encoding or errors args (GH-97826) * fix AttributeError, add unit test (cherry picked from commit db64fb9bbe92b212db7dd173f787ea3607ae971a) Co-authored-by: andrei kulakov files: A Misc/NEWS.d/next/Library/2022-10-04-07-55-19.gh-issue-97825.mNdv1l.rst M Lib/subprocess.py M Lib/test/test_subprocess.py diff --git a/Lib/subprocess.py b/Lib/subprocess.py index a414321b9d19..e5d7f0981861 100644 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -411,7 +411,8 @@ def check_output(*popenargs, timeout=None, **kwargs): if 'input' in kwargs and kwargs['input'] is None: # Explicitly passing input=None was previously equivalent to passing an # empty string. That is maintained here for backwards compatibility. - if kwargs.get('universal_newlines') or kwargs.get('text'): + if kwargs.get('universal_newlines') or kwargs.get('text') or kwargs.get('encoding') \ + or kwargs.get('errors'): empty = '' else: empty = b'' diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index b91791a02a2e..ea02a9ecb67a 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -227,6 +227,12 @@ def test_check_output_input_none_universal_newlines(self): input=None, universal_newlines=True) self.assertNotIn('XX', output) + def test_check_output_input_none_encoding_errors(self): + output = subprocess.check_output( + [sys.executable, "-c", "print('foo')"], + input=None, encoding='utf-8', errors='ignore') + self.assertIn('foo', output) + def test_check_output_stdout_arg(self): # check_output() refuses to accept 'stdout' argument with self.assertRaises(ValueError) as c: diff --git a/Misc/NEWS.d/next/Library/2022-10-04-07-55-19.gh-issue-97825.mNdv1l.rst b/Misc/NEWS.d/next/Library/2022-10-04-07-55-19.gh-issue-97825.mNdv1l.rst new file mode 100644 index 000000000000..4633dce7b663 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-04-07-55-19.gh-issue-97825.mNdv1l.rst @@ -0,0 +1 @@ +Fixes :exc:`AttributeError` when :meth:`subprocess.check_output` is used with argument ``input=None`` and either of the arguments *encoding* or *errors* are used. From webhook-mailer at python.org Tue Oct 4 23:55:11 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 05 Oct 2022 03:55:11 -0000 Subject: [Python-checkins] [3.11] gh-97837: Change deprecation warning message in `unittest` (GH-97838) (GH-97887) Message-ID: https://github.com/python/cpython/commit/8c517d88fb5ac6f1145128804fe10d5ef9d12b07 commit: 8c517d88fb5ac6f1145128804fe10d5ef9d12b07 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-04T20:55:06-07:00 summary: [3.11] gh-97837: Change deprecation warning message in `unittest` (GH-97838) (GH-97887) (cherry picked from commit c3648f4e4a12ec6efe65684facfcd08996e550ca) Co-authored-by: Nikita Sobolev Automerge-Triggered-By: GH:orsenthil files: A Misc/NEWS.d/next/Library/2022-10-04-21-21-41.gh-issue-97837.19q-eg.rst M Lib/unittest/async_case.py M Lib/unittest/case.py M Lib/unittest/test/test_async_case.py M Lib/unittest/test/test_case.py diff --git a/Lib/unittest/async_case.py b/Lib/unittest/async_case.py index 3457e92e5da2..bd2a47115606 100644 --- a/Lib/unittest/async_case.py +++ b/Lib/unittest/async_case.py @@ -88,7 +88,7 @@ def _callSetUp(self): def _callTestMethod(self, method): if self._callMaybeAsync(method) is not None: - warnings.warn(f'It is deprecated to return a value!=None from a ' + warnings.warn(f'It is deprecated to return a value that is not None from a ' f'test case ({method})', DeprecationWarning, stacklevel=4) def _callTearDown(self): diff --git a/Lib/unittest/case.py b/Lib/unittest/case.py index ffc8f19ddd38..8633f3837603 100644 --- a/Lib/unittest/case.py +++ b/Lib/unittest/case.py @@ -577,7 +577,7 @@ def _callSetUp(self): def _callTestMethod(self, method): if method() is not None: - warnings.warn(f'It is deprecated to return a value!=None from a ' + warnings.warn(f'It is deprecated to return a value that is not None from a ' f'test case ({method})', DeprecationWarning, stacklevel=3) def _callTearDown(self): diff --git a/Lib/unittest/test/test_async_case.py b/Lib/unittest/test/test_async_case.py index d7d4dc91316c..fab8270ea33a 100644 --- a/Lib/unittest/test/test_async_case.py +++ b/Lib/unittest/test/test_async_case.py @@ -277,25 +277,36 @@ async def on_cleanup2(self): self.assertEqual(events, ['asyncSetUp', 'test', 'asyncTearDown', 'cleanup2', 'cleanup1']) def test_deprecation_of_return_val_from_test(self): - # Issue 41322 - deprecate return of value!=None from a test + # Issue 41322 - deprecate return of value that is not None from a test + class Nothing: + def __eq__(self, o): + return o is None class Test(unittest.IsolatedAsyncioTestCase): async def test1(self): return 1 async def test2(self): yield 1 + async def test3(self): + return Nothing() with self.assertWarns(DeprecationWarning) as w: Test('test1').run() - self.assertIn('It is deprecated to return a value!=None', str(w.warning)) + self.assertIn('It is deprecated to return a value that is not None', str(w.warning)) self.assertIn('test1', str(w.warning)) self.assertEqual(w.filename, __file__) with self.assertWarns(DeprecationWarning) as w: Test('test2').run() - self.assertIn('It is deprecated to return a value!=None', str(w.warning)) + self.assertIn('It is deprecated to return a value that is not None', str(w.warning)) self.assertIn('test2', str(w.warning)) self.assertEqual(w.filename, __file__) + with self.assertWarns(DeprecationWarning) as w: + Test('test3').run() + self.assertIn('It is deprecated to return a value that is not None', str(w.warning)) + self.assertIn('test3', str(w.warning)) + self.assertEqual(w.filename, __file__) + def test_cleanups_interleave_order(self): events = [] diff --git a/Lib/unittest/test/test_case.py b/Lib/unittest/test/test_case.py index 374a25525556..78303b359f5e 100644 --- a/Lib/unittest/test/test_case.py +++ b/Lib/unittest/test/test_case.py @@ -307,25 +307,36 @@ def test(self): Foo('test').run() def test_deprecation_of_return_val_from_test(self): - # Issue 41322 - deprecate return of value!=None from a test + # Issue 41322 - deprecate return of value that is not None from a test + class Nothing: + def __eq__(self, o): + return o is None class Foo(unittest.TestCase): def test1(self): return 1 def test2(self): yield 1 + def test3(self): + return Nothing() with self.assertWarns(DeprecationWarning) as w: Foo('test1').run() - self.assertIn('It is deprecated to return a value!=None', str(w.warning)) + self.assertIn('It is deprecated to return a value that is not None', str(w.warning)) self.assertIn('test1', str(w.warning)) self.assertEqual(w.filename, __file__) with self.assertWarns(DeprecationWarning) as w: Foo('test2').run() - self.assertIn('It is deprecated to return a value!=None', str(w.warning)) + self.assertIn('It is deprecated to return a value that is not None', str(w.warning)) self.assertIn('test2', str(w.warning)) self.assertEqual(w.filename, __file__) + with self.assertWarns(DeprecationWarning) as w: + Foo('test3').run() + self.assertIn('It is deprecated to return a value that is not None', str(w.warning)) + self.assertIn('test3', str(w.warning)) + self.assertEqual(w.filename, __file__) + def _check_call_order__subtests(self, result, events, expected_events): class Foo(Test.LoggingTestCase): def test(self): diff --git a/Misc/NEWS.d/next/Library/2022-10-04-21-21-41.gh-issue-97837.19q-eg.rst b/Misc/NEWS.d/next/Library/2022-10-04-21-21-41.gh-issue-97837.19q-eg.rst new file mode 100644 index 000000000000..b1350c959e2b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-04-21-21-41.gh-issue-97837.19q-eg.rst @@ -0,0 +1,7 @@ +Change deprecate warning message in :mod:`unittest` from + +``It is deprecated to return a value!=None`` + +to + +``It is deprecated to return a value that is not None from a test case`` From webhook-mailer at python.org Wed Oct 5 01:46:39 2022 From: webhook-mailer at python.org (brandtbucher) Date: Wed, 05 Oct 2022 05:46:39 -0000 Subject: [Python-checkins] [3.11] GH-97779: Ensure that *all* frame objects are backed by "complete" frames (GH-97886) Message-ID: https://github.com/python/cpython/commit/015b49ac05eddcb7f653ed2c80daba24ff396fd9 commit: 015b49ac05eddcb7f653ed2c80daba24ff396fd9 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: brandtbucher date: 2022-10-04T22:46:34-07:00 summary: [3.11] GH-97779: Ensure that *all* frame objects are backed by "complete" frames (GH-97886) (cherry picked from commit 0ff8fd65838f9f9ed90d7a055d26a2ce9fc0ce85) Co-authored-by: Brandt Bucher files: A Misc/NEWS.d/next/Core and Builtins/2022-10-04-02-00-10.gh-issue-97779.f3N1hI.rst M Lib/test/test_code.py M Objects/codeobject.c M Objects/frameobject.c M Python/frame.c diff --git a/Lib/test/test_code.py b/Lib/test/test_code.py index 2386cf6b59f3..d3e20129eee8 100644 --- a/Lib/test/test_code.py +++ b/Lib/test/test_code.py @@ -132,6 +132,7 @@ import unittest import textwrap import weakref +import dis try: import ctypes @@ -671,6 +672,38 @@ def test_lines(self): self.check_lines(misshappen) self.check_lines(bug93662) + @cpython_only + def test_code_new_empty(self): + # If this test fails, it means that the construction of PyCode_NewEmpty + # needs to be modified! Please update this test *and* PyCode_NewEmpty, + # so that they both stay in sync. + def f(): + pass + PY_CODE_LOCATION_INFO_NO_COLUMNS = 13 + f.__code__ = f.__code__.replace( + co_firstlineno=42, + co_code=bytes( + [ + dis.opmap["RESUME"], 0, + dis.opmap["LOAD_ASSERTION_ERROR"], 0, + dis.opmap["RAISE_VARARGS"], 1, + ] + ), + co_linetable=bytes( + [ + (1 << 7) + | (PY_CODE_LOCATION_INFO_NO_COLUMNS << 3) + | (3 - 1), + 0, + ] + ), + ) + self.assertRaises(AssertionError, f) + self.assertEqual( + list(f.__code__.co_positions()), + 3 * [(42, 42, None, None)], + ) + if check_impl_detail(cpython=True) and ctypes is not None: py = ctypes.pythonapi diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-04-02-00-10.gh-issue-97779.f3N1hI.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-04-02-00-10.gh-issue-97779.f3N1hI.rst new file mode 100644 index 000000000000..611521808865 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-04-02-00-10.gh-issue-97779.f3N1hI.rst @@ -0,0 +1 @@ +Ensure that all Python frame objects are backed by "complete" frames. diff --git a/Objects/codeobject.c b/Objects/codeobject.c index d7434ddefbc0..32938b52ab40 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -636,12 +636,22 @@ PyCode_New(int argcount, int kwonlyargcount, exceptiontable); } -static const char assert0[6] = { +// NOTE: When modifying the construction of PyCode_NewEmpty, please also change +// test.test_code.CodeLocationTest.test_code_new_empty to keep it in sync! + +static const uint8_t assert0[6] = { RESUME, 0, LOAD_ASSERTION_ERROR, 0, RAISE_VARARGS, 1 }; +static const uint8_t linetable[2] = { + (1 << 7) // New entry. + | (PY_CODE_LOCATION_INFO_NO_COLUMNS << 3) + | (3 - 1), // Three code units. + 0, // Offset from co_firstlineno. +}; + PyCodeObject * PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno) { @@ -649,6 +659,7 @@ PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno) PyObject *filename_ob = NULL; PyObject *funcname_ob = NULL; PyObject *code_ob = NULL; + PyObject *linetable_ob = NULL; PyCodeObject *result = NULL; nulltuple = PyTuple_New(0); @@ -663,10 +674,14 @@ PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno) if (filename_ob == NULL) { goto failed; } - code_ob = PyBytes_FromStringAndSize(assert0, 6); + code_ob = PyBytes_FromStringAndSize((const char *)assert0, 6); if (code_ob == NULL) { goto failed; } + linetable_ob = PyBytes_FromStringAndSize((const char *)linetable, 2); + if (linetable_ob == NULL) { + goto failed; + } #define emptystring (PyObject *)&_Py_SINGLETON(bytes_empty) struct _PyCodeConstructor con = { @@ -675,7 +690,7 @@ PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno) .qualname = funcname_ob, .code = code_ob, .firstlineno = firstlineno, - .linetable = emptystring, + .linetable = linetable_ob, .consts = nulltuple, .names = nulltuple, .localsplusnames = nulltuple, @@ -690,6 +705,7 @@ PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno) Py_XDECREF(funcname_ob); Py_XDECREF(filename_ob); Py_XDECREF(code_ob); + Py_XDECREF(linetable_ob); return result; } diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 1ddfec2fb08a..f77f5ed39392 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -590,6 +590,7 @@ first_line_not_before(int *lines, int len, int line) static PyFrameState _PyFrame_GetState(PyFrameObject *frame) { + assert(!_PyFrame_IsIncomplete(frame->f_frame)); if (frame->f_frame->stacktop == 0) { return FRAME_CLEARED; } @@ -1063,6 +1064,9 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code, init_frame((_PyInterpreterFrame *)f->_f_frame_data, func, locals); f->f_frame = (_PyInterpreterFrame *)f->_f_frame_data; f->f_frame->owner = FRAME_OWNED_BY_FRAME_OBJECT; + // This frame needs to be "complete", so pretend that the first RESUME ran: + f->f_frame->prev_instr = _PyCode_CODE(code) + code->_co_firsttraceable; + assert(!_PyFrame_IsIncomplete(f->f_frame)); Py_DECREF(func); _PyObject_GC_TRACK(f); return f; @@ -1189,6 +1193,7 @@ _PyFrame_FastToLocalsWithError(_PyInterpreterFrame *frame) { int PyFrame_FastToLocalsWithError(PyFrameObject *f) { + assert(!_PyFrame_IsIncomplete(f->f_frame)); if (f == NULL) { PyErr_BadInternalCall(); return -1; @@ -1204,7 +1209,7 @@ void PyFrame_FastToLocals(PyFrameObject *f) { int res; - + assert(!_PyFrame_IsIncomplete(f->f_frame)); assert(!PyErr_Occurred()); res = PyFrame_FastToLocalsWithError(f); @@ -1282,6 +1287,7 @@ _PyFrame_LocalsToFast(_PyInterpreterFrame *frame, int clear) void PyFrame_LocalsToFast(PyFrameObject *f, int clear) { + assert(!_PyFrame_IsIncomplete(f->f_frame)); if (f && f->f_fast_as_locals && _PyFrame_GetState(f) != FRAME_CLEARED) { _PyFrame_LocalsToFast(f->f_frame, clear); f->f_fast_as_locals = 0; @@ -1292,6 +1298,7 @@ PyFrame_LocalsToFast(PyFrameObject *f, int clear) int _PyFrame_IsEntryFrame(PyFrameObject *frame) { assert(frame != NULL); + assert(!_PyFrame_IsIncomplete(frame->f_frame)); return frame->f_frame->is_entry; } @@ -1300,6 +1307,7 @@ PyCodeObject * PyFrame_GetCode(PyFrameObject *frame) { assert(frame != NULL); + assert(!_PyFrame_IsIncomplete(frame->f_frame)); PyCodeObject *code = frame->f_frame->f_code; assert(code != NULL); Py_INCREF(code); @@ -1311,6 +1319,7 @@ PyFrameObject* PyFrame_GetBack(PyFrameObject *frame) { assert(frame != NULL); + assert(!_PyFrame_IsIncomplete(frame->f_frame)); PyFrameObject *back = frame->f_back; if (back == NULL) { _PyInterpreterFrame *prev = frame->f_frame->previous; @@ -1328,24 +1337,28 @@ PyFrame_GetBack(PyFrameObject *frame) PyObject* PyFrame_GetLocals(PyFrameObject *frame) { + assert(!_PyFrame_IsIncomplete(frame->f_frame)); return frame_getlocals(frame, NULL); } PyObject* PyFrame_GetGlobals(PyFrameObject *frame) { + assert(!_PyFrame_IsIncomplete(frame->f_frame)); return frame_getglobals(frame, NULL); } PyObject* PyFrame_GetBuiltins(PyFrameObject *frame) { + assert(!_PyFrame_IsIncomplete(frame->f_frame)); return frame_getbuiltins(frame, NULL); } int PyFrame_GetLasti(PyFrameObject *frame) { + assert(!_PyFrame_IsIncomplete(frame->f_frame)); int lasti = _PyInterpreterFrame_LASTI(frame->f_frame); if (lasti < 0) { return -1; @@ -1356,6 +1369,7 @@ PyFrame_GetLasti(PyFrameObject *frame) PyObject * PyFrame_GetGenerator(PyFrameObject *frame) { + assert(!_PyFrame_IsIncomplete(frame->f_frame)); if (frame->f_frame->owner != FRAME_OWNED_BY_GENERATOR) { return NULL; } diff --git a/Python/frame.c b/Python/frame.c index 45072da04269..9f58c20d4fa2 100644 --- a/Python/frame.c +++ b/Python/frame.c @@ -68,6 +68,13 @@ take_ownership(PyFrameObject *f, _PyInterpreterFrame *frame) frame = (_PyInterpreterFrame *)f->_f_frame_data; f->f_frame = frame; frame->owner = FRAME_OWNED_BY_FRAME_OBJECT; + if (_PyFrame_IsIncomplete(frame)) { + // This may be a newly-created generator or coroutine frame. Since it's + // dead anyways, just pretend that the first RESUME ran: + PyCodeObject *code = frame->f_code; + frame->prev_instr = _PyCode_CODE(code) + code->_co_firsttraceable; + } + assert(!_PyFrame_IsIncomplete(frame)); assert(f->f_back == NULL); _PyInterpreterFrame *prev = frame->previous; while (prev && _PyFrame_IsIncomplete(prev)) { From webhook-mailer at python.org Wed Oct 5 02:49:19 2022 From: webhook-mailer at python.org (gvanrossum) Date: Wed, 05 Oct 2022 06:49:19 -0000 Subject: [Python-checkins] GH-96704: Add {Task, Handle}.get_context(), use it in call_exception_handler() (#96756) Message-ID: https://github.com/python/cpython/commit/8079bef56f2249ecedafe0be5a6d7a120a7f3ac3 commit: 8079bef56f2249ecedafe0be5a6d7a120a7f3ac3 branch: main author: Guido van Rossum committer: gvanrossum date: 2022-10-04T23:49:10-07:00 summary: GH-96704: Add {Task,Handle}.get_context(), use it in call_exception_handler() (#96756) Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> files: A Misc/NEWS.d/next/Library/2022-09-18-04-51-30.gh-issue-96704.DmamRX.rst M Doc/library/asyncio-eventloop.rst M Doc/library/asyncio-task.rst M Lib/asyncio/base_events.py M Lib/asyncio/events.py M Lib/asyncio/tasks.py M Lib/test/test_asyncio/test_futures2.py M Lib/test/test_asyncio/test_tasks.py M Modules/_asynciomodule.c M Modules/clinic/_asynciomodule.c.h diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index c51990eff8de..6fe95687c151 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -1271,6 +1271,15 @@ Allows customizing how exceptions are handled in the event loop. (see :meth:`call_exception_handler` documentation for details about context). + If the handler is called on behalf of a :class:`~asyncio.Task` or + :class:`~asyncio.Handle`, it is run in the + :class:`contextvars.Context` of that task or callback handle. + + .. versionchanged:: 3.12 + + The handler may be called in the :class:`~contextvars.Context` + of the task or handle where the exception originated. + .. method:: loop.get_exception_handler() Return the current exception handler, or ``None`` if no custom @@ -1474,6 +1483,13 @@ Callback Handles A callback wrapper object returned by :meth:`loop.call_soon`, :meth:`loop.call_soon_threadsafe`. + .. method:: get_context() + + Return the :class:`contextvars.Context` object + associated with the handle. + + .. versionadded:: 3.12 + .. method:: cancel() Cancel the callback. If the callback has already been canceled diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index ade969220ea7..d922f614954f 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -1097,6 +1097,13 @@ Task Object .. versionadded:: 3.8 + .. method:: get_context() + + Return the :class:`contextvars.Context` object + associated with the task. + + .. versionadded:: 3.12 + .. method:: get_name() Return the name of the Task. diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index 66202f09794d..c8a2f9f25634 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -1808,7 +1808,22 @@ def call_exception_handler(self, context): exc_info=True) else: try: - self._exception_handler(self, context) + ctx = None + thing = context.get("task") + if thing is None: + # Even though Futures don't have a context, + # Task is a subclass of Future, + # and sometimes the 'future' key holds a Task. + thing = context.get("future") + if thing is None: + # Handles also have a context. + thing = context.get("handle") + if thing is not None and hasattr(thing, "get_context"): + ctx = thing.get_context() + if ctx is not None and hasattr(ctx, "run"): + ctx.run(self._exception_handler, self, context) + else: + self._exception_handler(self, context) except (SystemExit, KeyboardInterrupt): raise except BaseException as exc: diff --git a/Lib/asyncio/events.py b/Lib/asyncio/events.py index 0d26ea545baa..a327ba54a323 100644 --- a/Lib/asyncio/events.py +++ b/Lib/asyncio/events.py @@ -61,6 +61,9 @@ def __repr__(self): info = self._repr_info() return '<{}>'.format(' '.join(info)) + def get_context(self): + return self._context + def cancel(self): if not self._cancelled: self._cancelled = True diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py index e48da0f20088..8d6dfcd81b73 100644 --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -139,6 +139,9 @@ def __repr__(self): def get_coro(self): return self._coro + def get_context(self): + return self._context + def get_name(self): return self._name diff --git a/Lib/test/test_asyncio/test_futures2.py b/Lib/test/test_asyncio/test_futures2.py index 71279b69c792..9e7a5775a703 100644 --- a/Lib/test/test_asyncio/test_futures2.py +++ b/Lib/test/test_asyncio/test_futures2.py @@ -1,5 +1,6 @@ # IsolatedAsyncioTestCase based tests import asyncio +import contextvars import traceback import unittest from asyncio import tasks @@ -27,6 +28,46 @@ async def raise_exc(): else: self.fail('TypeError was not raised') + async def test_task_exc_handler_correct_context(self): + # see https://github.com/python/cpython/issues/96704 + name = contextvars.ContextVar('name', default='foo') + exc_handler_called = False + + def exc_handler(*args): + self.assertEqual(name.get(), 'bar') + nonlocal exc_handler_called + exc_handler_called = True + + async def task(): + name.set('bar') + 1/0 + + loop = asyncio.get_running_loop() + loop.set_exception_handler(exc_handler) + self.cls(task()) + await asyncio.sleep(0) + self.assertTrue(exc_handler_called) + + async def test_handle_exc_handler_correct_context(self): + # see https://github.com/python/cpython/issues/96704 + name = contextvars.ContextVar('name', default='foo') + exc_handler_called = False + + def exc_handler(*args): + self.assertEqual(name.get(), 'bar') + nonlocal exc_handler_called + exc_handler_called = True + + def callback(): + name.set('bar') + 1/0 + + loop = asyncio.get_running_loop() + loop.set_exception_handler(exc_handler) + loop.call_soon(callback) + await asyncio.sleep(0) + self.assertTrue(exc_handler_called) + @unittest.skipUnless(hasattr(tasks, '_CTask'), 'requires the C _asyncio module') class CFutureTests(FutureTests, unittest.IsolatedAsyncioTestCase): diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py index 04bdf6483131..2491285206bc 100644 --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -2482,6 +2482,17 @@ def test_get_coro(self): finally: loop.close() + def test_get_context(self): + loop = asyncio.new_event_loop() + coro = coroutine_function() + context = contextvars.copy_context() + try: + task = self.new_task(loop, coro, context=context) + loop.run_until_complete(task) + self.assertIs(task.get_context(), context) + finally: + loop.close() + def add_subclass_tests(cls): BaseTask = cls.Task diff --git a/Misc/NEWS.d/next/Library/2022-09-18-04-51-30.gh-issue-96704.DmamRX.rst b/Misc/NEWS.d/next/Library/2022-09-18-04-51-30.gh-issue-96704.DmamRX.rst new file mode 100644 index 000000000000..6ac99197e685 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-09-18-04-51-30.gh-issue-96704.DmamRX.rst @@ -0,0 +1 @@ +Pass the correct ``contextvars.Context`` when a ``asyncio`` exception handler is called on behalf of a task or callback handle. This adds a new ``Task`` method, ``get_context``, and also a new ``Handle`` method with the same name. If this method is not found on a task object (perhaps because it is a third-party library that does not yet provide this method), the context prevailing at the time the exception handler is called is used. diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index 909171150bdd..efa0d2d6906e 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -2409,6 +2409,18 @@ _asyncio_Task_get_coro_impl(TaskObj *self) return self->task_coro; } +/*[clinic input] +_asyncio.Task.get_context +[clinic start generated code]*/ + +static PyObject * +_asyncio_Task_get_context_impl(TaskObj *self) +/*[clinic end generated code: output=6996f53d3dc01aef input=87c0b209b8fceeeb]*/ +{ + Py_INCREF(self->task_context); + return self->task_context; +} + /*[clinic input] _asyncio.Task.get_name [clinic start generated code]*/ @@ -2536,6 +2548,7 @@ static PyMethodDef TaskType_methods[] = { _ASYNCIO_TASK_GET_NAME_METHODDEF _ASYNCIO_TASK_SET_NAME_METHODDEF _ASYNCIO_TASK_GET_CORO_METHODDEF + _ASYNCIO_TASK_GET_CONTEXT_METHODDEF {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, {NULL, NULL} /* Sentinel */ }; diff --git a/Modules/clinic/_asynciomodule.c.h b/Modules/clinic/_asynciomodule.c.h index daf524c3456c..ddec54c8d7c2 100644 --- a/Modules/clinic/_asynciomodule.c.h +++ b/Modules/clinic/_asynciomodule.c.h @@ -772,6 +772,23 @@ _asyncio_Task_get_coro(TaskObj *self, PyObject *Py_UNUSED(ignored)) return _asyncio_Task_get_coro_impl(self); } +PyDoc_STRVAR(_asyncio_Task_get_context__doc__, +"get_context($self, /)\n" +"--\n" +"\n"); + +#define _ASYNCIO_TASK_GET_CONTEXT_METHODDEF \ + {"get_context", (PyCFunction)_asyncio_Task_get_context, METH_NOARGS, _asyncio_Task_get_context__doc__}, + +static PyObject * +_asyncio_Task_get_context_impl(TaskObj *self); + +static PyObject * +_asyncio_Task_get_context(TaskObj *self, PyObject *Py_UNUSED(ignored)) +{ + return _asyncio_Task_get_context_impl(self); +} + PyDoc_STRVAR(_asyncio_Task_get_name__doc__, "get_name($self, /)\n" "--\n" @@ -1172,4 +1189,4 @@ _asyncio__leave_task(PyObject *module, PyObject *const *args, Py_ssize_t nargs, exit: return return_value; } -/*[clinic end generated code: output=459a7c7f21bbc290 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=f117b2246eaf7a55 input=a9049054013a1b77]*/ From webhook-mailer at python.org Wed Oct 5 03:52:57 2022 From: webhook-mailer at python.org (iritkatriel) Date: Wed, 05 Oct 2022 07:52:57 -0000 Subject: [Python-checkins] gh-87092: bring compiler code closer to a preprocessing-opt-assembler organisation (GH-97644) Message-ID: https://github.com/python/cpython/commit/c529b451226bc704ce648cbe7e0b8cb48bcf5e1c commit: c529b451226bc704ce648cbe7e0b8cb48bcf5e1c branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2022-10-05T08:52:35+01:00 summary: gh-87092: bring compiler code closer to a preprocessing-opt-assembler organisation (GH-97644) files: M Lib/test/test_compile.py M Python/compile.c diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index 21dcc1a719cc..8bf8470ff16f 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -670,10 +670,22 @@ def test_merge_code_attrs(self): self.assertIs(f1.__code__.co_linetable, f2.__code__.co_linetable) + @support.cpython_only + def test_strip_unused_consts(self): + def f(): + "docstring" + if True: + return "used" + else: + return "unused" + + self.assertEqual(f.__code__.co_consts, + ("docstring", True, "used")) + # Stripping unused constants is not a strict requirement for the # Python semantics, it's a more an implementation detail. @support.cpython_only - def test_strip_unused_consts(self): + def test_strip_unused_None(self): # Python 3.10rc1 appended None to co_consts when None is not used # at all. See bpo-45056. def f1(): diff --git a/Python/compile.c b/Python/compile.c index 507fd040a89d..2da36d0f6316 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -912,6 +912,19 @@ cfg_builder_use_label(cfg_builder *g, jump_target_label lbl) return cfg_builder_maybe_start_new_block(g); } +static inline int +basicblock_append_instructions(basicblock *target, basicblock *source) +{ + for (int i = 0; i < source->b_iused; i++) { + int n = basicblock_next_instr(target); + if (n < 0) { + return -1; + } + target->b_instr[n] = source->b_instr[i]; + } + return 0; +} + static basicblock * copy_basicblock(cfg_builder *g, basicblock *block) { @@ -923,12 +936,8 @@ copy_basicblock(cfg_builder *g, basicblock *block) if (result == NULL) { return NULL; } - for (int i = 0; i < block->b_iused; i++) { - int n = basicblock_next_instr(result); - if (n < 0) { - return NULL; - } - result->b_instr[n] = block->b_instr[i]; + if (basicblock_append_instructions(result, block) < 0) { + return NULL; } return result; } @@ -7080,15 +7089,14 @@ stackdepth(basicblock *entryblock, int code_flags) if (new_depth > maxdepth) { maxdepth = new_depth; } - assert(depth >= 0); /* invalid code or bug in stackdepth() */ if (HAS_TARGET(instr->i_opcode)) { effect = stack_effect(instr->i_opcode, instr->i_oparg, 1); assert(effect != PY_INVALID_STACK_EFFECT); int target_depth = depth + effect; + assert(target_depth >= 0); /* invalid code or bug in stackdepth() */ if (target_depth > maxdepth) { maxdepth = target_depth; } - assert(target_depth >= 0); /* invalid code or bug in stackdepth() */ stackdepth_push(&sp, instr->i_target, target_depth); } depth = new_depth; @@ -7487,6 +7495,9 @@ convert_exception_handlers_to_nops(basicblock *entryblock) { } } } + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { + remove_redundant_nops(b); + } } static inline void @@ -7964,8 +7975,8 @@ scan_block_for_local(int target, basicblock *b, bool unsafe_to_start, #undef MAYBE_PUSH static int -add_checks_for_loads_of_unknown_variables(basicblock *entryblock, - struct compiler *c) +add_checks_for_loads_of_uninitialized_variables(basicblock *entryblock, + struct compiler *c) { basicblock **stack = make_cfg_traversal_stack(entryblock); if (stack == NULL) { @@ -8291,7 +8302,7 @@ dump_basicblock(const basicblock *b) static int -calculate_jump_targets(basicblock *entryblock); +translate_jump_labels_to_targets(basicblock *entryblock); static int optimize_cfg(cfg_builder *g, PyObject *consts, PyObject *const_cache); @@ -8628,11 +8639,9 @@ assemble(struct compiler *c, int addNone) } nlocalsplus -= numdropped; - consts = consts_dict_keys_inorder(c->u->u_consts); - if (consts == NULL) { - goto error; - } - if (calculate_jump_targets(g->g_entryblock)) { + /** Preprocessing **/ + /* Map labels to targets and mark exception handlers */ + if (translate_jump_labels_to_targets(g->g_entryblock)) { goto error; } if (mark_except_handlers(g->g_entryblock) < 0) { @@ -8641,18 +8650,31 @@ assemble(struct compiler *c, int addNone) if (label_exception_targets(g->g_entryblock)) { goto error; } + + /** Optimization **/ + consts = consts_dict_keys_inorder(c->u->u_consts); + if (consts == NULL) { + goto error; + } if (optimize_cfg(g, consts, c->c_const_cache)) { goto error; } - if (trim_unused_consts(g->g_entryblock, consts)) { + if (add_checks_for_loads_of_uninitialized_variables(g->g_entryblock, c) < 0) { goto error; } + + /** line numbers (TODO: move this before optimization stage) */ if (duplicate_exits_without_lineno(g) < 0) { goto error; } propagate_line_numbers(g->g_entryblock); guarantee_lineno_for_exits(g->g_entryblock, c->u->u_firstlineno); + if (push_cold_blocks_to_end(g, code_flags) < 0) { + goto error; + } + + /** Assembly **/ int maxdepth = stackdepth(g->g_entryblock, code_flags); if (maxdepth < 0) { goto error; @@ -8661,27 +8683,19 @@ assemble(struct compiler *c, int addNone) convert_exception_handlers_to_nops(g->g_entryblock); - if (push_cold_blocks_to_end(g, code_flags) < 0) { - goto error; - } - for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { - remove_redundant_nops(b); - } - /* Order of basic blocks must have been determined by now */ if (normalize_jumps(g) < 0) { goto error; } - if (add_checks_for_loads_of_unknown_variables(g->g_entryblock, c) < 0) { - goto error; - } - assert(no_redundant_jumps(g)); /* Can't modify the bytecode after computing jump offsets. */ assemble_jump_offsets(g->g_entryblock); + if (trim_unused_consts(g->g_entryblock, consts)) { + goto error; + } /* Create assembler */ if (!assemble_init(&a, c->u->u_firstlineno)) @@ -9265,12 +9279,8 @@ inline_small_exit_blocks(basicblock *bb) { basicblock *target = last->i_target; if (basicblock_exits_scope(target) && target->b_iused <= MAX_COPY_SIZE) { last->i_opcode = NOP; - for (int i = 0; i < target->b_iused; i++) { - int index = basicblock_next_instr(bb); - if (index < 0) { - return -1; - } - bb->b_instr[index] = target->b_instr[i]; + if (basicblock_append_instructions(bb, target) < 0) { + return -1; } return 1; } @@ -9456,7 +9466,7 @@ propagate_line_numbers(basicblock *entryblock) { /* Calculate the actual jump target from the target_label */ static int -calculate_jump_targets(basicblock *entryblock) +translate_jump_labels_to_targets(basicblock *entryblock) { int max_label = -1; for (basicblock *b = entryblock; b != NULL; b = b->b_next) { @@ -9599,12 +9609,14 @@ is_exit_without_lineno(basicblock *b) { static int duplicate_exits_without_lineno(cfg_builder *g) { + assert(no_empty_basic_blocks(g)); /* Copy all exit blocks without line number that are targets of a jump. */ basicblock *entryblock = g->g_entryblock; for (basicblock *b = entryblock; b != NULL; b = b->b_next) { struct instr *last = basicblock_last_instr(b); - if (last != NULL && is_jump(last)) { + assert(last != NULL); + if (is_jump(last)) { basicblock *target = last->i_target; if (is_exit_without_lineno(target) && target->b_predecessors > 1) { basicblock *new_target = copy_basicblock(g, target); @@ -9621,8 +9633,6 @@ duplicate_exits_without_lineno(cfg_builder *g) } } - assert(no_empty_basic_blocks(g)); - /* Any remaining reachable exit blocks without line number can only be reached by * fall through, and thus can only have a single predecessor */ for (basicblock *b = entryblock; b != NULL; b = b->b_next) { @@ -9775,7 +9785,7 @@ _PyCompile_OptimizeCfg(PyObject *instructions, PyObject *consts) if (const_cache == NULL) { goto error; } - if (calculate_jump_targets(g.g_entryblock)) { + if (translate_jump_labels_to_targets(g.g_entryblock)) { goto error; } if (optimize_cfg(&g, consts, const_cache) < 0) { From webhook-mailer at python.org Wed Oct 5 04:48:03 2022 From: webhook-mailer at python.org (erlend-aasland) Date: Wed, 05 Oct 2022 08:48:03 -0000 Subject: [Python-checkins] gh-97661: Improve accuracy of sqlite3.Cursor.fetchone docs (#97662) Message-ID: https://github.com/python/cpython/commit/4b83cd0b22428fbfccf1f0e85c0fc36be6ab7edf commit: 4b83cd0b22428fbfccf1f0e85c0fc36be6ab7edf branch: main author: Jia Junjie <62194633+jiajunjie at users.noreply.github.com> committer: erlend-aasland date: 2022-10-05T10:47:54+02:00 summary: gh-97661: Improve accuracy of sqlite3.Cursor.fetchone docs (#97662) Co-authored-by: C.A.M. Gerlach files: M Doc/library/sqlite3.rst diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index e2774a502403..26a085877ec1 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -1425,7 +1425,9 @@ Cursor objects .. method:: fetchone() - Return the next row of a query result set as a :class:`tuple`. + If :attr:`~Connection.row_factory` is ``None``, + return the next row query result set as a :class:`tuple`. + Else, pass it to the row factory and return its result. Return ``None`` if no more data is available. From webhook-mailer at python.org Wed Oct 5 04:57:04 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 05 Oct 2022 08:57:04 -0000 Subject: [Python-checkins] gh-97661: Improve accuracy of sqlite3.Cursor.fetchone docs (GH-97662) Message-ID: https://github.com/python/cpython/commit/3c09debaa72cab1f5eaa747faea3e77c9dc5e007 commit: 3c09debaa72cab1f5eaa747faea3e77c9dc5e007 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-05T01:56:47-07:00 summary: gh-97661: Improve accuracy of sqlite3.Cursor.fetchone docs (GH-97662) Co-authored-by: C.A.M. Gerlach (cherry picked from commit 4b83cd0b22428fbfccf1f0e85c0fc36be6ab7edf) Co-authored-by: Jia Junjie <62194633+jiajunjie at users.noreply.github.com> files: M Doc/library/sqlite3.rst diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index 01e600c1c0ba..5f276c8d8e68 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -1121,7 +1121,9 @@ Cursor objects .. method:: fetchone() - Return the next row of a query result set as a :class:`tuple`. + If :attr:`~Connection.row_factory` is ``None``, + return the next row query result set as a :class:`tuple`. + Else, pass it to the row factory and return its result. Return ``None`` if no more data is available. From webhook-mailer at python.org Wed Oct 5 04:57:35 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 05 Oct 2022 08:57:35 -0000 Subject: [Python-checkins] gh-97661: Improve accuracy of sqlite3.Cursor.fetchone docs (GH-97662) Message-ID: https://github.com/python/cpython/commit/79b5c1ad3c750312d6af062a70808555b4ea49ab commit: 79b5c1ad3c750312d6af062a70808555b4ea49ab branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-05T01:57:30-07:00 summary: gh-97661: Improve accuracy of sqlite3.Cursor.fetchone docs (GH-97662) Co-authored-by: C.A.M. Gerlach (cherry picked from commit 4b83cd0b22428fbfccf1f0e85c0fc36be6ab7edf) Co-authored-by: Jia Junjie <62194633+jiajunjie at users.noreply.github.com> files: M Doc/library/sqlite3.rst diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index 70cf43c2544e..8fdb75349540 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -1412,7 +1412,9 @@ Cursor objects .. method:: fetchone() - Return the next row of a query result set as a :class:`tuple`. + If :attr:`~Connection.row_factory` is ``None``, + return the next row query result set as a :class:`tuple`. + Else, pass it to the row factory and return its result. Return ``None`` if no more data is available. From webhook-mailer at python.org Wed Oct 5 05:49:21 2022 From: webhook-mailer at python.org (serhiy-storchaka) Date: Wed, 05 Oct 2022 09:49:21 -0000 Subject: [Python-checkins] gh-74696: Pass root_dir to custom archivers which support it (GH-94251) Message-ID: https://github.com/python/cpython/commit/e3ef400be74e027eaa19f7677af986fb05dd3334 commit: e3ef400be74e027eaa19f7677af986fb05dd3334 branch: main author: Serhiy Storchaka committer: serhiy-storchaka date: 2022-10-05T12:48:59+03:00 summary: gh-74696: Pass root_dir to custom archivers which support it (GH-94251) Co-authored-by: ?ric files: A Misc/NEWS.d/next/Library/2022-06-25-09-12-23.gh-issue-74696.fxC9ua.rst M Doc/library/shutil.rst M Doc/whatsnew/3.12.rst M Lib/shutil.py M Lib/test/test_shutil.py diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst index 8f1668f76b90..b33dbe21b1fa 100644 --- a/Doc/library/shutil.rst +++ b/Doc/library/shutil.rst @@ -575,9 +575,10 @@ provided. They rely on the :mod:`zipfile` and :mod:`tarfile` modules. .. note:: This function is not thread-safe when custom archivers registered - with :func:`register_archive_format` are used. In this case it + with :func:`register_archive_format` do not support the *root_dir* + argument. In this case it temporarily changes the current working directory of the process - to perform archiving. + to *root_dir* to perform archiving. .. versionchanged:: 3.8 The modern pax (POSIX.1-2001) format is now used instead of @@ -614,12 +615,21 @@ provided. They rely on the :mod:`zipfile` and :mod:`tarfile` modules. Further arguments are passed as keyword arguments: *owner*, *group*, *dry_run* and *logger* (as passed in :func:`make_archive`). + If *function* has the custom attribute ``function.supports_root_dir`` set to ``True``, + the *root_dir* argument is passed as a keyword argument. + Otherwise the current working directory of the process is temporarily + changed to *root_dir* before calling *function*. + In this case :func:`make_archive` is not thread-safe. + If given, *extra_args* is a sequence of ``(name, value)`` pairs that will be used as extra keywords arguments when the archiver callable is used. *description* is used by :func:`get_archive_formats` which returns the list of archivers. Defaults to an empty string. + .. versionchanged:: 3.12 + Added support for functions supporting the *root_dir* argument. + .. function:: unregister_archive_format(name) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 052507a4873f..62ec2de2e78c 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -127,6 +127,15 @@ os for a process with :func:`os.pidfd_open` in non-blocking mode. (Contributed by Kumar Aditya in :gh:`93312`.) +shutil +------ + +* :func:`shutil.make_archive` now passes the *root_dir* argument to custom + archivers which support it. + In this case it no longer temporarily changes the current working directory + of the process to *root_dir* to perform archiving. + (Contributed by Serhiy Storchaka in :gh:`74696`.) + sqlite3 ------- diff --git a/Lib/shutil.py b/Lib/shutil.py index b49437cd1f3e..ac1dd530528c 100644 --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -1023,28 +1023,30 @@ def _make_zipfile(base_name, base_dir, verbose=0, dry_run=0, zip_filename = os.path.abspath(zip_filename) return zip_filename +_make_tarball.supports_root_dir = True +_make_zipfile.supports_root_dir = True + # Maps the name of the archive format to a tuple containing: # * the archiving function # * extra keyword arguments # * description -# * does it support the root_dir argument? _ARCHIVE_FORMATS = { 'tar': (_make_tarball, [('compress', None)], - "uncompressed tar file", True), + "uncompressed tar file"), } if _ZLIB_SUPPORTED: _ARCHIVE_FORMATS['gztar'] = (_make_tarball, [('compress', 'gzip')], - "gzip'ed tar-file", True) - _ARCHIVE_FORMATS['zip'] = (_make_zipfile, [], "ZIP file", True) + "gzip'ed tar-file") + _ARCHIVE_FORMATS['zip'] = (_make_zipfile, [], "ZIP file") if _BZ2_SUPPORTED: _ARCHIVE_FORMATS['bztar'] = (_make_tarball, [('compress', 'bzip2')], - "bzip2'ed tar-file", True) + "bzip2'ed tar-file") if _LZMA_SUPPORTED: _ARCHIVE_FORMATS['xztar'] = (_make_tarball, [('compress', 'xz')], - "xz'ed tar-file", True) + "xz'ed tar-file") def get_archive_formats(): """Returns a list of supported formats for archiving and unarchiving. @@ -1075,7 +1077,7 @@ def register_archive_format(name, function, extra_args=None, description=''): if not isinstance(element, (tuple, list)) or len(element) !=2: raise TypeError('extra_args elements are : (arg_name, value)') - _ARCHIVE_FORMATS[name] = (function, extra_args, description, False) + _ARCHIVE_FORMATS[name] = (function, extra_args, description) def unregister_archive_format(name): del _ARCHIVE_FORMATS[name] @@ -1114,10 +1116,10 @@ def make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0, if base_dir is None: base_dir = os.curdir - support_root_dir = format_info[3] + supports_root_dir = getattr(func, 'supports_root_dir', False) save_cwd = None if root_dir is not None: - if support_root_dir: + if supports_root_dir: # Support path-like base_name here for backwards-compatibility. base_name = os.fspath(base_name) kwargs['root_dir'] = root_dir diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py index a2c4ab508195..6789fe4cc72e 100644 --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -1568,28 +1568,65 @@ def test_tarfile_root_owner(self): finally: archive.close() + def test_make_archive_cwd_default(self): + current_dir = os.getcwd() + def archiver(base_name, base_dir, **kw): + self.assertNotIn('root_dir', kw) + self.assertEqual(base_name, 'basename') + self.assertEqual(os.getcwd(), current_dir) + raise RuntimeError() + + register_archive_format('xxx', archiver, [], 'xxx file') + try: + with no_chdir: + with self.assertRaises(RuntimeError): + make_archive('basename', 'xxx') + self.assertEqual(os.getcwd(), current_dir) + finally: + unregister_archive_format('xxx') + def test_make_archive_cwd(self): current_dir = os.getcwd() root_dir = self.mkdtemp() - def _breaks(*args, **kw): + def archiver(base_name, base_dir, **kw): + self.assertNotIn('root_dir', kw) + self.assertEqual(base_name, os.path.join(current_dir, 'basename')) + self.assertEqual(os.getcwd(), root_dir) raise RuntimeError() dirs = [] def _chdir(path): dirs.append(path) orig_chdir(path) - register_archive_format('xxx', _breaks, [], 'xxx file') + register_archive_format('xxx', archiver, [], 'xxx file') try: with support.swap_attr(os, 'chdir', _chdir) as orig_chdir: - try: - make_archive('xxx', 'xxx', root_dir=root_dir) - except Exception: - pass + with self.assertRaises(RuntimeError): + make_archive('basename', 'xxx', root_dir=root_dir) self.assertEqual(os.getcwd(), current_dir) self.assertEqual(dirs, [root_dir, current_dir]) finally: unregister_archive_format('xxx') + def test_make_archive_cwd_supports_root_dir(self): + current_dir = os.getcwd() + root_dir = self.mkdtemp() + def archiver(base_name, base_dir, **kw): + self.assertEqual(base_name, 'basename') + self.assertEqual(kw['root_dir'], root_dir) + self.assertEqual(os.getcwd(), current_dir) + raise RuntimeError() + archiver.supports_root_dir = True + + register_archive_format('xxx', archiver, [], 'xxx file') + try: + with no_chdir: + with self.assertRaises(RuntimeError): + make_archive('basename', 'xxx', root_dir=root_dir) + self.assertEqual(os.getcwd(), current_dir) + finally: + unregister_archive_format('xxx') + def test_make_tarfile_in_curdir(self): # Issue #21280 root_dir = self.mkdtemp() diff --git a/Misc/NEWS.d/next/Library/2022-06-25-09-12-23.gh-issue-74696.fxC9ua.rst b/Misc/NEWS.d/next/Library/2022-06-25-09-12-23.gh-issue-74696.fxC9ua.rst new file mode 100644 index 000000000000..48beaff59a16 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-06-25-09-12-23.gh-issue-74696.fxC9ua.rst @@ -0,0 +1,2 @@ +:func:`shutil.make_archive` now passes the *root_dir* argument to custom +archivers which support it. From webhook-mailer at python.org Wed Oct 5 05:52:06 2022 From: webhook-mailer at python.org (serhiy-storchaka) Date: Wed, 05 Oct 2022 09:52:06 -0000 Subject: [Python-checkins] gh-97758: Fix a crash in getpath_joinpath() called without arguments (GH-97759) Message-ID: https://github.com/python/cpython/commit/f8cbd79d328d90443acabc41d246332c302c815a commit: f8cbd79d328d90443acabc41d246332c302c815a branch: main author: Serhiy Storchaka committer: serhiy-storchaka date: 2022-10-05T12:51:58+03:00 summary: gh-97758: Fix a crash in getpath_joinpath() called without arguments (GH-97759) files: M Modules/getpath.c diff --git a/Modules/getpath.c b/Modules/getpath.c index be704adbde94..ceacf36d8968 100644 --- a/Modules/getpath.c +++ b/Modules/getpath.c @@ -261,7 +261,7 @@ getpath_joinpath(PyObject *Py_UNUSED(self), PyObject *args) } Py_ssize_t n = PyTuple_GET_SIZE(args); if (n == 0) { - return PyUnicode_FromString(NULL); + return PyUnicode_FromStringAndSize(NULL, 0); } /* Convert all parts to wchar and accumulate max final length */ wchar_t **parts = (wchar_t **)PyMem_Malloc(n * sizeof(wchar_t *)); From webhook-mailer at python.org Wed Oct 5 06:20:37 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 05 Oct 2022 10:20:37 -0000 Subject: [Python-checkins] gh-97758: Fix a crash in getpath_joinpath() called without arguments (GH-97759) Message-ID: https://github.com/python/cpython/commit/73e3510bdb2762e371e8545f1a4c68b821fcdcf2 commit: 73e3510bdb2762e371e8545f1a4c68b821fcdcf2 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-05T03:20:32-07:00 summary: gh-97758: Fix a crash in getpath_joinpath() called without arguments (GH-97759) (cherry picked from commit f8cbd79d328d90443acabc41d246332c302c815a) Co-authored-by: Serhiy Storchaka files: M Modules/getpath.c diff --git a/Modules/getpath.c b/Modules/getpath.c index be704adbde94..ceacf36d8968 100644 --- a/Modules/getpath.c +++ b/Modules/getpath.c @@ -261,7 +261,7 @@ getpath_joinpath(PyObject *Py_UNUSED(self), PyObject *args) } Py_ssize_t n = PyTuple_GET_SIZE(args); if (n == 0) { - return PyUnicode_FromString(NULL); + return PyUnicode_FromStringAndSize(NULL, 0); } /* Convert all parts to wchar and accumulate max final length */ wchar_t **parts = (wchar_t **)PyMem_Malloc(n * sizeof(wchar_t *)); From webhook-mailer at python.org Wed Oct 5 07:21:26 2022 From: webhook-mailer at python.org (serhiy-storchaka) Date: Wed, 05 Oct 2022 11:21:26 -0000 Subject: [Python-checkins] gh-95196: Disable incorrect pickling of the C implemented classmethod descriptors (GH-96383) Message-ID: https://github.com/python/cpython/commit/77f0249308de76401bf4f3c6a057789c92f862d1 commit: 77f0249308de76401bf4f3c6a057789c92f862d1 branch: main author: Serhiy Storchaka committer: serhiy-storchaka date: 2022-10-05T14:21:16+03:00 summary: gh-95196: Disable incorrect pickling of the C implemented classmethod descriptors (GH-96383) files: A Misc/NEWS.d/next/Core and Builtins/2022-08-29-13-06-58.gh-issue-95196.eGRR4b.rst M Lib/test/pickletester.py M Objects/descrobject.c diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py index 21419e11c874..499f80a15f34 100644 --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -2776,6 +2776,15 @@ def pie(self): unpickled = self.loads(self.dumps(method, proto)) self.assertEqual(method(obj), unpickled(obj)) + descriptors = ( + PyMethodsTest.__dict__['cheese'], # static method descriptor + PyMethodsTest.__dict__['wine'], # class method descriptor + ) + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + for descr in descriptors: + with self.subTest(proto=proto, descr=descr): + self.assertRaises(TypeError, self.dumps, descr, proto) + def test_c_methods(self): global Subclass class Subclass(tuple): @@ -2811,6 +2820,15 @@ class Nested(str): unpickled = self.loads(self.dumps(method, proto)) self.assertEqual(method(*args), unpickled(*args)) + descriptors = ( + bytearray.__dict__['maketrans'], # built-in static method descriptor + dict.__dict__['fromkeys'], # built-in class method descriptor + ) + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + for descr in descriptors: + with self.subTest(proto=proto, descr=descr): + self.assertRaises(TypeError, self.dumps, descr, proto) + def test_compat_pickle(self): tests = [ (range(1, 7), '__builtin__', 'xrange'), diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-08-29-13-06-58.gh-issue-95196.eGRR4b.rst b/Misc/NEWS.d/next/Core and Builtins/2022-08-29-13-06-58.gh-issue-95196.eGRR4b.rst new file mode 100644 index 000000000000..37534fa17525 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-08-29-13-06-58.gh-issue-95196.eGRR4b.rst @@ -0,0 +1 @@ +Disable incorrect pickling of the C implemented classmethod descriptors. diff --git a/Objects/descrobject.c b/Objects/descrobject.c index 82570e085143..a2974f91aaae 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -776,7 +776,7 @@ PyTypeObject PyClassMethodDescr_Type = { 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ - descr_methods, /* tp_methods */ + 0, /* tp_methods */ descr_members, /* tp_members */ method_getset, /* tp_getset */ 0, /* tp_base */ From webhook-mailer at python.org Wed Oct 5 07:53:48 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 05 Oct 2022 11:53:48 -0000 Subject: [Python-checkins] gh-95196: Disable incorrect pickling of the C implemented classmethod descriptors (GH-96383) Message-ID: https://github.com/python/cpython/commit/d108eeb6786ab02799503a3f8afb998d0913a468 commit: d108eeb6786ab02799503a3f8afb998d0913a468 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-05T04:53:38-07:00 summary: gh-95196: Disable incorrect pickling of the C implemented classmethod descriptors (GH-96383) (cherry picked from commit 77f0249308de76401bf4f3c6a057789c92f862d1) Co-authored-by: Serhiy Storchaka files: A Misc/NEWS.d/next/Core and Builtins/2022-08-29-13-06-58.gh-issue-95196.eGRR4b.rst M Lib/test/pickletester.py M Objects/descrobject.c diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py index 4e8d4e4f6433..18d7f52ecffd 100644 --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -2773,6 +2773,15 @@ def pie(self): unpickled = self.loads(self.dumps(method, proto)) self.assertEqual(method(obj), unpickled(obj)) + descriptors = ( + PyMethodsTest.__dict__['cheese'], # static method descriptor + PyMethodsTest.__dict__['wine'], # class method descriptor + ) + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + for descr in descriptors: + with self.subTest(proto=proto, descr=descr): + self.assertRaises(TypeError, self.dumps, descr, proto) + def test_c_methods(self): global Subclass class Subclass(tuple): @@ -2808,6 +2817,15 @@ class Nested(str): unpickled = self.loads(self.dumps(method, proto)) self.assertEqual(method(*args), unpickled(*args)) + descriptors = ( + bytearray.__dict__['maketrans'], # built-in static method descriptor + dict.__dict__['fromkeys'], # built-in class method descriptor + ) + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + for descr in descriptors: + with self.subTest(proto=proto, descr=descr): + self.assertRaises(TypeError, self.dumps, descr, proto) + def test_compat_pickle(self): tests = [ (range(1, 7), '__builtin__', 'xrange'), diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-08-29-13-06-58.gh-issue-95196.eGRR4b.rst b/Misc/NEWS.d/next/Core and Builtins/2022-08-29-13-06-58.gh-issue-95196.eGRR4b.rst new file mode 100644 index 000000000000..37534fa17525 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-08-29-13-06-58.gh-issue-95196.eGRR4b.rst @@ -0,0 +1 @@ +Disable incorrect pickling of the C implemented classmethod descriptors. diff --git a/Objects/descrobject.c b/Objects/descrobject.c index 09b0f82c6990..ee3ad1b7a328 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -755,7 +755,7 @@ PyTypeObject PyClassMethodDescr_Type = { 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ - descr_methods, /* tp_methods */ + 0, /* tp_methods */ descr_members, /* tp_members */ method_getset, /* tp_getset */ 0, /* tp_base */ From webhook-mailer at python.org Wed Oct 5 07:59:14 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 05 Oct 2022 11:59:14 -0000 Subject: [Python-checkins] gh-95196: Disable incorrect pickling of the C implemented classmethod descriptors (GH-96383) Message-ID: https://github.com/python/cpython/commit/2b248b0ab58428ae9c6006c02808ae2241293da3 commit: 2b248b0ab58428ae9c6006c02808ae2241293da3 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-05T04:59:09-07:00 summary: gh-95196: Disable incorrect pickling of the C implemented classmethod descriptors (GH-96383) (cherry picked from commit 77f0249308de76401bf4f3c6a057789c92f862d1) Co-authored-by: Serhiy Storchaka files: A Misc/NEWS.d/next/Core and Builtins/2022-08-29-13-06-58.gh-issue-95196.eGRR4b.rst M Lib/test/pickletester.py M Objects/descrobject.c diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py index 21419e11c874..499f80a15f34 100644 --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -2776,6 +2776,15 @@ def pie(self): unpickled = self.loads(self.dumps(method, proto)) self.assertEqual(method(obj), unpickled(obj)) + descriptors = ( + PyMethodsTest.__dict__['cheese'], # static method descriptor + PyMethodsTest.__dict__['wine'], # class method descriptor + ) + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + for descr in descriptors: + with self.subTest(proto=proto, descr=descr): + self.assertRaises(TypeError, self.dumps, descr, proto) + def test_c_methods(self): global Subclass class Subclass(tuple): @@ -2811,6 +2820,15 @@ class Nested(str): unpickled = self.loads(self.dumps(method, proto)) self.assertEqual(method(*args), unpickled(*args)) + descriptors = ( + bytearray.__dict__['maketrans'], # built-in static method descriptor + dict.__dict__['fromkeys'], # built-in class method descriptor + ) + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + for descr in descriptors: + with self.subTest(proto=proto, descr=descr): + self.assertRaises(TypeError, self.dumps, descr, proto) + def test_compat_pickle(self): tests = [ (range(1, 7), '__builtin__', 'xrange'), diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-08-29-13-06-58.gh-issue-95196.eGRR4b.rst b/Misc/NEWS.d/next/Core and Builtins/2022-08-29-13-06-58.gh-issue-95196.eGRR4b.rst new file mode 100644 index 000000000000..37534fa17525 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-08-29-13-06-58.gh-issue-95196.eGRR4b.rst @@ -0,0 +1 @@ +Disable incorrect pickling of the C implemented classmethod descriptors. diff --git a/Objects/descrobject.c b/Objects/descrobject.c index c3c541bf3c32..73ac14d2a84b 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -775,7 +775,7 @@ PyTypeObject PyClassMethodDescr_Type = { 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ - descr_methods, /* tp_methods */ + 0, /* tp_methods */ descr_members, /* tp_members */ method_getset, /* tp_getset */ 0, /* tp_base */ From webhook-mailer at python.org Wed Oct 5 10:42:08 2022 From: webhook-mailer at python.org (gvanrossum) Date: Wed, 05 Oct 2022 14:42:08 -0000 Subject: [Python-checkins] gh-93357: Port test cases to IsolatedAsyncioTestCase, part 2 (#97896) Message-ID: https://github.com/python/cpython/commit/09aea94d291fed2f3e96558dcd6db04014c3e2fb commit: 09aea94d291fed2f3e96558dcd6db04014c3e2fb branch: main author: Oleg Iarygin committer: gvanrossum date: 2022-10-05T07:31:43-07:00 summary: gh-93357: Port test cases to IsolatedAsyncioTestCase, part 2 (#97896) This fixes the buildbots. files: M Lib/test/test_asyncio/test_streams.py diff --git a/Lib/test/test_asyncio/test_streams.py b/Lib/test/test_asyncio/test_streams.py index d1f8aef4bb9c..61d5e984dfbf 100644 --- a/Lib/test/test_asyncio/test_streams.py +++ b/Lib/test/test_asyncio/test_streams.py @@ -941,34 +941,32 @@ def test_LimitOverrunError_pickleable(self): self.assertEqual(str(e), str(e2)) self.assertEqual(e.consumed, e2.consumed) +class NewStreamTests2(unittest.IsolatedAsyncioTestCase): async def test_wait_closed_on_close(self): - async with test_utils.run_test_server() as httpd: - rd, wr = self.loop.run_until_complete( - asyncio.open_connection(*httpd.address)) + with test_utils.run_test_server() as httpd: + rd, wr = await asyncio.open_connection(*httpd.address) wr.write(b'GET / HTTP/1.0\r\n\r\n') data = await rd.readline() self.assertEqual(data, b'HTTP/1.0 200 OK\r\n') - await rd.read() + data = await rd.read() self.assertTrue(data.endswith(b'\r\n\r\nTest message')) self.assertFalse(wr.is_closing()) wr.close() self.assertTrue(wr.is_closing()) await wr.wait_closed() - def test_wait_closed_on_close_with_unread_data(self): + async def test_wait_closed_on_close_with_unread_data(self): with test_utils.run_test_server() as httpd: - rd, wr = self.loop.run_until_complete( - asyncio.open_connection(*httpd.address)) + rd, wr = await asyncio.open_connection(*httpd.address) wr.write(b'GET / HTTP/1.0\r\n\r\n') - f = rd.readline() - data = self.loop.run_until_complete(f) + data = await rd.readline() self.assertEqual(data, b'HTTP/1.0 200 OK\r\n') wr.close() - self.loop.run_until_complete(wr.wait_closed()) + await wr.wait_closed() - def test_async_writer_api(self): + async def test_async_writer_api(self): async def inner(httpd): rd, wr = await asyncio.open_connection(*httpd.address) @@ -980,15 +978,10 @@ async def inner(httpd): wr.close() await wr.wait_closed() - messages = [] - self.loop.set_exception_handler(lambda loop, ctx: messages.append(ctx)) - with test_utils.run_test_server() as httpd: - self.loop.run_until_complete(inner(httpd)) - - self.assertEqual(messages, []) + await inner(httpd) - def test_async_writer_api_exception_after_close(self): + async def test_async_writer_api_exception_after_close(self): async def inner(httpd): rd, wr = await asyncio.open_connection(*httpd.address) @@ -1002,24 +995,17 @@ async def inner(httpd): wr.write(b'data') await wr.drain() - messages = [] - self.loop.set_exception_handler(lambda loop, ctx: messages.append(ctx)) - with test_utils.run_test_server() as httpd: - self.loop.run_until_complete(inner(httpd)) - - self.assertEqual(messages, []) + await inner(httpd) async def test_eof_feed_when_closing_writer(self): # See http://bugs.python.org/issue35065 - async with test_utils.run_test_server() as httpd: + with test_utils.run_test_server() as httpd: rd, wr = await asyncio.open_connection(*httpd.address) wr.close() - f = wr.wait_closed() - self.loop.run_until_complete(f) + await wr.wait_closed() self.assertTrue(rd.at_eof()) - f = rd.read() - data = self.loop.run_until_complete(f) + data = await rd.read() self.assertEqual(data, b'') From webhook-mailer at python.org Wed Oct 5 11:18:17 2022 From: webhook-mailer at python.org (ambv) Date: Wed, 05 Oct 2022 15:18:17 -0000 Subject: [Python-checkins] [3.10] gh-93738: Documentation C syntax (:c:type:`PyObject` -> :c:expr:`PyObject`) (GH-97776) (#97888) Message-ID: https://github.com/python/cpython/commit/4245764fae0f09fe5ac1c7bc736d35aeb064a795 commit: 4245764fae0f09fe5ac1c7bc736d35aeb064a795 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-05T08:17:46-07:00 summary: [3.10] gh-93738: Documentation C syntax (:c:type:`PyObject` -> :c:expr:`PyObject`) (GH-97776) (#97888) :c:type:`PyObject` -> :c:expr:`PyObject` (cherry picked from commit 0bf6a617ed1832bc4803e532c8d6b3427cf48b13) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> files: M Doc/c-api/arg.rst M Doc/c-api/call.rst M Doc/c-api/dict.rst M Doc/c-api/exceptions.rst M Doc/c-api/init.rst M Doc/c-api/intro.rst M Doc/c-api/structures.rst M Doc/c-api/tuple.rst M Doc/c-api/typeobj.rst M Doc/library/ctypes.rst diff --git a/Doc/c-api/arg.rst b/Doc/c-api/arg.rst index 926e5249347f..fb921a4af6f3 100644 --- a/Doc/c-api/arg.rst +++ b/Doc/c-api/arg.rst @@ -129,12 +129,12 @@ which disallows mutable objects such as :class:`bytearray`. ``S`` (:class:`bytes`) [PyBytesObject \*] Requires that the Python object is a :class:`bytes` object, without attempting any conversion. Raises :exc:`TypeError` if the object is not - a bytes object. The C variable may also be declared as :c:type:`PyObject*`. + a bytes object. The C variable may also be declared as :c:expr:`PyObject*`. ``Y`` (:class:`bytearray`) [PyByteArrayObject \*] Requires that the Python object is a :class:`bytearray` object, without attempting any conversion. Raises :exc:`TypeError` if the object is not - a :class:`bytearray` object. The C variable may also be declared as :c:type:`PyObject*`. + a :class:`bytearray` object. The C variable may also be declared as :c:expr:`PyObject*`. ``u`` (:class:`str`) [const Py_UNICODE \*] Convert a Python Unicode object to a C pointer to a NUL-terminated buffer of @@ -181,7 +181,7 @@ which disallows mutable objects such as :class:`bytearray`. ``U`` (:class:`str`) [PyObject \*] Requires that the Python object is a Unicode object, without attempting any conversion. Raises :exc:`TypeError` if the object is not a Unicode - object. The C variable may also be declared as :c:type:`PyObject*`. + object. The C variable may also be declared as :c:expr:`PyObject*`. ``w*`` (read-write :term:`bytes-like object`) [Py_buffer] This format accepts any object which implements the read-write buffer @@ -320,7 +320,7 @@ Other objects ``O!`` (object) [*typeobject*, PyObject \*] Store a Python object in a C object pointer. This is similar to ``O``, but takes two C arguments: the first is the address of a Python type object, the - second is the address of the C variable (of type :c:type:`PyObject*`) into which + second is the address of the C variable (of type :c:expr:`PyObject*`) into which the object pointer is stored. If the Python object does not have the required type, :exc:`TypeError` is raised. @@ -481,7 +481,7 @@ API Functions *args*; it must actually be a tuple. The length of the tuple must be at least *min* and no more than *max*; *min* and *max* may be equal. Additional arguments must be passed to the function, each of which should be a pointer to a - :c:type:`PyObject*` variable; these will be filled in with the values from + :c:expr:`PyObject*` variable; these will be filled in with the values from *args*; they will contain :term:`borrowed references `. The variables which correspond to optional parameters not given by *args* will not be filled in; these should diff --git a/Doc/c-api/call.rst b/Doc/c-api/call.rst index 13ef8b217a16..36149f156c67 100644 --- a/Doc/c-api/call.rst +++ b/Doc/c-api/call.rst @@ -275,7 +275,7 @@ please see individual documentation for details. This is the equivalent of the Python expression: ``callable(*args)``. - Note that if you only pass :c:type:`PyObject *` args, + Note that if you only pass :c:expr:`PyObject *` args, :c:func:`PyObject_CallFunctionObjArgs` is a faster alternative. .. versionchanged:: 3.4 @@ -296,7 +296,7 @@ please see individual documentation for details. This is the equivalent of the Python expression: ``obj.name(arg1, arg2, ...)``. - Note that if you only pass :c:type:`PyObject *` args, + Note that if you only pass :c:expr:`PyObject *` args, :c:func:`PyObject_CallMethodObjArgs` is a faster alternative. .. versionchanged:: 3.4 @@ -306,7 +306,7 @@ please see individual documentation for details. .. c:function:: PyObject* PyObject_CallFunctionObjArgs(PyObject *callable, ...) Call a callable Python object *callable*, with a variable number of - :c:type:`PyObject *` arguments. The arguments are provided as a variable number + :c:expr:`PyObject *` arguments. The arguments are provided as a variable number of parameters followed by *NULL*. Return the result of the call on success, or raise an exception and return @@ -320,7 +320,7 @@ please see individual documentation for details. Call a method of the Python object *obj*, where the name of the method is given as a Python string object in *name*. It is called with a variable number of - :c:type:`PyObject *` arguments. The arguments are provided as a variable number + :c:expr:`PyObject *` arguments. The arguments are provided as a variable number of parameters followed by *NULL*. Return the result of the call on success, or raise an exception and return diff --git a/Doc/c-api/dict.rst b/Doc/c-api/dict.rst index d257c9b5f763..67c2026baa14 100644 --- a/Doc/c-api/dict.rst +++ b/Doc/c-api/dict.rst @@ -118,7 +118,7 @@ Dictionary Objects .. c:function:: PyObject* PyDict_GetItemString(PyObject *p, const char *key) This is the same as :c:func:`PyDict_GetItem`, but *key* is specified as a - :c:type:`const char*`, rather than a :c:type:`PyObject*`. + :c:type:`const char*`, rather than a :c:expr:`PyObject*`. Note that exceptions which occur while calling :meth:`__hash__` and :meth:`__eq__` methods and creating a temporary string object @@ -167,7 +167,7 @@ Dictionary Objects prior to the first call to this function to start the iteration; the function returns true for each pair in the dictionary, and false once all pairs have been reported. The parameters *pkey* and *pvalue* should either - point to :c:type:`PyObject*` variables that will be filled in with each key + point to :c:expr:`PyObject*` variables that will be filled in with each key and value, respectively, or may be ``NULL``. Any references returned through them are borrowed. *ppos* should not be altered during iteration. Its value represents offsets within the internal dictionary structure, and diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index 40759f7b0305..ad75ec5c62c0 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -828,7 +828,7 @@ Standard Exceptions All standard Python exceptions are available as global variables whose names are ``PyExc_`` followed by the Python exception name. These have the type -:c:type:`PyObject*`; they are all class objects. For completeness, here are all +:c:expr:`PyObject*`; they are all class objects. For completeness, here are all the variables: .. index:: @@ -1048,7 +1048,7 @@ Standard Warning Categories All standard Python warning categories are available as global variables whose names are ``PyExc_`` followed by the Python exception name. These have the type -:c:type:`PyObject*`; they are all class objects. For completeness, here are all +:c:expr:`PyObject*`; they are all class objects. For completeness, here are all the variables: .. index:: diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index 45efa8949878..dbde7f633b0e 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -1668,7 +1668,7 @@ you need to include :file:`pythread.h` to use thread-local storage. .. note:: None of these API functions handle memory management on behalf of the :c:type:`void*` values. You need to allocate and deallocate them yourself. - If the :c:type:`void*` values happen to be :c:type:`PyObject*`, these + If the :c:type:`void*` values happen to be :c:expr:`PyObject*`, these functions don't do refcount operations on them either. .. _thread-specific-storage-api: diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst index 2c09ac5c78fa..82e578fbacf8 100644 --- a/Doc/c-api/intro.rst +++ b/Doc/c-api/intro.rst @@ -229,13 +229,13 @@ Objects, Types and Reference Counts .. index:: object: type Most Python/C API functions have one or more arguments as well as a return value -of type :c:type:`PyObject*`. This type is a pointer to an opaque data type +of type :c:expr:`PyObject*`. This type is a pointer to an opaque data type representing an arbitrary Python object. Since all Python object types are treated the same way by the Python language in most situations (e.g., assignments, scope rules, and argument passing), it is only fitting that they should be represented by a single C type. Almost all Python objects live on the heap: you never declare an automatic or static variable of type -:c:type:`PyObject`, only pointer variables of type :c:type:`PyObject*` can be +:c:type:`PyObject`, only pointer variables of type :c:expr:`PyObject*` can be declared. The sole exception are the type objects; since these must never be deallocated, they are typically static :c:type:`PyTypeObject` objects. diff --git a/Doc/c-api/structures.rst b/Doc/c-api/structures.rst index c1c83b035c85..c1ff90fb8a64 100644 --- a/Doc/c-api/structures.rst +++ b/Doc/c-api/structures.rst @@ -27,7 +27,7 @@ the definition of all other Python objects. object. In a normal "release" build, it contains only the object's reference count and a pointer to the corresponding type object. Nothing is actually declared to be a :c:type:`PyObject`, but every pointer - to a Python object can be cast to a :c:type:`PyObject*`. Access to the + to a Python object can be cast to a :c:expr:`PyObject*`. Access to the members must be done by using the macros :c:macro:`Py_REFCNT` and :c:macro:`Py_TYPE`. @@ -172,7 +172,7 @@ Implementing functions and methods .. c:type:: PyCFunction Type of the functions used to implement most Python callables in C. - Functions of this type take two :c:type:`PyObject*` parameters and return + Functions of this type take two :c:expr:`PyObject*` parameters and return one such value. If the return value is ``NULL``, an exception shall have been set. If not ``NULL``, the return value is interpreted as the return value of the function as exposed in Python. The function must return a new @@ -251,10 +251,10 @@ Implementing functions and methods +------------------+---------------+-------------------------------+ The :attr:`ml_meth` is a C function pointer. The functions may be of different -types, but they always return :c:type:`PyObject*`. If the function is not of +types, but they always return :c:expr:`PyObject*`. If the function is not of the :c:type:`PyCFunction`, the compiler will require a cast in the method table. Even though :c:type:`PyCFunction` defines the first parameter as -:c:type:`PyObject*`, it is common that the method implementation uses the +:c:expr:`PyObject*`, it is common that the method implementation uses the specific C type of the *self* object. The :attr:`ml_flags` field is a bitfield which can include the following flags. @@ -266,7 +266,7 @@ There are these calling conventions: .. data:: METH_VARARGS This is the typical calling convention, where the methods have the type - :c:type:`PyCFunction`. The function expects two :c:type:`PyObject*` values. + :c:type:`PyCFunction`. The function expects two :c:expr:`PyObject*` values. The first one is the *self* object for methods; for module functions, it is the module object. The second parameter (often called *args*) is a tuple object representing all arguments. This parameter is typically processed @@ -287,7 +287,7 @@ There are these calling conventions: Fast calling convention supporting only positional arguments. The methods have the type :c:type:`_PyCFunctionFast`. The first parameter is *self*, the second parameter is a C array - of :c:type:`PyObject*` values indicating the arguments and the third + of :c:expr:`PyObject*` values indicating the arguments and the third parameter is the number of arguments (the length of the array). .. versionadded:: 3.7 @@ -303,7 +303,7 @@ There are these calling conventions: with methods of type :c:type:`_PyCFunctionFastWithKeywords`. Keyword arguments are passed the same way as in the :ref:`vectorcall protocol `: - there is an additional fourth :c:type:`PyObject*` parameter + there is an additional fourth :c:expr:`PyObject*` parameter which is a tuple representing the names of the keyword arguments (which are guaranteed to be strings) or possibly ``NULL`` if there are no keywords. The values of the keyword @@ -339,7 +339,7 @@ There are these calling conventions: Methods with a single object argument can be listed with the :const:`METH_O` flag, instead of invoking :c:func:`PyArg_ParseTuple` with a ``"O"`` argument. They have the type :c:type:`PyCFunction`, with the *self* parameter, and a - :c:type:`PyObject*` parameter representing the single argument. + :c:expr:`PyObject*` parameter representing the single argument. These two constants are not used to indicate the calling convention but the @@ -505,7 +505,7 @@ Accessing attributes of extension types | | | getter and setter | +-------------+------------------+-----------------------------------+ - The ``get`` function takes one :c:type:`PyObject*` parameter (the + The ``get`` function takes one :c:expr:`PyObject*` parameter (the instance) and a function pointer (the associated ``closure``):: typedef PyObject *(*getter)(PyObject *, void *); @@ -513,7 +513,7 @@ Accessing attributes of extension types It should return a new reference on success or ``NULL`` with a set exception on failure. - ``set`` functions take two :c:type:`PyObject*` parameters (the instance and + ``set`` functions take two :c:expr:`PyObject*` parameters (the instance and the value to be set) and a function pointer (the associated ``closure``):: typedef int (*setter)(PyObject *, PyObject *, void *); diff --git a/Doc/c-api/tuple.rst b/Doc/c-api/tuple.rst index 6919e6102278..b330cdac7651 100644 --- a/Doc/c-api/tuple.rst +++ b/Doc/c-api/tuple.rst @@ -161,7 +161,7 @@ type. .. c:type:: PyStructSequence_Field Describes a field of a struct sequence. As a struct sequence is modeled as a - tuple, all fields are typed as :c:type:`PyObject*`. The index in the + tuple, all fields are typed as :c:expr:`PyObject*`. The index in the :attr:`fields` array of the :c:type:`PyStructSequence_Desc` determines which field of the struct sequence is described. diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index 13de82f3700b..fd3d4b77086c 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -1484,7 +1484,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) than zero and contains the offset in the instance structure of the weak reference list head (ignoring the GC header, if present); this offset is used by :c:func:`PyObject_ClearWeakRefs` and the :c:func:`PyWeakref_\*` functions. The - instance structure needs to include a field of type :c:type:`PyObject*` which is + instance structure needs to include a field of type :c:expr:`PyObject*` which is initialized to ``NULL``. Do not confuse this field with :c:member:`~PyTypeObject.tp_weaklist`; that is the list head for diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index 19ce19b1d70d..3a9f3a8588a5 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -2367,8 +2367,8 @@ These are the fundamental ctypes data types: .. class:: py_object - Represents the C :c:type:`PyObject *` datatype. Calling this without an - argument creates a ``NULL`` :c:type:`PyObject *` pointer. + Represents the C :c:expr:`PyObject *` datatype. Calling this without an + argument creates a ``NULL`` :c:expr:`PyObject *` pointer. The :mod:`ctypes.wintypes` module provides quite some other Windows specific data types, for example :c:type:`HWND`, :c:type:`WPARAM`, or :c:type:`DWORD`. Some From webhook-mailer at python.org Wed Oct 5 11:18:33 2022 From: webhook-mailer at python.org (ambv) Date: Wed, 05 Oct 2022 15:18:33 -0000 Subject: [Python-checkins] [3.11] gh-93738: Documentation C syntax (:c:type:`PyObject` -> :c:expr:`PyObject`) (GH-97776) (#97889) Message-ID: https://github.com/python/cpython/commit/0a2008037f1a6e83372c6cebf5c5c02f94e280b0 commit: 0a2008037f1a6e83372c6cebf5c5c02f94e280b0 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-05T08:18:27-07:00 summary: [3.11] gh-93738: Documentation C syntax (:c:type:`PyObject` -> :c:expr:`PyObject`) (GH-97776) (#97889) :c:type:`PyObject` -> :c:expr:`PyObject` (cherry picked from commit 0bf6a617ed1832bc4803e532c8d6b3427cf48b13) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> files: M Doc/c-api/arg.rst M Doc/c-api/call.rst M Doc/c-api/dict.rst M Doc/c-api/exceptions.rst M Doc/c-api/init.rst M Doc/c-api/intro.rst M Doc/c-api/structures.rst M Doc/c-api/tuple.rst M Doc/c-api/typeobj.rst M Doc/library/ctypes.rst diff --git a/Doc/c-api/arg.rst b/Doc/c-api/arg.rst index 926e5249347f..fb921a4af6f3 100644 --- a/Doc/c-api/arg.rst +++ b/Doc/c-api/arg.rst @@ -129,12 +129,12 @@ which disallows mutable objects such as :class:`bytearray`. ``S`` (:class:`bytes`) [PyBytesObject \*] Requires that the Python object is a :class:`bytes` object, without attempting any conversion. Raises :exc:`TypeError` if the object is not - a bytes object. The C variable may also be declared as :c:type:`PyObject*`. + a bytes object. The C variable may also be declared as :c:expr:`PyObject*`. ``Y`` (:class:`bytearray`) [PyByteArrayObject \*] Requires that the Python object is a :class:`bytearray` object, without attempting any conversion. Raises :exc:`TypeError` if the object is not - a :class:`bytearray` object. The C variable may also be declared as :c:type:`PyObject*`. + a :class:`bytearray` object. The C variable may also be declared as :c:expr:`PyObject*`. ``u`` (:class:`str`) [const Py_UNICODE \*] Convert a Python Unicode object to a C pointer to a NUL-terminated buffer of @@ -181,7 +181,7 @@ which disallows mutable objects such as :class:`bytearray`. ``U`` (:class:`str`) [PyObject \*] Requires that the Python object is a Unicode object, without attempting any conversion. Raises :exc:`TypeError` if the object is not a Unicode - object. The C variable may also be declared as :c:type:`PyObject*`. + object. The C variable may also be declared as :c:expr:`PyObject*`. ``w*`` (read-write :term:`bytes-like object`) [Py_buffer] This format accepts any object which implements the read-write buffer @@ -320,7 +320,7 @@ Other objects ``O!`` (object) [*typeobject*, PyObject \*] Store a Python object in a C object pointer. This is similar to ``O``, but takes two C arguments: the first is the address of a Python type object, the - second is the address of the C variable (of type :c:type:`PyObject*`) into which + second is the address of the C variable (of type :c:expr:`PyObject*`) into which the object pointer is stored. If the Python object does not have the required type, :exc:`TypeError` is raised. @@ -481,7 +481,7 @@ API Functions *args*; it must actually be a tuple. The length of the tuple must be at least *min* and no more than *max*; *min* and *max* may be equal. Additional arguments must be passed to the function, each of which should be a pointer to a - :c:type:`PyObject*` variable; these will be filled in with the values from + :c:expr:`PyObject*` variable; these will be filled in with the values from *args*; they will contain :term:`borrowed references `. The variables which correspond to optional parameters not given by *args* will not be filled in; these should diff --git a/Doc/c-api/call.rst b/Doc/c-api/call.rst index 13ef8b217a16..36149f156c67 100644 --- a/Doc/c-api/call.rst +++ b/Doc/c-api/call.rst @@ -275,7 +275,7 @@ please see individual documentation for details. This is the equivalent of the Python expression: ``callable(*args)``. - Note that if you only pass :c:type:`PyObject *` args, + Note that if you only pass :c:expr:`PyObject *` args, :c:func:`PyObject_CallFunctionObjArgs` is a faster alternative. .. versionchanged:: 3.4 @@ -296,7 +296,7 @@ please see individual documentation for details. This is the equivalent of the Python expression: ``obj.name(arg1, arg2, ...)``. - Note that if you only pass :c:type:`PyObject *` args, + Note that if you only pass :c:expr:`PyObject *` args, :c:func:`PyObject_CallMethodObjArgs` is a faster alternative. .. versionchanged:: 3.4 @@ -306,7 +306,7 @@ please see individual documentation for details. .. c:function:: PyObject* PyObject_CallFunctionObjArgs(PyObject *callable, ...) Call a callable Python object *callable*, with a variable number of - :c:type:`PyObject *` arguments. The arguments are provided as a variable number + :c:expr:`PyObject *` arguments. The arguments are provided as a variable number of parameters followed by *NULL*. Return the result of the call on success, or raise an exception and return @@ -320,7 +320,7 @@ please see individual documentation for details. Call a method of the Python object *obj*, where the name of the method is given as a Python string object in *name*. It is called with a variable number of - :c:type:`PyObject *` arguments. The arguments are provided as a variable number + :c:expr:`PyObject *` arguments. The arguments are provided as a variable number of parameters followed by *NULL*. Return the result of the call on success, or raise an exception and return diff --git a/Doc/c-api/dict.rst b/Doc/c-api/dict.rst index d257c9b5f763..67c2026baa14 100644 --- a/Doc/c-api/dict.rst +++ b/Doc/c-api/dict.rst @@ -118,7 +118,7 @@ Dictionary Objects .. c:function:: PyObject* PyDict_GetItemString(PyObject *p, const char *key) This is the same as :c:func:`PyDict_GetItem`, but *key* is specified as a - :c:type:`const char*`, rather than a :c:type:`PyObject*`. + :c:type:`const char*`, rather than a :c:expr:`PyObject*`. Note that exceptions which occur while calling :meth:`__hash__` and :meth:`__eq__` methods and creating a temporary string object @@ -167,7 +167,7 @@ Dictionary Objects prior to the first call to this function to start the iteration; the function returns true for each pair in the dictionary, and false once all pairs have been reported. The parameters *pkey* and *pvalue* should either - point to :c:type:`PyObject*` variables that will be filled in with each key + point to :c:expr:`PyObject*` variables that will be filled in with each key and value, respectively, or may be ``NULL``. Any references returned through them are borrowed. *ppos* should not be altered during iteration. Its value represents offsets within the internal dictionary structure, and diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index df73f23d2de2..7221957fe1db 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -848,7 +848,7 @@ Standard Exceptions All standard Python exceptions are available as global variables whose names are ``PyExc_`` followed by the Python exception name. These have the type -:c:type:`PyObject*`; they are all class objects. For completeness, here are all +:c:expr:`PyObject*`; they are all class objects. For completeness, here are all the variables: .. index:: @@ -1068,7 +1068,7 @@ Standard Warning Categories All standard Python warning categories are available as global variables whose names are ``PyExc_`` followed by the Python exception name. These have the type -:c:type:`PyObject*`; they are all class objects. For completeness, here are all +:c:expr:`PyObject*`; they are all class objects. For completeness, here are all the variables: .. index:: diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index d573ef131280..60c4154da489 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -1742,7 +1742,7 @@ you need to include :file:`pythread.h` to use thread-local storage. .. note:: None of these API functions handle memory management on behalf of the :c:type:`void*` values. You need to allocate and deallocate them yourself. - If the :c:type:`void*` values happen to be :c:type:`PyObject*`, these + If the :c:type:`void*` values happen to be :c:expr:`PyObject*`, these functions don't do refcount operations on them either. .. _thread-specific-storage-api: diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst index d9fcd0de1fec..4b91a4b74aaa 100644 --- a/Doc/c-api/intro.rst +++ b/Doc/c-api/intro.rst @@ -264,13 +264,13 @@ Objects, Types and Reference Counts .. index:: object: type Most Python/C API functions have one or more arguments as well as a return value -of type :c:type:`PyObject*`. This type is a pointer to an opaque data type +of type :c:expr:`PyObject*`. This type is a pointer to an opaque data type representing an arbitrary Python object. Since all Python object types are treated the same way by the Python language in most situations (e.g., assignments, scope rules, and argument passing), it is only fitting that they should be represented by a single C type. Almost all Python objects live on the heap: you never declare an automatic or static variable of type -:c:type:`PyObject`, only pointer variables of type :c:type:`PyObject*` can be +:c:type:`PyObject`, only pointer variables of type :c:expr:`PyObject*` can be declared. The sole exception are the type objects; since these must never be deallocated, they are typically static :c:type:`PyTypeObject` objects. diff --git a/Doc/c-api/structures.rst b/Doc/c-api/structures.rst index 86d4536f8d28..f5585bc33a06 100644 --- a/Doc/c-api/structures.rst +++ b/Doc/c-api/structures.rst @@ -27,7 +27,7 @@ the definition of all other Python objects. object. In a normal "release" build, it contains only the object's reference count and a pointer to the corresponding type object. Nothing is actually declared to be a :c:type:`PyObject`, but every pointer - to a Python object can be cast to a :c:type:`PyObject*`. Access to the + to a Python object can be cast to a :c:expr:`PyObject*`. Access to the members must be done by using the macros :c:macro:`Py_REFCNT` and :c:macro:`Py_TYPE`. @@ -184,7 +184,7 @@ Implementing functions and methods .. c:type:: PyCFunction Type of the functions used to implement most Python callables in C. - Functions of this type take two :c:type:`PyObject*` parameters and return + Functions of this type take two :c:expr:`PyObject*` parameters and return one such value. If the return value is ``NULL``, an exception shall have been set. If not ``NULL``, the return value is interpreted as the return value of the function as exposed in Python. The function must return a new @@ -263,10 +263,10 @@ Implementing functions and methods +------------------+---------------+-------------------------------+ The :attr:`ml_meth` is a C function pointer. The functions may be of different -types, but they always return :c:type:`PyObject*`. If the function is not of +types, but they always return :c:expr:`PyObject*`. If the function is not of the :c:type:`PyCFunction`, the compiler will require a cast in the method table. Even though :c:type:`PyCFunction` defines the first parameter as -:c:type:`PyObject*`, it is common that the method implementation uses the +:c:expr:`PyObject*`, it is common that the method implementation uses the specific C type of the *self* object. The :attr:`ml_flags` field is a bitfield which can include the following flags. @@ -278,7 +278,7 @@ There are these calling conventions: .. data:: METH_VARARGS This is the typical calling convention, where the methods have the type - :c:type:`PyCFunction`. The function expects two :c:type:`PyObject*` values. + :c:type:`PyCFunction`. The function expects two :c:expr:`PyObject*` values. The first one is the *self* object for methods; for module functions, it is the module object. The second parameter (often called *args*) is a tuple object representing all arguments. This parameter is typically processed @@ -299,7 +299,7 @@ There are these calling conventions: Fast calling convention supporting only positional arguments. The methods have the type :c:type:`_PyCFunctionFast`. The first parameter is *self*, the second parameter is a C array - of :c:type:`PyObject*` values indicating the arguments and the third + of :c:expr:`PyObject*` values indicating the arguments and the third parameter is the number of arguments (the length of the array). .. versionadded:: 3.7 @@ -315,7 +315,7 @@ There are these calling conventions: with methods of type :c:type:`_PyCFunctionFastWithKeywords`. Keyword arguments are passed the same way as in the :ref:`vectorcall protocol `: - there is an additional fourth :c:type:`PyObject*` parameter + there is an additional fourth :c:expr:`PyObject*` parameter which is a tuple representing the names of the keyword arguments (which are guaranteed to be strings) or possibly ``NULL`` if there are no keywords. The values of the keyword @@ -354,7 +354,7 @@ There are these calling conventions: Methods with a single object argument can be listed with the :const:`METH_O` flag, instead of invoking :c:func:`PyArg_ParseTuple` with a ``"O"`` argument. They have the type :c:type:`PyCFunction`, with the *self* parameter, and a - :c:type:`PyObject*` parameter representing the single argument. + :c:expr:`PyObject*` parameter representing the single argument. These two constants are not used to indicate the calling convention but the @@ -520,7 +520,7 @@ Accessing attributes of extension types | | | getter and setter | +-------------+------------------+-----------------------------------+ - The ``get`` function takes one :c:type:`PyObject*` parameter (the + The ``get`` function takes one :c:expr:`PyObject*` parameter (the instance) and a function pointer (the associated ``closure``):: typedef PyObject *(*getter)(PyObject *, void *); @@ -528,7 +528,7 @@ Accessing attributes of extension types It should return a new reference on success or ``NULL`` with a set exception on failure. - ``set`` functions take two :c:type:`PyObject*` parameters (the instance and + ``set`` functions take two :c:expr:`PyObject*` parameters (the instance and the value to be set) and a function pointer (the associated ``closure``):: typedef int (*setter)(PyObject *, PyObject *, void *); diff --git a/Doc/c-api/tuple.rst b/Doc/c-api/tuple.rst index 9b85522600d4..0bfd4b308d93 100644 --- a/Doc/c-api/tuple.rst +++ b/Doc/c-api/tuple.rst @@ -161,7 +161,7 @@ type. .. c:type:: PyStructSequence_Field Describes a field of a struct sequence. As a struct sequence is modeled as a - tuple, all fields are typed as :c:type:`PyObject*`. The index in the + tuple, all fields are typed as :c:expr:`PyObject*`. The index in the :attr:`fields` array of the :c:type:`PyStructSequence_Desc` determines which field of the struct sequence is described. diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index 7fa8fcecb68f..6acd69cf56fe 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -1485,7 +1485,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) than zero and contains the offset in the instance structure of the weak reference list head (ignoring the GC header, if present); this offset is used by :c:func:`PyObject_ClearWeakRefs` and the :c:func:`PyWeakref_\*` functions. The - instance structure needs to include a field of type :c:type:`PyObject*` which is + instance structure needs to include a field of type :c:expr:`PyObject*` which is initialized to ``NULL``. Do not confuse this field with :c:member:`~PyTypeObject.tp_weaklist`; that is the list head for diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index 52950b551b75..7760fc2812c0 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -2366,8 +2366,8 @@ These are the fundamental ctypes data types: .. class:: py_object - Represents the C :c:type:`PyObject *` datatype. Calling this without an - argument creates a ``NULL`` :c:type:`PyObject *` pointer. + Represents the C :c:expr:`PyObject *` datatype. Calling this without an + argument creates a ``NULL`` :c:expr:`PyObject *` pointer. The :mod:`ctypes.wintypes` module provides quite some other Windows specific data types, for example :c:type:`HWND`, :c:type:`WPARAM`, or :c:type:`DWORD`. Some From webhook-mailer at python.org Wed Oct 5 11:19:00 2022 From: webhook-mailer at python.org (ambv) Date: Wed, 05 Oct 2022 15:19:00 -0000 Subject: [Python-checkins] [3.11] gh-93738: Documentation C syntax (:c:type: to :c:expr:, misc. cases) (GH-97775) (#97873) Message-ID: https://github.com/python/cpython/commit/ffafd31975a3322dd47aa8583e99e7c654785657 commit: ffafd31975a3322dd47aa8583e99e7c654785657 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-05T08:18:55-07:00 summary: [3.11] gh-93738: Documentation C syntax (:c:type: to :c:expr:, misc. cases) (GH-97775) (#97873) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> files: M Doc/c-api/file.rst M Doc/c-api/structures.rst M Doc/whatsnew/2.4.rst M Misc/NEWS.d/3.8.0a4.rst diff --git a/Doc/c-api/file.rst b/Doc/c-api/file.rst index 145dfe4962ac..745d892be7ea 100644 --- a/Doc/c-api/file.rst +++ b/Doc/c-api/file.rst @@ -65,7 +65,7 @@ the :mod:`io` APIs instead. Overrides the normal behavior of :func:`io.open_code` to pass its parameter through the provided handler. - The handler is a function of type :c:type:`PyObject *(\*)(PyObject *path, + The handler is a function of type :c:expr:`PyObject *(\*)(PyObject *path, void *userData)`, where *path* is guaranteed to be :c:type:`PyUnicodeObject`. The *userData* pointer is passed into the hook function. Since hook diff --git a/Doc/c-api/structures.rst b/Doc/c-api/structures.rst index f5585bc33a06..2b5d9a84822b 100644 --- a/Doc/c-api/structures.rst +++ b/Doc/c-api/structures.rst @@ -103,7 +103,7 @@ the definition of all other Python objects. .. versionchanged:: 3.11 :c:func:`Py_TYPE()` is changed to an inline static function. - The parameter type is no longer :c:type:`const PyObject*`. + The parameter type is no longer :c:expr:`const PyObject*`. .. c:function:: int Py_IS_TYPE(PyObject *o, PyTypeObject *type) @@ -128,7 +128,7 @@ the definition of all other Python objects. Use the :c:func:`Py_SET_REFCNT()` function to set an object reference count. .. versionchanged:: 3.11 - The parameter type is no longer :c:type:`const PyObject*`. + The parameter type is no longer :c:expr:`const PyObject*`. .. versionchanged:: 3.10 :c:func:`Py_REFCNT()` is changed to the inline static function. @@ -149,7 +149,7 @@ the definition of all other Python objects. .. versionchanged:: 3.11 :c:func:`Py_SIZE()` is changed to an inline static function. - The parameter type is no longer :c:type:`const PyVarObject*`. + The parameter type is no longer :c:expr:`const PyVarObject*`. .. c:function:: void Py_SET_SIZE(PyVarObject *o, Py_ssize_t size) diff --git a/Doc/whatsnew/2.4.rst b/Doc/whatsnew/2.4.rst index ddfac1a3f4e6..61f9eb43243c 100644 --- a/Doc/whatsnew/2.4.rst +++ b/Doc/whatsnew/2.4.rst @@ -1453,7 +1453,7 @@ Some of the changes to Python's build process and to the C API are: extension functions: :c:macro:`Py_RETURN_NONE`, :c:macro:`Py_RETURN_TRUE`, and :c:macro:`Py_RETURN_FALSE`. (Contributed by Brett Cannon.) -* Another new macro, :c:macro:`Py_CLEAR(obj)`, decreases the reference count of +* Another new macro, :c:macro:`Py_CLEAR`, decreases the reference count of *obj* and sets *obj* to the null pointer. (Contributed by Jim Fulton.) * A new function, ``PyTuple_Pack(N, obj1, obj2, ..., objN)``, constructs @@ -1464,7 +1464,7 @@ Some of the changes to Python's build process and to the C API are: lookups without masking exceptions raised during the look-up process. (Contributed by Raymond Hettinger.) -* The :c:macro:`Py_IS_NAN(X)` macro returns 1 if its float or double argument +* The :c:expr:`Py_IS_NAN(X)` macro returns 1 if its float or double argument *X* is a NaN. (Contributed by Tim Peters.) * C code can avoid unnecessary locking by using the new diff --git a/Misc/NEWS.d/3.8.0a4.rst b/Misc/NEWS.d/3.8.0a4.rst index fc952fa9dcc8..5250d82f65e7 100644 --- a/Misc/NEWS.d/3.8.0a4.rst +++ b/Misc/NEWS.d/3.8.0a4.rst @@ -1354,7 +1354,7 @@ the function is called twice. .. nonce: pz-DIR .. section: C API -:c:macro:`PyDoc_VAR(name)` and :c:macro:`PyDoc_STRVAR(name,str)` now create +:c:expr:`PyDoc_VAR(name)` and :c:expr:`PyDoc_STRVAR(name,str)` now create ``static const char name[]`` instead of ``static char name[]``. Patch by Inada Naoki. From webhook-mailer at python.org Wed Oct 5 11:19:43 2022 From: webhook-mailer at python.org (ambv) Date: Wed, 05 Oct 2022 15:19:43 -0000 Subject: [Python-checkins] [3.10] gh-93738: Documentation C syntax (:c:type: to :c:expr:, misc. cases) (GH-97775) (#97891) Message-ID: https://github.com/python/cpython/commit/d99ea4c7a2bf03bae567e567a14b5d130ce762f6 commit: d99ea4c7a2bf03bae567e567a14b5d130ce762f6 branch: 3.10 author: ?ukasz Langa committer: ambv date: 2022-10-05T08:19:38-07:00 summary: [3.10] gh-93738: Documentation C syntax (:c:type: to :c:expr:, misc. cases) (GH-97775) (#97891) (cherry picked from commit 6b3d4db02edc5883a7e7cbe088711edaef0d9853) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> files: M Doc/c-api/file.rst M Doc/c-api/structures.rst M Doc/whatsnew/2.4.rst M Misc/NEWS.d/3.8.0a4.rst diff --git a/Doc/c-api/file.rst b/Doc/c-api/file.rst index 145dfe4962ac..745d892be7ea 100644 --- a/Doc/c-api/file.rst +++ b/Doc/c-api/file.rst @@ -65,7 +65,7 @@ the :mod:`io` APIs instead. Overrides the normal behavior of :func:`io.open_code` to pass its parameter through the provided handler. - The handler is a function of type :c:type:`PyObject *(\*)(PyObject *path, + The handler is a function of type :c:expr:`PyObject *(\*)(PyObject *path, void *userData)`, where *path* is guaranteed to be :c:type:`PyUnicodeObject`. The *userData* pointer is passed into the hook function. Since hook diff --git a/Doc/c-api/structures.rst b/Doc/c-api/structures.rst index c1ff90fb8a64..069774745654 100644 --- a/Doc/c-api/structures.rst +++ b/Doc/c-api/structures.rst @@ -99,7 +99,7 @@ the definition of all other Python objects. Return a :term:`borrowed reference`. - The :c:func:`Py_SET_TYPE` function must be used to set an object type. + Use the :c:func:`Py_SET_TYPE` function to set an object type. .. c:function:: int Py_IS_TYPE(PyObject *o, PyTypeObject *type) @@ -137,7 +137,7 @@ the definition of all other Python objects. Get the size of the Python object *o*. - The :c:func:`Py_SET_SIZE` function must be used to set an object size. + Use the :c:func:`Py_SET_SIZE` function to set an object size. .. c:function:: void Py_SET_SIZE(PyVarObject *o, Py_ssize_t size) diff --git a/Doc/whatsnew/2.4.rst b/Doc/whatsnew/2.4.rst index ddfac1a3f4e6..61f9eb43243c 100644 --- a/Doc/whatsnew/2.4.rst +++ b/Doc/whatsnew/2.4.rst @@ -1453,7 +1453,7 @@ Some of the changes to Python's build process and to the C API are: extension functions: :c:macro:`Py_RETURN_NONE`, :c:macro:`Py_RETURN_TRUE`, and :c:macro:`Py_RETURN_FALSE`. (Contributed by Brett Cannon.) -* Another new macro, :c:macro:`Py_CLEAR(obj)`, decreases the reference count of +* Another new macro, :c:macro:`Py_CLEAR`, decreases the reference count of *obj* and sets *obj* to the null pointer. (Contributed by Jim Fulton.) * A new function, ``PyTuple_Pack(N, obj1, obj2, ..., objN)``, constructs @@ -1464,7 +1464,7 @@ Some of the changes to Python's build process and to the C API are: lookups without masking exceptions raised during the look-up process. (Contributed by Raymond Hettinger.) -* The :c:macro:`Py_IS_NAN(X)` macro returns 1 if its float or double argument +* The :c:expr:`Py_IS_NAN(X)` macro returns 1 if its float or double argument *X* is a NaN. (Contributed by Tim Peters.) * C code can avoid unnecessary locking by using the new diff --git a/Misc/NEWS.d/3.8.0a4.rst b/Misc/NEWS.d/3.8.0a4.rst index fc952fa9dcc8..5250d82f65e7 100644 --- a/Misc/NEWS.d/3.8.0a4.rst +++ b/Misc/NEWS.d/3.8.0a4.rst @@ -1354,7 +1354,7 @@ the function is called twice. .. nonce: pz-DIR .. section: C API -:c:macro:`PyDoc_VAR(name)` and :c:macro:`PyDoc_STRVAR(name,str)` now create +:c:expr:`PyDoc_VAR(name)` and :c:expr:`PyDoc_STRVAR(name,str)` now create ``static const char name[]`` instead of ``static char name[]``. Patch by Inada Naoki. From webhook-mailer at python.org Wed Oct 5 11:20:08 2022 From: webhook-mailer at python.org (ambv) Date: Wed, 05 Oct 2022 15:20:08 -0000 Subject: [Python-checkins] [3.11] gh-93738: Documentation C syntax (Use `c:struct`) (GH-97772) (#97869) Message-ID: https://github.com/python/cpython/commit/d5852a090fc5bfdc99e8d8f5e1e890cac8102d4e commit: d5852a090fc5bfdc99e8d8f5e1e890cac8102d4e branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-05T08:20:03-07:00 summary: [3.11] gh-93738: Documentation C syntax (Use `c:struct`) (GH-97772) (#97869) Use `c:struct` (cherry picked from commit a0f5599aac2037da715d09733e0a83a9cba7c37a) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> files: M Doc/c-api/import.rst M Doc/c-api/veryhigh.rst M Doc/library/ctypes.rst M Doc/library/socket.rst M Doc/whatsnew/3.11.rst M Doc/whatsnew/3.8.rst diff --git a/Doc/c-api/import.rst b/Doc/c-api/import.rst index 5e2333a74ce6..0922956c607b 100644 --- a/Doc/c-api/import.rst +++ b/Doc/c-api/import.rst @@ -243,7 +243,7 @@ Importing Modules UTF-8 encoded string instead of a Unicode object. -.. c:type:: struct _frozen +.. c:struct:: _frozen .. index:: single: freeze utility @@ -265,7 +265,7 @@ Importing Modules .. c:var:: const struct _frozen* PyImport_FrozenModules - This pointer is initialized to point to an array of :c:type:`struct _frozen` + This pointer is initialized to point to an array of :c:struct:`_frozen` records, terminated by one whose members are all ``NULL`` or zero. When a frozen module is imported, it is searched in this table. Third-party code could play tricks with this to provide a dynamically created collection of frozen modules. @@ -281,7 +281,7 @@ Importing Modules :c:func:`Py_Initialize`. -.. c:type:: struct _inittab +.. c:struct:: _inittab Structure describing a single entry in the list of built-in modules. Each of these structures gives the name and initialization function for a module built diff --git a/Doc/c-api/veryhigh.rst b/Doc/c-api/veryhigh.rst index d15adad3dfe6..bfb14ac912fc 100644 --- a/Doc/c-api/veryhigh.rst +++ b/Doc/c-api/veryhigh.rst @@ -82,7 +82,7 @@ the same library that the Python runtime is using. .. c:function:: int PyRun_SimpleString(const char *command) This is a simplified interface to :c:func:`PyRun_SimpleStringFlags` below, - leaving the :c:type:`PyCompilerFlags`\* argument set to ``NULL``. + leaving the :c:struct:`PyCompilerFlags`\* argument set to ``NULL``. .. c:function:: int PyRun_SimpleStringFlags(const char *command, PyCompilerFlags *flags) @@ -338,7 +338,7 @@ the same library that the Python runtime is using. interpreter loop. -.. c:type:: struct PyCompilerFlags +.. c:struct:: PyCompilerFlags This is the structure used to hold compiler flags. In cases where code is only being compiled, it is passed as ``int flags``, and in cases where code is being diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index 7760fc2812c0..0c341770a05b 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -1074,7 +1074,7 @@ An extended example which also demonstrates the use of pointers accesses the Quoting the docs for that value: - This pointer is initialized to point to an array of :c:type:`struct _frozen` + This pointer is initialized to point to an array of :c:struct:`_frozen` records, terminated by one whose members are all ``NULL`` or zero. When a frozen module is imported, it is searched in this table. Third-party code could play tricks with this to provide a dynamically created collection of frozen modules. @@ -1093,7 +1093,7 @@ size, we show only how this table can be read with :mod:`ctypes`:: ... >>> -We have defined the :c:type:`struct _frozen` data type, so we can get the pointer +We have defined the :c:struct:`_frozen` data type, so we can get the pointer to the table:: >>> FrozenTable = POINTER(struct_frozen) diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst index 9d1cfb510b0e..71d2c508c57f 100644 --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -1012,7 +1012,7 @@ The :mod:`socket` module also offers various network-related services: Convert an IPv4 address from dotted-quad string format (for example, '123.45.67.89') to 32-bit packed binary format, as a bytes object four characters in length. This is useful when conversing with a program that uses the standard C - library and needs objects of type :c:type:`struct in_addr`, which is the C type + library and needs objects of type :c:struct:`in_addr`, which is the C type for the 32-bit packed binary this function returns. :func:`inet_aton` also accepts strings with less than three dots; see the @@ -1031,7 +1031,7 @@ The :mod:`socket` module also offers various network-related services: Convert a 32-bit packed IPv4 address (a :term:`bytes-like object` four bytes in length) to its standard dotted-quad string representation (for example, '123.45.67.89'). This is useful when conversing with a program that uses the - standard C library and needs objects of type :c:type:`struct in_addr`, which + standard C library and needs objects of type :c:struct:`in_addr`, which is the C type for the 32-bit packed binary data this function takes as an argument. @@ -1048,8 +1048,8 @@ The :mod:`socket` module also offers various network-related services: Convert an IP address from its family-specific string format to a packed, binary format. :func:`inet_pton` is useful when a library or network protocol - calls for an object of type :c:type:`struct in_addr` (similar to - :func:`inet_aton`) or :c:type:`struct in6_addr`. + calls for an object of type :c:struct:`in_addr` (similar to + :func:`inet_aton`) or :c:struct:`in6_addr`. Supported values for *address_family* are currently :const:`AF_INET` and :const:`AF_INET6`. If the IP address string *ip_string* is invalid, @@ -1069,8 +1069,8 @@ The :mod:`socket` module also offers various network-related services: bytes) to its standard, family-specific string representation (for example, ``'7.10.0.5'`` or ``'5aef:2b::8'``). :func:`inet_ntop` is useful when a library or network protocol returns an - object of type :c:type:`struct in_addr` (similar to :func:`inet_ntoa`) or - :c:type:`struct in6_addr`. + object of type :c:struct:`in_addr` (similar to :func:`inet_ntoa`) or + :c:struct:`in6_addr`. Supported values for *address_family* are currently :const:`AF_INET` and :const:`AF_INET6`. If the bytes object *packed_ip* is not the correct diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 553261dbd4cc..1e8fb14b3cd4 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1906,7 +1906,7 @@ Porting to Python 3.11 fields of the result from the exception instance (the ``value`` field). (Contributed by Irit Katriel in :issue:`45711`.) -* :c:type:`_frozen` has a new ``is_package`` field to indicate whether +* :c:struct:`_frozen` has a new ``is_package`` field to indicate whether or not the frozen module is a package. Previously, a negative value in the ``size`` field was the indicator. Now only non-negative values be used for ``size``. diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst index e6febc36430f..7f85ff3ffa91 100644 --- a/Doc/whatsnew/3.8.rst +++ b/Doc/whatsnew/3.8.rst @@ -2012,7 +2012,7 @@ Changes in the Python API Changes in the C API -------------------- -* The :c:type:`PyCompilerFlags` structure got a new *cf_feature_version* +* The :c:struct:`PyCompilerFlags` structure got a new *cf_feature_version* field. It should be initialized to ``PY_MINOR_VERSION``. The field is ignored by default, and is used if and only if ``PyCF_ONLY_AST`` flag is set in *cf_flags*. From webhook-mailer at python.org Wed Oct 5 11:20:51 2022 From: webhook-mailer at python.org (ambv) Date: Wed, 05 Oct 2022 15:20:51 -0000 Subject: [Python-checkins] [3.10] gh-93738: Documentation C syntax (Use `c:struct`) (GH-97772) (#97893) Message-ID: https://github.com/python/cpython/commit/9aed6bdb2048ee12a3fc019dffc25d0d80237bbd commit: 9aed6bdb2048ee12a3fc019dffc25d0d80237bbd branch: 3.10 author: ?ukasz Langa committer: ambv date: 2022-10-05T08:20:46-07:00 summary: [3.10] gh-93738: Documentation C syntax (Use `c:struct`) (GH-97772) (#97893) Use `c:struct` (cherry picked from commit a0f5599aac2037da715d09733e0a83a9cba7c37a) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> files: M Doc/c-api/import.rst M Doc/c-api/veryhigh.rst M Doc/library/ctypes.rst M Doc/library/socket.rst M Doc/whatsnew/3.8.rst diff --git a/Doc/c-api/import.rst b/Doc/c-api/import.rst index d2ae6b6d4e47..46ba1f8bec03 100644 --- a/Doc/c-api/import.rst +++ b/Doc/c-api/import.rst @@ -243,7 +243,7 @@ Importing Modules UTF-8 encoded string instead of a Unicode object. -.. c:type:: struct _frozen +.. c:struct:: _frozen .. index:: single: freeze utility @@ -261,7 +261,7 @@ Importing Modules .. c:var:: const struct _frozen* PyImport_FrozenModules - This pointer is initialized to point to an array of :c:type:`struct _frozen` + This pointer is initialized to point to an array of :c:struct:`_frozen` records, terminated by one whose members are all ``NULL`` or zero. When a frozen module is imported, it is searched in this table. Third-party code could play tricks with this to provide a dynamically created collection of frozen modules. @@ -277,7 +277,7 @@ Importing Modules :c:func:`Py_Initialize`. -.. c:type:: struct _inittab +.. c:struct:: _inittab Structure describing a single entry in the list of built-in modules. Each of these structures gives the name and initialization function for a module built diff --git a/Doc/c-api/veryhigh.rst b/Doc/c-api/veryhigh.rst index 68d6604ace9e..628e628a4f35 100644 --- a/Doc/c-api/veryhigh.rst +++ b/Doc/c-api/veryhigh.rst @@ -82,7 +82,7 @@ the same library that the Python runtime is using. .. c:function:: int PyRun_SimpleString(const char *command) This is a simplified interface to :c:func:`PyRun_SimpleStringFlags` below, - leaving the :c:type:`PyCompilerFlags`\* argument set to ``NULL``. + leaving the :c:struct:`PyCompilerFlags`\* argument set to ``NULL``. .. c:function:: int PyRun_SimpleStringFlags(const char *command, PyCompilerFlags *flags) @@ -344,7 +344,7 @@ the same library that the Python runtime is using. interpreter loop. -.. c:type:: struct PyCompilerFlags +.. c:struct:: PyCompilerFlags This is the structure used to hold compiler flags. In cases where code is only being compiled, it is passed as ``int flags``, and in cases where code is being diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index 3a9f3a8588a5..877d1bad9ced 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -1075,7 +1075,7 @@ An extended example which also demonstrates the use of pointers accesses the Quoting the docs for that value: - This pointer is initialized to point to an array of :c:type:`struct _frozen` + This pointer is initialized to point to an array of :c:struct:`_frozen` records, terminated by one whose members are all ``NULL`` or zero. When a frozen module is imported, it is searched in this table. Third-party code could play tricks with this to provide a dynamically created collection of frozen modules. @@ -1092,7 +1092,7 @@ size, we show only how this table can be read with :mod:`ctypes`:: ... >>> -We have defined the :c:type:`struct _frozen` data type, so we can get the pointer +We have defined the :c:struct:`_frozen` data type, so we can get the pointer to the table:: >>> FrozenTable = POINTER(struct_frozen) diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst index 9c94b86991ca..6216e19751eb 100644 --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -948,7 +948,7 @@ The :mod:`socket` module also offers various network-related services: Convert an IPv4 address from dotted-quad string format (for example, '123.45.67.89') to 32-bit packed binary format, as a bytes object four characters in length. This is useful when conversing with a program that uses the standard C - library and needs objects of type :c:type:`struct in_addr`, which is the C type + library and needs objects of type :c:struct:`in_addr`, which is the C type for the 32-bit packed binary this function returns. :func:`inet_aton` also accepts strings with less than three dots; see the @@ -967,7 +967,7 @@ The :mod:`socket` module also offers various network-related services: Convert a 32-bit packed IPv4 address (a :term:`bytes-like object` four bytes in length) to its standard dotted-quad string representation (for example, '123.45.67.89'). This is useful when conversing with a program that uses the - standard C library and needs objects of type :c:type:`struct in_addr`, which + standard C library and needs objects of type :c:struct:`in_addr`, which is the C type for the 32-bit packed binary data this function takes as an argument. @@ -984,8 +984,8 @@ The :mod:`socket` module also offers various network-related services: Convert an IP address from its family-specific string format to a packed, binary format. :func:`inet_pton` is useful when a library or network protocol - calls for an object of type :c:type:`struct in_addr` (similar to - :func:`inet_aton`) or :c:type:`struct in6_addr`. + calls for an object of type :c:struct:`in_addr` (similar to + :func:`inet_aton`) or :c:struct:`in6_addr`. Supported values for *address_family* are currently :const:`AF_INET` and :const:`AF_INET6`. If the IP address string *ip_string* is invalid, @@ -1005,8 +1005,8 @@ The :mod:`socket` module also offers various network-related services: bytes) to its standard, family-specific string representation (for example, ``'7.10.0.5'`` or ``'5aef:2b::8'``). :func:`inet_ntop` is useful when a library or network protocol returns an - object of type :c:type:`struct in_addr` (similar to :func:`inet_ntoa`) or - :c:type:`struct in6_addr`. + object of type :c:struct:`in_addr` (similar to :func:`inet_ntoa`) or + :c:struct:`in6_addr`. Supported values for *address_family* are currently :const:`AF_INET` and :const:`AF_INET6`. If the bytes object *packed_ip* is not the correct diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst index e6febc36430f..7f85ff3ffa91 100644 --- a/Doc/whatsnew/3.8.rst +++ b/Doc/whatsnew/3.8.rst @@ -2012,7 +2012,7 @@ Changes in the Python API Changes in the C API -------------------- -* The :c:type:`PyCompilerFlags` structure got a new *cf_feature_version* +* The :c:struct:`PyCompilerFlags` structure got a new *cf_feature_version* field. It should be initialized to ``PY_MINOR_VERSION``. The field is ignored by default, and is used if and only if ``PyCF_ONLY_AST`` flag is set in *cf_flags*. From webhook-mailer at python.org Wed Oct 5 11:21:23 2022 From: webhook-mailer at python.org (ambv) Date: Wed, 05 Oct 2022 15:21:23 -0000 Subject: [Python-checkins] [3.10] gh-93738: Documentation C syntax (:c:type:`PyTypeObject*` -> :c:expr:`PyTypeObject*`) (GH-97778) (#97890) Message-ID: https://github.com/python/cpython/commit/de0a656d5b52c6ad54a04ec825380c4dc422e736 commit: de0a656d5b52c6ad54a04ec825380c4dc422e736 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-05T08:21:18-07:00 summary: [3.10] gh-93738: Documentation C syntax (:c:type:`PyTypeObject*` -> :c:expr:`PyTypeObject*`) (GH-97778) (#97890) Co-authored-by: Ezio Melotti (cherry picked from commit c70c8b69762f720377adaf22f2e5ec6496a7be53) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> files: M Doc/c-api/object.rst M Doc/c-api/typehints.rst diff --git a/Doc/c-api/object.rst b/Doc/c-api/object.rst index 07a625bac02f..eef42ca1326d 100644 --- a/Doc/c-api/object.rst +++ b/Doc/c-api/object.rst @@ -292,7 +292,7 @@ Object Protocol is equivalent to the Python expression ``type(o)``. This function increments the reference count of the return value. There's really no reason to use this function instead of the :c:func:`Py_TYPE()` function, which returns a - pointer of type :c:type:`PyTypeObject*`, except when the incremented reference + pointer of type :c:expr:`PyTypeObject*`, except when the incremented reference count is needed. diff --git a/Doc/c-api/typehints.rst b/Doc/c-api/typehints.rst index 79f29acc2e1e..360680005488 100644 --- a/Doc/c-api/typehints.rst +++ b/Doc/c-api/typehints.rst @@ -15,7 +15,7 @@ two types exist -- :ref:`GenericAlias ` and Equivalent to calling the Python class :class:`types.GenericAlias`. The *origin* and *args* arguments set the ``GenericAlias``\ 's ``__origin__`` and ``__args__`` attributes respectively. - *origin* should be a :c:type:`PyTypeObject*`, and *args* can be a + *origin* should be a :c:expr:`PyTypeObject*`, and *args* can be a :c:expr:`PyTupleObject*` or any ``PyObject*``. If *args* passed is not a tuple, a 1-tuple is automatically constructed and ``__args__`` is set to ``(args,)``. From webhook-mailer at python.org Wed Oct 5 11:21:37 2022 From: webhook-mailer at python.org (ambv) Date: Wed, 05 Oct 2022 15:21:37 -0000 Subject: [Python-checkins] [3.11] gh-93738: Documentation C syntax (:c:type:`PyTypeObject*` -> :c:expr:`PyTypeObject*`) (GH-97778) (#97892) Message-ID: https://github.com/python/cpython/commit/5c8aa2e0f224179e5ee3086b295a735610e9e5c7 commit: 5c8aa2e0f224179e5ee3086b295a735610e9e5c7 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-05T08:21:32-07:00 summary: [3.11] gh-93738: Documentation C syntax (:c:type:`PyTypeObject*` -> :c:expr:`PyTypeObject*`) (GH-97778) (#97892) Co-authored-by: Ezio Melotti (cherry picked from commit c70c8b69762f720377adaf22f2e5ec6496a7be53) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> files: M Doc/c-api/object.rst M Doc/c-api/typehints.rst diff --git a/Doc/c-api/object.rst b/Doc/c-api/object.rst index fb03366056b0..5a25a2b6c9d3 100644 --- a/Doc/c-api/object.rst +++ b/Doc/c-api/object.rst @@ -310,7 +310,7 @@ Object Protocol is equivalent to the Python expression ``type(o)``. This function increments the reference count of the return value. There's really no reason to use this function instead of the :c:func:`Py_TYPE()` function, which returns a - pointer of type :c:type:`PyTypeObject*`, except when the incremented reference + pointer of type :c:expr:`PyTypeObject*`, except when the incremented reference count is needed. diff --git a/Doc/c-api/typehints.rst b/Doc/c-api/typehints.rst index 88554a346c0d..4c1957a2a1db 100644 --- a/Doc/c-api/typehints.rst +++ b/Doc/c-api/typehints.rst @@ -15,7 +15,7 @@ two types exist -- :ref:`GenericAlias ` and Equivalent to calling the Python class :class:`types.GenericAlias`. The *origin* and *args* arguments set the ``GenericAlias``\ 's ``__origin__`` and ``__args__`` attributes respectively. - *origin* should be a :c:type:`PyTypeObject*`, and *args* can be a + *origin* should be a :c:expr:`PyTypeObject*`, and *args* can be a :c:expr:`PyTupleObject*` or any ``PyObject*``. If *args* passed is not a tuple, a 1-tuple is automatically constructed and ``__args__`` is set to ``(args,)``. From webhook-mailer at python.org Wed Oct 5 11:22:37 2022 From: webhook-mailer at python.org (ambv) Date: Wed, 05 Oct 2022 15:22:37 -0000 Subject: [Python-checkins] gh-93738: Documentation C syntax (Function glob patterns -> literal markup) (#97774) Message-ID: https://github.com/python/cpython/commit/0e72606dd4cf3023a4f8c2fe3c58082592b253f7 commit: 0e72606dd4cf3023a4f8c2fe3c58082592b253f7 branch: main author: Adam Turner <9087854+AA-Turner at users.noreply.github.com> committer: ambv date: 2022-10-05T08:22:28-07:00 summary: gh-93738: Documentation C syntax (Function glob patterns -> literal markup) (#97774) files: M Doc/c-api/arg.rst M Doc/c-api/exceptions.rst M Doc/c-api/init.rst M Doc/c-api/module.rst M Doc/c-api/typeobj.rst M Doc/extending/extending.rst M Doc/whatsnew/2.5.rst diff --git a/Doc/c-api/arg.rst b/Doc/c-api/arg.rst index c9dcf746ef2f..702c0869116a 100644 --- a/Doc/c-api/arg.rst +++ b/Doc/c-api/arg.rst @@ -298,7 +298,7 @@ Other objects status = converter(object, address); where *object* is the Python object to be converted and *address* is the - :c:type:`void*` argument that was passed to the :c:func:`PyArg_Parse\*` function. + :c:type:`void*` argument that was passed to the ``PyArg_Parse*`` function. The returned *status* should be ``1`` for a successful conversion and ``0`` if the conversion has failed. When the conversion fails, the *converter* function should raise an exception and leave the content of *address* unmodified. @@ -372,9 +372,9 @@ what is specified for the corresponding format unit in that case. For the conversion to succeed, the *arg* object must match the format and the format must be exhausted. On success, the -:c:func:`PyArg_Parse\*` functions return true, otherwise they return +``PyArg_Parse*`` functions return true, otherwise they return false and raise an appropriate exception. When the -:c:func:`PyArg_Parse\*` functions fail due to conversion failure in one +``PyArg_Parse*`` functions fail due to conversion failure in one of the format units, the variables at the addresses corresponding to that and the following format units are left untouched. @@ -481,7 +481,7 @@ Building values .. c:function:: PyObject* Py_BuildValue(const char *format, ...) Create a new value based on a format string similar to those accepted by the - :c:func:`PyArg_Parse\*` family of functions and a sequence of values. Returns + ``PyArg_Parse*`` family of functions and a sequence of values. Returns the value or ``NULL`` in the case of an error; an exception will be raised if ``NULL`` is returned. diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index 7221957fe1db..087e0a61d12d 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -14,7 +14,7 @@ there is a global indicator (per thread) of the last error that occurred. Most C API functions don't clear this on success, but will set it to indicate the cause of the error on failure. Most C API functions also return an error indicator, usually ``NULL`` if they are supposed to return a pointer, or ``-1`` -if they return an integer (exception: the :c:func:`PyArg_\*` functions +if they return an integer (exception: the ``PyArg_*`` functions return ``1`` for success and ``0`` for failure). Concretely, the error indicator consists of three object pointers: the @@ -370,7 +370,7 @@ Querying the error indicator .. c:function:: PyObject* PyErr_Occurred() Test whether the error indicator is set. If set, return the exception *type* - (the first argument to the last call to one of the :c:func:`PyErr_Set\*` + (the first argument to the last call to one of the ``PyErr_Set*`` functions or to :c:func:`PyErr_Restore`). If not set, return ``NULL``. You do not own a reference to the return value, so you do not need to :c:func:`Py_DECREF` it. diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index cb3bfedc97e8..efa58381d270 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -956,11 +956,11 @@ from a C thread is:: /* Release the thread. No Python API allowed beyond this point. */ PyGILState_Release(gstate); -Note that the :c:func:`PyGILState_\*` functions assume there is only one global +Note that the ``PyGILState_*`` functions assume there is only one global interpreter (created automatically by :c:func:`Py_Initialize`). Python supports the creation of additional interpreters (using :c:func:`Py_NewInterpreter`), but mixing multiple interpreters and the -:c:func:`PyGILState_\*` API is unsupported. +``PyGILState_*`` API is unsupported. .. _fork-and-threads: @@ -1587,7 +1587,7 @@ operations executed by such objects may affect the wrong (sub-)interpreter's dictionary of loaded modules. It is equally important to avoid sharing objects from which the above are reachable. -Also note that combining this functionality with :c:func:`PyGILState_\*` APIs +Also note that combining this functionality with ``PyGILState_*`` APIs is delicate, because these APIs assume a bijection between Python thread states and OS-level threads, an assumption broken by the presence of sub-interpreters. It is highly recommended that you don't switch sub-interpreters between a pair diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst index 94c8d9f98171..e2ba157b32c7 100644 --- a/Doc/c-api/module.rst +++ b/Doc/c-api/module.rst @@ -64,8 +64,8 @@ Module Objects If *module* is not a module object (or a subtype of a module object), :exc:`SystemError` is raised and ``NULL`` is returned. - It is recommended extensions use other :c:func:`PyModule_\*` and - :c:func:`PyObject_\*` functions rather than directly manipulate a module's + It is recommended extensions use other ``PyModule_*`` and + ``PyObject_*`` functions rather than directly manipulate a module's :attr:`~object.__dict__`. diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index 86c0830e7a9c..8ccdece3efc5 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -7,8 +7,8 @@ Type Objects Perhaps one of the most important structures of the Python object system is the structure that defines a new type: the :c:type:`PyTypeObject` structure. Type -objects can be handled using any of the :c:func:`PyObject_\*` or -:c:func:`PyType_\*` functions, but do not offer much that's interesting to most +objects can be handled using any of the ``PyObject_*`` or +``PyType_*`` functions, but do not offer much that's interesting to most Python applications. These objects are fundamental to how objects behave, so they are very important to the interpreter itself and to any extension module that implements new types. @@ -1519,7 +1519,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) If the instances of this type are weakly referenceable, this field is greater than zero and contains the offset in the instance structure of the weak reference list head (ignoring the GC header, if present); this offset is used by - :c:func:`PyObject_ClearWeakRefs` and the :c:func:`PyWeakref_\*` functions. The + :c:func:`PyObject_ClearWeakRefs` and the ``PyWeakref_*`` functions. The instance structure needs to include a field of type :c:expr:`PyObject*` which is initialized to ``NULL``. diff --git a/Doc/extending/extending.rst b/Doc/extending/extending.rst index 2e3362b834e6..0ef899f4c997 100644 --- a/Doc/extending/extending.rst +++ b/Doc/extending/extending.rst @@ -157,16 +157,16 @@ since you should be able to tell from the return value. When a function *f* that calls another function *g* detects that the latter fails, *f* should itself return an error value (usually ``NULL`` or ``-1``). It -should *not* call one of the :c:func:`PyErr_\*` functions --- one has already +should *not* call one of the ``PyErr_*`` functions --- one has already been called by *g*. *f*'s caller is then supposed to also return an error -indication to *its* caller, again *without* calling :c:func:`PyErr_\*`, and so on +indication to *its* caller, again *without* calling ``PyErr_*``, and so on --- the most detailed cause of the error was already reported by the function that first detected it. Once the error reaches the Python interpreter's main loop, this aborts the currently executing Python code and tries to find an exception handler specified by the Python programmer. (There are situations where a module can actually give a more detailed error -message by calling another :c:func:`PyErr_\*` function, and in such cases it is +message by calling another ``PyErr_*`` function, and in such cases it is fine to do so. As a general rule, however, this is not necessary, and can cause information about the cause of the error to be lost: most operations can fail for a variety of reasons.) diff --git a/Doc/whatsnew/2.5.rst b/Doc/whatsnew/2.5.rst index 6c216826fee0..dfa8f7e93f81 100644 --- a/Doc/whatsnew/2.5.rst +++ b/Doc/whatsnew/2.5.rst @@ -2270,9 +2270,9 @@ code: earlier section :ref:`pep-353` for a discussion of this change. * C API: The obmalloc changes mean that you must be careful to not mix usage - of the :c:func:`PyMem_\*` and :c:func:`PyObject_\*` families of functions. Memory - allocated with one family's :c:func:`\*_Malloc` must be freed with the - corresponding family's :c:func:`\*_Free` function. + of the ``PyMem_*`` and ``PyObject_*`` families of functions. Memory + allocated with one family's ``*_Malloc`` must be freed with the + corresponding family's ``*_Free`` function. .. ====================================================================== From webhook-mailer at python.org Wed Oct 5 13:15:41 2022 From: webhook-mailer at python.org (gvanrossum) Date: Wed, 05 Oct 2022 17:15:41 -0000 Subject: [Python-checkins] gh-88050: Fix asyncio subprocess to kill process cleanly when process is blocked (#32073) Message-ID: https://github.com/python/cpython/commit/7015e1379791cbf19908cd1a7c668a5d6e7165d5 commit: 7015e1379791cbf19908cd1a7c668a5d6e7165d5 branch: main author: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> committer: gvanrossum date: 2022-10-05T10:15:31-07:00 summary: gh-88050: Fix asyncio subprocess to kill process cleanly when process is blocked (#32073) files: A Misc/NEWS.d/next/Library/2022-07-08-08-39-35.gh-issue-88050.0aOC_m.rst M Lib/asyncio/base_subprocess.py M Lib/test/test_asyncio/test_subprocess.py diff --git a/Lib/asyncio/base_subprocess.py b/Lib/asyncio/base_subprocess.py index 14d505192288..c2ca4a2792f6 100644 --- a/Lib/asyncio/base_subprocess.py +++ b/Lib/asyncio/base_subprocess.py @@ -215,14 +215,10 @@ def _process_exited(self, returncode): # object. On Python 3.6, it is required to avoid a ResourceWarning. self._proc.returncode = returncode self._call(self._protocol.process_exited) + for p in self._pipes.values(): + p.pipe.close() self._try_finish() - # wake up futures waiting for wait() - for waiter in self._exit_waiters: - if not waiter.cancelled(): - waiter.set_result(returncode) - self._exit_waiters = None - async def _wait(self): """Wait until the process exit and return the process return code. @@ -247,6 +243,11 @@ def _call_connection_lost(self, exc): try: self._protocol.connection_lost(exc) finally: + # wake up futures waiting for wait() + for waiter in self._exit_waiters: + if not waiter.cancelled(): + waiter.set_result(self._returncode) + self._exit_waiters = None self._loop = None self._proc = None self._protocol = None diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py index 961c463f8dc1..9bc60b9dc2ae 100644 --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -1,4 +1,5 @@ import os +import shutil import signal import sys import unittest @@ -182,6 +183,30 @@ def test_kill(self): else: self.assertEqual(-signal.SIGKILL, returncode) + def test_kill_issue43884(self): + blocking_shell_command = f'{sys.executable} -c "import time; time.sleep(100000000)"' + creationflags = 0 + if sys.platform == 'win32': + from subprocess import CREATE_NEW_PROCESS_GROUP + # On windows create a new process group so that killing process + # kills the process and all its children. + creationflags = CREATE_NEW_PROCESS_GROUP + proc = self.loop.run_until_complete( + asyncio.create_subprocess_shell(blocking_shell_command, stdout=asyncio.subprocess.PIPE, + creationflags=creationflags) + ) + self.loop.run_until_complete(asyncio.sleep(1)) + if sys.platform == 'win32': + proc.send_signal(signal.CTRL_BREAK_EVENT) + # On windows it is an alias of terminate which sets the return code + proc.kill() + returncode = self.loop.run_until_complete(proc.wait()) + if sys.platform == 'win32': + self.assertIsInstance(returncode, int) + # expect 1 but sometimes get 0 + else: + self.assertEqual(-signal.SIGKILL, returncode) + def test_terminate(self): args = PROGRAM_BLOCKED proc = self.loop.run_until_complete( diff --git a/Misc/NEWS.d/next/Library/2022-07-08-08-39-35.gh-issue-88050.0aOC_m.rst b/Misc/NEWS.d/next/Library/2022-07-08-08-39-35.gh-issue-88050.0aOC_m.rst new file mode 100644 index 000000000000..43c0765d940d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-07-08-08-39-35.gh-issue-88050.0aOC_m.rst @@ -0,0 +1 @@ +Fix :mod:`asyncio` subprocess transport to kill process cleanly when process is blocked and avoid ``RuntimeError`` when loop is closed. Patch by Kumar Aditya. From webhook-mailer at python.org Wed Oct 5 13:48:58 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 05 Oct 2022 17:48:58 -0000 Subject: [Python-checkins] gh-88050: Fix asyncio subprocess to kill process cleanly when process is blocked (GH-32073) Message-ID: https://github.com/python/cpython/commit/aec133347e9307591d53ad825c0ed82a500e094d commit: aec133347e9307591d53ad825c0ed82a500e094d branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-05T10:48:48-07:00 summary: gh-88050: Fix asyncio subprocess to kill process cleanly when process is blocked (GH-32073) (cherry picked from commit 7015e1379791cbf19908cd1a7c668a5d6e7165d5) Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> files: A Misc/NEWS.d/next/Library/2022-07-08-08-39-35.gh-issue-88050.0aOC_m.rst M Lib/asyncio/base_subprocess.py M Lib/test/test_asyncio/test_subprocess.py diff --git a/Lib/asyncio/base_subprocess.py b/Lib/asyncio/base_subprocess.py index 14d505192288..c2ca4a2792f6 100644 --- a/Lib/asyncio/base_subprocess.py +++ b/Lib/asyncio/base_subprocess.py @@ -215,14 +215,10 @@ def _process_exited(self, returncode): # object. On Python 3.6, it is required to avoid a ResourceWarning. self._proc.returncode = returncode self._call(self._protocol.process_exited) + for p in self._pipes.values(): + p.pipe.close() self._try_finish() - # wake up futures waiting for wait() - for waiter in self._exit_waiters: - if not waiter.cancelled(): - waiter.set_result(returncode) - self._exit_waiters = None - async def _wait(self): """Wait until the process exit and return the process return code. @@ -247,6 +243,11 @@ def _call_connection_lost(self, exc): try: self._protocol.connection_lost(exc) finally: + # wake up futures waiting for wait() + for waiter in self._exit_waiters: + if not waiter.cancelled(): + waiter.set_result(self._returncode) + self._exit_waiters = None self._loop = None self._proc = None self._protocol = None diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py index 961c463f8dc1..9bc60b9dc2ae 100644 --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -1,4 +1,5 @@ import os +import shutil import signal import sys import unittest @@ -182,6 +183,30 @@ def test_kill(self): else: self.assertEqual(-signal.SIGKILL, returncode) + def test_kill_issue43884(self): + blocking_shell_command = f'{sys.executable} -c "import time; time.sleep(100000000)"' + creationflags = 0 + if sys.platform == 'win32': + from subprocess import CREATE_NEW_PROCESS_GROUP + # On windows create a new process group so that killing process + # kills the process and all its children. + creationflags = CREATE_NEW_PROCESS_GROUP + proc = self.loop.run_until_complete( + asyncio.create_subprocess_shell(blocking_shell_command, stdout=asyncio.subprocess.PIPE, + creationflags=creationflags) + ) + self.loop.run_until_complete(asyncio.sleep(1)) + if sys.platform == 'win32': + proc.send_signal(signal.CTRL_BREAK_EVENT) + # On windows it is an alias of terminate which sets the return code + proc.kill() + returncode = self.loop.run_until_complete(proc.wait()) + if sys.platform == 'win32': + self.assertIsInstance(returncode, int) + # expect 1 but sometimes get 0 + else: + self.assertEqual(-signal.SIGKILL, returncode) + def test_terminate(self): args = PROGRAM_BLOCKED proc = self.loop.run_until_complete( diff --git a/Misc/NEWS.d/next/Library/2022-07-08-08-39-35.gh-issue-88050.0aOC_m.rst b/Misc/NEWS.d/next/Library/2022-07-08-08-39-35.gh-issue-88050.0aOC_m.rst new file mode 100644 index 000000000000..43c0765d940d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-07-08-08-39-35.gh-issue-88050.0aOC_m.rst @@ -0,0 +1 @@ +Fix :mod:`asyncio` subprocess transport to kill process cleanly when process is blocked and avoid ``RuntimeError`` when loop is closed. Patch by Kumar Aditya. From webhook-mailer at python.org Wed Oct 5 13:53:08 2022 From: webhook-mailer at python.org (orsenthil) Date: Wed, 05 Oct 2022 17:53:08 -0000 Subject: [Python-checkins] GH-95172 Make the same version `versionadded` oneline (#95172) Message-ID: https://github.com/python/cpython/commit/d6062d1170199c4f02acf6de8fcbf5d748a03db2 commit: d6062d1170199c4f02acf6de8fcbf5d748a03db2 branch: main author: 180909 <734461790 at qq.com> committer: orsenthil date: 2022-10-05T10:52:59-07:00 summary: GH-95172 Make the same version `versionadded` oneline (#95172) * Make the same version versionadded oneline * Format versionadded for enum.rst * Format versionadded A single line versionadded was reading better. Co-authored-by: Senthil Kumaran files: M Doc/library/enum.rst diff --git a/Doc/library/enum.rst b/Doc/library/enum.rst index 01743b002ba9..a30a7a4ca343 100644 --- a/Doc/library/enum.rst +++ b/Doc/library/enum.rst @@ -134,8 +134,7 @@ Module Contents .. versionadded:: 3.6 ``Flag``, ``IntFlag``, ``auto`` -.. versionadded:: 3.11 ``StrEnum``, ``EnumCheck``, ``FlagBoundary``, ``property`` -.. versionadded:: 3.11 ``member``, ``nonmember`` +.. versionadded:: 3.11 ``StrEnum``, ``EnumCheck``, ``FlagBoundary``, ``property``, ``member``, ``nonmember`` --------------- From webhook-mailer at python.org Wed Oct 5 13:56:51 2022 From: webhook-mailer at python.org (ambv) Date: Wed, 05 Oct 2022 17:56:51 -0000 Subject: [Python-checkins] build(deps): bump actions/stale from 5 to 6 (#97701) Message-ID: https://github.com/python/cpython/commit/9442105ce71d86f86c21a8a0af332e480aec47ea commit: 9442105ce71d86f86c21a8a0af332e480aec47ea branch: main author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> committer: ambv date: 2022-10-05T10:56:42-07:00 summary: build(deps): bump actions/stale from 5 to 6 (#97701) Bumps [actions/stale](https://github.com/actions/stale) from 5 to 6. - [Release notes](https://github.com/actions/stale/releases) - [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/stale/compare/v5...v6) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> files: M .github/workflows/stale.yml diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index f422707afb9e..1c6f1641c885 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -15,7 +15,7 @@ jobs: steps: - name: "Check PRs" - uses: actions/stale at v5 + uses: actions/stale at v6 with: repo-token: ${{ secrets.GITHUB_TOKEN }} stale-pr-message: 'This PR is stale because it has been open for 30 days with no activity.' From webhook-mailer at python.org Wed Oct 5 13:58:01 2022 From: webhook-mailer at python.org (orsenthil) Date: Wed, 05 Oct 2022 17:58:01 -0000 Subject: [Python-checkins] gh-91539: improve performance of get_proxies_environment (#91566) Message-ID: https://github.com/python/cpython/commit/aeb28f51304ebe2ad9fd6a61b6e4e5a03d288aa1 commit: aeb28f51304ebe2ad9fd6a61b6e4e5a03d288aa1 branch: main author: Pieter Eendebak committer: orsenthil date: 2022-10-05T10:57:52-07:00 summary: gh-91539: improve performance of get_proxies_environment (#91566) * improve performance of get_proxies_environment when there are many environment variables * ?? Added by blurb_it. * fix case of short env name * fix formatting * fix whitespace * whitespace * Update Lib/urllib/request.py Co-authored-by: Carl Meyer * Update Lib/urllib/request.py Co-authored-by: Carl Meyer * Update Lib/urllib/request.py Co-authored-by: Carl Meyer * Update Lib/urllib/request.py Co-authored-by: Carl Meyer * whitespace * Update Misc/NEWS.d/next/Library/2022-04-15-11-29-38.gh-issue-91539.7WgVuA.rst Co-authored-by: Carl Meyer * Update Lib/urllib/request.py Co-authored-by: Carl Meyer Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Carl Meyer files: A Misc/NEWS.d/next/Library/2022-04-15-11-29-38.gh-issue-91539.7WgVuA.rst M Lib/urllib/request.py diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py index 1761e951e624..e2d5b8c5c59a 100644 --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -2508,28 +2508,34 @@ def getproxies_environment(): this seems to be the standard convention. If you need a different way, you can pass a proxies dictionary to the [Fancy]URLopener constructor. - """ - proxies = {} # in order to prefer lowercase variables, process environment in # two passes: first matches any, second pass matches lowercase only - for name, value in os.environ.items(): - name = name.lower() - if value and name[-6:] == '_proxy': - proxies[name[:-6]] = value + + # select only environment variables which end in (after making lowercase) _proxy + proxies = {} + environment = [] + for name in os.environ.keys(): + # fast screen underscore position before more expensive case-folding + if len(name) > 5 and name[-6] == "_" and name[-5:].lower() == "proxy": + value = os.environ[name] + proxy_name = name[:-6].lower() + environment.append((name, value, proxy_name)) + if value: + proxies[proxy_name] = value # CVE-2016-1000110 - If we are running as CGI script, forget HTTP_PROXY # (non-all-lowercase) as it may be set from the web server by a "Proxy:" # header from the client # If "proxy" is lowercase, it will still be used thanks to the next block if 'REQUEST_METHOD' in os.environ: proxies.pop('http', None) - for name, value in os.environ.items(): + for name, value, proxy_name in environment: + # not case-folded, checking here for lower-case env vars only if name[-6:] == '_proxy': - name = name.lower() if value: - proxies[name[:-6]] = value + proxies[proxy_name] = value else: - proxies.pop(name[:-6], None) + proxies.pop(proxy_name, None) return proxies def proxy_bypass_environment(host, proxies=None): diff --git a/Misc/NEWS.d/next/Library/2022-04-15-11-29-38.gh-issue-91539.7WgVuA.rst b/Misc/NEWS.d/next/Library/2022-04-15-11-29-38.gh-issue-91539.7WgVuA.rst new file mode 100644 index 000000000000..16d61f1b9110 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-04-15-11-29-38.gh-issue-91539.7WgVuA.rst @@ -0,0 +1 @@ +Improve performance of ``urllib.request.getproxies_environment`` when there are many environment variables From webhook-mailer at python.org Wed Oct 5 14:00:35 2022 From: webhook-mailer at python.org (ambv) Date: Wed, 05 Oct 2022 18:00:35 -0000 Subject: [Python-checkins] [3.11] gh-93738: Documentation C syntax (Function glob patterns -> literal markup) (GH-97774) (#97910) Message-ID: https://github.com/python/cpython/commit/92054dfe5d8cbb26795094e32215c71b70022ef4 commit: 92054dfe5d8cbb26795094e32215c71b70022ef4 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-05T11:00:29-07:00 summary: [3.11] gh-93738: Documentation C syntax (Function glob patterns -> literal markup) (GH-97774) (#97910) (cherry picked from commit 0e72606dd4cf3023a4f8c2fe3c58082592b253f7) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> Co-authored-by: ?ukasz Langa files: M Doc/c-api/arg.rst M Doc/c-api/exceptions.rst M Doc/c-api/init.rst M Doc/c-api/module.rst M Doc/c-api/typeobj.rst M Doc/extending/extending.rst M Doc/whatsnew/2.5.rst diff --git a/Doc/c-api/arg.rst b/Doc/c-api/arg.rst index fb921a4af6f3..91d764c13f67 100644 --- a/Doc/c-api/arg.rst +++ b/Doc/c-api/arg.rst @@ -335,7 +335,7 @@ Other objects status = converter(object, address); where *object* is the Python object to be converted and *address* is the - :c:type:`void*` argument that was passed to the :c:func:`PyArg_Parse\*` function. + :c:type:`void*` argument that was passed to the ``PyArg_Parse*`` function. The returned *status* should be ``1`` for a successful conversion and ``0`` if the conversion has failed. When the conversion fails, the *converter* function should raise an exception and leave the content of *address* unmodified. @@ -409,9 +409,9 @@ what is specified for the corresponding format unit in that case. For the conversion to succeed, the *arg* object must match the format and the format must be exhausted. On success, the -:c:func:`PyArg_Parse\*` functions return true, otherwise they return +``PyArg_Parse*`` functions return true, otherwise they return false and raise an appropriate exception. When the -:c:func:`PyArg_Parse\*` functions fail due to conversion failure in one +``PyArg_Parse*`` functions fail due to conversion failure in one of the format units, the variables at the addresses corresponding to that and the following format units are left untouched. @@ -518,7 +518,7 @@ Building values .. c:function:: PyObject* Py_BuildValue(const char *format, ...) Create a new value based on a format string similar to those accepted by the - :c:func:`PyArg_Parse\*` family of functions and a sequence of values. Returns + ``PyArg_Parse*`` family of functions and a sequence of values. Returns the value or ``NULL`` in the case of an error; an exception will be raised if ``NULL`` is returned. diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index 7221957fe1db..087e0a61d12d 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -14,7 +14,7 @@ there is a global indicator (per thread) of the last error that occurred. Most C API functions don't clear this on success, but will set it to indicate the cause of the error on failure. Most C API functions also return an error indicator, usually ``NULL`` if they are supposed to return a pointer, or ``-1`` -if they return an integer (exception: the :c:func:`PyArg_\*` functions +if they return an integer (exception: the ``PyArg_*`` functions return ``1`` for success and ``0`` for failure). Concretely, the error indicator consists of three object pointers: the @@ -370,7 +370,7 @@ Querying the error indicator .. c:function:: PyObject* PyErr_Occurred() Test whether the error indicator is set. If set, return the exception *type* - (the first argument to the last call to one of the :c:func:`PyErr_Set\*` + (the first argument to the last call to one of the ``PyErr_Set*`` functions or to :c:func:`PyErr_Restore`). If not set, return ``NULL``. You do not own a reference to the return value, so you do not need to :c:func:`Py_DECREF` it. diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index 60c4154da489..72b086532e5d 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -847,11 +847,11 @@ from a C thread is:: /* Release the thread. No Python API allowed beyond this point. */ PyGILState_Release(gstate); -Note that the :c:func:`PyGILState_\*` functions assume there is only one global +Note that the ``PyGILState_*`` functions assume there is only one global interpreter (created automatically by :c:func:`Py_Initialize`). Python supports the creation of additional interpreters (using :c:func:`Py_NewInterpreter`), but mixing multiple interpreters and the -:c:func:`PyGILState_\*` API is unsupported. +``PyGILState_*`` API is unsupported. .. _fork-and-threads: @@ -1478,7 +1478,7 @@ operations executed by such objects may affect the wrong (sub-)interpreter's dictionary of loaded modules. It is equally important to avoid sharing objects from which the above are reachable. -Also note that combining this functionality with :c:func:`PyGILState_\*` APIs +Also note that combining this functionality with ``PyGILState_*`` APIs is delicate, because these APIs assume a bijection between Python thread states and OS-level threads, an assumption broken by the presence of sub-interpreters. It is highly recommended that you don't switch sub-interpreters between a pair diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst index 94c8d9f98171..e2ba157b32c7 100644 --- a/Doc/c-api/module.rst +++ b/Doc/c-api/module.rst @@ -64,8 +64,8 @@ Module Objects If *module* is not a module object (or a subtype of a module object), :exc:`SystemError` is raised and ``NULL`` is returned. - It is recommended extensions use other :c:func:`PyModule_\*` and - :c:func:`PyObject_\*` functions rather than directly manipulate a module's + It is recommended extensions use other ``PyModule_*`` and + ``PyObject_*`` functions rather than directly manipulate a module's :attr:`~object.__dict__`. diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index 6acd69cf56fe..af0d760a30cb 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -7,8 +7,8 @@ Type Objects Perhaps one of the most important structures of the Python object system is the structure that defines a new type: the :c:type:`PyTypeObject` structure. Type -objects can be handled using any of the :c:func:`PyObject_\*` or -:c:func:`PyType_\*` functions, but do not offer much that's interesting to most +objects can be handled using any of the ``PyObject_*`` or +``PyType_*`` functions, but do not offer much that's interesting to most Python applications. These objects are fundamental to how objects behave, so they are very important to the interpreter itself and to any extension module that implements new types. @@ -1484,7 +1484,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) If the instances of this type are weakly referenceable, this field is greater than zero and contains the offset in the instance structure of the weak reference list head (ignoring the GC header, if present); this offset is used by - :c:func:`PyObject_ClearWeakRefs` and the :c:func:`PyWeakref_\*` functions. The + :c:func:`PyObject_ClearWeakRefs` and the ``PyWeakref_*`` functions. The instance structure needs to include a field of type :c:expr:`PyObject*` which is initialized to ``NULL``. diff --git a/Doc/extending/extending.rst b/Doc/extending/extending.rst index 2e3362b834e6..0ef899f4c997 100644 --- a/Doc/extending/extending.rst +++ b/Doc/extending/extending.rst @@ -157,16 +157,16 @@ since you should be able to tell from the return value. When a function *f* that calls another function *g* detects that the latter fails, *f* should itself return an error value (usually ``NULL`` or ``-1``). It -should *not* call one of the :c:func:`PyErr_\*` functions --- one has already +should *not* call one of the ``PyErr_*`` functions --- one has already been called by *g*. *f*'s caller is then supposed to also return an error -indication to *its* caller, again *without* calling :c:func:`PyErr_\*`, and so on +indication to *its* caller, again *without* calling ``PyErr_*``, and so on --- the most detailed cause of the error was already reported by the function that first detected it. Once the error reaches the Python interpreter's main loop, this aborts the currently executing Python code and tries to find an exception handler specified by the Python programmer. (There are situations where a module can actually give a more detailed error -message by calling another :c:func:`PyErr_\*` function, and in such cases it is +message by calling another ``PyErr_*`` function, and in such cases it is fine to do so. As a general rule, however, this is not necessary, and can cause information about the cause of the error to be lost: most operations can fail for a variety of reasons.) diff --git a/Doc/whatsnew/2.5.rst b/Doc/whatsnew/2.5.rst index 6c216826fee0..dfa8f7e93f81 100644 --- a/Doc/whatsnew/2.5.rst +++ b/Doc/whatsnew/2.5.rst @@ -2270,9 +2270,9 @@ code: earlier section :ref:`pep-353` for a discussion of this change. * C API: The obmalloc changes mean that you must be careful to not mix usage - of the :c:func:`PyMem_\*` and :c:func:`PyObject_\*` families of functions. Memory - allocated with one family's :c:func:`\*_Malloc` must be freed with the - corresponding family's :c:func:`\*_Free` function. + of the ``PyMem_*`` and ``PyObject_*`` families of functions. Memory + allocated with one family's ``*_Malloc`` must be freed with the + corresponding family's ``*_Free`` function. .. ====================================================================== From webhook-mailer at python.org Wed Oct 5 14:00:55 2022 From: webhook-mailer at python.org (ambv) Date: Wed, 05 Oct 2022 18:00:55 -0000 Subject: [Python-checkins] [3.10] gh-93738: Documentation C syntax (Function glob patterns -> literal markup) (GH-97774) (#97911) Message-ID: https://github.com/python/cpython/commit/b39182e4b0c476de3f2465b1af71e46a334ac9d5 commit: b39182e4b0c476de3f2465b1af71e46a334ac9d5 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-05T11:00:50-07:00 summary: [3.10] gh-93738: Documentation C syntax (Function glob patterns -> literal markup) (GH-97774) (#97911) (cherry picked from commit 0e72606dd4cf3023a4f8c2fe3c58082592b253f7) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> Co-authored-by: ?ukasz Langa files: M Doc/c-api/arg.rst M Doc/c-api/exceptions.rst M Doc/c-api/init.rst M Doc/c-api/module.rst M Doc/c-api/typeobj.rst M Doc/extending/extending.rst M Doc/whatsnew/2.5.rst diff --git a/Doc/c-api/arg.rst b/Doc/c-api/arg.rst index fb921a4af6f3..91d764c13f67 100644 --- a/Doc/c-api/arg.rst +++ b/Doc/c-api/arg.rst @@ -335,7 +335,7 @@ Other objects status = converter(object, address); where *object* is the Python object to be converted and *address* is the - :c:type:`void*` argument that was passed to the :c:func:`PyArg_Parse\*` function. + :c:type:`void*` argument that was passed to the ``PyArg_Parse*`` function. The returned *status* should be ``1`` for a successful conversion and ``0`` if the conversion has failed. When the conversion fails, the *converter* function should raise an exception and leave the content of *address* unmodified. @@ -409,9 +409,9 @@ what is specified for the corresponding format unit in that case. For the conversion to succeed, the *arg* object must match the format and the format must be exhausted. On success, the -:c:func:`PyArg_Parse\*` functions return true, otherwise they return +``PyArg_Parse*`` functions return true, otherwise they return false and raise an appropriate exception. When the -:c:func:`PyArg_Parse\*` functions fail due to conversion failure in one +``PyArg_Parse*`` functions fail due to conversion failure in one of the format units, the variables at the addresses corresponding to that and the following format units are left untouched. @@ -518,7 +518,7 @@ Building values .. c:function:: PyObject* Py_BuildValue(const char *format, ...) Create a new value based on a format string similar to those accepted by the - :c:func:`PyArg_Parse\*` family of functions and a sequence of values. Returns + ``PyArg_Parse*`` family of functions and a sequence of values. Returns the value or ``NULL`` in the case of an error; an exception will be raised if ``NULL`` is returned. diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index ad75ec5c62c0..37c938ae3d7e 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -14,7 +14,7 @@ there is a global indicator (per thread) of the last error that occurred. Most C API functions don't clear this on success, but will set it to indicate the cause of the error on failure. Most C API functions also return an error indicator, usually ``NULL`` if they are supposed to return a pointer, or ``-1`` -if they return an integer (exception: the :c:func:`PyArg_\*` functions +if they return an integer (exception: the ``PyArg_*`` functions return ``1`` for success and ``0`` for failure). Concretely, the error indicator consists of three object pointers: the @@ -370,7 +370,7 @@ Querying the error indicator .. c:function:: PyObject* PyErr_Occurred() Test whether the error indicator is set. If set, return the exception *type* - (the first argument to the last call to one of the :c:func:`PyErr_Set\*` + (the first argument to the last call to one of the ``PyErr_Set*`` functions or to :c:func:`PyErr_Restore`). If not set, return ``NULL``. You do not own a reference to the return value, so you do not need to :c:func:`Py_DECREF` it. diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index dbde7f633b0e..6a80386b18bb 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -800,11 +800,11 @@ from a C thread is:: /* Release the thread. No Python API allowed beyond this point. */ PyGILState_Release(gstate); -Note that the :c:func:`PyGILState_\*` functions assume there is only one global +Note that the ``PyGILState_*`` functions assume there is only one global interpreter (created automatically by :c:func:`Py_Initialize`). Python supports the creation of additional interpreters (using :c:func:`Py_NewInterpreter`), but mixing multiple interpreters and the -:c:func:`PyGILState_\*` API is unsupported. +``PyGILState_*`` API is unsupported. .. _fork-and-threads: @@ -1408,7 +1408,7 @@ operations executed by such objects may affect the wrong (sub-)interpreter's dictionary of loaded modules. It is equally important to avoid sharing objects from which the above are reachable. -Also note that combining this functionality with :c:func:`PyGILState_\*` APIs +Also note that combining this functionality with ``PyGILState_*`` APIs is delicate, because these APIs assume a bijection between Python thread states and OS-level threads, an assumption broken by the presence of sub-interpreters. It is highly recommended that you don't switch sub-interpreters between a pair diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst index 94c8d9f98171..e2ba157b32c7 100644 --- a/Doc/c-api/module.rst +++ b/Doc/c-api/module.rst @@ -64,8 +64,8 @@ Module Objects If *module* is not a module object (or a subtype of a module object), :exc:`SystemError` is raised and ``NULL`` is returned. - It is recommended extensions use other :c:func:`PyModule_\*` and - :c:func:`PyObject_\*` functions rather than directly manipulate a module's + It is recommended extensions use other ``PyModule_*`` and + ``PyObject_*`` functions rather than directly manipulate a module's :attr:`~object.__dict__`. diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index fd3d4b77086c..21385afb552f 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -7,8 +7,8 @@ Type Objects Perhaps one of the most important structures of the Python object system is the structure that defines a new type: the :c:type:`PyTypeObject` structure. Type -objects can be handled using any of the :c:func:`PyObject_\*` or -:c:func:`PyType_\*` functions, but do not offer much that's interesting to most +objects can be handled using any of the ``PyObject_*`` or +``PyType_*`` functions, but do not offer much that's interesting to most Python applications. These objects are fundamental to how objects behave, so they are very important to the interpreter itself and to any extension module that implements new types. @@ -1483,7 +1483,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) If the instances of this type are weakly referenceable, this field is greater than zero and contains the offset in the instance structure of the weak reference list head (ignoring the GC header, if present); this offset is used by - :c:func:`PyObject_ClearWeakRefs` and the :c:func:`PyWeakref_\*` functions. The + :c:func:`PyObject_ClearWeakRefs` and the ``PyWeakref_*`` functions. The instance structure needs to include a field of type :c:expr:`PyObject*` which is initialized to ``NULL``. diff --git a/Doc/extending/extending.rst b/Doc/extending/extending.rst index 2e3362b834e6..0ef899f4c997 100644 --- a/Doc/extending/extending.rst +++ b/Doc/extending/extending.rst @@ -157,16 +157,16 @@ since you should be able to tell from the return value. When a function *f* that calls another function *g* detects that the latter fails, *f* should itself return an error value (usually ``NULL`` or ``-1``). It -should *not* call one of the :c:func:`PyErr_\*` functions --- one has already +should *not* call one of the ``PyErr_*`` functions --- one has already been called by *g*. *f*'s caller is then supposed to also return an error -indication to *its* caller, again *without* calling :c:func:`PyErr_\*`, and so on +indication to *its* caller, again *without* calling ``PyErr_*``, and so on --- the most detailed cause of the error was already reported by the function that first detected it. Once the error reaches the Python interpreter's main loop, this aborts the currently executing Python code and tries to find an exception handler specified by the Python programmer. (There are situations where a module can actually give a more detailed error -message by calling another :c:func:`PyErr_\*` function, and in such cases it is +message by calling another ``PyErr_*`` function, and in such cases it is fine to do so. As a general rule, however, this is not necessary, and can cause information about the cause of the error to be lost: most operations can fail for a variety of reasons.) diff --git a/Doc/whatsnew/2.5.rst b/Doc/whatsnew/2.5.rst index 6c216826fee0..dfa8f7e93f81 100644 --- a/Doc/whatsnew/2.5.rst +++ b/Doc/whatsnew/2.5.rst @@ -2270,9 +2270,9 @@ code: earlier section :ref:`pep-353` for a discussion of this change. * C API: The obmalloc changes mean that you must be careful to not mix usage - of the :c:func:`PyMem_\*` and :c:func:`PyObject_\*` families of functions. Memory - allocated with one family's :c:func:`\*_Malloc` must be freed with the - corresponding family's :c:func:`\*_Free` function. + of the ``PyMem_*`` and ``PyObject_*`` families of functions. Memory + allocated with one family's ``*_Malloc`` must be freed with the + corresponding family's ``*_Free`` function. .. ====================================================================== From webhook-mailer at python.org Wed Oct 5 14:01:22 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 05 Oct 2022 18:01:22 -0000 Subject: [Python-checkins] GH-95172 Make the same version `versionadded` oneline (GH-95172) Message-ID: https://github.com/python/cpython/commit/ef77f2f06868f4e167ecaa1be2ffd9da4c4449c1 commit: ef77f2f06868f4e167ecaa1be2ffd9da4c4449c1 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-05T11:01:17-07:00 summary: GH-95172 Make the same version `versionadded` oneline (GH-95172) * Make the same version versionadded oneline * Format versionadded for enum.rst * Format versionadded A single line versionadded was reading better. Co-authored-by: Senthil Kumaran (cherry picked from commit d6062d1170199c4f02acf6de8fcbf5d748a03db2) Co-authored-by: 180909 <734461790 at qq.com> files: M Doc/library/enum.rst diff --git a/Doc/library/enum.rst b/Doc/library/enum.rst index b1333c7dd5cf..241d19d3bfb3 100644 --- a/Doc/library/enum.rst +++ b/Doc/library/enum.rst @@ -134,8 +134,7 @@ Module Contents .. versionadded:: 3.6 ``Flag``, ``IntFlag``, ``auto`` -.. versionadded:: 3.11 ``StrEnum``, ``EnumCheck``, ``FlagBoundary``, ``property`` -.. versionadded:: 3.11 ``member``, ``nonmember`` +.. versionadded:: 3.11 ``StrEnum``, ``EnumCheck``, ``FlagBoundary``, ``property``, ``member``, ``nonmember`` --------------- From webhook-mailer at python.org Wed Oct 5 14:01:24 2022 From: webhook-mailer at python.org (ambv) Date: Wed, 05 Oct 2022 18:01:24 -0000 Subject: [Python-checkins] gh-93738: Documentation C syntax (:c:type: -> :c:expr:) (#97768) Message-ID: https://github.com/python/cpython/commit/0031e62973801d34a9e19ab7bb199e9668e32d7b commit: 0031e62973801d34a9e19ab7bb199e9668e32d7b branch: main author: Adam Turner <9087854+AA-Turner at users.noreply.github.com> committer: ambv date: 2022-10-05T11:01:14-07:00 summary: gh-93738: Documentation C syntax (:c:type: -> :c:expr:) (#97768) :c:type:`` -> :c:expr:`` Co-authored-by: ?ukasz Langa files: M Doc/c-api/arg.rst M Doc/c-api/capsule.rst M Doc/c-api/complex.rst M Doc/c-api/conversion.rst M Doc/c-api/dict.rst M Doc/c-api/file.rst M Doc/c-api/float.rst M Doc/c-api/init.rst M Doc/c-api/intro.rst M Doc/c-api/long.rst M Doc/c-api/marshal.rst M Doc/c-api/memory.rst M Doc/c-api/sys.rst M Doc/c-api/unicode.rst M Doc/extending/extending.rst M Doc/extending/newtypes.rst M Doc/library/ctypes.rst M Doc/library/posix.rst M Doc/library/socket.rst M Doc/library/stdtypes.rst M Doc/library/struct.rst M Doc/reference/datamodel.rst M Doc/whatsnew/2.2.rst M Doc/whatsnew/2.3.rst M Doc/whatsnew/2.4.rst M Doc/whatsnew/2.5.rst M Doc/whatsnew/2.6.rst M Doc/whatsnew/2.7.rst M Doc/whatsnew/3.3.rst M Doc/whatsnew/3.7.rst M Doc/whatsnew/3.9.rst M Misc/NEWS.d/3.5.0a1.rst M Misc/NEWS.d/3.9.0a1.rst M Misc/NEWS.d/3.9.0b1.rst diff --git a/Doc/c-api/arg.rst b/Doc/c-api/arg.rst index 702c0869116a..c5be453c1533 100644 --- a/Doc/c-api/arg.rst +++ b/Doc/c-api/arg.rst @@ -152,10 +152,10 @@ which disallows mutable objects such as :class:`bytearray`. It only works for encoded data without embedded NUL bytes. This format requires two arguments. The first is only used as input, and - must be a :c:type:`const char*` which points to the name of an encoding as a + must be a :c:expr:`const char*` which points to the name of an encoding as a NUL-terminated string, or ``NULL``, in which case ``'utf-8'`` encoding is used. An exception is raised if the named encoding is not known to Python. The - second argument must be a :c:type:`char**`; the value of the pointer it + second argument must be a :c:expr:`char**`; the value of the pointer it references will be set to a buffer with the contents of the argument text. The text will be encoded in the encoding specified by the first argument. @@ -175,10 +175,10 @@ which disallows mutable objects such as :class:`bytearray`. characters. It requires three arguments. The first is only used as input, and must be a - :c:type:`const char*` which points to the name of an encoding as a + :c:expr:`const char*` which points to the name of an encoding as a NUL-terminated string, or ``NULL``, in which case ``'utf-8'`` encoding is used. An exception is raised if the named encoding is not known to Python. The - second argument must be a :c:type:`char**`; the value of the pointer it + second argument must be a :c:expr:`char**`; the value of the pointer it references will be set to a buffer with the contents of the argument text. The text will be encoded in the encoding specified by the first argument. The third argument must be a pointer to an integer; the referenced integer @@ -215,38 +215,38 @@ Numbers ``b`` (:class:`int`) [unsigned char] Convert a nonnegative Python integer to an unsigned tiny int, stored in a C - :c:type:`unsigned char`. + :c:expr:`unsigned char`. ``B`` (:class:`int`) [unsigned char] Convert a Python integer to a tiny int without overflow checking, stored in a C - :c:type:`unsigned char`. + :c:expr:`unsigned char`. ``h`` (:class:`int`) [short int] - Convert a Python integer to a C :c:type:`short int`. + Convert a Python integer to a C :c:expr:`short int`. ``H`` (:class:`int`) [unsigned short int] - Convert a Python integer to a C :c:type:`unsigned short int`, without overflow + Convert a Python integer to a C :c:expr:`unsigned short int`, without overflow checking. ``i`` (:class:`int`) [int] - Convert a Python integer to a plain C :c:type:`int`. + Convert a Python integer to a plain C :c:expr:`int`. ``I`` (:class:`int`) [unsigned int] - Convert a Python integer to a C :c:type:`unsigned int`, without overflow + Convert a Python integer to a C :c:expr:`unsigned int`, without overflow checking. ``l`` (:class:`int`) [long int] - Convert a Python integer to a C :c:type:`long int`. + Convert a Python integer to a C :c:expr:`long int`. ``k`` (:class:`int`) [unsigned long] - Convert a Python integer to a C :c:type:`unsigned long` without + Convert a Python integer to a C :c:expr:`unsigned long` without overflow checking. ``L`` (:class:`int`) [long long] - Convert a Python integer to a C :c:type:`long long`. + Convert a Python integer to a C :c:expr:`long long`. ``K`` (:class:`int`) [unsigned long long] - Convert a Python integer to a C :c:type:`unsigned long long` + Convert a Python integer to a C :c:expr:`unsigned long long` without overflow checking. ``n`` (:class:`int`) [:c:type:`Py_ssize_t`] @@ -254,20 +254,20 @@ Numbers ``c`` (:class:`bytes` or :class:`bytearray` of length 1) [char] Convert a Python byte, represented as a :class:`bytes` or - :class:`bytearray` object of length 1, to a C :c:type:`char`. + :class:`bytearray` object of length 1, to a C :c:expr:`char`. .. versionchanged:: 3.3 Allow :class:`bytearray` objects. ``C`` (:class:`str` of length 1) [int] Convert a Python character, represented as a :class:`str` object of - length 1, to a C :c:type:`int`. + length 1, to a C :c:expr:`int`. ``f`` (:class:`float`) [float] - Convert a Python floating point number to a C :c:type:`float`. + Convert a Python floating point number to a C :c:expr:`float`. ``d`` (:class:`float`) [double] - Convert a Python floating point number to a C :c:type:`double`. + Convert a Python floating point number to a C :c:expr:`double`. ``D`` (:class:`complex`) [Py_complex] Convert a Python complex number to a C :c:type:`Py_complex` structure. @@ -292,13 +292,13 @@ Other objects ``O&`` (object) [*converter*, *anything*] Convert a Python object to a C variable through a *converter* function. This takes two arguments: the first is a function, the second is the address of a C - variable (of arbitrary type), converted to :c:type:`void *`. The *converter* + variable (of arbitrary type), converted to :c:expr:`void *`. The *converter* function in turn is called as follows:: status = converter(object, address); where *object* is the Python object to be converted and *address* is the - :c:type:`void*` argument that was passed to the ``PyArg_Parse*`` function. + :c:expr:`void*` argument that was passed to the ``PyArg_Parse*`` function. The returned *status* should be ``1`` for a successful conversion and ``0`` if the conversion has failed. When the conversion fails, the *converter* function should raise an exception and leave the content of *address* unmodified. @@ -531,7 +531,7 @@ Building values Same as ``s#``. ``u`` (:class:`str`) [const wchar_t \*] - Convert a null-terminated :c:type:`wchar_t` buffer of Unicode (UTF-16 or UCS-4) + Convert a null-terminated :c:expr:`wchar_t` buffer of Unicode (UTF-16 or UCS-4) data to a Python Unicode object. If the Unicode buffer pointer is ``NULL``, ``None`` is returned. @@ -547,51 +547,51 @@ Building values Same as ``s#``. ``i`` (:class:`int`) [int] - Convert a plain C :c:type:`int` to a Python integer object. + Convert a plain C :c:expr:`int` to a Python integer object. ``b`` (:class:`int`) [char] - Convert a plain C :c:type:`char` to a Python integer object. + Convert a plain C :c:expr:`char` to a Python integer object. ``h`` (:class:`int`) [short int] - Convert a plain C :c:type:`short int` to a Python integer object. + Convert a plain C :c:expr:`short int` to a Python integer object. ``l`` (:class:`int`) [long int] - Convert a C :c:type:`long int` to a Python integer object. + Convert a C :c:expr:`long int` to a Python integer object. ``B`` (:class:`int`) [unsigned char] - Convert a C :c:type:`unsigned char` to a Python integer object. + Convert a C :c:expr:`unsigned char` to a Python integer object. ``H`` (:class:`int`) [unsigned short int] - Convert a C :c:type:`unsigned short int` to a Python integer object. + Convert a C :c:expr:`unsigned short int` to a Python integer object. ``I`` (:class:`int`) [unsigned int] - Convert a C :c:type:`unsigned int` to a Python integer object. + Convert a C :c:expr:`unsigned int` to a Python integer object. ``k`` (:class:`int`) [unsigned long] - Convert a C :c:type:`unsigned long` to a Python integer object. + Convert a C :c:expr:`unsigned long` to a Python integer object. ``L`` (:class:`int`) [long long] - Convert a C :c:type:`long long` to a Python integer object. + Convert a C :c:expr:`long long` to a Python integer object. ``K`` (:class:`int`) [unsigned long long] - Convert a C :c:type:`unsigned long long` to a Python integer object. + Convert a C :c:expr:`unsigned long long` to a Python integer object. ``n`` (:class:`int`) [:c:type:`Py_ssize_t`] Convert a C :c:type:`Py_ssize_t` to a Python integer. ``c`` (:class:`bytes` of length 1) [char] - Convert a C :c:type:`int` representing a byte to a Python :class:`bytes` object of + Convert a C :c:expr:`int` representing a byte to a Python :class:`bytes` object of length 1. ``C`` (:class:`str` of length 1) [int] - Convert a C :c:type:`int` representing a character to Python :class:`str` + Convert a C :c:expr:`int` representing a character to Python :class:`str` object of length 1. ``d`` (:class:`float`) [double] - Convert a C :c:type:`double` to a Python floating point number. + Convert a C :c:expr:`double` to a Python floating point number. ``f`` (:class:`float`) [float] - Convert a C :c:type:`float` to a Python floating point number. + Convert a C :c:expr:`float` to a Python floating point number. ``D`` (:class:`complex`) [Py_complex \*] Convert a C :c:type:`Py_complex` structure to a Python complex number. @@ -614,7 +614,7 @@ Building values ``O&`` (object) [*converter*, *anything*] Convert *anything* to a Python object through a *converter* function. The - function is called with *anything* (which should be compatible with :c:type:`void*`) + function is called with *anything* (which should be compatible with :c:expr:`void*`) as its argument and should return a "new" Python object, or ``NULL`` if an error occurred. diff --git a/Doc/c-api/capsule.rst b/Doc/c-api/capsule.rst index 2c4cfc48f9a2..1c8f432505ef 100644 --- a/Doc/c-api/capsule.rst +++ b/Doc/c-api/capsule.rst @@ -15,7 +15,7 @@ Refer to :ref:`using-capsules` for more information on using these objects. .. c:type:: PyCapsule This subtype of :c:type:`PyObject` represents an opaque value, useful for C - extension modules who need to pass an opaque value (as a :c:type:`void*` + extension modules who need to pass an opaque value (as a :c:expr:`void*` pointer) through Python code to other C code. It is often used to make a C function pointer defined in one module available to other modules, so the regular import mechanism can be used to access C APIs defined in dynamically diff --git a/Doc/c-api/complex.rst b/Doc/c-api/complex.rst index c25894681bca..9228ce852000 100644 --- a/Doc/c-api/complex.rst +++ b/Doc/c-api/complex.rst @@ -115,12 +115,12 @@ Complex Numbers as Python Objects .. c:function:: double PyComplex_RealAsDouble(PyObject *op) - Return the real part of *op* as a C :c:type:`double`. + Return the real part of *op* as a C :c:expr:`double`. .. c:function:: double PyComplex_ImagAsDouble(PyObject *op) - Return the imaginary part of *op* as a C :c:type:`double`. + Return the imaginary part of *op* as a C :c:expr:`double`. .. c:function:: Py_complex PyComplex_AsCComplex(PyObject *op) diff --git a/Doc/c-api/conversion.rst b/Doc/c-api/conversion.rst index 7b4cc1cacdd4..9b9c4ffa4d03 100644 --- a/Doc/c-api/conversion.rst +++ b/Doc/c-api/conversion.rst @@ -49,7 +49,7 @@ The following functions provide locale-independent string to number conversions. .. c:function:: double PyOS_string_to_double(const char *s, char **endptr, PyObject *overflow_exception) - Convert a string ``s`` to a :c:type:`double`, raising a Python + Convert a string ``s`` to a :c:expr:`double`, raising a Python exception on failure. The set of accepted strings corresponds to the set of strings accepted by Python's :func:`float` constructor, except that ``s`` must not have leading or trailing whitespace. @@ -83,7 +83,7 @@ The following functions provide locale-independent string to number conversions. .. c:function:: char* PyOS_double_to_string(double val, char format_code, int precision, int flags, int *ptype) - Convert a :c:type:`double` *val* to a string using supplied + Convert a :c:expr:`double` *val* to a string using supplied *format_code*, *precision*, and *flags*. *format_code* must be one of ``'e'``, ``'E'``, ``'f'``, ``'F'``, diff --git a/Doc/c-api/dict.rst b/Doc/c-api/dict.rst index 67c2026baa14..819168d48707 100644 --- a/Doc/c-api/dict.rst +++ b/Doc/c-api/dict.rst @@ -73,7 +73,7 @@ Dictionary Objects .. index:: single: PyUnicode_FromString() Insert *val* into the dictionary *p* using *key* as a key. *key* should - be a :c:type:`const char*`. The key object is created using + be a :c:expr:`const char*`. The key object is created using ``PyUnicode_FromString(key)``. Return ``0`` on success or ``-1`` on failure. This function *does not* steal a reference to *val*. @@ -118,7 +118,7 @@ Dictionary Objects .. c:function:: PyObject* PyDict_GetItemString(PyObject *p, const char *key) This is the same as :c:func:`PyDict_GetItem`, but *key* is specified as a - :c:type:`const char*`, rather than a :c:expr:`PyObject*`. + :c:expr:`const char*`, rather than a :c:expr:`PyObject*`. Note that exceptions which occur while calling :meth:`__hash__` and :meth:`__eq__` methods and creating a temporary string object diff --git a/Doc/c-api/file.rst b/Doc/c-api/file.rst index 745d892be7ea..58ed58e54668 100644 --- a/Doc/c-api/file.rst +++ b/Doc/c-api/file.rst @@ -38,7 +38,7 @@ the :mod:`io` APIs instead. .. c:function:: int PyObject_AsFileDescriptor(PyObject *p) - Return the file descriptor associated with *p* as an :c:type:`int`. If the + Return the file descriptor associated with *p* as an :c:expr:`int`. If the object is an integer, its value is returned. If not, the object's :meth:`~io.IOBase.fileno` method is called if it exists; the method must return an integer, which is returned as the file descriptor diff --git a/Doc/c-api/float.rst b/Doc/c-api/float.rst index b306caf74b7c..023b12c20b7c 100644 --- a/Doc/c-api/float.rst +++ b/Doc/c-api/float.rst @@ -44,7 +44,7 @@ Floating Point Objects .. c:function:: double PyFloat_AsDouble(PyObject *pyfloat) - Return a C :c:type:`double` representation of the contents of *pyfloat*. If + Return a C :c:expr:`double` representation of the contents of *pyfloat*. If *pyfloat* is not a Python floating point object but has a :meth:`__float__` method, this method will first be called to convert *pyfloat* into a float. If ``__float__()`` is not defined then it falls back to :meth:`__index__`. @@ -57,7 +57,7 @@ Floating Point Objects .. c:function:: double PyFloat_AS_DOUBLE(PyObject *pyfloat) - Return a C :c:type:`double` representation of the contents of *pyfloat*, but + Return a C :c:expr:`double` representation of the contents of *pyfloat*, but without error checking. @@ -70,12 +70,12 @@ Floating Point Objects .. c:function:: double PyFloat_GetMax() - Return the maximum representable finite float *DBL_MAX* as C :c:type:`double`. + Return the maximum representable finite float *DBL_MAX* as C :c:expr:`double`. .. c:function:: double PyFloat_GetMin() - Return the minimum normalized positive float *DBL_MIN* as C :c:type:`double`. + Return the minimum normalized positive float *DBL_MIN* as C :c:expr:`double`. Pack and Unpack functions @@ -83,8 +83,8 @@ Pack and Unpack functions The pack and unpack functions provide an efficient platform-independent way to store floating-point values as byte strings. The Pack routines produce a bytes -string from a C :c:type:`double`, and the Unpack routines produce a C -:c:type:`double` from such a bytes string. The suffix (2, 4 or 8) specifies the +string from a C :c:expr:`double`, and the Unpack routines produce a C +:c:expr:`double` from such a bytes string. The suffix (2, 4 or 8) specifies the number of bytes in the bytes string. On platforms that appear to use IEEE 754 formats these functions work by @@ -107,7 +107,7 @@ Pack functions -------------- The pack routines write 2, 4 or 8 bytes, starting at *p*. *le* is an -:c:type:`int` argument, non-zero if you want the bytes string in little-endian +:c:expr:`int` argument, non-zero if you want the bytes string in little-endian format (exponent last, at ``p+1``, ``p+3``, or ``p+6`` ``p+7``), zero if you want big-endian format (exponent first, at *p*). The :c:data:`PY_BIG_ENDIAN` constant can be used to use the native endian: it is equal to ``1`` on big @@ -138,7 +138,7 @@ Unpack functions ---------------- The unpack routines read 2, 4 or 8 bytes, starting at *p*. *le* is an -:c:type:`int` argument, non-zero if the bytes string is in little-endian format +:c:expr:`int` argument, non-zero if the bytes string is in little-endian format (exponent last, at ``p+1``, ``p+3`` or ``p+6`` and ``p+7``), zero if big-endian (exponent first, at *p*). The :c:data:`PY_BIG_ENDIAN` constant can be used to use the native endian: it is equal to ``1`` on big endian processor, or ``0`` diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index efa58381d270..513ef93a3842 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -485,7 +485,7 @@ Process-wide parameters interpreter will change the contents of this storage. Use :c:func:`Py_DecodeLocale` to decode a bytes string to get a - :c:type:`wchar_*` string. + :c:expr:`wchar_*` string. .. deprecated:: 3.11 @@ -636,7 +636,7 @@ Process-wide parameters if required after calling :c:func:`Py_Initialize`. Use :c:func:`Py_DecodeLocale` to decode a bytes string to get a - :c:type:`wchar_*` string. + :c:expr:`wchar_*` string. The path argument is copied internally, so the caller may free it after the call completes. @@ -751,7 +751,7 @@ Process-wide parameters directory (``"."``). Use :c:func:`Py_DecodeLocale` to decode a bytes string to get a - :c:type:`wchar_*` string. + :c:expr:`wchar_*` string. See also :c:member:`PyConfig.orig_argv` and :c:member:`PyConfig.argv` members of the :ref:`Python Initialization Configuration `. @@ -787,7 +787,7 @@ Process-wide parameters :option:`-I`. Use :c:func:`Py_DecodeLocale` to decode a bytes string to get a - :c:type:`wchar_*` string. + :c:expr:`wchar_*` string. See also :c:member:`PyConfig.orig_argv` and :c:member:`PyConfig.argv` members of the :ref:`Python Initialization Configuration `. @@ -813,7 +813,7 @@ Process-wide parameters this storage. Use :c:func:`Py_DecodeLocale` to decode a bytes string to get a - :c:type:`wchar_*` string. + :c:expr:`wchar_*` string. .. deprecated:: 3.11 @@ -1400,8 +1400,8 @@ All of the following functions must be called after :c:func:`Py_Initialize`. exception (if any) for the thread is cleared. This raises no exceptions. .. versionchanged:: 3.7 - The type of the *id* parameter changed from :c:type:`long` to - :c:type:`unsigned long`. + The type of the *id* parameter changed from :c:expr:`long` to + :c:expr:`unsigned long`. .. c:function:: void PyEval_AcquireThread(PyThreadState *tstate) @@ -1863,7 +1863,7 @@ The Python interpreter provides low-level support for thread-local storage (TLS) which wraps the underlying native TLS implementation to support the Python-level thread local storage API (:class:`threading.local`). The CPython C level APIs are similar to those offered by pthreads and Windows: -use a thread key and functions to associate a :c:type:`void*` value per +use a thread key and functions to associate a :c:expr:`void*` value per thread. The GIL does *not* need to be held when calling these functions; they supply @@ -1874,8 +1874,8 @@ you need to include :file:`pythread.h` to use thread-local storage. .. note:: None of these API functions handle memory management on behalf of the - :c:type:`void*` values. You need to allocate and deallocate them yourself. - If the :c:type:`void*` values happen to be :c:expr:`PyObject*`, these + :c:expr:`void*` values. You need to allocate and deallocate them yourself. + If the :c:expr:`void*` values happen to be :c:expr:`PyObject*`, these functions don't do refcount operations on them either. .. _thread-specific-storage-api: @@ -1885,7 +1885,7 @@ Thread Specific Storage (TSS) API TSS API is introduced to supersede the use of the existing TLS API within the CPython interpreter. This API uses a new type :c:type:`Py_tss_t` instead of -:c:type:`int` to represent thread keys. +:c:expr:`int` to represent thread keys. .. versionadded:: 3.7 @@ -1971,14 +1971,14 @@ undefined if the given :c:type:`Py_tss_t` has not been initialized by .. c:function:: int PyThread_tss_set(Py_tss_t *key, void *value) - Return a zero value to indicate successfully associating a :c:type:`void*` + Return a zero value to indicate successfully associating a :c:expr:`void*` value with a TSS key in the current thread. Each thread has a distinct - mapping of the key to a :c:type:`void*` value. + mapping of the key to a :c:expr:`void*` value. .. c:function:: void* PyThread_tss_get(Py_tss_t *key) - Return the :c:type:`void*` value associated with a TSS key in the current + Return the :c:expr:`void*` value associated with a TSS key in the current thread. This returns ``NULL`` if no value is associated with the key in the current thread. diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst index 991bc3b09fd8..85eb24a495b6 100644 --- a/Doc/c-api/intro.rst +++ b/Doc/c-api/intro.rst @@ -530,8 +530,8 @@ Types ----- There are few other data types that play a significant role in the Python/C -API; most are simple C types such as :c:type:`int`, :c:type:`long`, -:c:type:`double` and :c:type:`char*`. A few structure types are used to +API; most are simple C types such as :c:expr:`int`, :c:expr:`long`, +:c:expr:`double` and :c:expr:`char*`. A few structure types are used to describe static tables used to list the functions exported by a module or the data attributes of a new object type, and another is used to describe the value of a complex number. These will be discussed together with the functions that diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst index 56a7c069de90..4f6f865db8be 100644 --- a/Doc/c-api/long.rst +++ b/Doc/c-api/long.rst @@ -47,7 +47,7 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. c:function:: PyObject* PyLong_FromUnsignedLong(unsigned long v) - Return a new :c:type:`PyLongObject` object from a C :c:type:`unsigned long`, or + Return a new :c:type:`PyLongObject` object from a C :c:expr:`unsigned long`, or ``NULL`` on failure. @@ -65,13 +65,13 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. c:function:: PyObject* PyLong_FromLongLong(long long v) - Return a new :c:type:`PyLongObject` object from a C :c:type:`long long`, or ``NULL`` + Return a new :c:type:`PyLongObject` object from a C :c:expr:`long long`, or ``NULL`` on failure. .. c:function:: PyObject* PyLong_FromUnsignedLongLong(unsigned long long v) - Return a new :c:type:`PyLongObject` object from a C :c:type:`unsigned long long`, + Return a new :c:type:`PyLongObject` object from a C :c:expr:`unsigned long long`, or ``NULL`` on failure. @@ -116,12 +116,12 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. single: LONG_MAX single: OverflowError (built-in exception) - Return a C :c:type:`long` representation of *obj*. If *obj* is not an + Return a C :c:expr:`long` representation of *obj*. If *obj* is not an instance of :c:type:`PyLongObject`, first call its :meth:`__index__` method (if present) to convert it to a :c:type:`PyLongObject`. Raise :exc:`OverflowError` if the value of *obj* is out of range for a - :c:type:`long`. + :c:expr:`long`. Returns ``-1`` on error. Use :c:func:`PyErr_Occurred` to disambiguate. @@ -134,7 +134,7 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. c:function:: long PyLong_AsLongAndOverflow(PyObject *obj, int *overflow) - Return a C :c:type:`long` representation of *obj*. If *obj* is not an + Return a C :c:expr:`long` representation of *obj*. If *obj* is not an instance of :c:type:`PyLongObject`, first call its :meth:`__index__` method (if present) to convert it to a :c:type:`PyLongObject`. @@ -157,12 +157,12 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. index:: single: OverflowError (built-in exception) - Return a C :c:type:`long long` representation of *obj*. If *obj* is not an + Return a C :c:expr:`long long` representation of *obj*. If *obj* is not an instance of :c:type:`PyLongObject`, first call its :meth:`__index__` method (if present) to convert it to a :c:type:`PyLongObject`. Raise :exc:`OverflowError` if the value of *obj* is out of range for a - :c:type:`long long`. + :c:expr:`long long`. Returns ``-1`` on error. Use :c:func:`PyErr_Occurred` to disambiguate. @@ -175,7 +175,7 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. c:function:: long long PyLong_AsLongLongAndOverflow(PyObject *obj, int *overflow) - Return a C :c:type:`long long` representation of *obj*. If *obj* is not an + Return a C :c:expr:`long long` representation of *obj*. If *obj* is not an instance of :c:type:`PyLongObject`, first call its :meth:`__index__` method (if present) to convert it to a :c:type:`PyLongObject`. @@ -216,11 +216,11 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. single: ULONG_MAX single: OverflowError (built-in exception) - Return a C :c:type:`unsigned long` representation of *pylong*. *pylong* + Return a C :c:expr:`unsigned long` representation of *pylong*. *pylong* must be an instance of :c:type:`PyLongObject`. Raise :exc:`OverflowError` if the value of *pylong* is out of range for a - :c:type:`unsigned long`. + :c:expr:`unsigned long`. Returns ``(unsigned long)-1`` on error. Use :c:func:`PyErr_Occurred` to disambiguate. @@ -247,11 +247,11 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. index:: single: OverflowError (built-in exception) - Return a C :c:type:`unsigned long long` representation of *pylong*. *pylong* + Return a C :c:expr:`unsigned long long` representation of *pylong*. *pylong* must be an instance of :c:type:`PyLongObject`. Raise :exc:`OverflowError` if the value of *pylong* is out of range for an - :c:type:`unsigned long long`. + :c:expr:`unsigned long long`. Returns ``(unsigned long long)-1`` on error. Use :c:func:`PyErr_Occurred` to disambiguate. @@ -262,11 +262,11 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. c:function:: unsigned long PyLong_AsUnsignedLongMask(PyObject *obj) - Return a C :c:type:`unsigned long` representation of *obj*. If *obj* is not + Return a C :c:expr:`unsigned long` representation of *obj*. If *obj* is not an instance of :c:type:`PyLongObject`, first call its :meth:`__index__` method (if present) to convert it to a :c:type:`PyLongObject`. - If the value of *obj* is out of range for an :c:type:`unsigned long`, + If the value of *obj* is out of range for an :c:expr:`unsigned long`, return the reduction of that value modulo ``ULONG_MAX + 1``. Returns ``(unsigned long)-1`` on error. Use :c:func:`PyErr_Occurred` to @@ -281,12 +281,12 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. c:function:: unsigned long long PyLong_AsUnsignedLongLongMask(PyObject *obj) - Return a C :c:type:`unsigned long long` representation of *obj*. If *obj* + Return a C :c:expr:`unsigned long long` representation of *obj*. If *obj* is not an instance of :c:type:`PyLongObject`, first call its :meth:`__index__` method (if present) to convert it to a :c:type:`PyLongObject`. - If the value of *obj* is out of range for an :c:type:`unsigned long long`, + If the value of *obj* is out of range for an :c:expr:`unsigned long long`, return the reduction of that value modulo ``ULLONG_MAX + 1``. Returns ``(unsigned long long)-1`` on error. Use :c:func:`PyErr_Occurred` @@ -301,20 +301,20 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. c:function:: double PyLong_AsDouble(PyObject *pylong) - Return a C :c:type:`double` representation of *pylong*. *pylong* must be + Return a C :c:expr:`double` representation of *pylong*. *pylong* must be an instance of :c:type:`PyLongObject`. Raise :exc:`OverflowError` if the value of *pylong* is out of range for a - :c:type:`double`. + :c:expr:`double`. Returns ``-1.0`` on error. Use :c:func:`PyErr_Occurred` to disambiguate. .. c:function:: void* PyLong_AsVoidPtr(PyObject *pylong) - Convert a Python integer *pylong* to a C :c:type:`void` pointer. + Convert a Python integer *pylong* to a C :c:expr:`void` pointer. If *pylong* cannot be converted, an :exc:`OverflowError` will be raised. This - is only assured to produce a usable :c:type:`void` pointer for values created + is only assured to produce a usable :c:expr:`void` pointer for values created with :c:func:`PyLong_FromVoidPtr`. Returns ``NULL`` on error. Use :c:func:`PyErr_Occurred` to disambiguate. diff --git a/Doc/c-api/marshal.rst b/Doc/c-api/marshal.rst index 1ba18beb3ea0..8e25968c6909 100644 --- a/Doc/c-api/marshal.rst +++ b/Doc/c-api/marshal.rst @@ -21,9 +21,9 @@ unmarshalling. Version 2 uses a binary format for floating point numbers. .. c:function:: void PyMarshal_WriteLongToFile(long value, FILE *file, int version) - Marshal a :c:type:`long` integer, *value*, to *file*. This will only write + Marshal a :c:expr:`long` integer, *value*, to *file*. This will only write the least-significant 32 bits of *value*; regardless of the size of the - native :c:type:`long` type. *version* indicates the file format. + native :c:expr:`long` type. *version* indicates the file format. .. c:function:: void PyMarshal_WriteObjectToFile(PyObject *value, FILE *file, int version) @@ -43,9 +43,9 @@ The following functions allow marshalled values to be read back in. .. c:function:: long PyMarshal_ReadLongFromFile(FILE *file) - Return a C :c:type:`long` from the data stream in a :c:expr:`FILE*` opened + Return a C :c:expr:`long` from the data stream in a :c:expr:`FILE*` opened for reading. Only a 32-bit value can be read in using this function, - regardless of the native size of :c:type:`long`. + regardless of the native size of :c:expr:`long`. On error, sets the appropriate exception (:exc:`EOFError`) and returns ``-1``. @@ -53,9 +53,9 @@ The following functions allow marshalled values to be read back in. .. c:function:: int PyMarshal_ReadShortFromFile(FILE *file) - Return a C :c:type:`short` from the data stream in a :c:expr:`FILE*` opened + Return a C :c:expr:`short` from the data stream in a :c:expr:`FILE*` opened for reading. Only a 16-bit value can be read in using this function, - regardless of the native size of :c:type:`short`. + regardless of the native size of :c:expr:`short`. On error, sets the appropriate exception (:exc:`EOFError`) and returns ``-1``. diff --git a/Doc/c-api/memory.rst b/Doc/c-api/memory.rst index 4abbf340c5f4..f726cd48663b 100644 --- a/Doc/c-api/memory.rst +++ b/Doc/c-api/memory.rst @@ -141,7 +141,7 @@ zero bytes. .. c:function:: void* PyMem_RawMalloc(size_t n) - Allocates *n* bytes and returns a pointer of type :c:type:`void*` to the + Allocates *n* bytes and returns a pointer of type :c:expr:`void*` to the allocated memory, or ``NULL`` if the request fails. Requesting zero bytes returns a distinct non-``NULL`` pointer if possible, as @@ -152,7 +152,7 @@ zero bytes. .. c:function:: void* PyMem_RawCalloc(size_t nelem, size_t elsize) Allocates *nelem* elements each whose size in bytes is *elsize* and returns - a pointer of type :c:type:`void*` to the allocated memory, or ``NULL`` if the + a pointer of type :c:expr:`void*` to the allocated memory, or ``NULL`` if the request fails. The memory is initialized to zeros. Requesting zero elements or elements of size zero bytes returns a distinct @@ -212,7 +212,7 @@ The :ref:`default memory allocator ` uses the .. c:function:: void* PyMem_Malloc(size_t n) - Allocates *n* bytes and returns a pointer of type :c:type:`void*` to the + Allocates *n* bytes and returns a pointer of type :c:expr:`void*` to the allocated memory, or ``NULL`` if the request fails. Requesting zero bytes returns a distinct non-``NULL`` pointer if possible, as @@ -223,7 +223,7 @@ The :ref:`default memory allocator ` uses the .. c:function:: void* PyMem_Calloc(size_t nelem, size_t elsize) Allocates *nelem* elements each whose size in bytes is *elsize* and returns - a pointer of type :c:type:`void*` to the allocated memory, or ``NULL`` if the + a pointer of type :c:expr:`void*` to the allocated memory, or ``NULL`` if the request fails. The memory is initialized to zeros. Requesting zero elements or elements of size zero bytes returns a distinct @@ -320,7 +320,7 @@ The :ref:`default object allocator ` uses the .. c:function:: void* PyObject_Malloc(size_t n) - Allocates *n* bytes and returns a pointer of type :c:type:`void*` to the + Allocates *n* bytes and returns a pointer of type :c:expr:`void*` to the allocated memory, or ``NULL`` if the request fails. Requesting zero bytes returns a distinct non-``NULL`` pointer if possible, as @@ -331,7 +331,7 @@ The :ref:`default object allocator ` uses the .. c:function:: void* PyObject_Calloc(size_t nelem, size_t elsize) Allocates *nelem* elements each whose size in bytes is *elsize* and returns - a pointer of type :c:type:`void*` to the allocated memory, or ``NULL`` if the + a pointer of type :c:expr:`void*` to the allocated memory, or ``NULL`` if the request fails. The memory is initialized to zeros. Requesting zero elements or elements of size zero bytes returns a distinct diff --git a/Doc/c-api/sys.rst b/Doc/c-api/sys.rst index 11d5e0e03ec0..6fc8a3aff956 100644 --- a/Doc/c-api/sys.rst +++ b/Doc/c-api/sys.rst @@ -107,7 +107,7 @@ Operating System Utilities Return the current signal handler for signal *i*. This is a thin wrapper around either :c:func:`sigaction` or :c:func:`signal`. Do not call those functions - directly! :c:type:`PyOS_sighandler_t` is a typedef alias for :c:type:`void + directly! :c:type:`PyOS_sighandler_t` is a typedef alias for :c:expr:`void (\*)(int)`. @@ -116,7 +116,7 @@ Operating System Utilities Set the signal handler for signal *i* to be *h*; return the old signal handler. This is a thin wrapper around either :c:func:`sigaction` or :c:func:`signal`. Do not call those functions directly! :c:type:`PyOS_sighandler_t` is a typedef - alias for :c:type:`void (\*)(int)`. + alias for :c:expr:`void (\*)(int)`. .. c:function:: wchar_t* Py_DecodeLocale(const char* arg, size_t *size) @@ -379,7 +379,7 @@ accessible to C code. They all work with the current interpreter thread's silently abort the operation by raising an error subclassed from :class:`Exception` (other errors will not be silenced). - The hook function is of type :c:type:`int (*)(const char *event, PyObject + The hook function is of type :c:expr:`int (*)(const char *event, PyObject *args, void *userData)`, where *args* is guaranteed to be a :c:type:`PyTupleObject`. The hook function is always called with the GIL held by the Python interpreter that raised the event. diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst index ec9c5d089c57..f062f14e9a75 100644 --- a/Doc/c-api/unicode.rst +++ b/Doc/c-api/unicode.rst @@ -44,7 +44,7 @@ Python: .. c:type:: Py_UNICODE - This is a typedef of :c:type:`wchar_t`, which is a 16-bit type or 32-bit type + This is a typedef of :c:expr:`wchar_t`, which is a 16-bit type or 32-bit type depending on the platform. .. versionchanged:: 3.3 @@ -788,11 +788,11 @@ conversion function: wchar_t Support """"""""""""""" -:c:type:`wchar_t` support for platforms which support it: +:c:expr:`wchar_t` support for platforms which support it: .. c:function:: PyObject* PyUnicode_FromWideChar(const wchar_t *w, Py_ssize_t size) - Create a Unicode object from the :c:type:`wchar_t` buffer *w* of the given *size*. + Create a Unicode object from the :c:expr:`wchar_t` buffer *w* of the given *size*. Passing ``-1`` as the *size* indicates that the function must itself compute the length, using wcslen. Return ``NULL`` on failure. @@ -800,13 +800,13 @@ wchar_t Support .. c:function:: Py_ssize_t PyUnicode_AsWideChar(PyObject *unicode, wchar_t *w, Py_ssize_t size) - Copy the Unicode object contents into the :c:type:`wchar_t` buffer *w*. At most - *size* :c:type:`wchar_t` characters are copied (excluding a possibly trailing - null termination character). Return the number of :c:type:`wchar_t` characters - copied or ``-1`` in case of an error. Note that the resulting :c:type:`wchar_t*` + Copy the Unicode object contents into the :c:expr:`wchar_t` buffer *w*. At most + *size* :c:expr:`wchar_t` characters are copied (excluding a possibly trailing + null termination character). Return the number of :c:expr:`wchar_t` characters + copied or ``-1`` in case of an error. Note that the resulting :c:expr:`wchar_t*` string may or may not be null-terminated. It is the responsibility of the caller - to make sure that the :c:type:`wchar_t*` string is null-terminated in case this is - required by the application. Also, note that the :c:type:`wchar_t*` string + to make sure that the :c:expr:`wchar_t*` string is null-terminated in case this is + required by the application. Also, note that the :c:expr:`wchar_t*` string might contain null characters, which would cause the string to be truncated when used with most C functions. @@ -816,9 +816,9 @@ wchar_t Support Convert the Unicode object to a wide character string. The output string always ends with a null character. If *size* is not ``NULL``, write the number of wide characters (excluding the trailing null termination character) into - *\*size*. Note that the resulting :c:type:`wchar_t` string might contain + *\*size*. Note that the resulting :c:expr:`wchar_t` string might contain null characters, which would cause the string to be truncated when used with - most C functions. If *size* is ``NULL`` and the :c:type:`wchar_t*` string + most C functions. If *size* is ``NULL`` and the :c:expr:`wchar_t*` string contains null characters a :exc:`ValueError` is raised. Returns a buffer allocated by :c:func:`PyMem_New` (use @@ -829,7 +829,7 @@ wchar_t Support .. versionadded:: 3.2 .. versionchanged:: 3.7 - Raises a :exc:`ValueError` if *size* is ``NULL`` and the :c:type:`wchar_t*` + Raises a :exc:`ValueError` if *size* is ``NULL`` and the :c:expr:`wchar_t*` string contains null characters. diff --git a/Doc/extending/extending.rst b/Doc/extending/extending.rst index 0ef899f4c997..d9bf4fd6c7ae 100644 --- a/Doc/extending/extending.rst +++ b/Doc/extending/extending.rst @@ -298,7 +298,7 @@ In this case, it will return an integer object. (Yes, even integers are objects on the heap in Python!) If you have a C function that returns no useful argument (a function returning -:c:type:`void`), the corresponding Python function must return ``None``. You +:c:expr:`void`), the corresponding Python function must return ``None``. You need this idiom to do so (which is implemented by the :c:macro:`Py_RETURN_NONE` macro):: @@ -1171,7 +1171,7 @@ other extension modules must be exported in a different way. Python provides a special mechanism to pass C-level information (pointers) from one extension module to another one: Capsules. A Capsule is a Python data type -which stores a pointer (:c:type:`void \*`). Capsules can only be created and +which stores a pointer (:c:expr:`void \*`). Capsules can only be created and accessed via their C API, but they can be passed around like any other Python object. In particular, they can be assigned to a name in an extension module's namespace. Other extension modules can then import this module, retrieve the @@ -1185,7 +1185,7 @@ different ways between the module providing the code and the client modules. Whichever method you choose, it's important to name your Capsules properly. The function :c:func:`PyCapsule_New` takes a name parameter -(:c:type:`const char \*`); you're permitted to pass in a ``NULL`` name, but +(:c:expr:`const char \*`); you're permitted to pass in a ``NULL`` name, but we strongly encourage you to specify a name. Properly named Capsules provide a degree of runtime type-safety; there is no feasible way to tell one unnamed Capsule from another. @@ -1203,7 +1203,7 @@ of certainty that the Capsule they load contains the correct C API. The following example demonstrates an approach that puts most of the burden on the writer of the exporting module, which is appropriate for commonly used library modules. It stores all C API pointers (just one in the example!) in an -array of :c:type:`void` pointers which becomes the value of a Capsule. The header +array of :c:expr:`void` pointers which becomes the value of a Capsule. The header file corresponding to the module provides a macro that takes care of importing the module and retrieving its C API pointers; client modules only have to call this macro before accessing the C API. diff --git a/Doc/extending/newtypes.rst b/Doc/extending/newtypes.rst index b797dc2817c8..a076eae534b9 100644 --- a/Doc/extending/newtypes.rst +++ b/Doc/extending/newtypes.rst @@ -207,7 +207,7 @@ a special case, for which the new value passed to the handler is ``NULL``. Python supports two pairs of attribute handlers; a type that supports attributes only needs to implement the functions for one pair. The difference is that one -pair takes the name of the attribute as a :c:type:`char\*`, while the other +pair takes the name of the attribute as a :c:expr:`char\*`, while the other accepts a :c:type:`PyObject\*`. Each type can use whichever pair makes more sense for the implementation's convenience. :: @@ -339,8 +339,8 @@ of ``NULL`` is required. Type-specific Attribute Management ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -For simplicity, only the :c:type:`char\*` version will be demonstrated here; the -type of the name parameter is the only difference between the :c:type:`char\*` +For simplicity, only the :c:expr:`char\*` version will be demonstrated here; the +type of the name parameter is the only difference between the :c:expr:`char\*` and :c:type:`PyObject\*` flavors of the interface. This example effectively does the same thing as the generic example above, but does not use the generic support added in Python 2.2. It explains how the handler functions are diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index d4c52a27592a..4b6b26c991fd 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -196,9 +196,9 @@ calls). ``None``, integers, bytes objects and (unicode) strings are the only native Python objects that can directly be used as parameters in these function calls. ``None`` is passed as a C ``NULL`` pointer, bytes objects and strings are passed -as pointer to the memory block that contains their data (:c:type:`char *` or -:c:type:`wchar_t *`). Python integers are passed as the platforms default C -:c:type:`int` type, their value is masked to fit into the C type. +as pointer to the memory block that contains their data (:c:expr:`char *` or +:c:expr:`wchar_t *`). Python integers are passed as the platforms default C +:c:expr:`int` type, their value is masked to fit into the C type. Before we move on calling functions with other parameter types, we have to learn more about :mod:`ctypes` data types. @@ -214,51 +214,51 @@ Fundamental data types +----------------------+------------------------------------------+----------------------------+ | ctypes type | C type | Python type | +======================+==========================================+============================+ -| :class:`c_bool` | :c:type:`_Bool` | bool (1) | +| :class:`c_bool` | :c:expr:`_Bool` | bool (1) | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_char` | :c:type:`char` | 1-character bytes object | +| :class:`c_char` | :c:expr:`char` | 1-character bytes object | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_wchar` | :c:type:`wchar_t` | 1-character string | +| :class:`c_wchar` | :c:expr:`wchar_t` | 1-character string | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_byte` | :c:type:`char` | int | +| :class:`c_byte` | :c:expr:`char` | int | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_ubyte` | :c:type:`unsigned char` | int | +| :class:`c_ubyte` | :c:expr:`unsigned char` | int | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_short` | :c:type:`short` | int | +| :class:`c_short` | :c:expr:`short` | int | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_ushort` | :c:type:`unsigned short` | int | +| :class:`c_ushort` | :c:expr:`unsigned short` | int | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_int` | :c:type:`int` | int | +| :class:`c_int` | :c:expr:`int` | int | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_uint` | :c:type:`unsigned int` | int | +| :class:`c_uint` | :c:expr:`unsigned int` | int | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_long` | :c:type:`long` | int | +| :class:`c_long` | :c:expr:`long` | int | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_ulong` | :c:type:`unsigned long` | int | +| :class:`c_ulong` | :c:expr:`unsigned long` | int | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_longlong` | :c:type:`__int64` or :c:type:`long long` | int | +| :class:`c_longlong` | :c:expr:`__int64` or :c:expr:`long long` | int | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_ulonglong` | :c:type:`unsigned __int64` or | int | -| | :c:type:`unsigned long long` | | +| :class:`c_ulonglong` | :c:expr:`unsigned __int64` or | int | +| | :c:expr:`unsigned long long` | | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_size_t` | :c:type:`size_t` | int | +| :class:`c_size_t` | :c:expr:`size_t` | int | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_ssize_t` | :c:type:`ssize_t` or | int | -| | :c:type:`Py_ssize_t` | | +| :class:`c_ssize_t` | :c:expr:`ssize_t` or | int | +| | :c:expr:`Py_ssize_t` | | +----------------------+------------------------------------------+----------------------------+ | :class:`c_time_t` | :c:type:`time_t` | int | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_float` | :c:type:`float` | float | +| :class:`c_float` | :c:expr:`float` | float | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_double` | :c:type:`double` | float | +| :class:`c_double` | :c:expr:`double` | float | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_longdouble`| :c:type:`long double` | float | +| :class:`c_longdouble`| :c:expr:`long double` | float | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_char_p` | :c:type:`char *` (NUL terminated) | bytes object or ``None`` | +| :class:`c_char_p` | :c:expr:`char *` (NUL terminated) | bytes object or ``None`` | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_wchar_p` | :c:type:`wchar_t *` (NUL terminated) | string or ``None`` | +| :class:`c_wchar_p` | :c:expr:`wchar_t *` (NUL terminated) | string or ``None`` | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_void_p` | :c:type:`void *` | int or ``None`` | +| :class:`c_void_p` | :c:expr:`void *` | int or ``None`` | +----------------------+------------------------------------------+----------------------------+ (1) @@ -333,7 +333,7 @@ property:: The :func:`create_string_buffer` function replaces the old :func:`c_buffer` function (which is still available as an alias). To create a mutable memory -block containing unicode characters of the C type :c:type:`wchar_t`, use the +block containing unicode characters of the C type :c:expr:`wchar_t`, use the :func:`create_unicode_buffer` function. @@ -444,7 +444,7 @@ integer, string, bytes, a :mod:`ctypes` instance, or an object with an Return types ^^^^^^^^^^^^ -By default functions are assumed to return the C :c:type:`int` type. Other +By default functions are assumed to return the C :c:expr:`int` type. Other return types can be specified by setting the :attr:`restype` attribute of the function object. @@ -1337,7 +1337,7 @@ way is to instantiate one of the following classes: Instances of this class represent loaded shared libraries. Functions in these libraries use the standard C calling convention, and are assumed to return - :c:type:`int`. + :c:expr:`int`. On Windows creating a :class:`CDLL` instance may fail even if the DLL name exists. When a dependent DLL of the loaded DLL is not found, a @@ -1372,7 +1372,7 @@ way is to instantiate one of the following classes: Windows only: Instances of this class represent loaded shared libraries, functions in these libraries use the ``stdcall`` calling convention, and are - assumed to return :c:type:`int` by default. + assumed to return :c:expr:`int` by default. The Python :term:`global interpreter lock` is released before calling any function exported by these libraries, and reacquired afterwards. @@ -1528,7 +1528,7 @@ object is available: An instance of :class:`PyDLL` that exposes Python C API functions as attributes. Note that all these functions are assumed to return C - :c:type:`int`, which is of course not always the truth, so you have to assign + :c:expr:`int`, which is of course not always the truth, so you have to assign the correct :attr:`restype` attribute to use these functions. .. audit-event:: ctypes.dlopen name ctypes.LibraryLoader @@ -1574,10 +1574,10 @@ They are instances of a private class: .. attribute:: restype Assign a ctypes type to specify the result type of the foreign function. - Use ``None`` for :c:type:`void`, a function not returning anything. + Use ``None`` for :c:expr:`void`, a function not returning anything. It is possible to assign a callable Python object that is not a ctypes - type, in this case the function is assumed to return a C :c:type:`int`, and + type, in this case the function is assumed to return a C :c:expr:`int`, and the callable will be called with this integer, allowing further processing or error checking. Using this is deprecated, for more flexible post processing or error checking use a ctypes data type as @@ -2190,21 +2190,21 @@ These are the fundamental ctypes data types: .. class:: c_byte - Represents the C :c:type:`signed char` datatype, and interprets the value as + Represents the C :c:expr:`signed char` datatype, and interprets the value as small integer. The constructor accepts an optional integer initializer; no overflow checking is done. .. class:: c_char - Represents the C :c:type:`char` datatype, and interprets the value as a single + Represents the C :c:expr:`char` datatype, and interprets the value as a single character. The constructor accepts an optional string initializer, the length of the string must be exactly one character. .. class:: c_char_p - Represents the C :c:type:`char *` datatype when it points to a zero-terminated + Represents the C :c:expr:`char *` datatype when it points to a zero-terminated string. For a general character pointer that may also point to binary data, ``POINTER(c_char)`` must be used. The constructor accepts an integer address, or a bytes object. @@ -2212,68 +2212,68 @@ These are the fundamental ctypes data types: .. class:: c_double - Represents the C :c:type:`double` datatype. The constructor accepts an + Represents the C :c:expr:`double` datatype. The constructor accepts an optional float initializer. .. class:: c_longdouble - Represents the C :c:type:`long double` datatype. The constructor accepts an + Represents the C :c:expr:`long double` datatype. The constructor accepts an optional float initializer. On platforms where ``sizeof(long double) == sizeof(double)`` it is an alias to :class:`c_double`. .. class:: c_float - Represents the C :c:type:`float` datatype. The constructor accepts an + Represents the C :c:expr:`float` datatype. The constructor accepts an optional float initializer. .. class:: c_int - Represents the C :c:type:`signed int` datatype. The constructor accepts an + Represents the C :c:expr:`signed int` datatype. The constructor accepts an optional integer initializer; no overflow checking is done. On platforms where ``sizeof(int) == sizeof(long)`` it is an alias to :class:`c_long`. .. class:: c_int8 - Represents the C 8-bit :c:type:`signed int` datatype. Usually an alias for + Represents the C 8-bit :c:expr:`signed int` datatype. Usually an alias for :class:`c_byte`. .. class:: c_int16 - Represents the C 16-bit :c:type:`signed int` datatype. Usually an alias for + Represents the C 16-bit :c:expr:`signed int` datatype. Usually an alias for :class:`c_short`. .. class:: c_int32 - Represents the C 32-bit :c:type:`signed int` datatype. Usually an alias for + Represents the C 32-bit :c:expr:`signed int` datatype. Usually an alias for :class:`c_int`. .. class:: c_int64 - Represents the C 64-bit :c:type:`signed int` datatype. Usually an alias for + Represents the C 64-bit :c:expr:`signed int` datatype. Usually an alias for :class:`c_longlong`. .. class:: c_long - Represents the C :c:type:`signed long` datatype. The constructor accepts an + Represents the C :c:expr:`signed long` datatype. The constructor accepts an optional integer initializer; no overflow checking is done. .. class:: c_longlong - Represents the C :c:type:`signed long long` datatype. The constructor accepts + Represents the C :c:expr:`signed long long` datatype. The constructor accepts an optional integer initializer; no overflow checking is done. .. class:: c_short - Represents the C :c:type:`signed short` datatype. The constructor accepts an + Represents the C :c:expr:`signed short` datatype. The constructor accepts an optional integer initializer; no overflow checking is done. @@ -2298,83 +2298,83 @@ These are the fundamental ctypes data types: .. class:: c_ubyte - Represents the C :c:type:`unsigned char` datatype, it interprets the value as + Represents the C :c:expr:`unsigned char` datatype, it interprets the value as small integer. The constructor accepts an optional integer initializer; no overflow checking is done. .. class:: c_uint - Represents the C :c:type:`unsigned int` datatype. The constructor accepts an + Represents the C :c:expr:`unsigned int` datatype. The constructor accepts an optional integer initializer; no overflow checking is done. On platforms where ``sizeof(int) == sizeof(long)`` it is an alias for :class:`c_ulong`. .. class:: c_uint8 - Represents the C 8-bit :c:type:`unsigned int` datatype. Usually an alias for + Represents the C 8-bit :c:expr:`unsigned int` datatype. Usually an alias for :class:`c_ubyte`. .. class:: c_uint16 - Represents the C 16-bit :c:type:`unsigned int` datatype. Usually an alias for + Represents the C 16-bit :c:expr:`unsigned int` datatype. Usually an alias for :class:`c_ushort`. .. class:: c_uint32 - Represents the C 32-bit :c:type:`unsigned int` datatype. Usually an alias for + Represents the C 32-bit :c:expr:`unsigned int` datatype. Usually an alias for :class:`c_uint`. .. class:: c_uint64 - Represents the C 64-bit :c:type:`unsigned int` datatype. Usually an alias for + Represents the C 64-bit :c:expr:`unsigned int` datatype. Usually an alias for :class:`c_ulonglong`. .. class:: c_ulong - Represents the C :c:type:`unsigned long` datatype. The constructor accepts an + Represents the C :c:expr:`unsigned long` datatype. The constructor accepts an optional integer initializer; no overflow checking is done. .. class:: c_ulonglong - Represents the C :c:type:`unsigned long long` datatype. The constructor + Represents the C :c:expr:`unsigned long long` datatype. The constructor accepts an optional integer initializer; no overflow checking is done. .. class:: c_ushort - Represents the C :c:type:`unsigned short` datatype. The constructor accepts + Represents the C :c:expr:`unsigned short` datatype. The constructor accepts an optional integer initializer; no overflow checking is done. .. class:: c_void_p - Represents the C :c:type:`void *` type. The value is represented as integer. + Represents the C :c:expr:`void *` type. The value is represented as integer. The constructor accepts an optional integer initializer. .. class:: c_wchar - Represents the C :c:type:`wchar_t` datatype, and interprets the value as a + Represents the C :c:expr:`wchar_t` datatype, and interprets the value as a single character unicode string. The constructor accepts an optional string initializer, the length of the string must be exactly one character. .. class:: c_wchar_p - Represents the C :c:type:`wchar_t *` datatype, which must be a pointer to a + Represents the C :c:expr:`wchar_t *` datatype, which must be a pointer to a zero-terminated wide character string. The constructor accepts an integer address, or a string. .. class:: c_bool - Represent the C :c:type:`bool` datatype (more accurately, :c:type:`_Bool` from + Represent the C :c:expr:`bool` datatype (more accurately, :c:expr:`_Bool` from C99). Its value can be ``True`` or ``False``, and the constructor accepts any object that has a truth value. diff --git a/Doc/library/posix.rst b/Doc/library/posix.rst index 90be191aa2f8..ec04b0dcfc16 100644 --- a/Doc/library/posix.rst +++ b/Doc/library/posix.rst @@ -39,12 +39,12 @@ Large File Support Several operating systems (including AIX and Solaris) provide support for files that are larger than 2 GiB from a C programming model where -:c:type:`int` and :c:type:`long` are 32-bit values. This is typically accomplished +:c:expr:`int` and :c:expr:`long` are 32-bit values. This is typically accomplished by defining the relevant size and offset types as 64-bit values. Such files are sometimes referred to as :dfn:`large files`. Large file support is enabled in Python when the size of an :c:type:`off_t` is -larger than a :c:type:`long` and the :c:type:`long long` is at least as large +larger than a :c:expr:`long` and the :c:expr:`long long` is at least as large as an :c:type:`off_t`. It may be necessary to configure and compile Python with certain compiler flags to enable this mode. For example, with Solaris 2.6 and 2.7 you need to do diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst index 1a9e5fee77b7..ee0c68e3a707 100644 --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -1612,7 +1612,7 @@ to sockets. ancillary data, items of the form ``(socket.SOL_SOCKET, socket.SCM_RIGHTS, fds)``, where *fds* is a :class:`bytes` object representing the new file descriptors as a binary array of the - native C :c:type:`int` type. If :meth:`recvmsg` raises an + native C :c:expr:`int` type. If :meth:`recvmsg` raises an exception after the system call returns, it will first attempt to close any file descriptors received via this mechanism. diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index ad4b90bf21d8..2952c50787ad 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -215,7 +215,7 @@ Numeric Types --- :class:`int`, :class:`float`, :class:`complex` There are three distinct numeric types: :dfn:`integers`, :dfn:`floating point numbers`, and :dfn:`complex numbers`. In addition, Booleans are a subtype of integers. Integers have unlimited precision. Floating point -numbers are usually implemented using :c:type:`double` in C; information +numbers are usually implemented using :c:expr:`double` in C; information about the precision and internal representation of floating point numbers for the machine on which your program is running is available in :data:`sys.float_info`. Complex numbers have a real and imaginary diff --git a/Doc/library/struct.rst b/Doc/library/struct.rst index c1888d4a94fe..d12a5732fa4a 100644 --- a/Doc/library/struct.rst +++ b/Doc/library/struct.rst @@ -196,46 +196,46 @@ platform-dependent. +========+==========================+====================+================+============+ | ``x`` | pad byte | no value | | | +--------+--------------------------+--------------------+----------------+------------+ -| ``c`` | :c:type:`char` | bytes of length 1 | 1 | | +| ``c`` | :c:expr:`char` | bytes of length 1 | 1 | | +--------+--------------------------+--------------------+----------------+------------+ -| ``b`` | :c:type:`signed char` | integer | 1 | \(1), \(2) | +| ``b`` | :c:expr:`signed char` | integer | 1 | \(1), \(2) | +--------+--------------------------+--------------------+----------------+------------+ -| ``B`` | :c:type:`unsigned char` | integer | 1 | \(2) | +| ``B`` | :c:expr:`unsigned char` | integer | 1 | \(2) | +--------+--------------------------+--------------------+----------------+------------+ -| ``?`` | :c:type:`_Bool` | bool | 1 | \(1) | +| ``?`` | :c:expr:`_Bool` | bool | 1 | \(1) | +--------+--------------------------+--------------------+----------------+------------+ -| ``h`` | :c:type:`short` | integer | 2 | \(2) | +| ``h`` | :c:expr:`short` | integer | 2 | \(2) | +--------+--------------------------+--------------------+----------------+------------+ -| ``H`` | :c:type:`unsigned short` | integer | 2 | \(2) | +| ``H`` | :c:expr:`unsigned short` | integer | 2 | \(2) | +--------+--------------------------+--------------------+----------------+------------+ -| ``i`` | :c:type:`int` | integer | 4 | \(2) | +| ``i`` | :c:expr:`int` | integer | 4 | \(2) | +--------+--------------------------+--------------------+----------------+------------+ -| ``I`` | :c:type:`unsigned int` | integer | 4 | \(2) | +| ``I`` | :c:expr:`unsigned int` | integer | 4 | \(2) | +--------+--------------------------+--------------------+----------------+------------+ -| ``l`` | :c:type:`long` | integer | 4 | \(2) | +| ``l`` | :c:expr:`long` | integer | 4 | \(2) | +--------+--------------------------+--------------------+----------------+------------+ -| ``L`` | :c:type:`unsigned long` | integer | 4 | \(2) | +| ``L`` | :c:expr:`unsigned long` | integer | 4 | \(2) | +--------+--------------------------+--------------------+----------------+------------+ -| ``q`` | :c:type:`long long` | integer | 8 | \(2) | +| ``q`` | :c:expr:`long long` | integer | 8 | \(2) | +--------+--------------------------+--------------------+----------------+------------+ -| ``Q`` | :c:type:`unsigned long | integer | 8 | \(2) | +| ``Q`` | :c:expr:`unsigned long | integer | 8 | \(2) | | | long` | | | | +--------+--------------------------+--------------------+----------------+------------+ -| ``n`` | :c:type:`ssize_t` | integer | | \(3) | +| ``n`` | :c:expr:`ssize_t` | integer | | \(3) | +--------+--------------------------+--------------------+----------------+------------+ -| ``N`` | :c:type:`size_t` | integer | | \(3) | +| ``N`` | :c:expr:`size_t` | integer | | \(3) | +--------+--------------------------+--------------------+----------------+------------+ | ``e`` | \(6) | float | 2 | \(4) | +--------+--------------------------+--------------------+----------------+------------+ -| ``f`` | :c:type:`float` | float | 4 | \(4) | +| ``f`` | :c:expr:`float` | float | 4 | \(4) | +--------+--------------------------+--------------------+----------------+------------+ -| ``d`` | :c:type:`double` | float | 8 | \(4) | +| ``d`` | :c:expr:`double` | float | 8 | \(4) | +--------+--------------------------+--------------------+----------------+------------+ -| ``s`` | :c:type:`char[]` | bytes | | | +| ``s`` | :c:expr:`char[]` | bytes | | | +--------+--------------------------+--------------------+----------------+------------+ -| ``p`` | :c:type:`char[]` | bytes | | | +| ``p`` | :c:expr:`char[]` | bytes | | | +--------+--------------------------+--------------------+----------------+------------+ -| ``P`` | :c:type:`void \*` | integer | | \(5) | +| ``P`` | :c:expr:`void \*` | integer | | \(5) | +--------+--------------------------+--------------------+----------------+------------+ .. versionchanged:: 3.3 @@ -250,8 +250,8 @@ Notes: (1) .. index:: single: ? (question mark); in struct format strings - The ``'?'`` conversion code corresponds to the :c:type:`_Bool` type defined by - C99. If this type is not available, it is simulated using a :c:type:`char`. In + The ``'?'`` conversion code corresponds to the :c:expr:`_Bool` type defined by + C99. If this type is not available, it is simulated using a :c:expr:`char`. In standard mode, it is always represented by one byte. (2) diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index c93269ab04b6..9dacd66ee564 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -316,7 +316,7 @@ Sequences A string is a sequence of values that represent Unicode code points. All the code points in the range ``U+0000 - U+10FFFF`` can be - represented in a string. Python doesn't have a :c:type:`char` type; + represented in a string. Python doesn't have a :c:expr:`char` type; instead, every code point in the string is represented as a string object with length ``1``. The built-in function :func:`ord` converts a code point from its string form to an integer in the diff --git a/Doc/whatsnew/2.2.rst b/Doc/whatsnew/2.2.rst index 9355c1badaa2..bfb2aacbc077 100644 --- a/Doc/whatsnew/2.2.rst +++ b/Doc/whatsnew/2.2.rst @@ -983,7 +983,7 @@ New and Improved Modules Jun-ichiro "itojun" Hagino.) * Two new format characters were added to the :mod:`struct` module for 64-bit - integers on platforms that support the C :c:type:`long long` type. ``q`` is for + integers on platforms that support the C :c:expr:`long long` type. ``q`` is for a signed 64-bit integer, and ``Q`` is for an unsigned one. The value is returned in Python's long integer type. (Contributed by Tim Peters.) diff --git a/Doc/whatsnew/2.3.rst b/Doc/whatsnew/2.3.rst index 27a0756cbb84..c6e2003e92f1 100644 --- a/Doc/whatsnew/2.3.rst +++ b/Doc/whatsnew/2.3.rst @@ -1905,8 +1905,8 @@ Changes to Python's build process and to the C API include: "")`` instead, but this will be slower than using :const:`METH_NOARGS`. * :c:func:`PyArg_ParseTuple` accepts new format characters for various sizes of - unsigned integers: ``B`` for :c:type:`unsigned char`, ``H`` for :c:type:`unsigned - short int`, ``I`` for :c:type:`unsigned int`, and ``K`` for :c:type:`unsigned + unsigned integers: ``B`` for :c:expr:`unsigned char`, ``H`` for :c:expr:`unsigned + short int`, ``I`` for :c:expr:`unsigned int`, and ``K`` for :c:expr:`unsigned long long`. * A new function, ``PyObject_DelItemString(mapping, char *key)`` was added diff --git a/Doc/whatsnew/2.4.rst b/Doc/whatsnew/2.4.rst index 61f9eb43243c..63e819876ce3 100644 --- a/Doc/whatsnew/2.4.rst +++ b/Doc/whatsnew/2.4.rst @@ -472,7 +472,7 @@ PEP 327: Decimal Data Type ========================== Python has always supported floating-point (FP) numbers, based on the underlying -C :c:type:`double` type, as a data type. However, while most programming +C :c:expr:`double` type, as a data type. However, while most programming languages provide a floating-point type, many people (even programmers) are unaware that floating-point numbers don't represent certain decimal fractions accurately. The new :class:`Decimal` type can represent these fractions @@ -501,7 +501,7 @@ mantissa is multiplied by 4 (2 to the power of the exponent 2); 1.25 \* 4 equals 5. Modern systems usually provide floating-point support that conforms to a -standard called IEEE 754. C's :c:type:`double` type is usually implemented as a +standard called IEEE 754. C's :c:expr:`double` type is usually implemented as a 64-bit IEEE 754 number, which uses 52 bits of space for the mantissa. This means that numbers can only be specified to 52 bits of precision. If you're trying to represent numbers whose expansion repeats endlessly, the expansion is @@ -750,10 +750,10 @@ The solution described in the PEP is to add three new functions to the Python API that perform ASCII-only conversions, ignoring the locale setting: * ``PyOS_ascii_strtod(str, ptr)`` and ``PyOS_ascii_atof(str, ptr)`` - both convert a string to a C :c:type:`double`. + both convert a string to a C :c:expr:`double`. * ``PyOS_ascii_formatd(buffer, buf_len, format, d)`` converts a - :c:type:`double` to an ASCII string. + :c:expr:`double` to an ASCII string. The code for these functions came from the GLib library (https://developer.gnome.org/glib/stable/), whose developers kindly diff --git a/Doc/whatsnew/2.5.rst b/Doc/whatsnew/2.5.rst index dfa8f7e93f81..0aca2fe697cc 100644 --- a/Doc/whatsnew/2.5.rst +++ b/Doc/whatsnew/2.5.rst @@ -872,18 +872,18 @@ PEP 353: Using ssize_t as the index type ======================================== A wide-ranging change to Python's C API, using a new :c:type:`Py_ssize_t` type -definition instead of :c:type:`int`, will permit the interpreter to handle more +definition instead of :c:expr:`int`, will permit the interpreter to handle more data on 64-bit platforms. This change doesn't affect Python's capacity on 32-bit platforms. -Various pieces of the Python interpreter used C's :c:type:`int` type to store +Various pieces of the Python interpreter used C's :c:expr:`int` type to store sizes or counts; for example, the number of items in a list or tuple were stored -in an :c:type:`int`. The C compilers for most 64-bit platforms still define -:c:type:`int` as a 32-bit type, so that meant that lists could only hold up to +in an :c:expr:`int`. The C compilers for most 64-bit platforms still define +:c:expr:`int` as a 32-bit type, so that meant that lists could only hold up to ``2**31 - 1`` = 2147483647 items. (There are actually a few different programming models that 64-bit C compilers can use -- see https://unix.org/version2/whatsnew/lp64_wp.html for a discussion -- but the -most commonly available model leaves :c:type:`int` as 32 bits.) +most commonly available model leaves :c:expr:`int` as 32 bits.) A limit of 2147483647 items doesn't really matter on a 32-bit platform because you'll run out of memory before hitting the length limit. Each list item @@ -895,7 +895,7 @@ It's possible to address that much memory on a 64-bit platform, however. The pointers for a list that size would only require 16 GiB of space, so it's not unreasonable that Python programmers might construct lists that large. Therefore, the Python interpreter had to be changed to use some type other than -:c:type:`int`, and this will be a 64-bit type on 64-bit platforms. The change +:c:expr:`int`, and this will be a 64-bit type on 64-bit platforms. The change will cause incompatibilities on 64-bit machines, so it was deemed worth making the transition now, while the number of 64-bit users is still relatively small. (In 5 or 10 years, we may *all* be on 64-bit machines, and the transition would @@ -909,7 +909,7 @@ may therefore need to have some variables changed to :c:type:`Py_ssize_t`. The :c:func:`PyArg_ParseTuple` and :c:func:`Py_BuildValue` functions have a new conversion code, ``n``, for :c:type:`Py_ssize_t`. :c:func:`PyArg_ParseTuple`'s -``s#`` and ``t#`` still output :c:type:`int` by default, but you can define the +``s#`` and ``t#`` still output :c:expr:`int` by default, but you can define the macro :c:macro:`PY_SSIZE_T_CLEAN` before including :file:`Python.h` to make them return :c:type:`Py_ssize_t`. @@ -1695,7 +1695,7 @@ attributes of the :class:`CDLL` object. :: result = libc.printf("Line of output\n") Type constructors for the various C types are provided: :func:`c_int`, -:func:`c_float`, :func:`c_double`, :func:`c_char_p` (equivalent to :c:type:`char +:func:`c_float`, :func:`c_double`, :func:`c_char_p` (equivalent to :c:expr:`char \*`), and so forth. Unlike Python's types, the C versions are all mutable; you can assign to their :attr:`value` attribute to change the wrapped value. Python integers and strings will be automatically converted to the corresponding C @@ -2093,7 +2093,7 @@ Changes to Python's build process and to the C API include: * The largest change to the C API came from :pep:`353`, which modifies the interpreter to use a :c:type:`Py_ssize_t` type definition instead of - :c:type:`int`. See the earlier section :ref:`pep-353` for a discussion of this + :c:expr:`int`. See the earlier section :ref:`pep-353` for a discussion of this change. * The design of the bytecode compiler has changed a great deal, no longer @@ -2264,7 +2264,7 @@ code: Setting :attr:`rpc_paths` to ``None`` or an empty tuple disables this path checking. -* C API: Many functions now use :c:type:`Py_ssize_t` instead of :c:type:`int` to +* C API: Many functions now use :c:type:`Py_ssize_t` instead of :c:expr:`int` to allow processing more data on 64-bit machines. Extension code may need to make the same change to avoid warnings and to support 64-bit machines. See the earlier section :ref:`pep-353` for a discussion of this change. diff --git a/Doc/whatsnew/2.6.rst b/Doc/whatsnew/2.6.rst index 5a3c103f29a7..731ce6aac691 100644 --- a/Doc/whatsnew/2.6.rst +++ b/Doc/whatsnew/2.6.rst @@ -2389,7 +2389,7 @@ changes, or look through the Subversion logs for all the details. has been updated from version 2.3.2 in Python 2.5 to version 2.4.1. -* The :mod:`struct` module now supports the C99 :c:type:`_Bool` type, +* The :mod:`struct` module now supports the C99 :c:expr:`_Bool` type, using the format character ``'?'``. (Contributed by David Remahl.) diff --git a/Doc/whatsnew/2.7.rst b/Doc/whatsnew/2.7.rst index 01f140dac8ae..e8f701d254cd 100644 --- a/Doc/whatsnew/2.7.rst +++ b/Doc/whatsnew/2.7.rst @@ -2144,7 +2144,7 @@ Changes to Python's build process and to the C API include: * New functions: :c:func:`PyLong_AsLongAndOverflow` and :c:func:`PyLong_AsLongLongAndOverflow` approximates a Python long - integer as a C :c:type:`long` or :c:type:`long long`. + integer as a C :c:expr:`long` or :c:expr:`long long`. If the number is too large to fit into the output type, an *overflow* flag is set and returned to the caller. (Contributed by Case Van Horsen; :issue:`7528` and :issue:`7767`.) @@ -2202,7 +2202,7 @@ Changes to Python's build process and to the C API include: * New format codes: the :c:func:`PyFormat_FromString`, :c:func:`PyFormat_FromStringV`, and :c:func:`PyErr_Format` functions now accept ``%lld`` and ``%llu`` format codes for displaying - C's :c:type:`long long` types. + C's :c:expr:`long long` types. (Contributed by Mark Dickinson; :issue:`7228`.) * The complicated interaction between threads and process forking has diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst index 609370bad274..fef1a8ac4c01 100644 --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -932,7 +932,7 @@ it can now be used as a class decorator (:issue:`10868`). array ----- -The :mod:`array` module supports the :c:type:`long long` type using ``q`` and +The :mod:`array` module supports the :c:expr:`long long` type using ``q`` and ``Q`` type codes. (Contributed by Oren Tirosh and Hirokazu Yamamoto in :issue:`1172711`.) diff --git a/Doc/whatsnew/3.7.rst b/Doc/whatsnew/3.7.rst index 908f26823c12..f06cf29c713f 100644 --- a/Doc/whatsnew/3.7.rst +++ b/Doc/whatsnew/3.7.rst @@ -290,21 +290,21 @@ PEP 539: New C API for Thread-Local Storage While Python provides a C API for thread-local storage support; the existing :ref:`Thread Local Storage (TLS) API ` has used -:c:type:`int` to represent TLS keys across all platforms. This has not +:c:expr:`int` to represent TLS keys across all platforms. This has not generally been a problem for officially support platforms, but that is neither POSIX-compliant, nor portable in any practical sense. :pep:`539` changes this by providing a new :ref:`Thread Specific Storage (TSS) API ` to CPython which supersedes use of the existing TLS API within the CPython interpreter, while deprecating the existing -API. The TSS API uses a new type :c:type:`Py_tss_t` instead of :c:type:`int` +API. The TSS API uses a new type :c:type:`Py_tss_t` instead of :c:expr:`int` to represent TSS keys--an opaque type the definition of which may depend on the underlying TLS implementation. Therefore, this will allow to build CPython on platforms where the native TLS key is defined in a way that cannot be safely -cast to :c:type:`int`. +cast to :c:expr:`int`. Note that on platforms where the native TLS key is defined in a way that cannot -be safely cast to :c:type:`int`, all functions of the existing TLS API will be +be safely cast to :c:expr:`int`, all functions of the existing TLS API will be no-op and immediately return failure. This indicates clearly that the old API is not supported on platforms where it cannot be used reliably, and that no effort will be made to add such support. @@ -1708,12 +1708,12 @@ Contributed by Paul Ganssle in :issue:`10381`. The type of results of :c:func:`PyThread_start_new_thread` and :c:func:`PyThread_get_thread_ident`, and the *id* parameter of -:c:func:`PyThreadState_SetAsyncExc` changed from :c:type:`long` to -:c:type:`unsigned long`. +:c:func:`PyThreadState_SetAsyncExc` changed from :c:expr:`long` to +:c:expr:`unsigned long`. (Contributed by Serhiy Storchaka in :issue:`6532`.) :c:func:`PyUnicode_AsWideCharString` now raises a :exc:`ValueError` if the -second argument is ``NULL`` and the :c:type:`wchar_t*` string contains null +second argument is ``NULL`` and the :c:expr:`wchar_t*` string contains null characters. (Contributed by Serhiy Storchaka in :issue:`30708`.) Changes to the startup sequence and the management of dynamic memory diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index 6deaede4953b..ff01a6577299 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -773,7 +773,7 @@ Optimizations Stinner in :issue:`38061`.) * :c:func:`PyLong_FromDouble` is now up to 1.87x faster for values that - fit into :c:type:`long`. + fit into :c:expr:`long`. (Contributed by Sergey Fedoseev in :issue:`37986`.) * A number of Python builtins (:class:`range`, :class:`tuple`, :class:`set`, diff --git a/Misc/NEWS.d/3.5.0a1.rst b/Misc/NEWS.d/3.5.0a1.rst index 97bdef6c9321..96e59206cb12 100644 --- a/Misc/NEWS.d/3.5.0a1.rst +++ b/Misc/NEWS.d/3.5.0a1.rst @@ -3034,7 +3034,7 @@ by Phil Elson. .. nonce: LK_5S1 .. section: Library -os.read() now uses a :c:func:`Py_ssize_t` type instead of :c:type:`int` for +os.read() now uses a :c:func:`Py_ssize_t` type instead of :c:expr:`int` for the size to support reading more than 2 GB at once. On Windows, the size is truncated to INT_MAX. As any call to os.read(), the OS may read less bytes than the number of requested bytes. diff --git a/Misc/NEWS.d/3.9.0a1.rst b/Misc/NEWS.d/3.9.0a1.rst index eace8755a0d1..633620583838 100644 --- a/Misc/NEWS.d/3.9.0a1.rst +++ b/Misc/NEWS.d/3.9.0a1.rst @@ -1510,7 +1510,7 @@ asynchronous magic methods on a MagicMock now return an AsyncMock. .. section: Library Update the *length* parameter of :func:`os.pread` to accept -:c:type:`Py_ssize_t` instead of :c:type:`int`. +:c:type:`Py_ssize_t` instead of :c:expr:`int`. .. diff --git a/Misc/NEWS.d/3.9.0b1.rst b/Misc/NEWS.d/3.9.0b1.rst index 529be0eba586..a7f52f81a5cd 100644 --- a/Misc/NEWS.d/3.9.0b1.rst +++ b/Misc/NEWS.d/3.9.0b1.rst @@ -191,7 +191,7 @@ internal subinterpreters module. .. section: Core and Builtins Improve performance of :c:func:`PyLong_FromDouble` for values that fit into -:c:type:`long`. +:c:expr:`long`. .. From webhook-mailer at python.org Wed Oct 5 14:17:06 2022 From: webhook-mailer at python.org (nanjekyejoannah) Date: Wed, 05 Oct 2022 18:17:06 -0000 Subject: [Python-checkins] I changed my surname early this year (#96671) Message-ID: https://github.com/python/cpython/commit/815008a3a54a07c8523f9db35492b1750e104900 commit: 815008a3a54a07c8523f9db35492b1750e104900 branch: main author: Tshepang Mbambo committer: nanjekyejoannah <33177550+nanjekyejoannah at users.noreply.github.com> date: 2022-10-05T11:16:45-07:00 summary: I changed my surname early this year (#96671) * I recently changed my name * Update ACKS files: M Doc/howto/argparse.rst M Misc/ACKS diff --git a/Doc/howto/argparse.rst b/Doc/howto/argparse.rst index 3075b0142d16..f3ad117a3d3b 100644 --- a/Doc/howto/argparse.rst +++ b/Doc/howto/argparse.rst @@ -2,7 +2,7 @@ Argparse Tutorial ***************** -:author: Tshepang Lekhonkhobe +:author: Tshepang Mbambo .. _argparse-tutorial: diff --git a/Misc/ACKS b/Misc/ACKS index 6a14b546f691..ec5e326847b8 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1049,7 +1049,7 @@ Robert Lehmann Petri Lehtinen Luke Kenneth Casson Leighton John Leitch -Tshepang Lekhonkhobe +Tshepang Mbambo Marc-Andr? Lemburg Mateusz Lenik John Lenton From webhook-mailer at python.org Wed Oct 5 14:39:30 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 05 Oct 2022 18:39:30 -0000 Subject: [Python-checkins] gh-91539: improve performance of get_proxies_environment (GH-91566) Message-ID: https://github.com/python/cpython/commit/ac2427eeffef73d9c6d83fe35c50244d348e53e3 commit: ac2427eeffef73d9c6d83fe35c50244d348e53e3 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-05T11:39:24-07:00 summary: gh-91539: improve performance of get_proxies_environment (GH-91566) * improve performance of get_proxies_environment when there are many environment variables * ?? Added by blurb_it. * fix case of short env name * fix formatting * fix whitespace * whitespace * Update Lib/urllib/request.py Co-authored-by: Carl Meyer * Update Lib/urllib/request.py Co-authored-by: Carl Meyer * Update Lib/urllib/request.py Co-authored-by: Carl Meyer * Update Lib/urllib/request.py Co-authored-by: Carl Meyer * whitespace * Update Misc/NEWS.d/next/Library/2022-04-15-11-29-38.gh-issue-91539.7WgVuA.rst Co-authored-by: Carl Meyer * Update Lib/urllib/request.py Co-authored-by: Carl Meyer Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Carl Meyer (cherry picked from commit aeb28f51304ebe2ad9fd6a61b6e4e5a03d288aa1) Co-authored-by: Pieter Eendebak files: A Misc/NEWS.d/next/Library/2022-04-15-11-29-38.gh-issue-91539.7WgVuA.rst M Lib/urllib/request.py diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py index a0ef60b30de9..320163be63ad 100644 --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -2492,28 +2492,34 @@ def getproxies_environment(): this seems to be the standard convention. If you need a different way, you can pass a proxies dictionary to the [Fancy]URLopener constructor. - """ - proxies = {} # in order to prefer lowercase variables, process environment in # two passes: first matches any, second pass matches lowercase only - for name, value in os.environ.items(): - name = name.lower() - if value and name[-6:] == '_proxy': - proxies[name[:-6]] = value + + # select only environment variables which end in (after making lowercase) _proxy + proxies = {} + environment = [] + for name in os.environ.keys(): + # fast screen underscore position before more expensive case-folding + if len(name) > 5 and name[-6] == "_" and name[-5:].lower() == "proxy": + value = os.environ[name] + proxy_name = name[:-6].lower() + environment.append((name, value, proxy_name)) + if value: + proxies[proxy_name] = value # CVE-2016-1000110 - If we are running as CGI script, forget HTTP_PROXY # (non-all-lowercase) as it may be set from the web server by a "Proxy:" # header from the client # If "proxy" is lowercase, it will still be used thanks to the next block if 'REQUEST_METHOD' in os.environ: proxies.pop('http', None) - for name, value in os.environ.items(): + for name, value, proxy_name in environment: + # not case-folded, checking here for lower-case env vars only if name[-6:] == '_proxy': - name = name.lower() if value: - proxies[name[:-6]] = value + proxies[proxy_name] = value else: - proxies.pop(name[:-6], None) + proxies.pop(proxy_name, None) return proxies def proxy_bypass_environment(host, proxies=None): diff --git a/Misc/NEWS.d/next/Library/2022-04-15-11-29-38.gh-issue-91539.7WgVuA.rst b/Misc/NEWS.d/next/Library/2022-04-15-11-29-38.gh-issue-91539.7WgVuA.rst new file mode 100644 index 000000000000..16d61f1b9110 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-04-15-11-29-38.gh-issue-91539.7WgVuA.rst @@ -0,0 +1 @@ +Improve performance of ``urllib.request.getproxies_environment`` when there are many environment variables From webhook-mailer at python.org Wed Oct 5 14:42:35 2022 From: webhook-mailer at python.org (warsaw) Date: Wed, 05 Oct 2022 18:42:35 -0000 Subject: [Python-checkins] gh-97850: Remove all known instances of module_repr() (#97876) Message-ID: https://github.com/python/cpython/commit/5dc35991356306055ab2d85b886881ffd6577ae1 commit: 5dc35991356306055ab2d85b886881ffd6577ae1 branch: main author: Barry Warsaw committer: warsaw date: 2022-10-05T11:42:26-07:00 summary: gh-97850: Remove all known instances of module_repr() (#97876) Remove all known instances of module_repr() files: A Misc/NEWS.d/next/Core and Builtins/2022-10-04-17-02-18.gh-issue-97850.E3QTRA.rst M Doc/whatsnew/3.12.rst M Lib/importlib/_bootstrap.py M Lib/test/test_importlib/frozen/test_loader.py M Lib/test/test_importlib/test_abc.py M Lib/test/test_module.py diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 62ec2de2e78c..2e9515d036e7 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -426,6 +426,11 @@ Removed Validation. (Contributed by Victor Stinner in :gh:`94199`.) +* Many previously deprecated cleanups in :mod:`importlib` have now been + completed: + + * References to, and support for ``module_repr()`` has been eradicated. + Porting to Python 3.12 ====================== diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py index 67989c500f21..5d3c9fe3fbd2 100644 --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -728,17 +728,6 @@ class BuiltinImporter: _ORIGIN = "built-in" - @staticmethod - def module_repr(module): - """Return repr for the module. - - The method is deprecated. The import machinery does the job itself. - - """ - _warnings.warn("BuiltinImporter.module_repr() is deprecated and " - "slated for removal in Python 3.12", DeprecationWarning) - return f'' - @classmethod def find_spec(cls, fullname, path=None, target=None): if path is not None: @@ -808,17 +797,6 @@ class FrozenImporter: _ORIGIN = "frozen" - @staticmethod - def module_repr(m): - """Return repr for the module. - - The method is deprecated. The import machinery does the job itself. - - """ - _warnings.warn("FrozenImporter.module_repr() is deprecated and " - "slated for removal in Python 3.12", DeprecationWarning) - return ''.format(m.__name__, FrozenImporter._ORIGIN) - @classmethod def _fix_up_module(cls, module): spec = module.__spec__ diff --git a/Lib/test/test_importlib/frozen/test_loader.py b/Lib/test/test_importlib/frozen/test_loader.py index 32f951cb1aca..da1569e3d068 100644 --- a/Lib/test/test_importlib/frozen/test_loader.py +++ b/Lib/test/test_importlib/frozen/test_loader.py @@ -103,7 +103,7 @@ def test_lacking_parent(self): expected=value)) self.assertEqual(output, 'Hello world!\n') - def test_module_repr_indirect(self): + def test_module_repr_indirect_through_spec(self): name = '__hello__' module, output = self.exec_module(name) self.assertEqual(repr(module), @@ -190,13 +190,6 @@ def test_module_reuse(self): self.assertEqual(stdout.getvalue(), 'Hello world!\nHello world!\n') - def test_module_repr(self): - with fresh('__hello__', oldapi=True): - module = self.machinery.FrozenImporter.load_module('__hello__') - repr_str = self.machinery.FrozenImporter.module_repr(module) - self.assertEqual(repr_str, - "") - # No way to trigger an error in a frozen module. test_state_after_failure = None diff --git a/Lib/test/test_importlib/test_abc.py b/Lib/test/test_importlib/test_abc.py index c214209350a0..8641b6cc6830 100644 --- a/Lib/test/test_importlib/test_abc.py +++ b/Lib/test/test_importlib/test_abc.py @@ -687,9 +687,6 @@ def get_data(self, path): def get_filename(self, fullname): return self.path - def module_repr(self, module): - return '' - SPLIT_SOL = make_abc_subclasses(SourceOnlyLoader, 'SourceLoader') diff --git a/Lib/test/test_module.py b/Lib/test/test_module.py index 6c83d76c8e3c..70e4efea6935 100644 --- a/Lib/test/test_module.py +++ b/Lib/test/test_module.py @@ -239,7 +239,6 @@ def test_module_repr_with_full_loader(self): repr(m), ")>") def test_module_repr_with_bare_loader_and_filename(self): - # Because the loader has no module_repr(), use the file name. m = ModuleType('foo') # Yes, a class not an instance. m.__loader__ = BareLoader @@ -247,7 +246,6 @@ def test_module_repr_with_bare_loader_and_filename(self): self.assertEqual(repr(m), "") def test_module_repr_with_full_loader_and_filename(self): - # Even though the module has an __file__, use __loader__.module_repr() m = ModuleType('foo') # Yes, a class not an instance. m.__loader__ = FullLoader diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-04-17-02-18.gh-issue-97850.E3QTRA.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-04-17-02-18.gh-issue-97850.E3QTRA.rst new file mode 100644 index 000000000000..f880d9663842 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-04-17-02-18.gh-issue-97850.E3QTRA.rst @@ -0,0 +1 @@ +Long deprecated, ``module_repr()`` should now be completely eradicated. From webhook-mailer at python.org Wed Oct 5 16:08:17 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Wed, 05 Oct 2022 20:08:17 -0000 Subject: [Python-checkins] docs(typing): add "see PEP 675" to LiteralString (#97926) Message-ID: https://github.com/python/cpython/commit/2016bc54a22b83d0ca9174b64257cc7bb67a0916 commit: 2016bc54a22b83d0ca9174b64257cc7bb67a0916 branch: main author: Simon Legner committer: JelleZijlstra date: 2022-10-05T13:08:07-07:00 summary: docs(typing): add "see PEP 675" to LiteralString (#97926) files: M Doc/library/typing.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 786f579a07d0..f63d61eb1ea3 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -631,6 +631,8 @@ These can be used as types in annotations and do not support ``[]``. that generate type checker errors could be vulnerable to an SQL injection attack. + See :pep:`675` for more details. + .. versionadded:: 3.11 .. data:: Never From webhook-mailer at python.org Wed Oct 5 16:16:17 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 05 Oct 2022 20:16:17 -0000 Subject: [Python-checkins] docs(typing): add "see PEP 675" to LiteralString (GH-97926) Message-ID: https://github.com/python/cpython/commit/61183b95ae68c6439840b58ef8eff6371338dd80 commit: 61183b95ae68c6439840b58ef8eff6371338dd80 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-05T13:16:12-07:00 summary: docs(typing): add "see PEP 675" to LiteralString (GH-97926) (cherry picked from commit 2016bc54a22b83d0ca9174b64257cc7bb67a0916) Co-authored-by: Simon Legner files: M Doc/library/typing.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index bcdedd533547..b75aa333f73e 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -631,6 +631,8 @@ These can be used as types in annotations and do not support ``[]``. that generate type checker errors could be vulnerable to an SQL injection attack. + See :pep:`675` for more details. + .. versionadded:: 3.11 .. data:: Never From webhook-mailer at python.org Wed Oct 5 17:11:13 2022 From: webhook-mailer at python.org (ambv) Date: Wed, 05 Oct 2022 21:11:13 -0000 Subject: [Python-checkins] [3.10] gh-93738: Documentation C syntax (:c:type: -> :c:expr:) (GH-97768) (#97925) Message-ID: https://github.com/python/cpython/commit/3b0f2a7ff068f24198b848f25662078c4223b10a commit: 3b0f2a7ff068f24198b848f25662078c4223b10a branch: 3.10 author: ?ukasz Langa committer: ambv date: 2022-10-05T14:10:55-07:00 summary: [3.10] gh-93738: Documentation C syntax (:c:type: -> :c:expr:) (GH-97768) (#97925) :c:type:`` -> :c:expr:`` Co-authored-by: ?ukasz Langa (cherry picked from commit 0031e62973801d34a9e19ab7bb199e9668e32d7b) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> files: M Doc/c-api/arg.rst M Doc/c-api/capsule.rst M Doc/c-api/complex.rst M Doc/c-api/conversion.rst M Doc/c-api/dict.rst M Doc/c-api/file.rst M Doc/c-api/float.rst M Doc/c-api/init.rst M Doc/c-api/intro.rst M Doc/c-api/long.rst M Doc/c-api/marshal.rst M Doc/c-api/memory.rst M Doc/c-api/sys.rst M Doc/c-api/unicode.rst M Doc/extending/extending.rst M Doc/extending/newtypes.rst M Doc/library/ctypes.rst M Doc/library/posix.rst M Doc/library/socket.rst M Doc/library/stdtypes.rst M Doc/library/struct.rst M Doc/reference/datamodel.rst M Doc/whatsnew/2.2.rst M Doc/whatsnew/2.3.rst M Doc/whatsnew/2.4.rst M Doc/whatsnew/2.5.rst M Doc/whatsnew/2.6.rst M Doc/whatsnew/2.7.rst M Doc/whatsnew/3.3.rst M Doc/whatsnew/3.7.rst M Doc/whatsnew/3.9.rst M Misc/NEWS.d/3.5.0a1.rst M Misc/NEWS.d/3.9.0a1.rst M Misc/NEWS.d/3.9.0b1.rst diff --git a/Doc/c-api/arg.rst b/Doc/c-api/arg.rst index 91d764c13f67..85f9eda17a20 100644 --- a/Doc/c-api/arg.rst +++ b/Doc/c-api/arg.rst @@ -194,10 +194,10 @@ which disallows mutable objects such as :class:`bytearray`. It only works for encoded data without embedded NUL bytes. This format requires two arguments. The first is only used as input, and - must be a :c:type:`const char*` which points to the name of an encoding as a + must be a :c:expr:`const char*` which points to the name of an encoding as a NUL-terminated string, or ``NULL``, in which case ``'utf-8'`` encoding is used. An exception is raised if the named encoding is not known to Python. The - second argument must be a :c:type:`char**`; the value of the pointer it + second argument must be a :c:expr:`char**`; the value of the pointer it references will be set to a buffer with the contents of the argument text. The text will be encoded in the encoding specified by the first argument. @@ -217,10 +217,10 @@ which disallows mutable objects such as :class:`bytearray`. characters. It requires three arguments. The first is only used as input, and must be a - :c:type:`const char*` which points to the name of an encoding as a + :c:expr:`const char*` which points to the name of an encoding as a NUL-terminated string, or ``NULL``, in which case ``'utf-8'`` encoding is used. An exception is raised if the named encoding is not known to Python. The - second argument must be a :c:type:`char**`; the value of the pointer it + second argument must be a :c:expr:`char**`; the value of the pointer it references will be set to a buffer with the contents of the argument text. The text will be encoded in the encoding specified by the first argument. The third argument must be a pointer to an integer; the referenced integer @@ -252,38 +252,38 @@ Numbers ``b`` (:class:`int`) [unsigned char] Convert a nonnegative Python integer to an unsigned tiny int, stored in a C - :c:type:`unsigned char`. + :c:expr:`unsigned char`. ``B`` (:class:`int`) [unsigned char] Convert a Python integer to a tiny int without overflow checking, stored in a C - :c:type:`unsigned char`. + :c:expr:`unsigned char`. ``h`` (:class:`int`) [short int] - Convert a Python integer to a C :c:type:`short int`. + Convert a Python integer to a C :c:expr:`short int`. ``H`` (:class:`int`) [unsigned short int] - Convert a Python integer to a C :c:type:`unsigned short int`, without overflow + Convert a Python integer to a C :c:expr:`unsigned short int`, without overflow checking. ``i`` (:class:`int`) [int] - Convert a Python integer to a plain C :c:type:`int`. + Convert a Python integer to a plain C :c:expr:`int`. ``I`` (:class:`int`) [unsigned int] - Convert a Python integer to a C :c:type:`unsigned int`, without overflow + Convert a Python integer to a C :c:expr:`unsigned int`, without overflow checking. ``l`` (:class:`int`) [long int] - Convert a Python integer to a C :c:type:`long int`. + Convert a Python integer to a C :c:expr:`long int`. ``k`` (:class:`int`) [unsigned long] - Convert a Python integer to a C :c:type:`unsigned long` without + Convert a Python integer to a C :c:expr:`unsigned long` without overflow checking. ``L`` (:class:`int`) [long long] - Convert a Python integer to a C :c:type:`long long`. + Convert a Python integer to a C :c:expr:`long long`. ``K`` (:class:`int`) [unsigned long long] - Convert a Python integer to a C :c:type:`unsigned long long` + Convert a Python integer to a C :c:expr:`unsigned long long` without overflow checking. ``n`` (:class:`int`) [:c:type:`Py_ssize_t`] @@ -291,20 +291,20 @@ Numbers ``c`` (:class:`bytes` or :class:`bytearray` of length 1) [char] Convert a Python byte, represented as a :class:`bytes` or - :class:`bytearray` object of length 1, to a C :c:type:`char`. + :class:`bytearray` object of length 1, to a C :c:expr:`char`. .. versionchanged:: 3.3 Allow :class:`bytearray` objects. ``C`` (:class:`str` of length 1) [int] Convert a Python character, represented as a :class:`str` object of - length 1, to a C :c:type:`int`. + length 1, to a C :c:expr:`int`. ``f`` (:class:`float`) [float] - Convert a Python floating point number to a C :c:type:`float`. + Convert a Python floating point number to a C :c:expr:`float`. ``d`` (:class:`float`) [double] - Convert a Python floating point number to a C :c:type:`double`. + Convert a Python floating point number to a C :c:expr:`double`. ``D`` (:class:`complex`) [Py_complex] Convert a Python complex number to a C :c:type:`Py_complex` structure. @@ -329,13 +329,13 @@ Other objects ``O&`` (object) [*converter*, *anything*] Convert a Python object to a C variable through a *converter* function. This takes two arguments: the first is a function, the second is the address of a C - variable (of arbitrary type), converted to :c:type:`void *`. The *converter* + variable (of arbitrary type), converted to :c:expr:`void *`. The *converter* function in turn is called as follows:: status = converter(object, address); where *object* is the Python object to be converted and *address* is the - :c:type:`void*` argument that was passed to the ``PyArg_Parse*`` function. + :c:expr:`void*` argument that was passed to the ``PyArg_Parse*`` function. The returned *status* should be ``1`` for a successful conversion and ``0`` if the conversion has failed. When the conversion fails, the *converter* function should raise an exception and leave the content of *address* unmodified. @@ -568,7 +568,7 @@ Building values Same as ``s#``. ``u`` (:class:`str`) [const wchar_t \*] - Convert a null-terminated :c:type:`wchar_t` buffer of Unicode (UTF-16 or UCS-4) + Convert a null-terminated :c:expr:`wchar_t` buffer of Unicode (UTF-16 or UCS-4) data to a Python Unicode object. If the Unicode buffer pointer is ``NULL``, ``None`` is returned. @@ -584,51 +584,51 @@ Building values Same as ``s#``. ``i`` (:class:`int`) [int] - Convert a plain C :c:type:`int` to a Python integer object. + Convert a plain C :c:expr:`int` to a Python integer object. ``b`` (:class:`int`) [char] - Convert a plain C :c:type:`char` to a Python integer object. + Convert a plain C :c:expr:`char` to a Python integer object. ``h`` (:class:`int`) [short int] - Convert a plain C :c:type:`short int` to a Python integer object. + Convert a plain C :c:expr:`short int` to a Python integer object. ``l`` (:class:`int`) [long int] - Convert a C :c:type:`long int` to a Python integer object. + Convert a C :c:expr:`long int` to a Python integer object. ``B`` (:class:`int`) [unsigned char] - Convert a C :c:type:`unsigned char` to a Python integer object. + Convert a C :c:expr:`unsigned char` to a Python integer object. ``H`` (:class:`int`) [unsigned short int] - Convert a C :c:type:`unsigned short int` to a Python integer object. + Convert a C :c:expr:`unsigned short int` to a Python integer object. ``I`` (:class:`int`) [unsigned int] - Convert a C :c:type:`unsigned int` to a Python integer object. + Convert a C :c:expr:`unsigned int` to a Python integer object. ``k`` (:class:`int`) [unsigned long] - Convert a C :c:type:`unsigned long` to a Python integer object. + Convert a C :c:expr:`unsigned long` to a Python integer object. ``L`` (:class:`int`) [long long] - Convert a C :c:type:`long long` to a Python integer object. + Convert a C :c:expr:`long long` to a Python integer object. ``K`` (:class:`int`) [unsigned long long] - Convert a C :c:type:`unsigned long long` to a Python integer object. + Convert a C :c:expr:`unsigned long long` to a Python integer object. ``n`` (:class:`int`) [:c:type:`Py_ssize_t`] Convert a C :c:type:`Py_ssize_t` to a Python integer. ``c`` (:class:`bytes` of length 1) [char] - Convert a C :c:type:`int` representing a byte to a Python :class:`bytes` object of + Convert a C :c:expr:`int` representing a byte to a Python :class:`bytes` object of length 1. ``C`` (:class:`str` of length 1) [int] - Convert a C :c:type:`int` representing a character to Python :class:`str` + Convert a C :c:expr:`int` representing a character to Python :class:`str` object of length 1. ``d`` (:class:`float`) [double] - Convert a C :c:type:`double` to a Python floating point number. + Convert a C :c:expr:`double` to a Python floating point number. ``f`` (:class:`float`) [float] - Convert a C :c:type:`float` to a Python floating point number. + Convert a C :c:expr:`float` to a Python floating point number. ``D`` (:class:`complex`) [Py_complex \*] Convert a C :c:type:`Py_complex` structure to a Python complex number. @@ -651,7 +651,7 @@ Building values ``O&`` (object) [*converter*, *anything*] Convert *anything* to a Python object through a *converter* function. The - function is called with *anything* (which should be compatible with :c:type:`void*`) + function is called with *anything* (which should be compatible with :c:expr:`void*`) as its argument and should return a "new" Python object, or ``NULL`` if an error occurred. diff --git a/Doc/c-api/capsule.rst b/Doc/c-api/capsule.rst index 908e92653dd4..6049b248f9cc 100644 --- a/Doc/c-api/capsule.rst +++ b/Doc/c-api/capsule.rst @@ -15,7 +15,7 @@ Refer to :ref:`using-capsules` for more information on using these objects. .. c:type:: PyCapsule This subtype of :c:type:`PyObject` represents an opaque value, useful for C - extension modules who need to pass an opaque value (as a :c:type:`void*` + extension modules who need to pass an opaque value (as a :c:expr:`void*` pointer) through Python code to other C code. It is often used to make a C function pointer defined in one module available to other modules, so the regular import mechanism can be used to access C APIs defined in dynamically diff --git a/Doc/c-api/complex.rst b/Doc/c-api/complex.rst index c25894681bca..9228ce852000 100644 --- a/Doc/c-api/complex.rst +++ b/Doc/c-api/complex.rst @@ -115,12 +115,12 @@ Complex Numbers as Python Objects .. c:function:: double PyComplex_RealAsDouble(PyObject *op) - Return the real part of *op* as a C :c:type:`double`. + Return the real part of *op* as a C :c:expr:`double`. .. c:function:: double PyComplex_ImagAsDouble(PyObject *op) - Return the imaginary part of *op* as a C :c:type:`double`. + Return the imaginary part of *op* as a C :c:expr:`double`. .. c:function:: Py_complex PyComplex_AsCComplex(PyObject *op) diff --git a/Doc/c-api/conversion.rst b/Doc/c-api/conversion.rst index 7b4cc1cacdd4..9b9c4ffa4d03 100644 --- a/Doc/c-api/conversion.rst +++ b/Doc/c-api/conversion.rst @@ -49,7 +49,7 @@ The following functions provide locale-independent string to number conversions. .. c:function:: double PyOS_string_to_double(const char *s, char **endptr, PyObject *overflow_exception) - Convert a string ``s`` to a :c:type:`double`, raising a Python + Convert a string ``s`` to a :c:expr:`double`, raising a Python exception on failure. The set of accepted strings corresponds to the set of strings accepted by Python's :func:`float` constructor, except that ``s`` must not have leading or trailing whitespace. @@ -83,7 +83,7 @@ The following functions provide locale-independent string to number conversions. .. c:function:: char* PyOS_double_to_string(double val, char format_code, int precision, int flags, int *ptype) - Convert a :c:type:`double` *val* to a string using supplied + Convert a :c:expr:`double` *val* to a string using supplied *format_code*, *precision*, and *flags*. *format_code* must be one of ``'e'``, ``'E'``, ``'f'``, ``'F'``, diff --git a/Doc/c-api/dict.rst b/Doc/c-api/dict.rst index 67c2026baa14..819168d48707 100644 --- a/Doc/c-api/dict.rst +++ b/Doc/c-api/dict.rst @@ -73,7 +73,7 @@ Dictionary Objects .. index:: single: PyUnicode_FromString() Insert *val* into the dictionary *p* using *key* as a key. *key* should - be a :c:type:`const char*`. The key object is created using + be a :c:expr:`const char*`. The key object is created using ``PyUnicode_FromString(key)``. Return ``0`` on success or ``-1`` on failure. This function *does not* steal a reference to *val*. @@ -118,7 +118,7 @@ Dictionary Objects .. c:function:: PyObject* PyDict_GetItemString(PyObject *p, const char *key) This is the same as :c:func:`PyDict_GetItem`, but *key* is specified as a - :c:type:`const char*`, rather than a :c:expr:`PyObject*`. + :c:expr:`const char*`, rather than a :c:expr:`PyObject*`. Note that exceptions which occur while calling :meth:`__hash__` and :meth:`__eq__` methods and creating a temporary string object diff --git a/Doc/c-api/file.rst b/Doc/c-api/file.rst index 745d892be7ea..58ed58e54668 100644 --- a/Doc/c-api/file.rst +++ b/Doc/c-api/file.rst @@ -38,7 +38,7 @@ the :mod:`io` APIs instead. .. c:function:: int PyObject_AsFileDescriptor(PyObject *p) - Return the file descriptor associated with *p* as an :c:type:`int`. If the + Return the file descriptor associated with *p* as an :c:expr:`int`. If the object is an integer, its value is returned. If not, the object's :meth:`~io.IOBase.fileno` method is called if it exists; the method must return an integer, which is returned as the file descriptor diff --git a/Doc/c-api/float.rst b/Doc/c-api/float.rst index c107243a88df..6b6f99ff66aa 100644 --- a/Doc/c-api/float.rst +++ b/Doc/c-api/float.rst @@ -44,7 +44,7 @@ Floating Point Objects .. c:function:: double PyFloat_AsDouble(PyObject *pyfloat) - Return a C :c:type:`double` representation of the contents of *pyfloat*. If + Return a C :c:expr:`double` representation of the contents of *pyfloat*. If *pyfloat* is not a Python floating point object but has a :meth:`__float__` method, this method will first be called to convert *pyfloat* into a float. If ``__float__()`` is not defined then it falls back to :meth:`__index__`. @@ -57,7 +57,7 @@ Floating Point Objects .. c:function:: double PyFloat_AS_DOUBLE(PyObject *pyfloat) - Return a C :c:type:`double` representation of the contents of *pyfloat*, but + Return a C :c:expr:`double` representation of the contents of *pyfloat*, but without error checking. @@ -70,9 +70,9 @@ Floating Point Objects .. c:function:: double PyFloat_GetMax() - Return the maximum representable finite float *DBL_MAX* as C :c:type:`double`. + Return the maximum representable finite float *DBL_MAX* as C :c:expr:`double`. .. c:function:: double PyFloat_GetMin() - Return the minimum normalized positive float *DBL_MIN* as C :c:type:`double`. + Return the minimum normalized positive float *DBL_MIN* as C :c:expr:`double`. diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index 6a80386b18bb..31921896687c 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -365,7 +365,7 @@ Process-wide parameters interpreter will change the contents of this storage. Use :c:func:`Py_DecodeLocale` to decode a bytes string to get a - :c:type:`wchar_*` string. + :c:expr:`wchar_*` string. .. c:function:: wchar* Py_GetProgramName() @@ -509,7 +509,7 @@ Process-wide parameters if required after calling :c:func:`Py_Initialize`. Use :c:func:`Py_DecodeLocale` to decode a bytes string to get a - :c:type:`wchar_*` string. + :c:expr:`wchar_*` string. The path argument is copied internally, so the caller may free it after the call completes. @@ -615,7 +615,7 @@ Process-wide parameters directory (``"."``). Use :c:func:`Py_DecodeLocale` to decode a bytes string to get a - :c:type:`wchar_*` string. + :c:expr:`wchar_*` string. .. note:: It is recommended that applications embedding the Python interpreter @@ -642,7 +642,7 @@ Process-wide parameters :option:`-I`. Use :c:func:`Py_DecodeLocale` to decode a bytes string to get a - :c:type:`wchar_*` string. + :c:expr:`wchar_*` string. .. versionchanged:: 3.4 The *updatepath* value depends on :option:`-I`. @@ -659,7 +659,7 @@ Process-wide parameters this storage. Use :c:func:`Py_DecodeLocale` to decode a bytes string to get a - :c:type:`wchar_*` string. + :c:expr:`wchar_*` string. .. c:function:: w_char* Py_GetPythonHome() @@ -1221,8 +1221,8 @@ All of the following functions must be called after :c:func:`Py_Initialize`. exception (if any) for the thread is cleared. This raises no exceptions. .. versionchanged:: 3.7 - The type of the *id* parameter changed from :c:type:`long` to - :c:type:`unsigned long`. + The type of the *id* parameter changed from :c:expr:`long` to + :c:expr:`unsigned long`. .. c:function:: void PyEval_AcquireThread(PyThreadState *tstate) @@ -1656,7 +1656,7 @@ The Python interpreter provides low-level support for thread-local storage (TLS) which wraps the underlying native TLS implementation to support the Python-level thread local storage API (:class:`threading.local`). The CPython C level APIs are similar to those offered by pthreads and Windows: -use a thread key and functions to associate a :c:type:`void*` value per +use a thread key and functions to associate a :c:expr:`void*` value per thread. The GIL does *not* need to be held when calling these functions; they supply @@ -1667,8 +1667,8 @@ you need to include :file:`pythread.h` to use thread-local storage. .. note:: None of these API functions handle memory management on behalf of the - :c:type:`void*` values. You need to allocate and deallocate them yourself. - If the :c:type:`void*` values happen to be :c:expr:`PyObject*`, these + :c:expr:`void*` values. You need to allocate and deallocate them yourself. + If the :c:expr:`void*` values happen to be :c:expr:`PyObject*`, these functions don't do refcount operations on them either. .. _thread-specific-storage-api: @@ -1678,7 +1678,7 @@ Thread Specific Storage (TSS) API TSS API is introduced to supersede the use of the existing TLS API within the CPython interpreter. This API uses a new type :c:type:`Py_tss_t` instead of -:c:type:`int` to represent thread keys. +:c:expr:`int` to represent thread keys. .. versionadded:: 3.7 @@ -1764,14 +1764,14 @@ undefined if the given :c:type:`Py_tss_t` has not been initialized by .. c:function:: int PyThread_tss_set(Py_tss_t *key, void *value) - Return a zero value to indicate successfully associating a :c:type:`void*` + Return a zero value to indicate successfully associating a :c:expr:`void*` value with a TSS key in the current thread. Each thread has a distinct - mapping of the key to a :c:type:`void*` value. + mapping of the key to a :c:expr:`void*` value. .. c:function:: void* PyThread_tss_get(Py_tss_t *key) - Return the :c:type:`void*` value associated with a TSS key in the current + Return the :c:expr:`void*` value associated with a TSS key in the current thread. This returns ``NULL`` if no value is associated with the key in the current thread. diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst index 82e578fbacf8..80713c565bb8 100644 --- a/Doc/c-api/intro.rst +++ b/Doc/c-api/intro.rst @@ -495,8 +495,8 @@ Types ----- There are few other data types that play a significant role in the Python/C -API; most are simple C types such as :c:type:`int`, :c:type:`long`, -:c:type:`double` and :c:type:`char*`. A few structure types are used to +API; most are simple C types such as :c:expr:`int`, :c:expr:`long`, +:c:expr:`double` and :c:expr:`char*`. A few structure types are used to describe static tables used to list the functions exported by a module or the data attributes of a new object type, and another is used to describe the value of a complex number. These will be discussed together with the functions that diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst index 620344e71373..bd3d731d8464 100644 --- a/Doc/c-api/long.rst +++ b/Doc/c-api/long.rst @@ -47,7 +47,7 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. c:function:: PyObject* PyLong_FromUnsignedLong(unsigned long v) - Return a new :c:type:`PyLongObject` object from a C :c:type:`unsigned long`, or + Return a new :c:type:`PyLongObject` object from a C :c:expr:`unsigned long`, or ``NULL`` on failure. @@ -65,13 +65,13 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. c:function:: PyObject* PyLong_FromLongLong(long long v) - Return a new :c:type:`PyLongObject` object from a C :c:type:`long long`, or ``NULL`` + Return a new :c:type:`PyLongObject` object from a C :c:expr:`long long`, or ``NULL`` on failure. .. c:function:: PyObject* PyLong_FromUnsignedLongLong(unsigned long long v) - Return a new :c:type:`PyLongObject` object from a C :c:type:`unsigned long long`, + Return a new :c:type:`PyLongObject` object from a C :c:expr:`unsigned long long`, or ``NULL`` on failure. @@ -115,12 +115,12 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. single: LONG_MAX single: OverflowError (built-in exception) - Return a C :c:type:`long` representation of *obj*. If *obj* is not an + Return a C :c:expr:`long` representation of *obj*. If *obj* is not an instance of :c:type:`PyLongObject`, first call its :meth:`__index__` method (if present) to convert it to a :c:type:`PyLongObject`. Raise :exc:`OverflowError` if the value of *obj* is out of range for a - :c:type:`long`. + :c:expr:`long`. Returns ``-1`` on error. Use :c:func:`PyErr_Occurred` to disambiguate. @@ -133,7 +133,7 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. c:function:: long PyLong_AsLongAndOverflow(PyObject *obj, int *overflow) - Return a C :c:type:`long` representation of *obj*. If *obj* is not an + Return a C :c:expr:`long` representation of *obj*. If *obj* is not an instance of :c:type:`PyLongObject`, first call its :meth:`__index__` method (if present) to convert it to a :c:type:`PyLongObject`. @@ -156,12 +156,12 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. index:: single: OverflowError (built-in exception) - Return a C :c:type:`long long` representation of *obj*. If *obj* is not an + Return a C :c:expr:`long long` representation of *obj*. If *obj* is not an instance of :c:type:`PyLongObject`, first call its :meth:`__index__` method (if present) to convert it to a :c:type:`PyLongObject`. Raise :exc:`OverflowError` if the value of *obj* is out of range for a - :c:type:`long long`. + :c:expr:`long long`. Returns ``-1`` on error. Use :c:func:`PyErr_Occurred` to disambiguate. @@ -174,7 +174,7 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. c:function:: long long PyLong_AsLongLongAndOverflow(PyObject *obj, int *overflow) - Return a C :c:type:`long long` representation of *obj*. If *obj* is not an + Return a C :c:expr:`long long` representation of *obj*. If *obj* is not an instance of :c:type:`PyLongObject`, first call its :meth:`__index__` method (if present) to convert it to a :c:type:`PyLongObject`. @@ -215,11 +215,11 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. single: ULONG_MAX single: OverflowError (built-in exception) - Return a C :c:type:`unsigned long` representation of *pylong*. *pylong* + Return a C :c:expr:`unsigned long` representation of *pylong*. *pylong* must be an instance of :c:type:`PyLongObject`. Raise :exc:`OverflowError` if the value of *pylong* is out of range for a - :c:type:`unsigned long`. + :c:expr:`unsigned long`. Returns ``(unsigned long)-1`` on error. Use :c:func:`PyErr_Occurred` to disambiguate. @@ -246,11 +246,11 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. index:: single: OverflowError (built-in exception) - Return a C :c:type:`unsigned long long` representation of *pylong*. *pylong* + Return a C :c:expr:`unsigned long long` representation of *pylong*. *pylong* must be an instance of :c:type:`PyLongObject`. Raise :exc:`OverflowError` if the value of *pylong* is out of range for an - :c:type:`unsigned long long`. + :c:expr:`unsigned long long`. Returns ``(unsigned long long)-1`` on error. Use :c:func:`PyErr_Occurred` to disambiguate. @@ -261,11 +261,11 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. c:function:: unsigned long PyLong_AsUnsignedLongMask(PyObject *obj) - Return a C :c:type:`unsigned long` representation of *obj*. If *obj* is not + Return a C :c:expr:`unsigned long` representation of *obj*. If *obj* is not an instance of :c:type:`PyLongObject`, first call its :meth:`__index__` method (if present) to convert it to a :c:type:`PyLongObject`. - If the value of *obj* is out of range for an :c:type:`unsigned long`, + If the value of *obj* is out of range for an :c:expr:`unsigned long`, return the reduction of that value modulo ``ULONG_MAX + 1``. Returns ``(unsigned long)-1`` on error. Use :c:func:`PyErr_Occurred` to @@ -280,12 +280,12 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. c:function:: unsigned long long PyLong_AsUnsignedLongLongMask(PyObject *obj) - Return a C :c:type:`unsigned long long` representation of *obj*. If *obj* + Return a C :c:expr:`unsigned long long` representation of *obj*. If *obj* is not an instance of :c:type:`PyLongObject`, first call its :meth:`__index__` method (if present) to convert it to a :c:type:`PyLongObject`. - If the value of *obj* is out of range for an :c:type:`unsigned long long`, + If the value of *obj* is out of range for an :c:expr:`unsigned long long`, return the reduction of that value modulo ``ULLONG_MAX + 1``. Returns ``(unsigned long long)-1`` on error. Use :c:func:`PyErr_Occurred` @@ -300,20 +300,20 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. c:function:: double PyLong_AsDouble(PyObject *pylong) - Return a C :c:type:`double` representation of *pylong*. *pylong* must be + Return a C :c:expr:`double` representation of *pylong*. *pylong* must be an instance of :c:type:`PyLongObject`. Raise :exc:`OverflowError` if the value of *pylong* is out of range for a - :c:type:`double`. + :c:expr:`double`. Returns ``-1.0`` on error. Use :c:func:`PyErr_Occurred` to disambiguate. .. c:function:: void* PyLong_AsVoidPtr(PyObject *pylong) - Convert a Python integer *pylong* to a C :c:type:`void` pointer. + Convert a Python integer *pylong* to a C :c:expr:`void` pointer. If *pylong* cannot be converted, an :exc:`OverflowError` will be raised. This - is only assured to produce a usable :c:type:`void` pointer for values created + is only assured to produce a usable :c:expr:`void` pointer for values created with :c:func:`PyLong_FromVoidPtr`. Returns ``NULL`` on error. Use :c:func:`PyErr_Occurred` to disambiguate. diff --git a/Doc/c-api/marshal.rst b/Doc/c-api/marshal.rst index 1ba18beb3ea0..8e25968c6909 100644 --- a/Doc/c-api/marshal.rst +++ b/Doc/c-api/marshal.rst @@ -21,9 +21,9 @@ unmarshalling. Version 2 uses a binary format for floating point numbers. .. c:function:: void PyMarshal_WriteLongToFile(long value, FILE *file, int version) - Marshal a :c:type:`long` integer, *value*, to *file*. This will only write + Marshal a :c:expr:`long` integer, *value*, to *file*. This will only write the least-significant 32 bits of *value*; regardless of the size of the - native :c:type:`long` type. *version* indicates the file format. + native :c:expr:`long` type. *version* indicates the file format. .. c:function:: void PyMarshal_WriteObjectToFile(PyObject *value, FILE *file, int version) @@ -43,9 +43,9 @@ The following functions allow marshalled values to be read back in. .. c:function:: long PyMarshal_ReadLongFromFile(FILE *file) - Return a C :c:type:`long` from the data stream in a :c:expr:`FILE*` opened + Return a C :c:expr:`long` from the data stream in a :c:expr:`FILE*` opened for reading. Only a 32-bit value can be read in using this function, - regardless of the native size of :c:type:`long`. + regardless of the native size of :c:expr:`long`. On error, sets the appropriate exception (:exc:`EOFError`) and returns ``-1``. @@ -53,9 +53,9 @@ The following functions allow marshalled values to be read back in. .. c:function:: int PyMarshal_ReadShortFromFile(FILE *file) - Return a C :c:type:`short` from the data stream in a :c:expr:`FILE*` opened + Return a C :c:expr:`short` from the data stream in a :c:expr:`FILE*` opened for reading. Only a 16-bit value can be read in using this function, - regardless of the native size of :c:type:`short`. + regardless of the native size of :c:expr:`short`. On error, sets the appropriate exception (:exc:`EOFError`) and returns ``-1``. diff --git a/Doc/c-api/memory.rst b/Doc/c-api/memory.rst index 419efb758991..1372dc45d782 100644 --- a/Doc/c-api/memory.rst +++ b/Doc/c-api/memory.rst @@ -141,7 +141,7 @@ zero bytes. .. c:function:: void* PyMem_RawMalloc(size_t n) - Allocates *n* bytes and returns a pointer of type :c:type:`void*` to the + Allocates *n* bytes and returns a pointer of type :c:expr:`void*` to the allocated memory, or ``NULL`` if the request fails. Requesting zero bytes returns a distinct non-``NULL`` pointer if possible, as @@ -152,7 +152,7 @@ zero bytes. .. c:function:: void* PyMem_RawCalloc(size_t nelem, size_t elsize) Allocates *nelem* elements each whose size in bytes is *elsize* and returns - a pointer of type :c:type:`void*` to the allocated memory, or ``NULL`` if the + a pointer of type :c:expr:`void*` to the allocated memory, or ``NULL`` if the request fails. The memory is initialized to zeros. Requesting zero elements or elements of size zero bytes returns a distinct @@ -212,7 +212,7 @@ The :ref:`default memory allocator ` uses the .. c:function:: void* PyMem_Malloc(size_t n) - Allocates *n* bytes and returns a pointer of type :c:type:`void*` to the + Allocates *n* bytes and returns a pointer of type :c:expr:`void*` to the allocated memory, or ``NULL`` if the request fails. Requesting zero bytes returns a distinct non-``NULL`` pointer if possible, as @@ -223,7 +223,7 @@ The :ref:`default memory allocator ` uses the .. c:function:: void* PyMem_Calloc(size_t nelem, size_t elsize) Allocates *nelem* elements each whose size in bytes is *elsize* and returns - a pointer of type :c:type:`void*` to the allocated memory, or ``NULL`` if the + a pointer of type :c:expr:`void*` to the allocated memory, or ``NULL`` if the request fails. The memory is initialized to zeros. Requesting zero elements or elements of size zero bytes returns a distinct @@ -320,7 +320,7 @@ The :ref:`default object allocator ` uses the .. c:function:: void* PyObject_Malloc(size_t n) - Allocates *n* bytes and returns a pointer of type :c:type:`void*` to the + Allocates *n* bytes and returns a pointer of type :c:expr:`void*` to the allocated memory, or ``NULL`` if the request fails. Requesting zero bytes returns a distinct non-``NULL`` pointer if possible, as @@ -331,7 +331,7 @@ The :ref:`default object allocator ` uses the .. c:function:: void* PyObject_Calloc(size_t nelem, size_t elsize) Allocates *nelem* elements each whose size in bytes is *elsize* and returns - a pointer of type :c:type:`void*` to the allocated memory, or ``NULL`` if the + a pointer of type :c:expr:`void*` to the allocated memory, or ``NULL`` if the request fails. The memory is initialized to zeros. Requesting zero elements or elements of size zero bytes returns a distinct diff --git a/Doc/c-api/sys.rst b/Doc/c-api/sys.rst index 7cf0a6b51f7d..8ea90dae0eef 100644 --- a/Doc/c-api/sys.rst +++ b/Doc/c-api/sys.rst @@ -105,7 +105,7 @@ Operating System Utilities Return the current signal handler for signal *i*. This is a thin wrapper around either :c:func:`sigaction` or :c:func:`signal`. Do not call those functions - directly! :c:type:`PyOS_sighandler_t` is a typedef alias for :c:type:`void + directly! :c:type:`PyOS_sighandler_t` is a typedef alias for :c:expr:`void (\*)(int)`. @@ -114,7 +114,7 @@ Operating System Utilities Set the signal handler for signal *i* to be *h*; return the old signal handler. This is a thin wrapper around either :c:func:`sigaction` or :c:func:`signal`. Do not call those functions directly! :c:type:`PyOS_sighandler_t` is a typedef - alias for :c:type:`void (\*)(int)`. + alias for :c:expr:`void (\*)(int)`. .. c:function:: wchar_t* Py_DecodeLocale(const char* arg, size_t *size) @@ -352,7 +352,7 @@ accessible to C code. They all work with the current interpreter thread's silently abort the operation by raising an error subclassed from :class:`Exception` (other errors will not be silenced). - The hook function is of type :c:type:`int (*)(const char *event, PyObject + The hook function is of type :c:expr:`int (*)(const char *event, PyObject *args, void *userData)`, where *args* is guaranteed to be a :c:type:`PyTupleObject`. The hook function is always called with the GIL held by the Python interpreter that raised the event. diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst index fbf51d31d56e..f82bc6ca27bc 100644 --- a/Doc/c-api/unicode.rst +++ b/Doc/c-api/unicode.rst @@ -58,7 +58,7 @@ Python: .. c:type:: Py_UNICODE - This is a typedef of :c:type:`wchar_t`, which is a 16-bit type or 32-bit type + This is a typedef of :c:expr:`wchar_t`, which is a 16-bit type or 32-bit type depending on the platform. .. versionchanged:: 3.3 @@ -939,11 +939,11 @@ conversion function: wchar_t Support """"""""""""""" -:c:type:`wchar_t` support for platforms which support it: +:c:expr:`wchar_t` support for platforms which support it: .. c:function:: PyObject* PyUnicode_FromWideChar(const wchar_t *w, Py_ssize_t size) - Create a Unicode object from the :c:type:`wchar_t` buffer *w* of the given *size*. + Create a Unicode object from the :c:expr:`wchar_t` buffer *w* of the given *size*. Passing ``-1`` as the *size* indicates that the function must itself compute the length, using wcslen. Return ``NULL`` on failure. @@ -951,13 +951,13 @@ wchar_t Support .. c:function:: Py_ssize_t PyUnicode_AsWideChar(PyObject *unicode, wchar_t *w, Py_ssize_t size) - Copy the Unicode object contents into the :c:type:`wchar_t` buffer *w*. At most - *size* :c:type:`wchar_t` characters are copied (excluding a possibly trailing - null termination character). Return the number of :c:type:`wchar_t` characters - copied or ``-1`` in case of an error. Note that the resulting :c:type:`wchar_t*` + Copy the Unicode object contents into the :c:expr:`wchar_t` buffer *w*. At most + *size* :c:expr:`wchar_t` characters are copied (excluding a possibly trailing + null termination character). Return the number of :c:expr:`wchar_t` characters + copied or ``-1`` in case of an error. Note that the resulting :c:expr:`wchar_t*` string may or may not be null-terminated. It is the responsibility of the caller - to make sure that the :c:type:`wchar_t*` string is null-terminated in case this is - required by the application. Also, note that the :c:type:`wchar_t*` string + to make sure that the :c:expr:`wchar_t*` string is null-terminated in case this is + required by the application. Also, note that the :c:expr:`wchar_t*` string might contain null characters, which would cause the string to be truncated when used with most C functions. @@ -967,9 +967,9 @@ wchar_t Support Convert the Unicode object to a wide character string. The output string always ends with a null character. If *size* is not ``NULL``, write the number of wide characters (excluding the trailing null termination character) into - *\*size*. Note that the resulting :c:type:`wchar_t` string might contain + *\*size*. Note that the resulting :c:expr:`wchar_t` string might contain null characters, which would cause the string to be truncated when used with - most C functions. If *size* is ``NULL`` and the :c:type:`wchar_t*` string + most C functions. If *size* is ``NULL`` and the :c:expr:`wchar_t*` string contains null characters a :exc:`ValueError` is raised. Returns a buffer allocated by :c:func:`PyMem_Alloc` (use @@ -980,7 +980,7 @@ wchar_t Support .. versionadded:: 3.2 .. versionchanged:: 3.7 - Raises a :exc:`ValueError` if *size* is ``NULL`` and the :c:type:`wchar_t*` + Raises a :exc:`ValueError` if *size* is ``NULL`` and the :c:expr:`wchar_t*` string contains null characters. diff --git a/Doc/extending/extending.rst b/Doc/extending/extending.rst index 0ef899f4c997..d9bf4fd6c7ae 100644 --- a/Doc/extending/extending.rst +++ b/Doc/extending/extending.rst @@ -298,7 +298,7 @@ In this case, it will return an integer object. (Yes, even integers are objects on the heap in Python!) If you have a C function that returns no useful argument (a function returning -:c:type:`void`), the corresponding Python function must return ``None``. You +:c:expr:`void`), the corresponding Python function must return ``None``. You need this idiom to do so (which is implemented by the :c:macro:`Py_RETURN_NONE` macro):: @@ -1171,7 +1171,7 @@ other extension modules must be exported in a different way. Python provides a special mechanism to pass C-level information (pointers) from one extension module to another one: Capsules. A Capsule is a Python data type -which stores a pointer (:c:type:`void \*`). Capsules can only be created and +which stores a pointer (:c:expr:`void \*`). Capsules can only be created and accessed via their C API, but they can be passed around like any other Python object. In particular, they can be assigned to a name in an extension module's namespace. Other extension modules can then import this module, retrieve the @@ -1185,7 +1185,7 @@ different ways between the module providing the code and the client modules. Whichever method you choose, it's important to name your Capsules properly. The function :c:func:`PyCapsule_New` takes a name parameter -(:c:type:`const char \*`); you're permitted to pass in a ``NULL`` name, but +(:c:expr:`const char \*`); you're permitted to pass in a ``NULL`` name, but we strongly encourage you to specify a name. Properly named Capsules provide a degree of runtime type-safety; there is no feasible way to tell one unnamed Capsule from another. @@ -1203,7 +1203,7 @@ of certainty that the Capsule they load contains the correct C API. The following example demonstrates an approach that puts most of the burden on the writer of the exporting module, which is appropriate for commonly used library modules. It stores all C API pointers (just one in the example!) in an -array of :c:type:`void` pointers which becomes the value of a Capsule. The header +array of :c:expr:`void` pointers which becomes the value of a Capsule. The header file corresponding to the module provides a macro that takes care of importing the module and retrieving its C API pointers; client modules only have to call this macro before accessing the C API. diff --git a/Doc/extending/newtypes.rst b/Doc/extending/newtypes.rst index c7c434e58bf0..1eef7f6e8eb9 100644 --- a/Doc/extending/newtypes.rst +++ b/Doc/extending/newtypes.rst @@ -207,7 +207,7 @@ a special case, for which the new value passed to the handler is ``NULL``. Python supports two pairs of attribute handlers; a type that supports attributes only needs to implement the functions for one pair. The difference is that one -pair takes the name of the attribute as a :c:type:`char\*`, while the other +pair takes the name of the attribute as a :c:expr:`char\*`, while the other accepts a :c:type:`PyObject\*`. Each type can use whichever pair makes more sense for the implementation's convenience. :: @@ -339,8 +339,8 @@ of ``NULL`` is required. Type-specific Attribute Management ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -For simplicity, only the :c:type:`char\*` version will be demonstrated here; the -type of the name parameter is the only difference between the :c:type:`char\*` +For simplicity, only the :c:expr:`char\*` version will be demonstrated here; the +type of the name parameter is the only difference between the :c:expr:`char\*` and :c:type:`PyObject\*` flavors of the interface. This example effectively does the same thing as the generic example above, but does not use the generic support added in Python 2.2. It explains how the handler functions are diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index 877d1bad9ced..822a9b0dfec5 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -197,9 +197,9 @@ calls). ``None``, integers, bytes objects and (unicode) strings are the only native Python objects that can directly be used as parameters in these function calls. ``None`` is passed as a C ``NULL`` pointer, bytes objects and strings are passed -as pointer to the memory block that contains their data (:c:type:`char *` or -:c:type:`wchar_t *`). Python integers are passed as the platforms default C -:c:type:`int` type, their value is masked to fit into the C type. +as pointer to the memory block that contains their data (:c:expr:`char *` or +:c:expr:`wchar_t *`). Python integers are passed as the platforms default C +:c:expr:`int` type, their value is masked to fit into the C type. Before we move on calling functions with other parameter types, we have to learn more about :mod:`ctypes` data types. @@ -215,49 +215,49 @@ Fundamental data types +----------------------+------------------------------------------+----------------------------+ | ctypes type | C type | Python type | +======================+==========================================+============================+ -| :class:`c_bool` | :c:type:`_Bool` | bool (1) | +| :class:`c_bool` | :c:expr:`_Bool` | bool (1) | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_char` | :c:type:`char` | 1-character bytes object | +| :class:`c_char` | :c:expr:`char` | 1-character bytes object | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_wchar` | :c:type:`wchar_t` | 1-character string | +| :class:`c_wchar` | :c:expr:`wchar_t` | 1-character string | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_byte` | :c:type:`char` | int | +| :class:`c_byte` | :c:expr:`char` | int | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_ubyte` | :c:type:`unsigned char` | int | +| :class:`c_ubyte` | :c:expr:`unsigned char` | int | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_short` | :c:type:`short` | int | +| :class:`c_short` | :c:expr:`short` | int | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_ushort` | :c:type:`unsigned short` | int | +| :class:`c_ushort` | :c:expr:`unsigned short` | int | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_int` | :c:type:`int` | int | +| :class:`c_int` | :c:expr:`int` | int | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_uint` | :c:type:`unsigned int` | int | +| :class:`c_uint` | :c:expr:`unsigned int` | int | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_long` | :c:type:`long` | int | +| :class:`c_long` | :c:expr:`long` | int | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_ulong` | :c:type:`unsigned long` | int | +| :class:`c_ulong` | :c:expr:`unsigned long` | int | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_longlong` | :c:type:`__int64` or :c:type:`long long` | int | +| :class:`c_longlong` | :c:expr:`__int64` or :c:expr:`long long` | int | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_ulonglong` | :c:type:`unsigned __int64` or | int | -| | :c:type:`unsigned long long` | | +| :class:`c_ulonglong` | :c:expr:`unsigned __int64` or | int | +| | :c:expr:`unsigned long long` | | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_size_t` | :c:type:`size_t` | int | +| :class:`c_size_t` | :c:expr:`size_t` | int | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_ssize_t` | :c:type:`ssize_t` or | int | -| | :c:type:`Py_ssize_t` | | +| :class:`c_ssize_t` | :c:expr:`ssize_t` or | int | +| | :c:expr:`Py_ssize_t` | | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_float` | :c:type:`float` | float | +| :class:`c_float` | :c:expr:`float` | float | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_double` | :c:type:`double` | float | +| :class:`c_double` | :c:expr:`double` | float | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_longdouble`| :c:type:`long double` | float | +| :class:`c_longdouble`| :c:expr:`long double` | float | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_char_p` | :c:type:`char *` (NUL terminated) | bytes object or ``None`` | +| :class:`c_char_p` | :c:expr:`char *` (NUL terminated) | bytes object or ``None`` | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_wchar_p` | :c:type:`wchar_t *` (NUL terminated) | string or ``None`` | +| :class:`c_wchar_p` | :c:expr:`wchar_t *` (NUL terminated) | string or ``None`` | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_void_p` | :c:type:`void *` | int or ``None`` | +| :class:`c_void_p` | :c:expr:`void *` | int or ``None`` | +----------------------+------------------------------------------+----------------------------+ (1) @@ -333,7 +333,7 @@ property:: The :func:`create_string_buffer` function replaces the :func:`c_buffer` function (which is still available as an alias), as well as the :func:`c_string` function from earlier ctypes releases. To create a mutable memory block containing -unicode characters of the C type :c:type:`wchar_t` use the +unicode characters of the C type :c:expr:`wchar_t` use the :func:`create_unicode_buffer` function. @@ -444,7 +444,7 @@ integer, string, bytes, a :mod:`ctypes` instance, or an object with an Return types ^^^^^^^^^^^^ -By default functions are assumed to return the C :c:type:`int` type. Other +By default functions are assumed to return the C :c:expr:`int` type. Other return types can be specified by setting the :attr:`restype` attribute of the function object. @@ -1324,7 +1324,7 @@ way is to instantiate one of the following classes: Instances of this class represent loaded shared libraries. Functions in these libraries use the standard C calling convention, and are assumed to return - :c:type:`int`. + :c:expr:`int`. On Windows creating a :class:`CDLL` instance may fail even if the DLL name exists. When a dependent DLL of the loaded DLL is not found, a @@ -1359,7 +1359,7 @@ way is to instantiate one of the following classes: Windows only: Instances of this class represent loaded shared libraries, functions in these libraries use the ``stdcall`` calling convention, and are - assumed to return :c:type:`int` by default. + assumed to return :c:expr:`int` by default. The Python :term:`global interpreter lock` is released before calling any function exported by these libraries, and reacquired afterwards. @@ -1515,7 +1515,7 @@ object is available: An instance of :class:`PyDLL` that exposes Python C API functions as attributes. Note that all these functions are assumed to return C - :c:type:`int`, which is of course not always the truth, so you have to assign + :c:expr:`int`, which is of course not always the truth, so you have to assign the correct :attr:`restype` attribute to use these functions. .. audit-event:: ctypes.dlopen name ctypes.LibraryLoader @@ -1561,10 +1561,10 @@ They are instances of a private class: .. attribute:: restype Assign a ctypes type to specify the result type of the foreign function. - Use ``None`` for :c:type:`void`, a function not returning anything. + Use ``None`` for :c:expr:`void`, a function not returning anything. It is possible to assign a callable Python object that is not a ctypes - type, in this case the function is assumed to return a C :c:type:`int`, and + type, in this case the function is assumed to return a C :c:expr:`int`, and the callable will be called with this integer, allowing further processing or error checking. Using this is deprecated, for more flexible post processing or error checking use a ctypes data type as @@ -2177,21 +2177,21 @@ These are the fundamental ctypes data types: .. class:: c_byte - Represents the C :c:type:`signed char` datatype, and interprets the value as + Represents the C :c:expr:`signed char` datatype, and interprets the value as small integer. The constructor accepts an optional integer initializer; no overflow checking is done. .. class:: c_char - Represents the C :c:type:`char` datatype, and interprets the value as a single + Represents the C :c:expr:`char` datatype, and interprets the value as a single character. The constructor accepts an optional string initializer, the length of the string must be exactly one character. .. class:: c_char_p - Represents the C :c:type:`char *` datatype when it points to a zero-terminated + Represents the C :c:expr:`char *` datatype when it points to a zero-terminated string. For a general character pointer that may also point to binary data, ``POINTER(c_char)`` must be used. The constructor accepts an integer address, or a bytes object. @@ -2199,68 +2199,68 @@ These are the fundamental ctypes data types: .. class:: c_double - Represents the C :c:type:`double` datatype. The constructor accepts an + Represents the C :c:expr:`double` datatype. The constructor accepts an optional float initializer. .. class:: c_longdouble - Represents the C :c:type:`long double` datatype. The constructor accepts an + Represents the C :c:expr:`long double` datatype. The constructor accepts an optional float initializer. On platforms where ``sizeof(long double) == sizeof(double)`` it is an alias to :class:`c_double`. .. class:: c_float - Represents the C :c:type:`float` datatype. The constructor accepts an + Represents the C :c:expr:`float` datatype. The constructor accepts an optional float initializer. .. class:: c_int - Represents the C :c:type:`signed int` datatype. The constructor accepts an + Represents the C :c:expr:`signed int` datatype. The constructor accepts an optional integer initializer; no overflow checking is done. On platforms where ``sizeof(int) == sizeof(long)`` it is an alias to :class:`c_long`. .. class:: c_int8 - Represents the C 8-bit :c:type:`signed int` datatype. Usually an alias for + Represents the C 8-bit :c:expr:`signed int` datatype. Usually an alias for :class:`c_byte`. .. class:: c_int16 - Represents the C 16-bit :c:type:`signed int` datatype. Usually an alias for + Represents the C 16-bit :c:expr:`signed int` datatype. Usually an alias for :class:`c_short`. .. class:: c_int32 - Represents the C 32-bit :c:type:`signed int` datatype. Usually an alias for + Represents the C 32-bit :c:expr:`signed int` datatype. Usually an alias for :class:`c_int`. .. class:: c_int64 - Represents the C 64-bit :c:type:`signed int` datatype. Usually an alias for + Represents the C 64-bit :c:expr:`signed int` datatype. Usually an alias for :class:`c_longlong`. .. class:: c_long - Represents the C :c:type:`signed long` datatype. The constructor accepts an + Represents the C :c:expr:`signed long` datatype. The constructor accepts an optional integer initializer; no overflow checking is done. .. class:: c_longlong - Represents the C :c:type:`signed long long` datatype. The constructor accepts + Represents the C :c:expr:`signed long long` datatype. The constructor accepts an optional integer initializer; no overflow checking is done. .. class:: c_short - Represents the C :c:type:`signed short` datatype. The constructor accepts an + Represents the C :c:expr:`signed short` datatype. The constructor accepts an optional integer initializer; no overflow checking is done. @@ -2278,83 +2278,83 @@ These are the fundamental ctypes data types: .. class:: c_ubyte - Represents the C :c:type:`unsigned char` datatype, it interprets the value as + Represents the C :c:expr:`unsigned char` datatype, it interprets the value as small integer. The constructor accepts an optional integer initializer; no overflow checking is done. .. class:: c_uint - Represents the C :c:type:`unsigned int` datatype. The constructor accepts an + Represents the C :c:expr:`unsigned int` datatype. The constructor accepts an optional integer initializer; no overflow checking is done. On platforms where ``sizeof(int) == sizeof(long)`` it is an alias for :class:`c_ulong`. .. class:: c_uint8 - Represents the C 8-bit :c:type:`unsigned int` datatype. Usually an alias for + Represents the C 8-bit :c:expr:`unsigned int` datatype. Usually an alias for :class:`c_ubyte`. .. class:: c_uint16 - Represents the C 16-bit :c:type:`unsigned int` datatype. Usually an alias for + Represents the C 16-bit :c:expr:`unsigned int` datatype. Usually an alias for :class:`c_ushort`. .. class:: c_uint32 - Represents the C 32-bit :c:type:`unsigned int` datatype. Usually an alias for + Represents the C 32-bit :c:expr:`unsigned int` datatype. Usually an alias for :class:`c_uint`. .. class:: c_uint64 - Represents the C 64-bit :c:type:`unsigned int` datatype. Usually an alias for + Represents the C 64-bit :c:expr:`unsigned int` datatype. Usually an alias for :class:`c_ulonglong`. .. class:: c_ulong - Represents the C :c:type:`unsigned long` datatype. The constructor accepts an + Represents the C :c:expr:`unsigned long` datatype. The constructor accepts an optional integer initializer; no overflow checking is done. .. class:: c_ulonglong - Represents the C :c:type:`unsigned long long` datatype. The constructor + Represents the C :c:expr:`unsigned long long` datatype. The constructor accepts an optional integer initializer; no overflow checking is done. .. class:: c_ushort - Represents the C :c:type:`unsigned short` datatype. The constructor accepts + Represents the C :c:expr:`unsigned short` datatype. The constructor accepts an optional integer initializer; no overflow checking is done. .. class:: c_void_p - Represents the C :c:type:`void *` type. The value is represented as integer. + Represents the C :c:expr:`void *` type. The value is represented as integer. The constructor accepts an optional integer initializer. .. class:: c_wchar - Represents the C :c:type:`wchar_t` datatype, and interprets the value as a + Represents the C :c:expr:`wchar_t` datatype, and interprets the value as a single character unicode string. The constructor accepts an optional string initializer, the length of the string must be exactly one character. .. class:: c_wchar_p - Represents the C :c:type:`wchar_t *` datatype, which must be a pointer to a + Represents the C :c:expr:`wchar_t *` datatype, which must be a pointer to a zero-terminated wide character string. The constructor accepts an integer address, or a string. .. class:: c_bool - Represent the C :c:type:`bool` datatype (more accurately, :c:type:`_Bool` from + Represent the C :c:expr:`bool` datatype (more accurately, :c:expr:`_Bool` from C99). Its value can be ``True`` or ``False``, and the constructor accepts any object that has a truth value. diff --git a/Doc/library/posix.rst b/Doc/library/posix.rst index 90be191aa2f8..ec04b0dcfc16 100644 --- a/Doc/library/posix.rst +++ b/Doc/library/posix.rst @@ -39,12 +39,12 @@ Large File Support Several operating systems (including AIX and Solaris) provide support for files that are larger than 2 GiB from a C programming model where -:c:type:`int` and :c:type:`long` are 32-bit values. This is typically accomplished +:c:expr:`int` and :c:expr:`long` are 32-bit values. This is typically accomplished by defining the relevant size and offset types as 64-bit values. Such files are sometimes referred to as :dfn:`large files`. Large file support is enabled in Python when the size of an :c:type:`off_t` is -larger than a :c:type:`long` and the :c:type:`long long` is at least as large +larger than a :c:expr:`long` and the :c:expr:`long long` is at least as large as an :c:type:`off_t`. It may be necessary to configure and compile Python with certain compiler flags to enable this mode. For example, with Solaris 2.6 and 2.7 you need to do diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst index 6216e19751eb..205d08bf82cf 100644 --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -1477,7 +1477,7 @@ to sockets. ancillary data, items of the form ``(socket.SOL_SOCKET, socket.SCM_RIGHTS, fds)``, where *fds* is a :class:`bytes` object representing the new file descriptors as a binary array of the - native C :c:type:`int` type. If :meth:`recvmsg` raises an + native C :c:expr:`int` type. If :meth:`recvmsg` raises an exception after the system call returns, it will first attempt to close any file descriptors received via this mechanism. diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index a91b44fadd04..868d7bb2501b 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -215,7 +215,7 @@ Numeric Types --- :class:`int`, :class:`float`, :class:`complex` There are three distinct numeric types: :dfn:`integers`, :dfn:`floating point numbers`, and :dfn:`complex numbers`. In addition, Booleans are a subtype of integers. Integers have unlimited precision. Floating point -numbers are usually implemented using :c:type:`double` in C; information +numbers are usually implemented using :c:expr:`double` in C; information about the precision and internal representation of floating point numbers for the machine on which your program is running is available in :data:`sys.float_info`. Complex numbers have a real and imaginary diff --git a/Doc/library/struct.rst b/Doc/library/struct.rst index c1888d4a94fe..d12a5732fa4a 100644 --- a/Doc/library/struct.rst +++ b/Doc/library/struct.rst @@ -196,46 +196,46 @@ platform-dependent. +========+==========================+====================+================+============+ | ``x`` | pad byte | no value | | | +--------+--------------------------+--------------------+----------------+------------+ -| ``c`` | :c:type:`char` | bytes of length 1 | 1 | | +| ``c`` | :c:expr:`char` | bytes of length 1 | 1 | | +--------+--------------------------+--------------------+----------------+------------+ -| ``b`` | :c:type:`signed char` | integer | 1 | \(1), \(2) | +| ``b`` | :c:expr:`signed char` | integer | 1 | \(1), \(2) | +--------+--------------------------+--------------------+----------------+------------+ -| ``B`` | :c:type:`unsigned char` | integer | 1 | \(2) | +| ``B`` | :c:expr:`unsigned char` | integer | 1 | \(2) | +--------+--------------------------+--------------------+----------------+------------+ -| ``?`` | :c:type:`_Bool` | bool | 1 | \(1) | +| ``?`` | :c:expr:`_Bool` | bool | 1 | \(1) | +--------+--------------------------+--------------------+----------------+------------+ -| ``h`` | :c:type:`short` | integer | 2 | \(2) | +| ``h`` | :c:expr:`short` | integer | 2 | \(2) | +--------+--------------------------+--------------------+----------------+------------+ -| ``H`` | :c:type:`unsigned short` | integer | 2 | \(2) | +| ``H`` | :c:expr:`unsigned short` | integer | 2 | \(2) | +--------+--------------------------+--------------------+----------------+------------+ -| ``i`` | :c:type:`int` | integer | 4 | \(2) | +| ``i`` | :c:expr:`int` | integer | 4 | \(2) | +--------+--------------------------+--------------------+----------------+------------+ -| ``I`` | :c:type:`unsigned int` | integer | 4 | \(2) | +| ``I`` | :c:expr:`unsigned int` | integer | 4 | \(2) | +--------+--------------------------+--------------------+----------------+------------+ -| ``l`` | :c:type:`long` | integer | 4 | \(2) | +| ``l`` | :c:expr:`long` | integer | 4 | \(2) | +--------+--------------------------+--------------------+----------------+------------+ -| ``L`` | :c:type:`unsigned long` | integer | 4 | \(2) | +| ``L`` | :c:expr:`unsigned long` | integer | 4 | \(2) | +--------+--------------------------+--------------------+----------------+------------+ -| ``q`` | :c:type:`long long` | integer | 8 | \(2) | +| ``q`` | :c:expr:`long long` | integer | 8 | \(2) | +--------+--------------------------+--------------------+----------------+------------+ -| ``Q`` | :c:type:`unsigned long | integer | 8 | \(2) | +| ``Q`` | :c:expr:`unsigned long | integer | 8 | \(2) | | | long` | | | | +--------+--------------------------+--------------------+----------------+------------+ -| ``n`` | :c:type:`ssize_t` | integer | | \(3) | +| ``n`` | :c:expr:`ssize_t` | integer | | \(3) | +--------+--------------------------+--------------------+----------------+------------+ -| ``N`` | :c:type:`size_t` | integer | | \(3) | +| ``N`` | :c:expr:`size_t` | integer | | \(3) | +--------+--------------------------+--------------------+----------------+------------+ | ``e`` | \(6) | float | 2 | \(4) | +--------+--------------------------+--------------------+----------------+------------+ -| ``f`` | :c:type:`float` | float | 4 | \(4) | +| ``f`` | :c:expr:`float` | float | 4 | \(4) | +--------+--------------------------+--------------------+----------------+------------+ -| ``d`` | :c:type:`double` | float | 8 | \(4) | +| ``d`` | :c:expr:`double` | float | 8 | \(4) | +--------+--------------------------+--------------------+----------------+------------+ -| ``s`` | :c:type:`char[]` | bytes | | | +| ``s`` | :c:expr:`char[]` | bytes | | | +--------+--------------------------+--------------------+----------------+------------+ -| ``p`` | :c:type:`char[]` | bytes | | | +| ``p`` | :c:expr:`char[]` | bytes | | | +--------+--------------------------+--------------------+----------------+------------+ -| ``P`` | :c:type:`void \*` | integer | | \(5) | +| ``P`` | :c:expr:`void \*` | integer | | \(5) | +--------+--------------------------+--------------------+----------------+------------+ .. versionchanged:: 3.3 @@ -250,8 +250,8 @@ Notes: (1) .. index:: single: ? (question mark); in struct format strings - The ``'?'`` conversion code corresponds to the :c:type:`_Bool` type defined by - C99. If this type is not available, it is simulated using a :c:type:`char`. In + The ``'?'`` conversion code corresponds to the :c:expr:`_Bool` type defined by + C99. If this type is not available, it is simulated using a :c:expr:`char`. In standard mode, it is always represented by one byte. (2) diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index ea9192bd8232..e92b9a2eaf4e 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -316,7 +316,7 @@ Sequences A string is a sequence of values that represent Unicode code points. All the code points in the range ``U+0000 - U+10FFFF`` can be - represented in a string. Python doesn't have a :c:type:`char` type; + represented in a string. Python doesn't have a :c:expr:`char` type; instead, every code point in the string is represented as a string object with length ``1``. The built-in function :func:`ord` converts a code point from its string form to an integer in the diff --git a/Doc/whatsnew/2.2.rst b/Doc/whatsnew/2.2.rst index 9355c1badaa2..bfb2aacbc077 100644 --- a/Doc/whatsnew/2.2.rst +++ b/Doc/whatsnew/2.2.rst @@ -983,7 +983,7 @@ New and Improved Modules Jun-ichiro "itojun" Hagino.) * Two new format characters were added to the :mod:`struct` module for 64-bit - integers on platforms that support the C :c:type:`long long` type. ``q`` is for + integers on platforms that support the C :c:expr:`long long` type. ``q`` is for a signed 64-bit integer, and ``Q`` is for an unsigned one. The value is returned in Python's long integer type. (Contributed by Tim Peters.) diff --git a/Doc/whatsnew/2.3.rst b/Doc/whatsnew/2.3.rst index 27a0756cbb84..c6e2003e92f1 100644 --- a/Doc/whatsnew/2.3.rst +++ b/Doc/whatsnew/2.3.rst @@ -1905,8 +1905,8 @@ Changes to Python's build process and to the C API include: "")`` instead, but this will be slower than using :const:`METH_NOARGS`. * :c:func:`PyArg_ParseTuple` accepts new format characters for various sizes of - unsigned integers: ``B`` for :c:type:`unsigned char`, ``H`` for :c:type:`unsigned - short int`, ``I`` for :c:type:`unsigned int`, and ``K`` for :c:type:`unsigned + unsigned integers: ``B`` for :c:expr:`unsigned char`, ``H`` for :c:expr:`unsigned + short int`, ``I`` for :c:expr:`unsigned int`, and ``K`` for :c:expr:`unsigned long long`. * A new function, ``PyObject_DelItemString(mapping, char *key)`` was added diff --git a/Doc/whatsnew/2.4.rst b/Doc/whatsnew/2.4.rst index 61f9eb43243c..63e819876ce3 100644 --- a/Doc/whatsnew/2.4.rst +++ b/Doc/whatsnew/2.4.rst @@ -472,7 +472,7 @@ PEP 327: Decimal Data Type ========================== Python has always supported floating-point (FP) numbers, based on the underlying -C :c:type:`double` type, as a data type. However, while most programming +C :c:expr:`double` type, as a data type. However, while most programming languages provide a floating-point type, many people (even programmers) are unaware that floating-point numbers don't represent certain decimal fractions accurately. The new :class:`Decimal` type can represent these fractions @@ -501,7 +501,7 @@ mantissa is multiplied by 4 (2 to the power of the exponent 2); 1.25 \* 4 equals 5. Modern systems usually provide floating-point support that conforms to a -standard called IEEE 754. C's :c:type:`double` type is usually implemented as a +standard called IEEE 754. C's :c:expr:`double` type is usually implemented as a 64-bit IEEE 754 number, which uses 52 bits of space for the mantissa. This means that numbers can only be specified to 52 bits of precision. If you're trying to represent numbers whose expansion repeats endlessly, the expansion is @@ -750,10 +750,10 @@ The solution described in the PEP is to add three new functions to the Python API that perform ASCII-only conversions, ignoring the locale setting: * ``PyOS_ascii_strtod(str, ptr)`` and ``PyOS_ascii_atof(str, ptr)`` - both convert a string to a C :c:type:`double`. + both convert a string to a C :c:expr:`double`. * ``PyOS_ascii_formatd(buffer, buf_len, format, d)`` converts a - :c:type:`double` to an ASCII string. + :c:expr:`double` to an ASCII string. The code for these functions came from the GLib library (https://developer.gnome.org/glib/stable/), whose developers kindly diff --git a/Doc/whatsnew/2.5.rst b/Doc/whatsnew/2.5.rst index dfa8f7e93f81..0aca2fe697cc 100644 --- a/Doc/whatsnew/2.5.rst +++ b/Doc/whatsnew/2.5.rst @@ -872,18 +872,18 @@ PEP 353: Using ssize_t as the index type ======================================== A wide-ranging change to Python's C API, using a new :c:type:`Py_ssize_t` type -definition instead of :c:type:`int`, will permit the interpreter to handle more +definition instead of :c:expr:`int`, will permit the interpreter to handle more data on 64-bit platforms. This change doesn't affect Python's capacity on 32-bit platforms. -Various pieces of the Python interpreter used C's :c:type:`int` type to store +Various pieces of the Python interpreter used C's :c:expr:`int` type to store sizes or counts; for example, the number of items in a list or tuple were stored -in an :c:type:`int`. The C compilers for most 64-bit platforms still define -:c:type:`int` as a 32-bit type, so that meant that lists could only hold up to +in an :c:expr:`int`. The C compilers for most 64-bit platforms still define +:c:expr:`int` as a 32-bit type, so that meant that lists could only hold up to ``2**31 - 1`` = 2147483647 items. (There are actually a few different programming models that 64-bit C compilers can use -- see https://unix.org/version2/whatsnew/lp64_wp.html for a discussion -- but the -most commonly available model leaves :c:type:`int` as 32 bits.) +most commonly available model leaves :c:expr:`int` as 32 bits.) A limit of 2147483647 items doesn't really matter on a 32-bit platform because you'll run out of memory before hitting the length limit. Each list item @@ -895,7 +895,7 @@ It's possible to address that much memory on a 64-bit platform, however. The pointers for a list that size would only require 16 GiB of space, so it's not unreasonable that Python programmers might construct lists that large. Therefore, the Python interpreter had to be changed to use some type other than -:c:type:`int`, and this will be a 64-bit type on 64-bit platforms. The change +:c:expr:`int`, and this will be a 64-bit type on 64-bit platforms. The change will cause incompatibilities on 64-bit machines, so it was deemed worth making the transition now, while the number of 64-bit users is still relatively small. (In 5 or 10 years, we may *all* be on 64-bit machines, and the transition would @@ -909,7 +909,7 @@ may therefore need to have some variables changed to :c:type:`Py_ssize_t`. The :c:func:`PyArg_ParseTuple` and :c:func:`Py_BuildValue` functions have a new conversion code, ``n``, for :c:type:`Py_ssize_t`. :c:func:`PyArg_ParseTuple`'s -``s#`` and ``t#`` still output :c:type:`int` by default, but you can define the +``s#`` and ``t#`` still output :c:expr:`int` by default, but you can define the macro :c:macro:`PY_SSIZE_T_CLEAN` before including :file:`Python.h` to make them return :c:type:`Py_ssize_t`. @@ -1695,7 +1695,7 @@ attributes of the :class:`CDLL` object. :: result = libc.printf("Line of output\n") Type constructors for the various C types are provided: :func:`c_int`, -:func:`c_float`, :func:`c_double`, :func:`c_char_p` (equivalent to :c:type:`char +:func:`c_float`, :func:`c_double`, :func:`c_char_p` (equivalent to :c:expr:`char \*`), and so forth. Unlike Python's types, the C versions are all mutable; you can assign to their :attr:`value` attribute to change the wrapped value. Python integers and strings will be automatically converted to the corresponding C @@ -2093,7 +2093,7 @@ Changes to Python's build process and to the C API include: * The largest change to the C API came from :pep:`353`, which modifies the interpreter to use a :c:type:`Py_ssize_t` type definition instead of - :c:type:`int`. See the earlier section :ref:`pep-353` for a discussion of this + :c:expr:`int`. See the earlier section :ref:`pep-353` for a discussion of this change. * The design of the bytecode compiler has changed a great deal, no longer @@ -2264,7 +2264,7 @@ code: Setting :attr:`rpc_paths` to ``None`` or an empty tuple disables this path checking. -* C API: Many functions now use :c:type:`Py_ssize_t` instead of :c:type:`int` to +* C API: Many functions now use :c:type:`Py_ssize_t` instead of :c:expr:`int` to allow processing more data on 64-bit machines. Extension code may need to make the same change to avoid warnings and to support 64-bit machines. See the earlier section :ref:`pep-353` for a discussion of this change. diff --git a/Doc/whatsnew/2.6.rst b/Doc/whatsnew/2.6.rst index 5a3c103f29a7..731ce6aac691 100644 --- a/Doc/whatsnew/2.6.rst +++ b/Doc/whatsnew/2.6.rst @@ -2389,7 +2389,7 @@ changes, or look through the Subversion logs for all the details. has been updated from version 2.3.2 in Python 2.5 to version 2.4.1. -* The :mod:`struct` module now supports the C99 :c:type:`_Bool` type, +* The :mod:`struct` module now supports the C99 :c:expr:`_Bool` type, using the format character ``'?'``. (Contributed by David Remahl.) diff --git a/Doc/whatsnew/2.7.rst b/Doc/whatsnew/2.7.rst index f79dcdc74bcf..fbfcc5db5f5f 100644 --- a/Doc/whatsnew/2.7.rst +++ b/Doc/whatsnew/2.7.rst @@ -2144,7 +2144,7 @@ Changes to Python's build process and to the C API include: * New functions: :c:func:`PyLong_AsLongAndOverflow` and :c:func:`PyLong_AsLongLongAndOverflow` approximates a Python long - integer as a C :c:type:`long` or :c:type:`long long`. + integer as a C :c:expr:`long` or :c:expr:`long long`. If the number is too large to fit into the output type, an *overflow* flag is set and returned to the caller. (Contributed by Case Van Horsen; :issue:`7528` and :issue:`7767`.) @@ -2202,7 +2202,7 @@ Changes to Python's build process and to the C API include: * New format codes: the :c:func:`PyFormat_FromString`, :c:func:`PyFormat_FromStringV`, and :c:func:`PyErr_Format` functions now accept ``%lld`` and ``%llu`` format codes for displaying - C's :c:type:`long long` types. + C's :c:expr:`long long` types. (Contributed by Mark Dickinson; :issue:`7228`.) * The complicated interaction between threads and process forking has diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst index 609370bad274..fef1a8ac4c01 100644 --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -932,7 +932,7 @@ it can now be used as a class decorator (:issue:`10868`). array ----- -The :mod:`array` module supports the :c:type:`long long` type using ``q`` and +The :mod:`array` module supports the :c:expr:`long long` type using ``q`` and ``Q`` type codes. (Contributed by Oren Tirosh and Hirokazu Yamamoto in :issue:`1172711`.) diff --git a/Doc/whatsnew/3.7.rst b/Doc/whatsnew/3.7.rst index 06df10df80a7..ece406983b94 100644 --- a/Doc/whatsnew/3.7.rst +++ b/Doc/whatsnew/3.7.rst @@ -290,21 +290,21 @@ PEP 539: New C API for Thread-Local Storage While Python provides a C API for thread-local storage support; the existing :ref:`Thread Local Storage (TLS) API ` has used -:c:type:`int` to represent TLS keys across all platforms. This has not +:c:expr:`int` to represent TLS keys across all platforms. This has not generally been a problem for officially support platforms, but that is neither POSIX-compliant, nor portable in any practical sense. :pep:`539` changes this by providing a new :ref:`Thread Specific Storage (TSS) API ` to CPython which supersedes use of the existing TLS API within the CPython interpreter, while deprecating the existing -API. The TSS API uses a new type :c:type:`Py_tss_t` instead of :c:type:`int` +API. The TSS API uses a new type :c:type:`Py_tss_t` instead of :c:expr:`int` to represent TSS keys--an opaque type the definition of which may depend on the underlying TLS implementation. Therefore, this will allow to build CPython on platforms where the native TLS key is defined in a way that cannot be safely -cast to :c:type:`int`. +cast to :c:expr:`int`. Note that on platforms where the native TLS key is defined in a way that cannot -be safely cast to :c:type:`int`, all functions of the existing TLS API will be +be safely cast to :c:expr:`int`, all functions of the existing TLS API will be no-op and immediately return failure. This indicates clearly that the old API is not supported on platforms where it cannot be used reliably, and that no effort will be made to add such support. @@ -1708,12 +1708,12 @@ Contributed by Paul Ganssle in :issue:`10381`. The type of results of :c:func:`PyThread_start_new_thread` and :c:func:`PyThread_get_thread_ident`, and the *id* parameter of -:c:func:`PyThreadState_SetAsyncExc` changed from :c:type:`long` to -:c:type:`unsigned long`. +:c:func:`PyThreadState_SetAsyncExc` changed from :c:expr:`long` to +:c:expr:`unsigned long`. (Contributed by Serhiy Storchaka in :issue:`6532`.) :c:func:`PyUnicode_AsWideCharString` now raises a :exc:`ValueError` if the -second argument is ``NULL`` and the :c:type:`wchar_t*` string contains null +second argument is ``NULL`` and the :c:expr:`wchar_t*` string contains null characters. (Contributed by Serhiy Storchaka in :issue:`30708`.) Changes to the startup sequence and the management of dynamic memory diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index 9408e3609e8c..20d79defeed1 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -773,7 +773,7 @@ Optimizations Stinner in :issue:`38061`.) * :c:func:`PyLong_FromDouble` is now up to 1.87x faster for values that - fit into :c:type:`long`. + fit into :c:expr:`long`. (Contributed by Sergey Fedoseev in :issue:`37986`.) * A number of Python builtins (:class:`range`, :class:`tuple`, :class:`set`, diff --git a/Misc/NEWS.d/3.5.0a1.rst b/Misc/NEWS.d/3.5.0a1.rst index 97bdef6c9321..96e59206cb12 100644 --- a/Misc/NEWS.d/3.5.0a1.rst +++ b/Misc/NEWS.d/3.5.0a1.rst @@ -3034,7 +3034,7 @@ by Phil Elson. .. nonce: LK_5S1 .. section: Library -os.read() now uses a :c:func:`Py_ssize_t` type instead of :c:type:`int` for +os.read() now uses a :c:func:`Py_ssize_t` type instead of :c:expr:`int` for the size to support reading more than 2 GB at once. On Windows, the size is truncated to INT_MAX. As any call to os.read(), the OS may read less bytes than the number of requested bytes. diff --git a/Misc/NEWS.d/3.9.0a1.rst b/Misc/NEWS.d/3.9.0a1.rst index 45f232f1948d..63d77fd3ac0c 100644 --- a/Misc/NEWS.d/3.9.0a1.rst +++ b/Misc/NEWS.d/3.9.0a1.rst @@ -1510,7 +1510,7 @@ asynchronous magic methods on a MagicMock now return an AsyncMock. .. section: Library Update the *length* parameter of :func:`os.pread` to accept -:c:type:`Py_ssize_t` instead of :c:type:`int`. +:c:type:`Py_ssize_t` instead of :c:expr:`int`. .. diff --git a/Misc/NEWS.d/3.9.0b1.rst b/Misc/NEWS.d/3.9.0b1.rst index 51dc9ce0ec03..b4bd5f3faeaa 100644 --- a/Misc/NEWS.d/3.9.0b1.rst +++ b/Misc/NEWS.d/3.9.0b1.rst @@ -191,7 +191,7 @@ internal subinterpreters module. .. section: Core and Builtins Improve performance of :c:func:`PyLong_FromDouble` for values that fit into -:c:type:`long`. +:c:expr:`long`. .. From webhook-mailer at python.org Wed Oct 5 17:11:18 2022 From: webhook-mailer at python.org (ambv) Date: Wed, 05 Oct 2022 21:11:18 -0000 Subject: [Python-checkins] [3.11] gh-93738: Documentation C syntax (:c:type: -> :c:expr:) (GH-97768) (#97924) Message-ID: https://github.com/python/cpython/commit/83ad76275c983ed6e6960f00ab3d10e31abb5182 commit: 83ad76275c983ed6e6960f00ab3d10e31abb5182 branch: 3.11 author: ?ukasz Langa committer: ambv date: 2022-10-05T14:11:12-07:00 summary: [3.11] gh-93738: Documentation C syntax (:c:type: -> :c:expr:) (GH-97768) (#97924) :c:type:`` -> :c:expr:`` Co-authored-by: ?ukasz Langa (cherry picked from commit 0031e62973801d34a9e19ab7bb199e9668e32d7b) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> files: M Doc/c-api/arg.rst M Doc/c-api/capsule.rst M Doc/c-api/complex.rst M Doc/c-api/conversion.rst M Doc/c-api/dict.rst M Doc/c-api/file.rst M Doc/c-api/float.rst M Doc/c-api/init.rst M Doc/c-api/intro.rst M Doc/c-api/long.rst M Doc/c-api/marshal.rst M Doc/c-api/memory.rst M Doc/c-api/sys.rst M Doc/c-api/unicode.rst M Doc/extending/extending.rst M Doc/extending/newtypes.rst M Doc/library/ctypes.rst M Doc/library/posix.rst M Doc/library/socket.rst M Doc/library/stdtypes.rst M Doc/library/struct.rst M Doc/reference/datamodel.rst M Doc/whatsnew/2.2.rst M Doc/whatsnew/2.3.rst M Doc/whatsnew/2.4.rst M Doc/whatsnew/2.5.rst M Doc/whatsnew/2.6.rst M Doc/whatsnew/2.7.rst M Doc/whatsnew/3.3.rst M Doc/whatsnew/3.7.rst M Doc/whatsnew/3.9.rst M Misc/NEWS.d/3.5.0a1.rst M Misc/NEWS.d/3.9.0a1.rst M Misc/NEWS.d/3.9.0b1.rst diff --git a/Doc/c-api/arg.rst b/Doc/c-api/arg.rst index 91d764c13f67..85f9eda17a20 100644 --- a/Doc/c-api/arg.rst +++ b/Doc/c-api/arg.rst @@ -194,10 +194,10 @@ which disallows mutable objects such as :class:`bytearray`. It only works for encoded data without embedded NUL bytes. This format requires two arguments. The first is only used as input, and - must be a :c:type:`const char*` which points to the name of an encoding as a + must be a :c:expr:`const char*` which points to the name of an encoding as a NUL-terminated string, or ``NULL``, in which case ``'utf-8'`` encoding is used. An exception is raised if the named encoding is not known to Python. The - second argument must be a :c:type:`char**`; the value of the pointer it + second argument must be a :c:expr:`char**`; the value of the pointer it references will be set to a buffer with the contents of the argument text. The text will be encoded in the encoding specified by the first argument. @@ -217,10 +217,10 @@ which disallows mutable objects such as :class:`bytearray`. characters. It requires three arguments. The first is only used as input, and must be a - :c:type:`const char*` which points to the name of an encoding as a + :c:expr:`const char*` which points to the name of an encoding as a NUL-terminated string, or ``NULL``, in which case ``'utf-8'`` encoding is used. An exception is raised if the named encoding is not known to Python. The - second argument must be a :c:type:`char**`; the value of the pointer it + second argument must be a :c:expr:`char**`; the value of the pointer it references will be set to a buffer with the contents of the argument text. The text will be encoded in the encoding specified by the first argument. The third argument must be a pointer to an integer; the referenced integer @@ -252,38 +252,38 @@ Numbers ``b`` (:class:`int`) [unsigned char] Convert a nonnegative Python integer to an unsigned tiny int, stored in a C - :c:type:`unsigned char`. + :c:expr:`unsigned char`. ``B`` (:class:`int`) [unsigned char] Convert a Python integer to a tiny int without overflow checking, stored in a C - :c:type:`unsigned char`. + :c:expr:`unsigned char`. ``h`` (:class:`int`) [short int] - Convert a Python integer to a C :c:type:`short int`. + Convert a Python integer to a C :c:expr:`short int`. ``H`` (:class:`int`) [unsigned short int] - Convert a Python integer to a C :c:type:`unsigned short int`, without overflow + Convert a Python integer to a C :c:expr:`unsigned short int`, without overflow checking. ``i`` (:class:`int`) [int] - Convert a Python integer to a plain C :c:type:`int`. + Convert a Python integer to a plain C :c:expr:`int`. ``I`` (:class:`int`) [unsigned int] - Convert a Python integer to a C :c:type:`unsigned int`, without overflow + Convert a Python integer to a C :c:expr:`unsigned int`, without overflow checking. ``l`` (:class:`int`) [long int] - Convert a Python integer to a C :c:type:`long int`. + Convert a Python integer to a C :c:expr:`long int`. ``k`` (:class:`int`) [unsigned long] - Convert a Python integer to a C :c:type:`unsigned long` without + Convert a Python integer to a C :c:expr:`unsigned long` without overflow checking. ``L`` (:class:`int`) [long long] - Convert a Python integer to a C :c:type:`long long`. + Convert a Python integer to a C :c:expr:`long long`. ``K`` (:class:`int`) [unsigned long long] - Convert a Python integer to a C :c:type:`unsigned long long` + Convert a Python integer to a C :c:expr:`unsigned long long` without overflow checking. ``n`` (:class:`int`) [:c:type:`Py_ssize_t`] @@ -291,20 +291,20 @@ Numbers ``c`` (:class:`bytes` or :class:`bytearray` of length 1) [char] Convert a Python byte, represented as a :class:`bytes` or - :class:`bytearray` object of length 1, to a C :c:type:`char`. + :class:`bytearray` object of length 1, to a C :c:expr:`char`. .. versionchanged:: 3.3 Allow :class:`bytearray` objects. ``C`` (:class:`str` of length 1) [int] Convert a Python character, represented as a :class:`str` object of - length 1, to a C :c:type:`int`. + length 1, to a C :c:expr:`int`. ``f`` (:class:`float`) [float] - Convert a Python floating point number to a C :c:type:`float`. + Convert a Python floating point number to a C :c:expr:`float`. ``d`` (:class:`float`) [double] - Convert a Python floating point number to a C :c:type:`double`. + Convert a Python floating point number to a C :c:expr:`double`. ``D`` (:class:`complex`) [Py_complex] Convert a Python complex number to a C :c:type:`Py_complex` structure. @@ -329,13 +329,13 @@ Other objects ``O&`` (object) [*converter*, *anything*] Convert a Python object to a C variable through a *converter* function. This takes two arguments: the first is a function, the second is the address of a C - variable (of arbitrary type), converted to :c:type:`void *`. The *converter* + variable (of arbitrary type), converted to :c:expr:`void *`. The *converter* function in turn is called as follows:: status = converter(object, address); where *object* is the Python object to be converted and *address* is the - :c:type:`void*` argument that was passed to the ``PyArg_Parse*`` function. + :c:expr:`void*` argument that was passed to the ``PyArg_Parse*`` function. The returned *status* should be ``1`` for a successful conversion and ``0`` if the conversion has failed. When the conversion fails, the *converter* function should raise an exception and leave the content of *address* unmodified. @@ -568,7 +568,7 @@ Building values Same as ``s#``. ``u`` (:class:`str`) [const wchar_t \*] - Convert a null-terminated :c:type:`wchar_t` buffer of Unicode (UTF-16 or UCS-4) + Convert a null-terminated :c:expr:`wchar_t` buffer of Unicode (UTF-16 or UCS-4) data to a Python Unicode object. If the Unicode buffer pointer is ``NULL``, ``None`` is returned. @@ -584,51 +584,51 @@ Building values Same as ``s#``. ``i`` (:class:`int`) [int] - Convert a plain C :c:type:`int` to a Python integer object. + Convert a plain C :c:expr:`int` to a Python integer object. ``b`` (:class:`int`) [char] - Convert a plain C :c:type:`char` to a Python integer object. + Convert a plain C :c:expr:`char` to a Python integer object. ``h`` (:class:`int`) [short int] - Convert a plain C :c:type:`short int` to a Python integer object. + Convert a plain C :c:expr:`short int` to a Python integer object. ``l`` (:class:`int`) [long int] - Convert a C :c:type:`long int` to a Python integer object. + Convert a C :c:expr:`long int` to a Python integer object. ``B`` (:class:`int`) [unsigned char] - Convert a C :c:type:`unsigned char` to a Python integer object. + Convert a C :c:expr:`unsigned char` to a Python integer object. ``H`` (:class:`int`) [unsigned short int] - Convert a C :c:type:`unsigned short int` to a Python integer object. + Convert a C :c:expr:`unsigned short int` to a Python integer object. ``I`` (:class:`int`) [unsigned int] - Convert a C :c:type:`unsigned int` to a Python integer object. + Convert a C :c:expr:`unsigned int` to a Python integer object. ``k`` (:class:`int`) [unsigned long] - Convert a C :c:type:`unsigned long` to a Python integer object. + Convert a C :c:expr:`unsigned long` to a Python integer object. ``L`` (:class:`int`) [long long] - Convert a C :c:type:`long long` to a Python integer object. + Convert a C :c:expr:`long long` to a Python integer object. ``K`` (:class:`int`) [unsigned long long] - Convert a C :c:type:`unsigned long long` to a Python integer object. + Convert a C :c:expr:`unsigned long long` to a Python integer object. ``n`` (:class:`int`) [:c:type:`Py_ssize_t`] Convert a C :c:type:`Py_ssize_t` to a Python integer. ``c`` (:class:`bytes` of length 1) [char] - Convert a C :c:type:`int` representing a byte to a Python :class:`bytes` object of + Convert a C :c:expr:`int` representing a byte to a Python :class:`bytes` object of length 1. ``C`` (:class:`str` of length 1) [int] - Convert a C :c:type:`int` representing a character to Python :class:`str` + Convert a C :c:expr:`int` representing a character to Python :class:`str` object of length 1. ``d`` (:class:`float`) [double] - Convert a C :c:type:`double` to a Python floating point number. + Convert a C :c:expr:`double` to a Python floating point number. ``f`` (:class:`float`) [float] - Convert a C :c:type:`float` to a Python floating point number. + Convert a C :c:expr:`float` to a Python floating point number. ``D`` (:class:`complex`) [Py_complex \*] Convert a C :c:type:`Py_complex` structure to a Python complex number. @@ -651,7 +651,7 @@ Building values ``O&`` (object) [*converter*, *anything*] Convert *anything* to a Python object through a *converter* function. The - function is called with *anything* (which should be compatible with :c:type:`void*`) + function is called with *anything* (which should be compatible with :c:expr:`void*`) as its argument and should return a "new" Python object, or ``NULL`` if an error occurred. diff --git a/Doc/c-api/capsule.rst b/Doc/c-api/capsule.rst index 2c4cfc48f9a2..1c8f432505ef 100644 --- a/Doc/c-api/capsule.rst +++ b/Doc/c-api/capsule.rst @@ -15,7 +15,7 @@ Refer to :ref:`using-capsules` for more information on using these objects. .. c:type:: PyCapsule This subtype of :c:type:`PyObject` represents an opaque value, useful for C - extension modules who need to pass an opaque value (as a :c:type:`void*` + extension modules who need to pass an opaque value (as a :c:expr:`void*` pointer) through Python code to other C code. It is often used to make a C function pointer defined in one module available to other modules, so the regular import mechanism can be used to access C APIs defined in dynamically diff --git a/Doc/c-api/complex.rst b/Doc/c-api/complex.rst index c25894681bca..9228ce852000 100644 --- a/Doc/c-api/complex.rst +++ b/Doc/c-api/complex.rst @@ -115,12 +115,12 @@ Complex Numbers as Python Objects .. c:function:: double PyComplex_RealAsDouble(PyObject *op) - Return the real part of *op* as a C :c:type:`double`. + Return the real part of *op* as a C :c:expr:`double`. .. c:function:: double PyComplex_ImagAsDouble(PyObject *op) - Return the imaginary part of *op* as a C :c:type:`double`. + Return the imaginary part of *op* as a C :c:expr:`double`. .. c:function:: Py_complex PyComplex_AsCComplex(PyObject *op) diff --git a/Doc/c-api/conversion.rst b/Doc/c-api/conversion.rst index 7b4cc1cacdd4..9b9c4ffa4d03 100644 --- a/Doc/c-api/conversion.rst +++ b/Doc/c-api/conversion.rst @@ -49,7 +49,7 @@ The following functions provide locale-independent string to number conversions. .. c:function:: double PyOS_string_to_double(const char *s, char **endptr, PyObject *overflow_exception) - Convert a string ``s`` to a :c:type:`double`, raising a Python + Convert a string ``s`` to a :c:expr:`double`, raising a Python exception on failure. The set of accepted strings corresponds to the set of strings accepted by Python's :func:`float` constructor, except that ``s`` must not have leading or trailing whitespace. @@ -83,7 +83,7 @@ The following functions provide locale-independent string to number conversions. .. c:function:: char* PyOS_double_to_string(double val, char format_code, int precision, int flags, int *ptype) - Convert a :c:type:`double` *val* to a string using supplied + Convert a :c:expr:`double` *val* to a string using supplied *format_code*, *precision*, and *flags*. *format_code* must be one of ``'e'``, ``'E'``, ``'f'``, ``'F'``, diff --git a/Doc/c-api/dict.rst b/Doc/c-api/dict.rst index 67c2026baa14..819168d48707 100644 --- a/Doc/c-api/dict.rst +++ b/Doc/c-api/dict.rst @@ -73,7 +73,7 @@ Dictionary Objects .. index:: single: PyUnicode_FromString() Insert *val* into the dictionary *p* using *key* as a key. *key* should - be a :c:type:`const char*`. The key object is created using + be a :c:expr:`const char*`. The key object is created using ``PyUnicode_FromString(key)``. Return ``0`` on success or ``-1`` on failure. This function *does not* steal a reference to *val*. @@ -118,7 +118,7 @@ Dictionary Objects .. c:function:: PyObject* PyDict_GetItemString(PyObject *p, const char *key) This is the same as :c:func:`PyDict_GetItem`, but *key* is specified as a - :c:type:`const char*`, rather than a :c:expr:`PyObject*`. + :c:expr:`const char*`, rather than a :c:expr:`PyObject*`. Note that exceptions which occur while calling :meth:`__hash__` and :meth:`__eq__` methods and creating a temporary string object diff --git a/Doc/c-api/file.rst b/Doc/c-api/file.rst index 745d892be7ea..58ed58e54668 100644 --- a/Doc/c-api/file.rst +++ b/Doc/c-api/file.rst @@ -38,7 +38,7 @@ the :mod:`io` APIs instead. .. c:function:: int PyObject_AsFileDescriptor(PyObject *p) - Return the file descriptor associated with *p* as an :c:type:`int`. If the + Return the file descriptor associated with *p* as an :c:expr:`int`. If the object is an integer, its value is returned. If not, the object's :meth:`~io.IOBase.fileno` method is called if it exists; the method must return an integer, which is returned as the file descriptor diff --git a/Doc/c-api/float.rst b/Doc/c-api/float.rst index b306caf74b7c..023b12c20b7c 100644 --- a/Doc/c-api/float.rst +++ b/Doc/c-api/float.rst @@ -44,7 +44,7 @@ Floating Point Objects .. c:function:: double PyFloat_AsDouble(PyObject *pyfloat) - Return a C :c:type:`double` representation of the contents of *pyfloat*. If + Return a C :c:expr:`double` representation of the contents of *pyfloat*. If *pyfloat* is not a Python floating point object but has a :meth:`__float__` method, this method will first be called to convert *pyfloat* into a float. If ``__float__()`` is not defined then it falls back to :meth:`__index__`. @@ -57,7 +57,7 @@ Floating Point Objects .. c:function:: double PyFloat_AS_DOUBLE(PyObject *pyfloat) - Return a C :c:type:`double` representation of the contents of *pyfloat*, but + Return a C :c:expr:`double` representation of the contents of *pyfloat*, but without error checking. @@ -70,12 +70,12 @@ Floating Point Objects .. c:function:: double PyFloat_GetMax() - Return the maximum representable finite float *DBL_MAX* as C :c:type:`double`. + Return the maximum representable finite float *DBL_MAX* as C :c:expr:`double`. .. c:function:: double PyFloat_GetMin() - Return the minimum normalized positive float *DBL_MIN* as C :c:type:`double`. + Return the minimum normalized positive float *DBL_MIN* as C :c:expr:`double`. Pack and Unpack functions @@ -83,8 +83,8 @@ Pack and Unpack functions The pack and unpack functions provide an efficient platform-independent way to store floating-point values as byte strings. The Pack routines produce a bytes -string from a C :c:type:`double`, and the Unpack routines produce a C -:c:type:`double` from such a bytes string. The suffix (2, 4 or 8) specifies the +string from a C :c:expr:`double`, and the Unpack routines produce a C +:c:expr:`double` from such a bytes string. The suffix (2, 4 or 8) specifies the number of bytes in the bytes string. On platforms that appear to use IEEE 754 formats these functions work by @@ -107,7 +107,7 @@ Pack functions -------------- The pack routines write 2, 4 or 8 bytes, starting at *p*. *le* is an -:c:type:`int` argument, non-zero if you want the bytes string in little-endian +:c:expr:`int` argument, non-zero if you want the bytes string in little-endian format (exponent last, at ``p+1``, ``p+3``, or ``p+6`` ``p+7``), zero if you want big-endian format (exponent first, at *p*). The :c:data:`PY_BIG_ENDIAN` constant can be used to use the native endian: it is equal to ``1`` on big @@ -138,7 +138,7 @@ Unpack functions ---------------- The unpack routines read 2, 4 or 8 bytes, starting at *p*. *le* is an -:c:type:`int` argument, non-zero if the bytes string is in little-endian format +:c:expr:`int` argument, non-zero if the bytes string is in little-endian format (exponent last, at ``p+1``, ``p+3`` or ``p+6`` and ``p+7``), zero if big-endian (exponent first, at *p*). The :c:data:`PY_BIG_ENDIAN` constant can be used to use the native endian: it is equal to ``1`` on big endian processor, or ``0`` diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index 72b086532e5d..dd9847c3e3d2 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -376,7 +376,7 @@ Process-wide parameters interpreter will change the contents of this storage. Use :c:func:`Py_DecodeLocale` to decode a bytes string to get a - :c:type:`wchar_*` string. + :c:expr:`wchar_*` string. .. deprecated:: 3.11 @@ -527,7 +527,7 @@ Process-wide parameters if required after calling :c:func:`Py_Initialize`. Use :c:func:`Py_DecodeLocale` to decode a bytes string to get a - :c:type:`wchar_*` string. + :c:expr:`wchar_*` string. The path argument is copied internally, so the caller may free it after the call completes. @@ -642,7 +642,7 @@ Process-wide parameters directory (``"."``). Use :c:func:`Py_DecodeLocale` to decode a bytes string to get a - :c:type:`wchar_*` string. + :c:expr:`wchar_*` string. See also :c:member:`PyConfig.orig_argv` and :c:member:`PyConfig.argv` members of the :ref:`Python Initialization Configuration `. @@ -678,7 +678,7 @@ Process-wide parameters :option:`-I`. Use :c:func:`Py_DecodeLocale` to decode a bytes string to get a - :c:type:`wchar_*` string. + :c:expr:`wchar_*` string. See also :c:member:`PyConfig.orig_argv` and :c:member:`PyConfig.argv` members of the :ref:`Python Initialization Configuration `. @@ -704,7 +704,7 @@ Process-wide parameters this storage. Use :c:func:`Py_DecodeLocale` to decode a bytes string to get a - :c:type:`wchar_*` string. + :c:expr:`wchar_*` string. .. deprecated:: 3.11 @@ -1291,8 +1291,8 @@ All of the following functions must be called after :c:func:`Py_Initialize`. exception (if any) for the thread is cleared. This raises no exceptions. .. versionchanged:: 3.7 - The type of the *id* parameter changed from :c:type:`long` to - :c:type:`unsigned long`. + The type of the *id* parameter changed from :c:expr:`long` to + :c:expr:`unsigned long`. .. c:function:: void PyEval_AcquireThread(PyThreadState *tstate) @@ -1730,7 +1730,7 @@ The Python interpreter provides low-level support for thread-local storage (TLS) which wraps the underlying native TLS implementation to support the Python-level thread local storage API (:class:`threading.local`). The CPython C level APIs are similar to those offered by pthreads and Windows: -use a thread key and functions to associate a :c:type:`void*` value per +use a thread key and functions to associate a :c:expr:`void*` value per thread. The GIL does *not* need to be held when calling these functions; they supply @@ -1741,8 +1741,8 @@ you need to include :file:`pythread.h` to use thread-local storage. .. note:: None of these API functions handle memory management on behalf of the - :c:type:`void*` values. You need to allocate and deallocate them yourself. - If the :c:type:`void*` values happen to be :c:expr:`PyObject*`, these + :c:expr:`void*` values. You need to allocate and deallocate them yourself. + If the :c:expr:`void*` values happen to be :c:expr:`PyObject*`, these functions don't do refcount operations on them either. .. _thread-specific-storage-api: @@ -1752,7 +1752,7 @@ Thread Specific Storage (TSS) API TSS API is introduced to supersede the use of the existing TLS API within the CPython interpreter. This API uses a new type :c:type:`Py_tss_t` instead of -:c:type:`int` to represent thread keys. +:c:expr:`int` to represent thread keys. .. versionadded:: 3.7 @@ -1838,14 +1838,14 @@ undefined if the given :c:type:`Py_tss_t` has not been initialized by .. c:function:: int PyThread_tss_set(Py_tss_t *key, void *value) - Return a zero value to indicate successfully associating a :c:type:`void*` + Return a zero value to indicate successfully associating a :c:expr:`void*` value with a TSS key in the current thread. Each thread has a distinct - mapping of the key to a :c:type:`void*` value. + mapping of the key to a :c:expr:`void*` value. .. c:function:: void* PyThread_tss_get(Py_tss_t *key) - Return the :c:type:`void*` value associated with a TSS key in the current + Return the :c:expr:`void*` value associated with a TSS key in the current thread. This returns ``NULL`` if no value is associated with the key in the current thread. diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst index 4b91a4b74aaa..ac2afa18b743 100644 --- a/Doc/c-api/intro.rst +++ b/Doc/c-api/intro.rst @@ -530,8 +530,8 @@ Types ----- There are few other data types that play a significant role in the Python/C -API; most are simple C types such as :c:type:`int`, :c:type:`long`, -:c:type:`double` and :c:type:`char*`. A few structure types are used to +API; most are simple C types such as :c:expr:`int`, :c:expr:`long`, +:c:expr:`double` and :c:expr:`char*`. A few structure types are used to describe static tables used to list the functions exported by a module or the data attributes of a new object type, and another is used to describe the value of a complex number. These will be discussed together with the functions that diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst index 620344e71373..bd3d731d8464 100644 --- a/Doc/c-api/long.rst +++ b/Doc/c-api/long.rst @@ -47,7 +47,7 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. c:function:: PyObject* PyLong_FromUnsignedLong(unsigned long v) - Return a new :c:type:`PyLongObject` object from a C :c:type:`unsigned long`, or + Return a new :c:type:`PyLongObject` object from a C :c:expr:`unsigned long`, or ``NULL`` on failure. @@ -65,13 +65,13 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. c:function:: PyObject* PyLong_FromLongLong(long long v) - Return a new :c:type:`PyLongObject` object from a C :c:type:`long long`, or ``NULL`` + Return a new :c:type:`PyLongObject` object from a C :c:expr:`long long`, or ``NULL`` on failure. .. c:function:: PyObject* PyLong_FromUnsignedLongLong(unsigned long long v) - Return a new :c:type:`PyLongObject` object from a C :c:type:`unsigned long long`, + Return a new :c:type:`PyLongObject` object from a C :c:expr:`unsigned long long`, or ``NULL`` on failure. @@ -115,12 +115,12 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. single: LONG_MAX single: OverflowError (built-in exception) - Return a C :c:type:`long` representation of *obj*. If *obj* is not an + Return a C :c:expr:`long` representation of *obj*. If *obj* is not an instance of :c:type:`PyLongObject`, first call its :meth:`__index__` method (if present) to convert it to a :c:type:`PyLongObject`. Raise :exc:`OverflowError` if the value of *obj* is out of range for a - :c:type:`long`. + :c:expr:`long`. Returns ``-1`` on error. Use :c:func:`PyErr_Occurred` to disambiguate. @@ -133,7 +133,7 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. c:function:: long PyLong_AsLongAndOverflow(PyObject *obj, int *overflow) - Return a C :c:type:`long` representation of *obj*. If *obj* is not an + Return a C :c:expr:`long` representation of *obj*. If *obj* is not an instance of :c:type:`PyLongObject`, first call its :meth:`__index__` method (if present) to convert it to a :c:type:`PyLongObject`. @@ -156,12 +156,12 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. index:: single: OverflowError (built-in exception) - Return a C :c:type:`long long` representation of *obj*. If *obj* is not an + Return a C :c:expr:`long long` representation of *obj*. If *obj* is not an instance of :c:type:`PyLongObject`, first call its :meth:`__index__` method (if present) to convert it to a :c:type:`PyLongObject`. Raise :exc:`OverflowError` if the value of *obj* is out of range for a - :c:type:`long long`. + :c:expr:`long long`. Returns ``-1`` on error. Use :c:func:`PyErr_Occurred` to disambiguate. @@ -174,7 +174,7 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. c:function:: long long PyLong_AsLongLongAndOverflow(PyObject *obj, int *overflow) - Return a C :c:type:`long long` representation of *obj*. If *obj* is not an + Return a C :c:expr:`long long` representation of *obj*. If *obj* is not an instance of :c:type:`PyLongObject`, first call its :meth:`__index__` method (if present) to convert it to a :c:type:`PyLongObject`. @@ -215,11 +215,11 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. single: ULONG_MAX single: OverflowError (built-in exception) - Return a C :c:type:`unsigned long` representation of *pylong*. *pylong* + Return a C :c:expr:`unsigned long` representation of *pylong*. *pylong* must be an instance of :c:type:`PyLongObject`. Raise :exc:`OverflowError` if the value of *pylong* is out of range for a - :c:type:`unsigned long`. + :c:expr:`unsigned long`. Returns ``(unsigned long)-1`` on error. Use :c:func:`PyErr_Occurred` to disambiguate. @@ -246,11 +246,11 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. index:: single: OverflowError (built-in exception) - Return a C :c:type:`unsigned long long` representation of *pylong*. *pylong* + Return a C :c:expr:`unsigned long long` representation of *pylong*. *pylong* must be an instance of :c:type:`PyLongObject`. Raise :exc:`OverflowError` if the value of *pylong* is out of range for an - :c:type:`unsigned long long`. + :c:expr:`unsigned long long`. Returns ``(unsigned long long)-1`` on error. Use :c:func:`PyErr_Occurred` to disambiguate. @@ -261,11 +261,11 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. c:function:: unsigned long PyLong_AsUnsignedLongMask(PyObject *obj) - Return a C :c:type:`unsigned long` representation of *obj*. If *obj* is not + Return a C :c:expr:`unsigned long` representation of *obj*. If *obj* is not an instance of :c:type:`PyLongObject`, first call its :meth:`__index__` method (if present) to convert it to a :c:type:`PyLongObject`. - If the value of *obj* is out of range for an :c:type:`unsigned long`, + If the value of *obj* is out of range for an :c:expr:`unsigned long`, return the reduction of that value modulo ``ULONG_MAX + 1``. Returns ``(unsigned long)-1`` on error. Use :c:func:`PyErr_Occurred` to @@ -280,12 +280,12 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. c:function:: unsigned long long PyLong_AsUnsignedLongLongMask(PyObject *obj) - Return a C :c:type:`unsigned long long` representation of *obj*. If *obj* + Return a C :c:expr:`unsigned long long` representation of *obj*. If *obj* is not an instance of :c:type:`PyLongObject`, first call its :meth:`__index__` method (if present) to convert it to a :c:type:`PyLongObject`. - If the value of *obj* is out of range for an :c:type:`unsigned long long`, + If the value of *obj* is out of range for an :c:expr:`unsigned long long`, return the reduction of that value modulo ``ULLONG_MAX + 1``. Returns ``(unsigned long long)-1`` on error. Use :c:func:`PyErr_Occurred` @@ -300,20 +300,20 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. c:function:: double PyLong_AsDouble(PyObject *pylong) - Return a C :c:type:`double` representation of *pylong*. *pylong* must be + Return a C :c:expr:`double` representation of *pylong*. *pylong* must be an instance of :c:type:`PyLongObject`. Raise :exc:`OverflowError` if the value of *pylong* is out of range for a - :c:type:`double`. + :c:expr:`double`. Returns ``-1.0`` on error. Use :c:func:`PyErr_Occurred` to disambiguate. .. c:function:: void* PyLong_AsVoidPtr(PyObject *pylong) - Convert a Python integer *pylong* to a C :c:type:`void` pointer. + Convert a Python integer *pylong* to a C :c:expr:`void` pointer. If *pylong* cannot be converted, an :exc:`OverflowError` will be raised. This - is only assured to produce a usable :c:type:`void` pointer for values created + is only assured to produce a usable :c:expr:`void` pointer for values created with :c:func:`PyLong_FromVoidPtr`. Returns ``NULL`` on error. Use :c:func:`PyErr_Occurred` to disambiguate. diff --git a/Doc/c-api/marshal.rst b/Doc/c-api/marshal.rst index 1ba18beb3ea0..8e25968c6909 100644 --- a/Doc/c-api/marshal.rst +++ b/Doc/c-api/marshal.rst @@ -21,9 +21,9 @@ unmarshalling. Version 2 uses a binary format for floating point numbers. .. c:function:: void PyMarshal_WriteLongToFile(long value, FILE *file, int version) - Marshal a :c:type:`long` integer, *value*, to *file*. This will only write + Marshal a :c:expr:`long` integer, *value*, to *file*. This will only write the least-significant 32 bits of *value*; regardless of the size of the - native :c:type:`long` type. *version* indicates the file format. + native :c:expr:`long` type. *version* indicates the file format. .. c:function:: void PyMarshal_WriteObjectToFile(PyObject *value, FILE *file, int version) @@ -43,9 +43,9 @@ The following functions allow marshalled values to be read back in. .. c:function:: long PyMarshal_ReadLongFromFile(FILE *file) - Return a C :c:type:`long` from the data stream in a :c:expr:`FILE*` opened + Return a C :c:expr:`long` from the data stream in a :c:expr:`FILE*` opened for reading. Only a 32-bit value can be read in using this function, - regardless of the native size of :c:type:`long`. + regardless of the native size of :c:expr:`long`. On error, sets the appropriate exception (:exc:`EOFError`) and returns ``-1``. @@ -53,9 +53,9 @@ The following functions allow marshalled values to be read back in. .. c:function:: int PyMarshal_ReadShortFromFile(FILE *file) - Return a C :c:type:`short` from the data stream in a :c:expr:`FILE*` opened + Return a C :c:expr:`short` from the data stream in a :c:expr:`FILE*` opened for reading. Only a 16-bit value can be read in using this function, - regardless of the native size of :c:type:`short`. + regardless of the native size of :c:expr:`short`. On error, sets the appropriate exception (:exc:`EOFError`) and returns ``-1``. diff --git a/Doc/c-api/memory.rst b/Doc/c-api/memory.rst index 4abbf340c5f4..f726cd48663b 100644 --- a/Doc/c-api/memory.rst +++ b/Doc/c-api/memory.rst @@ -141,7 +141,7 @@ zero bytes. .. c:function:: void* PyMem_RawMalloc(size_t n) - Allocates *n* bytes and returns a pointer of type :c:type:`void*` to the + Allocates *n* bytes and returns a pointer of type :c:expr:`void*` to the allocated memory, or ``NULL`` if the request fails. Requesting zero bytes returns a distinct non-``NULL`` pointer if possible, as @@ -152,7 +152,7 @@ zero bytes. .. c:function:: void* PyMem_RawCalloc(size_t nelem, size_t elsize) Allocates *nelem* elements each whose size in bytes is *elsize* and returns - a pointer of type :c:type:`void*` to the allocated memory, or ``NULL`` if the + a pointer of type :c:expr:`void*` to the allocated memory, or ``NULL`` if the request fails. The memory is initialized to zeros. Requesting zero elements or elements of size zero bytes returns a distinct @@ -212,7 +212,7 @@ The :ref:`default memory allocator ` uses the .. c:function:: void* PyMem_Malloc(size_t n) - Allocates *n* bytes and returns a pointer of type :c:type:`void*` to the + Allocates *n* bytes and returns a pointer of type :c:expr:`void*` to the allocated memory, or ``NULL`` if the request fails. Requesting zero bytes returns a distinct non-``NULL`` pointer if possible, as @@ -223,7 +223,7 @@ The :ref:`default memory allocator ` uses the .. c:function:: void* PyMem_Calloc(size_t nelem, size_t elsize) Allocates *nelem* elements each whose size in bytes is *elsize* and returns - a pointer of type :c:type:`void*` to the allocated memory, or ``NULL`` if the + a pointer of type :c:expr:`void*` to the allocated memory, or ``NULL`` if the request fails. The memory is initialized to zeros. Requesting zero elements or elements of size zero bytes returns a distinct @@ -320,7 +320,7 @@ The :ref:`default object allocator ` uses the .. c:function:: void* PyObject_Malloc(size_t n) - Allocates *n* bytes and returns a pointer of type :c:type:`void*` to the + Allocates *n* bytes and returns a pointer of type :c:expr:`void*` to the allocated memory, or ``NULL`` if the request fails. Requesting zero bytes returns a distinct non-``NULL`` pointer if possible, as @@ -331,7 +331,7 @@ The :ref:`default object allocator ` uses the .. c:function:: void* PyObject_Calloc(size_t nelem, size_t elsize) Allocates *nelem* elements each whose size in bytes is *elsize* and returns - a pointer of type :c:type:`void*` to the allocated memory, or ``NULL`` if the + a pointer of type :c:expr:`void*` to the allocated memory, or ``NULL`` if the request fails. The memory is initialized to zeros. Requesting zero elements or elements of size zero bytes returns a distinct diff --git a/Doc/c-api/sys.rst b/Doc/c-api/sys.rst index 7b714678444b..517b57b14768 100644 --- a/Doc/c-api/sys.rst +++ b/Doc/c-api/sys.rst @@ -105,7 +105,7 @@ Operating System Utilities Return the current signal handler for signal *i*. This is a thin wrapper around either :c:func:`sigaction` or :c:func:`signal`. Do not call those functions - directly! :c:type:`PyOS_sighandler_t` is a typedef alias for :c:type:`void + directly! :c:type:`PyOS_sighandler_t` is a typedef alias for :c:expr:`void (\*)(int)`. @@ -114,7 +114,7 @@ Operating System Utilities Set the signal handler for signal *i* to be *h*; return the old signal handler. This is a thin wrapper around either :c:func:`sigaction` or :c:func:`signal`. Do not call those functions directly! :c:type:`PyOS_sighandler_t` is a typedef - alias for :c:type:`void (\*)(int)`. + alias for :c:expr:`void (\*)(int)`. .. c:function:: wchar_t* Py_DecodeLocale(const char* arg, size_t *size) @@ -377,7 +377,7 @@ accessible to C code. They all work with the current interpreter thread's silently abort the operation by raising an error subclassed from :class:`Exception` (other errors will not be silenced). - The hook function is of type :c:type:`int (*)(const char *event, PyObject + The hook function is of type :c:expr:`int (*)(const char *event, PyObject *args, void *userData)`, where *args* is guaranteed to be a :c:type:`PyTupleObject`. The hook function is always called with the GIL held by the Python interpreter that raised the event. diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst index d26bac83ec6d..26d34052972a 100644 --- a/Doc/c-api/unicode.rst +++ b/Doc/c-api/unicode.rst @@ -58,7 +58,7 @@ Python: .. c:type:: Py_UNICODE - This is a typedef of :c:type:`wchar_t`, which is a 16-bit type or 32-bit type + This is a typedef of :c:expr:`wchar_t`, which is a 16-bit type or 32-bit type depending on the platform. .. versionchanged:: 3.3 @@ -935,11 +935,11 @@ conversion function: wchar_t Support """"""""""""""" -:c:type:`wchar_t` support for platforms which support it: +:c:expr:`wchar_t` support for platforms which support it: .. c:function:: PyObject* PyUnicode_FromWideChar(const wchar_t *w, Py_ssize_t size) - Create a Unicode object from the :c:type:`wchar_t` buffer *w* of the given *size*. + Create a Unicode object from the :c:expr:`wchar_t` buffer *w* of the given *size*. Passing ``-1`` as the *size* indicates that the function must itself compute the length, using wcslen. Return ``NULL`` on failure. @@ -947,13 +947,13 @@ wchar_t Support .. c:function:: Py_ssize_t PyUnicode_AsWideChar(PyObject *unicode, wchar_t *w, Py_ssize_t size) - Copy the Unicode object contents into the :c:type:`wchar_t` buffer *w*. At most - *size* :c:type:`wchar_t` characters are copied (excluding a possibly trailing - null termination character). Return the number of :c:type:`wchar_t` characters - copied or ``-1`` in case of an error. Note that the resulting :c:type:`wchar_t*` + Copy the Unicode object contents into the :c:expr:`wchar_t` buffer *w*. At most + *size* :c:expr:`wchar_t` characters are copied (excluding a possibly trailing + null termination character). Return the number of :c:expr:`wchar_t` characters + copied or ``-1`` in case of an error. Note that the resulting :c:expr:`wchar_t*` string may or may not be null-terminated. It is the responsibility of the caller - to make sure that the :c:type:`wchar_t*` string is null-terminated in case this is - required by the application. Also, note that the :c:type:`wchar_t*` string + to make sure that the :c:expr:`wchar_t*` string is null-terminated in case this is + required by the application. Also, note that the :c:expr:`wchar_t*` string might contain null characters, which would cause the string to be truncated when used with most C functions. @@ -963,9 +963,9 @@ wchar_t Support Convert the Unicode object to a wide character string. The output string always ends with a null character. If *size* is not ``NULL``, write the number of wide characters (excluding the trailing null termination character) into - *\*size*. Note that the resulting :c:type:`wchar_t` string might contain + *\*size*. Note that the resulting :c:expr:`wchar_t` string might contain null characters, which would cause the string to be truncated when used with - most C functions. If *size* is ``NULL`` and the :c:type:`wchar_t*` string + most C functions. If *size* is ``NULL`` and the :c:expr:`wchar_t*` string contains null characters a :exc:`ValueError` is raised. Returns a buffer allocated by :c:func:`PyMem_Alloc` (use @@ -976,7 +976,7 @@ wchar_t Support .. versionadded:: 3.2 .. versionchanged:: 3.7 - Raises a :exc:`ValueError` if *size* is ``NULL`` and the :c:type:`wchar_t*` + Raises a :exc:`ValueError` if *size* is ``NULL`` and the :c:expr:`wchar_t*` string contains null characters. diff --git a/Doc/extending/extending.rst b/Doc/extending/extending.rst index 0ef899f4c997..d9bf4fd6c7ae 100644 --- a/Doc/extending/extending.rst +++ b/Doc/extending/extending.rst @@ -298,7 +298,7 @@ In this case, it will return an integer object. (Yes, even integers are objects on the heap in Python!) If you have a C function that returns no useful argument (a function returning -:c:type:`void`), the corresponding Python function must return ``None``. You +:c:expr:`void`), the corresponding Python function must return ``None``. You need this idiom to do so (which is implemented by the :c:macro:`Py_RETURN_NONE` macro):: @@ -1171,7 +1171,7 @@ other extension modules must be exported in a different way. Python provides a special mechanism to pass C-level information (pointers) from one extension module to another one: Capsules. A Capsule is a Python data type -which stores a pointer (:c:type:`void \*`). Capsules can only be created and +which stores a pointer (:c:expr:`void \*`). Capsules can only be created and accessed via their C API, but they can be passed around like any other Python object. In particular, they can be assigned to a name in an extension module's namespace. Other extension modules can then import this module, retrieve the @@ -1185,7 +1185,7 @@ different ways between the module providing the code and the client modules. Whichever method you choose, it's important to name your Capsules properly. The function :c:func:`PyCapsule_New` takes a name parameter -(:c:type:`const char \*`); you're permitted to pass in a ``NULL`` name, but +(:c:expr:`const char \*`); you're permitted to pass in a ``NULL`` name, but we strongly encourage you to specify a name. Properly named Capsules provide a degree of runtime type-safety; there is no feasible way to tell one unnamed Capsule from another. @@ -1203,7 +1203,7 @@ of certainty that the Capsule they load contains the correct C API. The following example demonstrates an approach that puts most of the burden on the writer of the exporting module, which is appropriate for commonly used library modules. It stores all C API pointers (just one in the example!) in an -array of :c:type:`void` pointers which becomes the value of a Capsule. The header +array of :c:expr:`void` pointers which becomes the value of a Capsule. The header file corresponding to the module provides a macro that takes care of importing the module and retrieving its C API pointers; client modules only have to call this macro before accessing the C API. diff --git a/Doc/extending/newtypes.rst b/Doc/extending/newtypes.rst index c7c434e58bf0..1eef7f6e8eb9 100644 --- a/Doc/extending/newtypes.rst +++ b/Doc/extending/newtypes.rst @@ -207,7 +207,7 @@ a special case, for which the new value passed to the handler is ``NULL``. Python supports two pairs of attribute handlers; a type that supports attributes only needs to implement the functions for one pair. The difference is that one -pair takes the name of the attribute as a :c:type:`char\*`, while the other +pair takes the name of the attribute as a :c:expr:`char\*`, while the other accepts a :c:type:`PyObject\*`. Each type can use whichever pair makes more sense for the implementation's convenience. :: @@ -339,8 +339,8 @@ of ``NULL`` is required. Type-specific Attribute Management ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -For simplicity, only the :c:type:`char\*` version will be demonstrated here; the -type of the name parameter is the only difference between the :c:type:`char\*` +For simplicity, only the :c:expr:`char\*` version will be demonstrated here; the +type of the name parameter is the only difference between the :c:expr:`char\*` and :c:type:`PyObject\*` flavors of the interface. This example effectively does the same thing as the generic example above, but does not use the generic support added in Python 2.2. It explains how the handler functions are diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index 0c341770a05b..99c35a8e595f 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -197,9 +197,9 @@ calls). ``None``, integers, bytes objects and (unicode) strings are the only native Python objects that can directly be used as parameters in these function calls. ``None`` is passed as a C ``NULL`` pointer, bytes objects and strings are passed -as pointer to the memory block that contains their data (:c:type:`char *` or -:c:type:`wchar_t *`). Python integers are passed as the platforms default C -:c:type:`int` type, their value is masked to fit into the C type. +as pointer to the memory block that contains their data (:c:expr:`char *` or +:c:expr:`wchar_t *`). Python integers are passed as the platforms default C +:c:expr:`int` type, their value is masked to fit into the C type. Before we move on calling functions with other parameter types, we have to learn more about :mod:`ctypes` data types. @@ -215,49 +215,49 @@ Fundamental data types +----------------------+------------------------------------------+----------------------------+ | ctypes type | C type | Python type | +======================+==========================================+============================+ -| :class:`c_bool` | :c:type:`_Bool` | bool (1) | +| :class:`c_bool` | :c:expr:`_Bool` | bool (1) | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_char` | :c:type:`char` | 1-character bytes object | +| :class:`c_char` | :c:expr:`char` | 1-character bytes object | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_wchar` | :c:type:`wchar_t` | 1-character string | +| :class:`c_wchar` | :c:expr:`wchar_t` | 1-character string | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_byte` | :c:type:`char` | int | +| :class:`c_byte` | :c:expr:`char` | int | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_ubyte` | :c:type:`unsigned char` | int | +| :class:`c_ubyte` | :c:expr:`unsigned char` | int | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_short` | :c:type:`short` | int | +| :class:`c_short` | :c:expr:`short` | int | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_ushort` | :c:type:`unsigned short` | int | +| :class:`c_ushort` | :c:expr:`unsigned short` | int | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_int` | :c:type:`int` | int | +| :class:`c_int` | :c:expr:`int` | int | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_uint` | :c:type:`unsigned int` | int | +| :class:`c_uint` | :c:expr:`unsigned int` | int | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_long` | :c:type:`long` | int | +| :class:`c_long` | :c:expr:`long` | int | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_ulong` | :c:type:`unsigned long` | int | +| :class:`c_ulong` | :c:expr:`unsigned long` | int | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_longlong` | :c:type:`__int64` or :c:type:`long long` | int | +| :class:`c_longlong` | :c:expr:`__int64` or :c:expr:`long long` | int | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_ulonglong` | :c:type:`unsigned __int64` or | int | -| | :c:type:`unsigned long long` | | +| :class:`c_ulonglong` | :c:expr:`unsigned __int64` or | int | +| | :c:expr:`unsigned long long` | | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_size_t` | :c:type:`size_t` | int | +| :class:`c_size_t` | :c:expr:`size_t` | int | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_ssize_t` | :c:type:`ssize_t` or | int | -| | :c:type:`Py_ssize_t` | | +| :class:`c_ssize_t` | :c:expr:`ssize_t` or | int | +| | :c:expr:`Py_ssize_t` | | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_float` | :c:type:`float` | float | +| :class:`c_float` | :c:expr:`float` | float | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_double` | :c:type:`double` | float | +| :class:`c_double` | :c:expr:`double` | float | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_longdouble`| :c:type:`long double` | float | +| :class:`c_longdouble`| :c:expr:`long double` | float | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_char_p` | :c:type:`char *` (NUL terminated) | bytes object or ``None`` | +| :class:`c_char_p` | :c:expr:`char *` (NUL terminated) | bytes object or ``None`` | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_wchar_p` | :c:type:`wchar_t *` (NUL terminated) | string or ``None`` | +| :class:`c_wchar_p` | :c:expr:`wchar_t *` (NUL terminated) | string or ``None`` | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_void_p` | :c:type:`void *` | int or ``None`` | +| :class:`c_void_p` | :c:expr:`void *` | int or ``None`` | +----------------------+------------------------------------------+----------------------------+ (1) @@ -332,7 +332,7 @@ property:: The :func:`create_string_buffer` function replaces the old :func:`c_buffer` function (which is still available as an alias). To create a mutable memory -block containing unicode characters of the C type :c:type:`wchar_t`, use the +block containing unicode characters of the C type :c:expr:`wchar_t`, use the :func:`create_unicode_buffer` function. @@ -443,7 +443,7 @@ integer, string, bytes, a :mod:`ctypes` instance, or an object with an Return types ^^^^^^^^^^^^ -By default functions are assumed to return the C :c:type:`int` type. Other +By default functions are assumed to return the C :c:expr:`int` type. Other return types can be specified by setting the :attr:`restype` attribute of the function object. @@ -1323,7 +1323,7 @@ way is to instantiate one of the following classes: Instances of this class represent loaded shared libraries. Functions in these libraries use the standard C calling convention, and are assumed to return - :c:type:`int`. + :c:expr:`int`. On Windows creating a :class:`CDLL` instance may fail even if the DLL name exists. When a dependent DLL of the loaded DLL is not found, a @@ -1358,7 +1358,7 @@ way is to instantiate one of the following classes: Windows only: Instances of this class represent loaded shared libraries, functions in these libraries use the ``stdcall`` calling convention, and are - assumed to return :c:type:`int` by default. + assumed to return :c:expr:`int` by default. The Python :term:`global interpreter lock` is released before calling any function exported by these libraries, and reacquired afterwards. @@ -1514,7 +1514,7 @@ object is available: An instance of :class:`PyDLL` that exposes Python C API functions as attributes. Note that all these functions are assumed to return C - :c:type:`int`, which is of course not always the truth, so you have to assign + :c:expr:`int`, which is of course not always the truth, so you have to assign the correct :attr:`restype` attribute to use these functions. .. audit-event:: ctypes.dlopen name ctypes.LibraryLoader @@ -1560,10 +1560,10 @@ They are instances of a private class: .. attribute:: restype Assign a ctypes type to specify the result type of the foreign function. - Use ``None`` for :c:type:`void`, a function not returning anything. + Use ``None`` for :c:expr:`void`, a function not returning anything. It is possible to assign a callable Python object that is not a ctypes - type, in this case the function is assumed to return a C :c:type:`int`, and + type, in this case the function is assumed to return a C :c:expr:`int`, and the callable will be called with this integer, allowing further processing or error checking. Using this is deprecated, for more flexible post processing or error checking use a ctypes data type as @@ -2176,21 +2176,21 @@ These are the fundamental ctypes data types: .. class:: c_byte - Represents the C :c:type:`signed char` datatype, and interprets the value as + Represents the C :c:expr:`signed char` datatype, and interprets the value as small integer. The constructor accepts an optional integer initializer; no overflow checking is done. .. class:: c_char - Represents the C :c:type:`char` datatype, and interprets the value as a single + Represents the C :c:expr:`char` datatype, and interprets the value as a single character. The constructor accepts an optional string initializer, the length of the string must be exactly one character. .. class:: c_char_p - Represents the C :c:type:`char *` datatype when it points to a zero-terminated + Represents the C :c:expr:`char *` datatype when it points to a zero-terminated string. For a general character pointer that may also point to binary data, ``POINTER(c_char)`` must be used. The constructor accepts an integer address, or a bytes object. @@ -2198,68 +2198,68 @@ These are the fundamental ctypes data types: .. class:: c_double - Represents the C :c:type:`double` datatype. The constructor accepts an + Represents the C :c:expr:`double` datatype. The constructor accepts an optional float initializer. .. class:: c_longdouble - Represents the C :c:type:`long double` datatype. The constructor accepts an + Represents the C :c:expr:`long double` datatype. The constructor accepts an optional float initializer. On platforms where ``sizeof(long double) == sizeof(double)`` it is an alias to :class:`c_double`. .. class:: c_float - Represents the C :c:type:`float` datatype. The constructor accepts an + Represents the C :c:expr:`float` datatype. The constructor accepts an optional float initializer. .. class:: c_int - Represents the C :c:type:`signed int` datatype. The constructor accepts an + Represents the C :c:expr:`signed int` datatype. The constructor accepts an optional integer initializer; no overflow checking is done. On platforms where ``sizeof(int) == sizeof(long)`` it is an alias to :class:`c_long`. .. class:: c_int8 - Represents the C 8-bit :c:type:`signed int` datatype. Usually an alias for + Represents the C 8-bit :c:expr:`signed int` datatype. Usually an alias for :class:`c_byte`. .. class:: c_int16 - Represents the C 16-bit :c:type:`signed int` datatype. Usually an alias for + Represents the C 16-bit :c:expr:`signed int` datatype. Usually an alias for :class:`c_short`. .. class:: c_int32 - Represents the C 32-bit :c:type:`signed int` datatype. Usually an alias for + Represents the C 32-bit :c:expr:`signed int` datatype. Usually an alias for :class:`c_int`. .. class:: c_int64 - Represents the C 64-bit :c:type:`signed int` datatype. Usually an alias for + Represents the C 64-bit :c:expr:`signed int` datatype. Usually an alias for :class:`c_longlong`. .. class:: c_long - Represents the C :c:type:`signed long` datatype. The constructor accepts an + Represents the C :c:expr:`signed long` datatype. The constructor accepts an optional integer initializer; no overflow checking is done. .. class:: c_longlong - Represents the C :c:type:`signed long long` datatype. The constructor accepts + Represents the C :c:expr:`signed long long` datatype. The constructor accepts an optional integer initializer; no overflow checking is done. .. class:: c_short - Represents the C :c:type:`signed short` datatype. The constructor accepts an + Represents the C :c:expr:`signed short` datatype. The constructor accepts an optional integer initializer; no overflow checking is done. @@ -2277,83 +2277,83 @@ These are the fundamental ctypes data types: .. class:: c_ubyte - Represents the C :c:type:`unsigned char` datatype, it interprets the value as + Represents the C :c:expr:`unsigned char` datatype, it interprets the value as small integer. The constructor accepts an optional integer initializer; no overflow checking is done. .. class:: c_uint - Represents the C :c:type:`unsigned int` datatype. The constructor accepts an + Represents the C :c:expr:`unsigned int` datatype. The constructor accepts an optional integer initializer; no overflow checking is done. On platforms where ``sizeof(int) == sizeof(long)`` it is an alias for :class:`c_ulong`. .. class:: c_uint8 - Represents the C 8-bit :c:type:`unsigned int` datatype. Usually an alias for + Represents the C 8-bit :c:expr:`unsigned int` datatype. Usually an alias for :class:`c_ubyte`. .. class:: c_uint16 - Represents the C 16-bit :c:type:`unsigned int` datatype. Usually an alias for + Represents the C 16-bit :c:expr:`unsigned int` datatype. Usually an alias for :class:`c_ushort`. .. class:: c_uint32 - Represents the C 32-bit :c:type:`unsigned int` datatype. Usually an alias for + Represents the C 32-bit :c:expr:`unsigned int` datatype. Usually an alias for :class:`c_uint`. .. class:: c_uint64 - Represents the C 64-bit :c:type:`unsigned int` datatype. Usually an alias for + Represents the C 64-bit :c:expr:`unsigned int` datatype. Usually an alias for :class:`c_ulonglong`. .. class:: c_ulong - Represents the C :c:type:`unsigned long` datatype. The constructor accepts an + Represents the C :c:expr:`unsigned long` datatype. The constructor accepts an optional integer initializer; no overflow checking is done. .. class:: c_ulonglong - Represents the C :c:type:`unsigned long long` datatype. The constructor + Represents the C :c:expr:`unsigned long long` datatype. The constructor accepts an optional integer initializer; no overflow checking is done. .. class:: c_ushort - Represents the C :c:type:`unsigned short` datatype. The constructor accepts + Represents the C :c:expr:`unsigned short` datatype. The constructor accepts an optional integer initializer; no overflow checking is done. .. class:: c_void_p - Represents the C :c:type:`void *` type. The value is represented as integer. + Represents the C :c:expr:`void *` type. The value is represented as integer. The constructor accepts an optional integer initializer. .. class:: c_wchar - Represents the C :c:type:`wchar_t` datatype, and interprets the value as a + Represents the C :c:expr:`wchar_t` datatype, and interprets the value as a single character unicode string. The constructor accepts an optional string initializer, the length of the string must be exactly one character. .. class:: c_wchar_p - Represents the C :c:type:`wchar_t *` datatype, which must be a pointer to a + Represents the C :c:expr:`wchar_t *` datatype, which must be a pointer to a zero-terminated wide character string. The constructor accepts an integer address, or a string. .. class:: c_bool - Represent the C :c:type:`bool` datatype (more accurately, :c:type:`_Bool` from + Represent the C :c:expr:`bool` datatype (more accurately, :c:expr:`_Bool` from C99). Its value can be ``True`` or ``False``, and the constructor accepts any object that has a truth value. diff --git a/Doc/library/posix.rst b/Doc/library/posix.rst index 90be191aa2f8..ec04b0dcfc16 100644 --- a/Doc/library/posix.rst +++ b/Doc/library/posix.rst @@ -39,12 +39,12 @@ Large File Support Several operating systems (including AIX and Solaris) provide support for files that are larger than 2 GiB from a C programming model where -:c:type:`int` and :c:type:`long` are 32-bit values. This is typically accomplished +:c:expr:`int` and :c:expr:`long` are 32-bit values. This is typically accomplished by defining the relevant size and offset types as 64-bit values. Such files are sometimes referred to as :dfn:`large files`. Large file support is enabled in Python when the size of an :c:type:`off_t` is -larger than a :c:type:`long` and the :c:type:`long long` is at least as large +larger than a :c:expr:`long` and the :c:expr:`long long` is at least as large as an :c:type:`off_t`. It may be necessary to configure and compile Python with certain compiler flags to enable this mode. For example, with Solaris 2.6 and 2.7 you need to do diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst index 71d2c508c57f..b1c2ab07740f 100644 --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -1565,7 +1565,7 @@ to sockets. ancillary data, items of the form ``(socket.SOL_SOCKET, socket.SCM_RIGHTS, fds)``, where *fds* is a :class:`bytes` object representing the new file descriptors as a binary array of the - native C :c:type:`int` type. If :meth:`recvmsg` raises an + native C :c:expr:`int` type. If :meth:`recvmsg` raises an exception after the system call returns, it will first attempt to close any file descriptors received via this mechanism. diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index e92909125b32..14d2a27a87ba 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -215,7 +215,7 @@ Numeric Types --- :class:`int`, :class:`float`, :class:`complex` There are three distinct numeric types: :dfn:`integers`, :dfn:`floating point numbers`, and :dfn:`complex numbers`. In addition, Booleans are a subtype of integers. Integers have unlimited precision. Floating point -numbers are usually implemented using :c:type:`double` in C; information +numbers are usually implemented using :c:expr:`double` in C; information about the precision and internal representation of floating point numbers for the machine on which your program is running is available in :data:`sys.float_info`. Complex numbers have a real and imaginary diff --git a/Doc/library/struct.rst b/Doc/library/struct.rst index c1888d4a94fe..d12a5732fa4a 100644 --- a/Doc/library/struct.rst +++ b/Doc/library/struct.rst @@ -196,46 +196,46 @@ platform-dependent. +========+==========================+====================+================+============+ | ``x`` | pad byte | no value | | | +--------+--------------------------+--------------------+----------------+------------+ -| ``c`` | :c:type:`char` | bytes of length 1 | 1 | | +| ``c`` | :c:expr:`char` | bytes of length 1 | 1 | | +--------+--------------------------+--------------------+----------------+------------+ -| ``b`` | :c:type:`signed char` | integer | 1 | \(1), \(2) | +| ``b`` | :c:expr:`signed char` | integer | 1 | \(1), \(2) | +--------+--------------------------+--------------------+----------------+------------+ -| ``B`` | :c:type:`unsigned char` | integer | 1 | \(2) | +| ``B`` | :c:expr:`unsigned char` | integer | 1 | \(2) | +--------+--------------------------+--------------------+----------------+------------+ -| ``?`` | :c:type:`_Bool` | bool | 1 | \(1) | +| ``?`` | :c:expr:`_Bool` | bool | 1 | \(1) | +--------+--------------------------+--------------------+----------------+------------+ -| ``h`` | :c:type:`short` | integer | 2 | \(2) | +| ``h`` | :c:expr:`short` | integer | 2 | \(2) | +--------+--------------------------+--------------------+----------------+------------+ -| ``H`` | :c:type:`unsigned short` | integer | 2 | \(2) | +| ``H`` | :c:expr:`unsigned short` | integer | 2 | \(2) | +--------+--------------------------+--------------------+----------------+------------+ -| ``i`` | :c:type:`int` | integer | 4 | \(2) | +| ``i`` | :c:expr:`int` | integer | 4 | \(2) | +--------+--------------------------+--------------------+----------------+------------+ -| ``I`` | :c:type:`unsigned int` | integer | 4 | \(2) | +| ``I`` | :c:expr:`unsigned int` | integer | 4 | \(2) | +--------+--------------------------+--------------------+----------------+------------+ -| ``l`` | :c:type:`long` | integer | 4 | \(2) | +| ``l`` | :c:expr:`long` | integer | 4 | \(2) | +--------+--------------------------+--------------------+----------------+------------+ -| ``L`` | :c:type:`unsigned long` | integer | 4 | \(2) | +| ``L`` | :c:expr:`unsigned long` | integer | 4 | \(2) | +--------+--------------------------+--------------------+----------------+------------+ -| ``q`` | :c:type:`long long` | integer | 8 | \(2) | +| ``q`` | :c:expr:`long long` | integer | 8 | \(2) | +--------+--------------------------+--------------------+----------------+------------+ -| ``Q`` | :c:type:`unsigned long | integer | 8 | \(2) | +| ``Q`` | :c:expr:`unsigned long | integer | 8 | \(2) | | | long` | | | | +--------+--------------------------+--------------------+----------------+------------+ -| ``n`` | :c:type:`ssize_t` | integer | | \(3) | +| ``n`` | :c:expr:`ssize_t` | integer | | \(3) | +--------+--------------------------+--------------------+----------------+------------+ -| ``N`` | :c:type:`size_t` | integer | | \(3) | +| ``N`` | :c:expr:`size_t` | integer | | \(3) | +--------+--------------------------+--------------------+----------------+------------+ | ``e`` | \(6) | float | 2 | \(4) | +--------+--------------------------+--------------------+----------------+------------+ -| ``f`` | :c:type:`float` | float | 4 | \(4) | +| ``f`` | :c:expr:`float` | float | 4 | \(4) | +--------+--------------------------+--------------------+----------------+------------+ -| ``d`` | :c:type:`double` | float | 8 | \(4) | +| ``d`` | :c:expr:`double` | float | 8 | \(4) | +--------+--------------------------+--------------------+----------------+------------+ -| ``s`` | :c:type:`char[]` | bytes | | | +| ``s`` | :c:expr:`char[]` | bytes | | | +--------+--------------------------+--------------------+----------------+------------+ -| ``p`` | :c:type:`char[]` | bytes | | | +| ``p`` | :c:expr:`char[]` | bytes | | | +--------+--------------------------+--------------------+----------------+------------+ -| ``P`` | :c:type:`void \*` | integer | | \(5) | +| ``P`` | :c:expr:`void \*` | integer | | \(5) | +--------+--------------------------+--------------------+----------------+------------+ .. versionchanged:: 3.3 @@ -250,8 +250,8 @@ Notes: (1) .. index:: single: ? (question mark); in struct format strings - The ``'?'`` conversion code corresponds to the :c:type:`_Bool` type defined by - C99. If this type is not available, it is simulated using a :c:type:`char`. In + The ``'?'`` conversion code corresponds to the :c:expr:`_Bool` type defined by + C99. If this type is not available, it is simulated using a :c:expr:`char`. In standard mode, it is always represented by one byte. (2) diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index 758f3aef3ee3..f2465cdf40f6 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -316,7 +316,7 @@ Sequences A string is a sequence of values that represent Unicode code points. All the code points in the range ``U+0000 - U+10FFFF`` can be - represented in a string. Python doesn't have a :c:type:`char` type; + represented in a string. Python doesn't have a :c:expr:`char` type; instead, every code point in the string is represented as a string object with length ``1``. The built-in function :func:`ord` converts a code point from its string form to an integer in the diff --git a/Doc/whatsnew/2.2.rst b/Doc/whatsnew/2.2.rst index 9355c1badaa2..bfb2aacbc077 100644 --- a/Doc/whatsnew/2.2.rst +++ b/Doc/whatsnew/2.2.rst @@ -983,7 +983,7 @@ New and Improved Modules Jun-ichiro "itojun" Hagino.) * Two new format characters were added to the :mod:`struct` module for 64-bit - integers on platforms that support the C :c:type:`long long` type. ``q`` is for + integers on platforms that support the C :c:expr:`long long` type. ``q`` is for a signed 64-bit integer, and ``Q`` is for an unsigned one. The value is returned in Python's long integer type. (Contributed by Tim Peters.) diff --git a/Doc/whatsnew/2.3.rst b/Doc/whatsnew/2.3.rst index 27a0756cbb84..c6e2003e92f1 100644 --- a/Doc/whatsnew/2.3.rst +++ b/Doc/whatsnew/2.3.rst @@ -1905,8 +1905,8 @@ Changes to Python's build process and to the C API include: "")`` instead, but this will be slower than using :const:`METH_NOARGS`. * :c:func:`PyArg_ParseTuple` accepts new format characters for various sizes of - unsigned integers: ``B`` for :c:type:`unsigned char`, ``H`` for :c:type:`unsigned - short int`, ``I`` for :c:type:`unsigned int`, and ``K`` for :c:type:`unsigned + unsigned integers: ``B`` for :c:expr:`unsigned char`, ``H`` for :c:expr:`unsigned + short int`, ``I`` for :c:expr:`unsigned int`, and ``K`` for :c:expr:`unsigned long long`. * A new function, ``PyObject_DelItemString(mapping, char *key)`` was added diff --git a/Doc/whatsnew/2.4.rst b/Doc/whatsnew/2.4.rst index 61f9eb43243c..63e819876ce3 100644 --- a/Doc/whatsnew/2.4.rst +++ b/Doc/whatsnew/2.4.rst @@ -472,7 +472,7 @@ PEP 327: Decimal Data Type ========================== Python has always supported floating-point (FP) numbers, based on the underlying -C :c:type:`double` type, as a data type. However, while most programming +C :c:expr:`double` type, as a data type. However, while most programming languages provide a floating-point type, many people (even programmers) are unaware that floating-point numbers don't represent certain decimal fractions accurately. The new :class:`Decimal` type can represent these fractions @@ -501,7 +501,7 @@ mantissa is multiplied by 4 (2 to the power of the exponent 2); 1.25 \* 4 equals 5. Modern systems usually provide floating-point support that conforms to a -standard called IEEE 754. C's :c:type:`double` type is usually implemented as a +standard called IEEE 754. C's :c:expr:`double` type is usually implemented as a 64-bit IEEE 754 number, which uses 52 bits of space for the mantissa. This means that numbers can only be specified to 52 bits of precision. If you're trying to represent numbers whose expansion repeats endlessly, the expansion is @@ -750,10 +750,10 @@ The solution described in the PEP is to add three new functions to the Python API that perform ASCII-only conversions, ignoring the locale setting: * ``PyOS_ascii_strtod(str, ptr)`` and ``PyOS_ascii_atof(str, ptr)`` - both convert a string to a C :c:type:`double`. + both convert a string to a C :c:expr:`double`. * ``PyOS_ascii_formatd(buffer, buf_len, format, d)`` converts a - :c:type:`double` to an ASCII string. + :c:expr:`double` to an ASCII string. The code for these functions came from the GLib library (https://developer.gnome.org/glib/stable/), whose developers kindly diff --git a/Doc/whatsnew/2.5.rst b/Doc/whatsnew/2.5.rst index dfa8f7e93f81..0aca2fe697cc 100644 --- a/Doc/whatsnew/2.5.rst +++ b/Doc/whatsnew/2.5.rst @@ -872,18 +872,18 @@ PEP 353: Using ssize_t as the index type ======================================== A wide-ranging change to Python's C API, using a new :c:type:`Py_ssize_t` type -definition instead of :c:type:`int`, will permit the interpreter to handle more +definition instead of :c:expr:`int`, will permit the interpreter to handle more data on 64-bit platforms. This change doesn't affect Python's capacity on 32-bit platforms. -Various pieces of the Python interpreter used C's :c:type:`int` type to store +Various pieces of the Python interpreter used C's :c:expr:`int` type to store sizes or counts; for example, the number of items in a list or tuple were stored -in an :c:type:`int`. The C compilers for most 64-bit platforms still define -:c:type:`int` as a 32-bit type, so that meant that lists could only hold up to +in an :c:expr:`int`. The C compilers for most 64-bit platforms still define +:c:expr:`int` as a 32-bit type, so that meant that lists could only hold up to ``2**31 - 1`` = 2147483647 items. (There are actually a few different programming models that 64-bit C compilers can use -- see https://unix.org/version2/whatsnew/lp64_wp.html for a discussion -- but the -most commonly available model leaves :c:type:`int` as 32 bits.) +most commonly available model leaves :c:expr:`int` as 32 bits.) A limit of 2147483647 items doesn't really matter on a 32-bit platform because you'll run out of memory before hitting the length limit. Each list item @@ -895,7 +895,7 @@ It's possible to address that much memory on a 64-bit platform, however. The pointers for a list that size would only require 16 GiB of space, so it's not unreasonable that Python programmers might construct lists that large. Therefore, the Python interpreter had to be changed to use some type other than -:c:type:`int`, and this will be a 64-bit type on 64-bit platforms. The change +:c:expr:`int`, and this will be a 64-bit type on 64-bit platforms. The change will cause incompatibilities on 64-bit machines, so it was deemed worth making the transition now, while the number of 64-bit users is still relatively small. (In 5 or 10 years, we may *all* be on 64-bit machines, and the transition would @@ -909,7 +909,7 @@ may therefore need to have some variables changed to :c:type:`Py_ssize_t`. The :c:func:`PyArg_ParseTuple` and :c:func:`Py_BuildValue` functions have a new conversion code, ``n``, for :c:type:`Py_ssize_t`. :c:func:`PyArg_ParseTuple`'s -``s#`` and ``t#`` still output :c:type:`int` by default, but you can define the +``s#`` and ``t#`` still output :c:expr:`int` by default, but you can define the macro :c:macro:`PY_SSIZE_T_CLEAN` before including :file:`Python.h` to make them return :c:type:`Py_ssize_t`. @@ -1695,7 +1695,7 @@ attributes of the :class:`CDLL` object. :: result = libc.printf("Line of output\n") Type constructors for the various C types are provided: :func:`c_int`, -:func:`c_float`, :func:`c_double`, :func:`c_char_p` (equivalent to :c:type:`char +:func:`c_float`, :func:`c_double`, :func:`c_char_p` (equivalent to :c:expr:`char \*`), and so forth. Unlike Python's types, the C versions are all mutable; you can assign to their :attr:`value` attribute to change the wrapped value. Python integers and strings will be automatically converted to the corresponding C @@ -2093,7 +2093,7 @@ Changes to Python's build process and to the C API include: * The largest change to the C API came from :pep:`353`, which modifies the interpreter to use a :c:type:`Py_ssize_t` type definition instead of - :c:type:`int`. See the earlier section :ref:`pep-353` for a discussion of this + :c:expr:`int`. See the earlier section :ref:`pep-353` for a discussion of this change. * The design of the bytecode compiler has changed a great deal, no longer @@ -2264,7 +2264,7 @@ code: Setting :attr:`rpc_paths` to ``None`` or an empty tuple disables this path checking. -* C API: Many functions now use :c:type:`Py_ssize_t` instead of :c:type:`int` to +* C API: Many functions now use :c:type:`Py_ssize_t` instead of :c:expr:`int` to allow processing more data on 64-bit machines. Extension code may need to make the same change to avoid warnings and to support 64-bit machines. See the earlier section :ref:`pep-353` for a discussion of this change. diff --git a/Doc/whatsnew/2.6.rst b/Doc/whatsnew/2.6.rst index 5a3c103f29a7..731ce6aac691 100644 --- a/Doc/whatsnew/2.6.rst +++ b/Doc/whatsnew/2.6.rst @@ -2389,7 +2389,7 @@ changes, or look through the Subversion logs for all the details. has been updated from version 2.3.2 in Python 2.5 to version 2.4.1. -* The :mod:`struct` module now supports the C99 :c:type:`_Bool` type, +* The :mod:`struct` module now supports the C99 :c:expr:`_Bool` type, using the format character ``'?'``. (Contributed by David Remahl.) diff --git a/Doc/whatsnew/2.7.rst b/Doc/whatsnew/2.7.rst index d48a9f7c45f8..3df9f8a4798f 100644 --- a/Doc/whatsnew/2.7.rst +++ b/Doc/whatsnew/2.7.rst @@ -2144,7 +2144,7 @@ Changes to Python's build process and to the C API include: * New functions: :c:func:`PyLong_AsLongAndOverflow` and :c:func:`PyLong_AsLongLongAndOverflow` approximates a Python long - integer as a C :c:type:`long` or :c:type:`long long`. + integer as a C :c:expr:`long` or :c:expr:`long long`. If the number is too large to fit into the output type, an *overflow* flag is set and returned to the caller. (Contributed by Case Van Horsen; :issue:`7528` and :issue:`7767`.) @@ -2202,7 +2202,7 @@ Changes to Python's build process and to the C API include: * New format codes: the :c:func:`PyFormat_FromString`, :c:func:`PyFormat_FromStringV`, and :c:func:`PyErr_Format` functions now accept ``%lld`` and ``%llu`` format codes for displaying - C's :c:type:`long long` types. + C's :c:expr:`long long` types. (Contributed by Mark Dickinson; :issue:`7228`.) * The complicated interaction between threads and process forking has diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst index 609370bad274..fef1a8ac4c01 100644 --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -932,7 +932,7 @@ it can now be used as a class decorator (:issue:`10868`). array ----- -The :mod:`array` module supports the :c:type:`long long` type using ``q`` and +The :mod:`array` module supports the :c:expr:`long long` type using ``q`` and ``Q`` type codes. (Contributed by Oren Tirosh and Hirokazu Yamamoto in :issue:`1172711`.) diff --git a/Doc/whatsnew/3.7.rst b/Doc/whatsnew/3.7.rst index 3facd88994eb..5bb3d2a436b6 100644 --- a/Doc/whatsnew/3.7.rst +++ b/Doc/whatsnew/3.7.rst @@ -290,21 +290,21 @@ PEP 539: New C API for Thread-Local Storage While Python provides a C API for thread-local storage support; the existing :ref:`Thread Local Storage (TLS) API ` has used -:c:type:`int` to represent TLS keys across all platforms. This has not +:c:expr:`int` to represent TLS keys across all platforms. This has not generally been a problem for officially support platforms, but that is neither POSIX-compliant, nor portable in any practical sense. :pep:`539` changes this by providing a new :ref:`Thread Specific Storage (TSS) API ` to CPython which supersedes use of the existing TLS API within the CPython interpreter, while deprecating the existing -API. The TSS API uses a new type :c:type:`Py_tss_t` instead of :c:type:`int` +API. The TSS API uses a new type :c:type:`Py_tss_t` instead of :c:expr:`int` to represent TSS keys--an opaque type the definition of which may depend on the underlying TLS implementation. Therefore, this will allow to build CPython on platforms where the native TLS key is defined in a way that cannot be safely -cast to :c:type:`int`. +cast to :c:expr:`int`. Note that on platforms where the native TLS key is defined in a way that cannot -be safely cast to :c:type:`int`, all functions of the existing TLS API will be +be safely cast to :c:expr:`int`, all functions of the existing TLS API will be no-op and immediately return failure. This indicates clearly that the old API is not supported on platforms where it cannot be used reliably, and that no effort will be made to add such support. @@ -1708,12 +1708,12 @@ Contributed by Paul Ganssle in :issue:`10381`. The type of results of :c:func:`PyThread_start_new_thread` and :c:func:`PyThread_get_thread_ident`, and the *id* parameter of -:c:func:`PyThreadState_SetAsyncExc` changed from :c:type:`long` to -:c:type:`unsigned long`. +:c:func:`PyThreadState_SetAsyncExc` changed from :c:expr:`long` to +:c:expr:`unsigned long`. (Contributed by Serhiy Storchaka in :issue:`6532`.) :c:func:`PyUnicode_AsWideCharString` now raises a :exc:`ValueError` if the -second argument is ``NULL`` and the :c:type:`wchar_t*` string contains null +second argument is ``NULL`` and the :c:expr:`wchar_t*` string contains null characters. (Contributed by Serhiy Storchaka in :issue:`30708`.) Changes to the startup sequence and the management of dynamic memory diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index 6deaede4953b..ff01a6577299 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -773,7 +773,7 @@ Optimizations Stinner in :issue:`38061`.) * :c:func:`PyLong_FromDouble` is now up to 1.87x faster for values that - fit into :c:type:`long`. + fit into :c:expr:`long`. (Contributed by Sergey Fedoseev in :issue:`37986`.) * A number of Python builtins (:class:`range`, :class:`tuple`, :class:`set`, diff --git a/Misc/NEWS.d/3.5.0a1.rst b/Misc/NEWS.d/3.5.0a1.rst index 97bdef6c9321..96e59206cb12 100644 --- a/Misc/NEWS.d/3.5.0a1.rst +++ b/Misc/NEWS.d/3.5.0a1.rst @@ -3034,7 +3034,7 @@ by Phil Elson. .. nonce: LK_5S1 .. section: Library -os.read() now uses a :c:func:`Py_ssize_t` type instead of :c:type:`int` for +os.read() now uses a :c:func:`Py_ssize_t` type instead of :c:expr:`int` for the size to support reading more than 2 GB at once. On Windows, the size is truncated to INT_MAX. As any call to os.read(), the OS may read less bytes than the number of requested bytes. diff --git a/Misc/NEWS.d/3.9.0a1.rst b/Misc/NEWS.d/3.9.0a1.rst index 45f232f1948d..63d77fd3ac0c 100644 --- a/Misc/NEWS.d/3.9.0a1.rst +++ b/Misc/NEWS.d/3.9.0a1.rst @@ -1510,7 +1510,7 @@ asynchronous magic methods on a MagicMock now return an AsyncMock. .. section: Library Update the *length* parameter of :func:`os.pread` to accept -:c:type:`Py_ssize_t` instead of :c:type:`int`. +:c:type:`Py_ssize_t` instead of :c:expr:`int`. .. diff --git a/Misc/NEWS.d/3.9.0b1.rst b/Misc/NEWS.d/3.9.0b1.rst index 529be0eba586..a7f52f81a5cd 100644 --- a/Misc/NEWS.d/3.9.0b1.rst +++ b/Misc/NEWS.d/3.9.0b1.rst @@ -191,7 +191,7 @@ internal subinterpreters module. .. section: Core and Builtins Improve performance of :c:func:`PyLong_FromDouble` for values that fit into -:c:type:`long`. +:c:expr:`long`. .. From webhook-mailer at python.org Wed Oct 5 17:50:51 2022 From: webhook-mailer at python.org (ambv) Date: Wed, 05 Oct 2022 21:50:51 -0000 Subject: [Python-checkins] [3.11] gh-97654: Add auto exception chaining example to tutorial (GH-97703) (#97885) Message-ID: https://github.com/python/cpython/commit/3dc7bfee3e2791783c3d1be73c38452ba1b9b0f3 commit: 3dc7bfee3e2791783c3d1be73c38452ba1b9b0f3 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-05T14:50:46-07:00 summary: [3.11] gh-97654: Add auto exception chaining example to tutorial (GH-97703) (#97885) gh-97654: Add auto exception chaining example to tutorial (GH-97703) Add auto exception chaining example to tutorial (cherry picked from commit 395b66a0ae5237eec195ca97daaaf8563706ed34) Co-authored-by: Shahriar Heidrich files: M Doc/tutorial/errors.rst diff --git a/Doc/tutorial/errors.rst b/Doc/tutorial/errors.rst index 57919e3bad13..67bb19556681 100644 --- a/Doc/tutorial/errors.rst +++ b/Doc/tutorial/errors.rst @@ -284,8 +284,27 @@ re-raise the exception:: Exception Chaining ================== -The :keyword:`raise` statement allows an optional :keyword:`from` which enables -chaining exceptions. For example:: +If an unhandled exception occurs inside an :keyword:`except` section, it will +have the exception being handled attached to it and included in the error +message:: + + >>> try: + ... open("database.sqlite") + ... except OSError: + ... raise RuntimeError("unable to handle error") + ... + Traceback (most recent call last): + File "", line 2, in + FileNotFoundError: [Errno 2] No such file or directory: 'database.sqlite' + + During handling of the above exception, another exception occurred: + + Traceback (most recent call last): + File "", line 4, in + RuntimeError: unable to handle error + +To indicate that an exception is a direct consequence of another, the +:keyword:`raise` statement allows an optional :keyword:`from` clause:: # exc must be exception instance or None. raise RuntimeError from exc @@ -311,9 +330,8 @@ This can be useful when you are transforming exceptions. For example:: File "", line 4, in RuntimeError: Failed to open database -Exception chaining happens automatically when an exception is raised inside an -:keyword:`except` or :keyword:`finally` section. This can be -disabled by using ``from None`` idiom: +It also allows disabling automatic exception chaining using the ``from None`` +idiom:: >>> try: ... open('database.sqlite') From webhook-mailer at python.org Wed Oct 5 17:51:16 2022 From: webhook-mailer at python.org (ambv) Date: Wed, 05 Oct 2022 21:51:16 -0000 Subject: [Python-checkins] [3.10] gh-97654: Add auto exception chaining example to tutorial (GH-97703) (#97884) Message-ID: https://github.com/python/cpython/commit/9f1c9b1a7a04513fcc8a679fb1075701f37ab621 commit: 9f1c9b1a7a04513fcc8a679fb1075701f37ab621 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-05T14:51:10-07:00 summary: [3.10] gh-97654: Add auto exception chaining example to tutorial (GH-97703) (#97884) Add auto exception chaining example to tutorial (cherry picked from commit 395b66a0ae5237eec195ca97daaaf8563706ed34) Co-authored-by: Shahriar Heidrich files: M Doc/tutorial/errors.rst diff --git a/Doc/tutorial/errors.rst b/Doc/tutorial/errors.rst index 3f09db210406..ecfb61288390 100644 --- a/Doc/tutorial/errors.rst +++ b/Doc/tutorial/errors.rst @@ -275,8 +275,27 @@ re-raise the exception:: Exception Chaining ================== -The :keyword:`raise` statement allows an optional :keyword:`from` which enables -chaining exceptions. For example:: +If an unhandled exception occurs inside an :keyword:`except` section, it will +have the exception being handled attached to it and included in the error +message:: + + >>> try: + ... open("database.sqlite") + ... except OSError: + ... raise RuntimeError("unable to handle error") + ... + Traceback (most recent call last): + File "", line 2, in + FileNotFoundError: [Errno 2] No such file or directory: 'database.sqlite' + + During handling of the above exception, another exception occurred: + + Traceback (most recent call last): + File "", line 4, in + RuntimeError: unable to handle error + +To indicate that an exception is a direct consequence of another, the +:keyword:`raise` statement allows an optional :keyword:`from` clause:: # exc must be exception instance or None. raise RuntimeError from exc @@ -302,9 +321,8 @@ This can be useful when you are transforming exceptions. For example:: File "", line 4, in RuntimeError: Failed to open database -Exception chaining happens automatically when an exception is raised inside an -:keyword:`except` or :keyword:`finally` section. This can be -disabled by using ``from None`` idiom: +It also allows disabling automatic exception chaining using the ``from None`` +idiom:: >>> try: ... open('database.sqlite') From webhook-mailer at python.org Wed Oct 5 17:54:44 2022 From: webhook-mailer at python.org (ambv) Date: Wed, 05 Oct 2022 21:54:44 -0000 Subject: [Python-checkins] [3.7] gh-97005: Update libexpat from 2.4.7 to 2.4.9 (gh-97006) (#97014) Message-ID: https://github.com/python/cpython/commit/46796ed391e2e749f19d158429e07ec692526b6d commit: 46796ed391e2e749f19d158429e07ec692526b6d branch: 3.7 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-05T14:54:39-07:00 summary: [3.7] gh-97005: Update libexpat from 2.4.7 to 2.4.9 (gh-97006) (#97014) Co-authored-by: Gregory P. Smith [Google] (cherry picked from commit 10e3d398c31cc1695752fc52bc6ca2ce9ef6237e) Co-authored-by: Dong-hee Na files: A Misc/NEWS.d/next/Library/2022-09-22-14-35-02.gh-issue-97005.yf21Q7.rst M Modules/expat/COPYING M Modules/expat/expat.h M Modules/expat/internal.h M Modules/expat/siphash.h M Modules/expat/xmlparse.c M Modules/expat/xmltok.c M Modules/expat/xmltok_impl.c diff --git a/Misc/NEWS.d/next/Library/2022-09-22-14-35-02.gh-issue-97005.yf21Q7.rst b/Misc/NEWS.d/next/Library/2022-09-22-14-35-02.gh-issue-97005.yf21Q7.rst new file mode 100644 index 000000000000..d57999aa29b7 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-09-22-14-35-02.gh-issue-97005.yf21Q7.rst @@ -0,0 +1 @@ +Update bundled libexpat to 2.4.9 diff --git a/Modules/expat/COPYING b/Modules/expat/COPYING index 3c0142e71c8d..ce9e5939291e 100644 --- a/Modules/expat/COPYING +++ b/Modules/expat/COPYING @@ -1,5 +1,5 @@ Copyright (c) 1998-2000 Thai Open Source Software Center Ltd and Clark Cooper -Copyright (c) 2001-2019 Expat maintainers +Copyright (c) 2001-2022 Expat maintainers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/Modules/expat/expat.h b/Modules/expat/expat.h index c9214f64070a..2b47ce2a8d3a 100644 --- a/Modules/expat/expat.h +++ b/Modules/expat/expat.h @@ -1055,7 +1055,7 @@ XML_SetBillionLaughsAttackProtectionActivationThreshold( */ #define XML_MAJOR_VERSION 2 #define XML_MINOR_VERSION 4 -#define XML_MICRO_VERSION 7 +#define XML_MICRO_VERSION 9 #ifdef __cplusplus } diff --git a/Modules/expat/internal.h b/Modules/expat/internal.h index 444eba0fb031..e09f533b23c9 100644 --- a/Modules/expat/internal.h +++ b/Modules/expat/internal.h @@ -28,7 +28,7 @@ Copyright (c) 2002-2003 Fred L. Drake, Jr. Copyright (c) 2002-2006 Karl Waclawek Copyright (c) 2003 Greg Stein - Copyright (c) 2016-2021 Sebastian Pipping + Copyright (c) 2016-2022 Sebastian Pipping Copyright (c) 2018 Yury Gribov Copyright (c) 2019 David Loffredo Licensed under the MIT license: @@ -107,7 +107,9 @@ #include // ULONG_MAX -#if defined(_WIN32) && ! defined(__USE_MINGW_ANSI_STDIO) +#if defined(_WIN32) \ + && (! defined(__USE_MINGW_ANSI_STDIO) \ + || (1 - __USE_MINGW_ANSI_STDIO - 1 == 0)) # define EXPAT_FMT_ULL(midpart) "%" midpart "I64u" # if defined(_WIN64) // Note: modifiers "td" and "zu" do not work for MinGW # define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "I64d" diff --git a/Modules/expat/siphash.h b/Modules/expat/siphash.h index e5406d7ee9eb..303283ad2de9 100644 --- a/Modules/expat/siphash.h +++ b/Modules/expat/siphash.h @@ -106,7 +106,7 @@ * if this code is included and compiled as C++; related GCC warning is: * warning: use of C++11 long long integer constant [-Wlong-long] */ -#define _SIP_ULL(high, low) (((uint64_t)high << 32) | low) +#define _SIP_ULL(high, low) ((((uint64_t)high) << 32) | (low)) #define SIP_ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b)))) diff --git a/Modules/expat/xmlparse.c b/Modules/expat/xmlparse.c index 05216d997b07..c0bece51d700 100644 --- a/Modules/expat/xmlparse.c +++ b/Modules/expat/xmlparse.c @@ -1,4 +1,4 @@ -/* fcb1a62fefa945567301146eb98e3ad3413e823a41c4378e84e8b6b6f308d824 (2.4.7+) +/* 90815a2b2c80c03b2b889fe1d427bb2b9e3282aa065e42784e001db4f23de324 (2.4.9+) __ __ _ ___\ \/ /_ __ __ _| |_ / _ \\ /| '_ \ / _` | __| @@ -19,7 +19,7 @@ Copyright (c) 2016 Gustavo Grieco Copyright (c) 2016 Pascal Cuoq Copyright (c) 2016 Ed Schouten - Copyright (c) 2017-2018 Rhodri James + Copyright (c) 2017-2022 Rhodri James Copyright (c) 2017 V?clav Slav?k Copyright (c) 2017 Viktor Szakats Copyright (c) 2017 Chanho Park @@ -4271,7 +4271,7 @@ processXmlDecl(XML_Parser parser, int isGeneralTextEntity, const char *s, const XML_Char *storedEncName = NULL; const ENCODING *newEncoding = NULL; const char *version = NULL; - const char *versionend; + const char *versionend = NULL; const XML_Char *storedversion = NULL; int standalone = -1; @@ -5826,10 +5826,15 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end, { parser->m_processor = contentProcessor; /* see externalEntityContentProcessor vs contentProcessor */ - return doContent(parser, parser->m_parentParser ? 1 : 0, parser->m_encoding, - s, end, nextPtr, - (XML_Bool)! parser->m_parsingStatus.finalBuffer, - XML_ACCOUNT_DIRECT); + result = doContent(parser, parser->m_parentParser ? 1 : 0, + parser->m_encoding, s, end, nextPtr, + (XML_Bool)! parser->m_parsingStatus.finalBuffer, + XML_ACCOUNT_DIRECT); + if (result == XML_ERROR_NONE) { + if (! storeRawNames(parser)) + return XML_ERROR_NO_MEMORY; + } + return result; } } diff --git a/Modules/expat/xmltok.c b/Modules/expat/xmltok.c index c659983b4008..2b7012a58be4 100644 --- a/Modules/expat/xmltok.c +++ b/Modules/expat/xmltok.c @@ -21,6 +21,7 @@ Copyright (c) 2017 Jos? Guti?rrez de la Concha Copyright (c) 2019 David Loffredo Copyright (c) 2021 Dong-hee Na + Copyright (c) 2022 Martin Ettl Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -296,7 +297,7 @@ sb_charMatches(const ENCODING *enc, const char *p, int c) { } #else /* c is an ASCII character */ -# define CHAR_MATCHES(enc, p, c) (*(p) == c) +# define CHAR_MATCHES(enc, p, c) (*(p) == (c)) #endif #define PREFIX(ident) normal_##ident @@ -740,7 +741,7 @@ DEFINE_UTF16_TO_UTF16(big2_) ((p)[1] == 0 ? ((struct normal_encoding *)(enc))->type[(unsigned char)*(p)] \ : unicode_byte_type((p)[1], (p)[0])) #define LITTLE2_BYTE_TO_ASCII(p) ((p)[1] == 0 ? (p)[0] : -1) -#define LITTLE2_CHAR_MATCHES(p, c) ((p)[1] == 0 && (p)[0] == c) +#define LITTLE2_CHAR_MATCHES(p, c) ((p)[1] == 0 && (p)[0] == (c)) #define LITTLE2_IS_NAME_CHAR_MINBPC(p) \ UCS2_GET_NAMING(namePages, (unsigned char)p[1], (unsigned char)p[0]) #define LITTLE2_IS_NMSTRT_CHAR_MINBPC(p) \ @@ -875,7 +876,7 @@ static const struct normal_encoding internal_little2_encoding ? ((struct normal_encoding *)(enc))->type[(unsigned char)(p)[1]] \ : unicode_byte_type((p)[0], (p)[1])) #define BIG2_BYTE_TO_ASCII(p) ((p)[0] == 0 ? (p)[1] : -1) -#define BIG2_CHAR_MATCHES(p, c) ((p)[0] == 0 && (p)[1] == c) +#define BIG2_CHAR_MATCHES(p, c) ((p)[0] == 0 && (p)[1] == (c)) #define BIG2_IS_NAME_CHAR_MINBPC(p) \ UCS2_GET_NAMING(namePages, (unsigned char)p[0], (unsigned char)p[1]) #define BIG2_IS_NMSTRT_CHAR_MINBPC(p) \ diff --git a/Modules/expat/xmltok_impl.c b/Modules/expat/xmltok_impl.c index 4072b06497d1..1971d74bf8c9 100644 --- a/Modules/expat/xmltok_impl.c +++ b/Modules/expat/xmltok_impl.c @@ -16,6 +16,7 @@ Copyright (c) 2018 Anton Maklakov Copyright (c) 2019 David Loffredo Copyright (c) 2020 Boris Kolpackov + Copyright (c) 2022 Martin Ettl Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -96,7 +97,7 @@ # define CHECK_NMSTRT_CASE(n, enc, ptr, end, nextTokPtr) \ case BT_LEAD##n: \ - if (end - ptr < n) \ + if ((end) - (ptr) < (n)) \ return XML_TOK_PARTIAL_CHAR; \ if (IS_INVALID_CHAR(enc, ptr, n) || ! IS_NMSTRT_CHAR(enc, ptr, n)) { \ *nextTokPtr = ptr; \ @@ -124,7 +125,8 @@ # define PREFIX(ident) ident # endif -# define HAS_CHARS(enc, ptr, end, count) (end - ptr >= count * MINBPC(enc)) +# define HAS_CHARS(enc, ptr, end, count) \ + ((end) - (ptr) >= ((count)*MINBPC(enc))) # define HAS_CHAR(enc, ptr, end) HAS_CHARS(enc, ptr, end, 1) From webhook-mailer at python.org Wed Oct 5 17:55:34 2022 From: webhook-mailer at python.org (ambv) Date: Wed, 05 Oct 2022 21:55:34 -0000 Subject: [Python-checkins] [3.7] gh-96848: Fix -X int_max_str_digits option parsing (#96988) (#97576) Message-ID: https://github.com/python/cpython/commit/98884f523d783ecd9933c1ca52d80fbbd7d6bdf5 commit: 98884f523d783ecd9933c1ca52d80fbbd7d6bdf5 branch: 3.7 author: Victor Stinner committer: ambv date: 2022-10-05T14:55:28-07:00 summary: [3.7] gh-96848: Fix -X int_max_str_digits option parsing (#96988) (#97576) Fix command line parsing: reject "-X int_max_str_digits" option with no value (invalid) when the PYTHONINTMAXSTRDIGITS environment variable is set to a valid limit. (cherry picked from commit 41351662bcd21672d8ccfa62fe44d72027e6bcf8) files: A Misc/NEWS.d/next/Core and Builtins/2022-09-21-14-38-31.gh-issue-96848.WuoLzU.rst M Lib/test/test_cmd_line.py M Modules/main.c diff --git a/Lib/test/test_cmd_line.py b/Lib/test/test_cmd_line.py index 0ca90fd4ab45..56455ac9dc7e 100644 --- a/Lib/test/test_cmd_line.py +++ b/Lib/test/test_cmd_line.py @@ -717,6 +717,8 @@ def test_int_max_str_digits(self): assert_python_failure('-X', 'int_max_str_digits', '-c', code) assert_python_failure('-X', 'int_max_str_digits=foo', '-c', code) assert_python_failure('-X', 'int_max_str_digits=100', '-c', code) + assert_python_failure('-X', 'int_max_str_digits', '-c', code, + PYTHONINTMAXSTRDIGITS='4000') assert_python_failure('-c', code, PYTHONINTMAXSTRDIGITS='foo') assert_python_failure('-c', code, PYTHONINTMAXSTRDIGITS='100') diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-21-14-38-31.gh-issue-96848.WuoLzU.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-21-14-38-31.gh-issue-96848.WuoLzU.rst new file mode 100644 index 000000000000..a9b04ce87d4d --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-09-21-14-38-31.gh-issue-96848.WuoLzU.rst @@ -0,0 +1,3 @@ +Fix command line parsing: reject :option:`-X int_max_str_digits <-X>` option +with no value (invalid) when the :envvar:`PYTHONINTMAXSTRDIGITS` environment +variable is set to a valid limit. Patch by Victor Stinner. diff --git a/Modules/main.c b/Modules/main.c index b646fe52e6b3..dfb618017938 100644 --- a/Modules/main.c +++ b/Modules/main.c @@ -1813,10 +1813,10 @@ static _PyInitError config_init_int_max_str_digits(_PyCoreConfig *config) { int maxdigits; - int valid = 0; const char *env = config_get_env_var("PYTHONINTMAXSTRDIGITS"); if (env) { + int valid = 0; if (!pymain_str_to_int(env, &maxdigits)) { valid = ((maxdigits == 0) || (maxdigits >= _PY_LONG_MAX_STR_DIGITS_THRESHOLD)); } @@ -1834,6 +1834,7 @@ config_init_int_max_str_digits(_PyCoreConfig *config) const wchar_t *xoption = config_get_xoption(config, L"int_max_str_digits"); if (xoption) { const wchar_t *sep = wcschr(xoption, L'='); + int valid = 0; if (sep) { if (!pymain_wstr_to_int(sep + 1, &maxdigits)) { valid = ((maxdigits == 0) || (maxdigits >= _PY_LONG_MAX_STR_DIGITS_THRESHOLD)); From webhook-mailer at python.org Wed Oct 5 17:55:58 2022 From: webhook-mailer at python.org (ambv) Date: Wed, 05 Oct 2022 21:55:58 -0000 Subject: [Python-checkins] [3.7] gh-97616: list_resize() checks for integer overflow (GH-97617) (#97629) Message-ID: https://github.com/python/cpython/commit/fd82f16c1e4d9a0661e9a2250004032797652e69 commit: fd82f16c1e4d9a0661e9a2250004032797652e69 branch: 3.7 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-05T14:55:53-07:00 summary: [3.7] gh-97616: list_resize() checks for integer overflow (GH-97617) (#97629) Fix multiplying a list by an integer (list *= int): detect the integer overflow when the new allocated length is close to the maximum size. Issue reported by Jordan Limor. list_resize() now checks for integer overflow before multiplying the new allocated length by the list item size (sizeof(PyObject*)). (cherry picked from commit a5f092f3c469b674b8d9ccbd4e4377230c9ac7cf) Co-authored-by: Victor Stinner files: A Misc/NEWS.d/next/Security/2022-09-28-17-09-37.gh-issue-97616.K1e3Xs.rst M Lib/test/test_list.py M Objects/listobject.c diff --git a/Lib/test/test_list.py b/Lib/test/test_list.py index 32bf17564c9d..c9cdc1e384a6 100644 --- a/Lib/test/test_list.py +++ b/Lib/test/test_list.py @@ -67,6 +67,19 @@ def imul(a, b): a *= b self.assertRaises((MemoryError, OverflowError), mul, lst, n) self.assertRaises((MemoryError, OverflowError), imul, lst, n) + def test_list_resize_overflow(self): + # gh-97616: test new_allocated * sizeof(PyObject*) overflow + # check in list_resize() + lst = [0] * 65 + del lst[1:] + self.assertEqual(len(lst), 1) + + size = ((2 ** (tuple.__itemsize__ * 8) - 1) // 2) + with self.assertRaises((MemoryError, OverflowError)): + lst * size + with self.assertRaises((MemoryError, OverflowError)): + lst *= size + def test_repr_large(self): # Check the repr of large list objects def check(n): diff --git a/Misc/NEWS.d/next/Security/2022-09-28-17-09-37.gh-issue-97616.K1e3Xs.rst b/Misc/NEWS.d/next/Security/2022-09-28-17-09-37.gh-issue-97616.K1e3Xs.rst new file mode 100644 index 000000000000..721427fe6465 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2022-09-28-17-09-37.gh-issue-97616.K1e3Xs.rst @@ -0,0 +1,3 @@ +Fix multiplying a list by an integer (``list *= int``): detect the integer +overflow when the new allocated length is close to the maximum size. Issue +reported by Jordan Limor. Patch by Victor Stinner. diff --git a/Objects/listobject.c b/Objects/listobject.c index 158ca11d0329..60837fcf1e1e 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -64,8 +64,14 @@ list_resize(PyListObject *self, Py_ssize_t newsize) if (newsize == 0) new_allocated = 0; - num_allocated_bytes = new_allocated * sizeof(PyObject *); - items = (PyObject **)PyMem_Realloc(self->ob_item, num_allocated_bytes); + if (new_allocated <= (size_t)PY_SSIZE_T_MAX / sizeof(PyObject *)) { + num_allocated_bytes = new_allocated * sizeof(PyObject *); + items = (PyObject **)PyMem_Realloc(self->ob_item, num_allocated_bytes); + } + else { + // integer overflow + items = NULL; + } if (items == NULL) { PyErr_NoMemory(); return -1; From webhook-mailer at python.org Wed Oct 5 17:56:18 2022 From: webhook-mailer at python.org (ambv) Date: Wed, 05 Oct 2022 21:56:18 -0000 Subject: [Python-checkins] [3.7] gh-97612: Fix shell injection in get-remote-certificate.py (#97613) (#97634) Message-ID: https://github.com/python/cpython/commit/c7ec7808191fc29f75d96496b682bd34be770a8f commit: c7ec7808191fc29f75d96496b682bd34be770a8f branch: 3.7 author: Victor Stinner committer: ambv date: 2022-10-05T14:56:13-07:00 summary: [3.7] gh-97612: Fix shell injection in get-remote-certificate.py (#97613) (#97634) Fix a shell code injection vulnerability in the get-remote-certificate.py example script. The script no longer uses a shell to run "openssl" commands. Issue reported and initial fix by Caleb Shortt. Remove the Windows code path to send "quit" on stdin to the "openssl s_client" command: use DEVNULL on all platforms instead. Co-authored-by: Caleb Shortt (cherry picked from commit 83a0f44ffd8b398673ae56c310cf5768d359c341) files: A Misc/NEWS.d/next/Security/2022-09-28-12-10-57.gh-issue-97612.y6NvOQ.rst M Tools/scripts/get-remote-certificate.py diff --git a/Misc/NEWS.d/next/Security/2022-09-28-12-10-57.gh-issue-97612.y6NvOQ.rst b/Misc/NEWS.d/next/Security/2022-09-28-12-10-57.gh-issue-97612.y6NvOQ.rst new file mode 100644 index 000000000000..2f113492d42d --- /dev/null +++ b/Misc/NEWS.d/next/Security/2022-09-28-12-10-57.gh-issue-97612.y6NvOQ.rst @@ -0,0 +1,3 @@ +Fix a shell code injection vulnerability in the ``get-remote-certificate.py`` +example script. The script no longer uses a shell to run ``openssl`` commands. +Issue reported and initial fix by Caleb Shortt. Patch by Victor Stinner. diff --git a/Tools/scripts/get-remote-certificate.py b/Tools/scripts/get-remote-certificate.py index 5811f202eda9..24cc61f32d5f 100755 --- a/Tools/scripts/get-remote-certificate.py +++ b/Tools/scripts/get-remote-certificate.py @@ -15,8 +15,8 @@ def fetch_server_certificate (host, port): def subproc(cmd): - from subprocess import Popen, PIPE, STDOUT - proc = Popen(cmd, stdout=PIPE, stderr=STDOUT, shell=True) + from subprocess import Popen, PIPE, STDOUT, DEVNULL + proc = Popen(cmd, stdout=PIPE, stderr=STDOUT, stdin=DEVNULL) status = proc.wait() output = proc.stdout.read() return status, output @@ -34,8 +34,8 @@ def strip_to_x509_cert(certfile_contents, outfile=None): fp.close() try: tn2 = (outfile or tempfile.mktemp()) - status, output = subproc(r'openssl x509 -in "%s" -out "%s"' % - (tn, tn2)) + cmd = ['openssl', 'x509', '-in', tn, '-out', tn2] + status, output = subproc(cmd) if status != 0: raise RuntimeError('OpenSSL x509 failed with status %s and ' 'output: %r' % (status, output)) @@ -47,21 +47,9 @@ def strip_to_x509_cert(certfile_contents, outfile=None): finally: os.unlink(tn) - if sys.platform.startswith("win"): - tfile = tempfile.mktemp() - fp = open(tfile, "w") - fp.write("quit\n") - fp.close() - try: - status, output = subproc( - 'openssl s_client -connect "%s:%s" -showcerts < "%s"' % - (host, port, tfile)) - finally: - os.unlink(tfile) - else: - status, output = subproc( - 'openssl s_client -connect "%s:%s" -showcerts < /dev/null' % - (host, port)) + cmd = ['openssl', 's_client', '-connect', '%s:%s' % (host, port), '-showcerts'] + status, output = subproc(cmd) + if status != 0: raise RuntimeError('OpenSSL connect failed with status %s and ' 'output: %r' % (status, output)) From webhook-mailer at python.org Wed Oct 5 17:57:16 2022 From: webhook-mailer at python.org (ambv) Date: Wed, 05 Oct 2022 21:57:16 -0000 Subject: [Python-checkins] [3.11] Fix type annotation of `pstats.FunctionProfile.ncalls` (GH-96741) (#96835) Message-ID: https://github.com/python/cpython/commit/a8d50aeada9b6e2be1a4b6e498002c11b783a32a commit: a8d50aeada9b6e2be1a4b6e498002c11b783a32a branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-05T14:57:11-07:00 summary: [3.11] Fix type annotation of `pstats.FunctionProfile.ncalls` (GH-96741) (#96835) This change aligns the type annotation of `pstats.FunctionProfile.ncalls` with its runtime type. (cherry picked from commit 8e9a37dde44c9fa0b961cb2db5dc8266e1f85d11) Co-authored-by: Ruan Comelli files: A Misc/NEWS.d/next/Library/2022-09-15-00-37-33.gh-issue-96741.4b6czN.rst M Lib/pstats.py diff --git a/Lib/pstats.py b/Lib/pstats.py index 8e0743f2e5f2..80408313e8b2 100644 --- a/Lib/pstats.py +++ b/Lib/pstats.py @@ -57,7 +57,7 @@ def __new__(cls, *values): @dataclass(unsafe_hash=True) class FunctionProfile: - ncalls: int + ncalls: str tottime: float percall_tottime: float cumtime: float diff --git a/Misc/NEWS.d/next/Library/2022-09-15-00-37-33.gh-issue-96741.4b6czN.rst b/Misc/NEWS.d/next/Library/2022-09-15-00-37-33.gh-issue-96741.4b6czN.rst new file mode 100644 index 000000000000..e7f53311e589 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-09-15-00-37-33.gh-issue-96741.4b6czN.rst @@ -0,0 +1 @@ +Corrected type annotation for dataclass attribute ``pstats.FunctionProfile.ncalls`` to be ``str``. From webhook-mailer at python.org Wed Oct 5 17:57:31 2022 From: webhook-mailer at python.org (ambv) Date: Wed, 05 Oct 2022 21:57:31 -0000 Subject: [Python-checkins] [3.10] Fix type annotation of `pstats.FunctionProfile.ncalls` (GH-96741) (#96836) Message-ID: https://github.com/python/cpython/commit/6f23472345aedbba414620561ba89fa3cf6eda24 commit: 6f23472345aedbba414620561ba89fa3cf6eda24 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-05T14:57:26-07:00 summary: [3.10] Fix type annotation of `pstats.FunctionProfile.ncalls` (GH-96741) (#96836) This change aligns the type annotation of `pstats.FunctionProfile.ncalls` with its runtime type. (cherry picked from commit 8e9a37dde44c9fa0b961cb2db5dc8266e1f85d11) Co-authored-by: Ruan Comelli files: A Misc/NEWS.d/next/Library/2022-09-15-00-37-33.gh-issue-96741.4b6czN.rst M Lib/pstats.py diff --git a/Lib/pstats.py b/Lib/pstats.py index 0f93ae02c950..ac88c04dee25 100644 --- a/Lib/pstats.py +++ b/Lib/pstats.py @@ -56,7 +56,7 @@ def __new__(cls, *values): @dataclass(unsafe_hash=True) class FunctionProfile: - ncalls: int + ncalls: str tottime: float percall_tottime: float cumtime: float diff --git a/Misc/NEWS.d/next/Library/2022-09-15-00-37-33.gh-issue-96741.4b6czN.rst b/Misc/NEWS.d/next/Library/2022-09-15-00-37-33.gh-issue-96741.4b6czN.rst new file mode 100644 index 000000000000..e7f53311e589 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-09-15-00-37-33.gh-issue-96741.4b6czN.rst @@ -0,0 +1 @@ +Corrected type annotation for dataclass attribute ``pstats.FunctionProfile.ncalls`` to be ``str``. From webhook-mailer at python.org Wed Oct 5 18:00:18 2022 From: webhook-mailer at python.org (ambv) Date: Wed, 05 Oct 2022 22:00:18 -0000 Subject: [Python-checkins] [3.11] gh-96587: Raise `SyntaxError` for PEP654 on older `feature_version` (GH-96588) (#96591) Message-ID: https://github.com/python/cpython/commit/8c6ced36abb9ccc5dc6c8def1b376484685255c5 commit: 8c6ced36abb9ccc5dc6c8def1b376484685255c5 branch: 3.11 author: Nikita Sobolev committer: ambv date: 2022-10-05T15:00:13-07:00 summary: [3.11] gh-96587: Raise `SyntaxError` for PEP654 on older `feature_version` (GH-96588) (#96591) (cherry picked from commit 2c7d2e8d46164efb6e27a64081d8e949f6876515) Co-authored-by: Nikita Sobolev files: A Misc/NEWS.d/next/Core and Builtins/2022-09-05-19-20-44.gh-issue-96587.bVxhX2.rst M Grammar/python.gram M Lib/test/test_ast.py M Parser/parser.c diff --git a/Grammar/python.gram b/Grammar/python.gram index d4df78b679a4..51f846a57f40 100644 --- a/Grammar/python.gram +++ b/Grammar/python.gram @@ -412,7 +412,9 @@ try_stmt[stmt_ty]: | invalid_try_stmt | 'try' &&':' b=block f=finally_block { _PyAST_Try(b, NULL, NULL, f, EXTRA) } | 'try' &&':' b=block ex[asdl_excepthandler_seq*]=except_block+ el=[else_block] f=[finally_block] { _PyAST_Try(b, ex, el, f, EXTRA) } - | 'try' &&':' b=block ex[asdl_excepthandler_seq*]=except_star_block+ el=[else_block] f=[finally_block] { _PyAST_TryStar(b, ex, el, f, EXTRA) } + | 'try' &&':' b=block ex[asdl_excepthandler_seq*]=except_star_block+ el=[else_block] f=[finally_block] { + CHECK_VERSION(stmt_ty, 11, "Exception groups are", + _PyAST_TryStar(b, ex, el, f, EXTRA)) } # Except statement diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py index 7275e1559e5b..90ad6af56fdb 100644 --- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -771,6 +771,15 @@ def test_assignment_expression_feature_version(self): with self.assertRaises(SyntaxError): ast.parse('(x := 0)', feature_version=(3, 7)) + def test_exception_groups_feature_version(self): + code = dedent(''' + try: ... + except* Exception: ... + ''') + ast.parse(code) + with self.assertRaises(SyntaxError): + ast.parse(code, feature_version=(3, 10)) + def test_constant_as_name(self): for constant in "True", "False", "None": expr = ast.Expression(ast.Name(constant, ast.Load())) diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-05-19-20-44.gh-issue-96587.bVxhX2.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-05-19-20-44.gh-issue-96587.bVxhX2.rst new file mode 100644 index 000000000000..37e9dcbb11f0 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-09-05-19-20-44.gh-issue-96587.bVxhX2.rst @@ -0,0 +1,2 @@ +Correctly raise ``SyntaxError`` on exception groups (:pep:`654`) on python +versions prior to 3.11 diff --git a/Parser/parser.c b/Parser/parser.c index e13dbe04cf98..3fc12e50833c 100644 --- a/Parser/parser.c +++ b/Parser/parser.c @@ -6970,7 +6970,7 @@ try_stmt_rule(Parser *p) UNUSED(_end_lineno); // Only used by EXTRA macro int _end_col_offset = _token->end_col_offset; UNUSED(_end_col_offset); // Only used by EXTRA macro - _res = _PyAST_TryStar ( b , ex , el , f , EXTRA ); + _res = CHECK_VERSION ( stmt_ty , 11 , "Exception groups are" , _PyAST_TryStar ( b , ex , el , f , EXTRA ) ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; p->level--; From webhook-mailer at python.org Wed Oct 5 18:00:54 2022 From: webhook-mailer at python.org (brettcannon) Date: Wed, 05 Oct 2022 22:00:54 -0000 Subject: [Python-checkins] gh-65961: Raise `DeprecationWarning` when `__package__` differs from `__spec__.parent` (#97879) Message-ID: https://github.com/python/cpython/commit/c206e53bb726fa795d10cfb0e8d1d1a1a5d1aaa7 commit: c206e53bb726fa795d10cfb0e8d1d1a1a5d1aaa7 branch: main author: Brett Cannon committer: brettcannon date: 2022-10-05T15:00:45-07:00 summary: gh-65961: Raise `DeprecationWarning` when `__package__` differs from `__spec__.parent` (#97879) Also remove `importlib.util.set_package()` which was already slated for removal. Co-authored-by: Eric Snow files: A Misc/NEWS.d/next/Core and Builtins/2022-10-05-00-37-27.gh-issue-65961.z0Ys0y.rst M Doc/library/importlib.rst M Doc/reference/import.rst M Doc/whatsnew/3.12.rst M Lib/importlib/_bootstrap.py M Lib/importlib/util.py M Lib/test/test_importlib/import_/test___package__.py M Lib/test/test_importlib/test_util.py M Python/import.c diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst index 0fd765f5985f..a7c067c06e8e 100644 --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -1378,15 +1378,6 @@ an :term:`importer`. .. deprecated:: 3.4 The import machinery takes care of this automatically. -.. decorator:: set_package - - A :term:`decorator` for :meth:`importlib.abc.Loader.load_module` to set the - :attr:`__package__` attribute on the returned module. If :attr:`__package__` - is set and has a value other than ``None`` it will not be changed. - - .. deprecated:: 3.4 - The import machinery takes care of this automatically. - .. function:: spec_from_loader(name, loader, *, origin=None, is_package=None) A factory function for creating a :class:`~importlib.machinery.ModuleSpec` diff --git a/Doc/reference/import.rst b/Doc/reference/import.rst index 507f2b3763ca..58f4ef897bdb 100644 --- a/Doc/reference/import.rst +++ b/Doc/reference/import.rst @@ -358,7 +358,6 @@ of what happens during the loading portion of import:: sys.modules[spec.name] = module elif not hasattr(spec.loader, 'exec_module'): module = spec.loader.load_module(spec.name) - # Set __loader__ and __package__ if missing. else: sys.modules[spec.name] = module try: @@ -539,6 +538,10 @@ The import machinery fills in these attributes on each module object during loading, based on the module's spec, before the loader executes the module. +It is **strongly** recommended that you rely on :attr:`__spec__` and +its attributes instead of any of the other individual attributes +listed below. + .. attribute:: __name__ The ``__name__`` attribute must be set to the fully qualified name of @@ -552,9 +555,12 @@ the module. for introspection, but can be used for additional loader-specific functionality, for example getting data associated with a loader. + It is **strongly** recommended that you rely on :attr:`__spec__` + instead instead of this attribute. + .. attribute:: __package__ - The module's ``__package__`` attribute must be set. Its value must + The module's ``__package__`` attribute may be set. Its value must be a string, but it can be the same value as its ``__name__``. When the module is a package, its ``__package__`` value should be set to its ``__name__``. When the module is not a package, ``__package__`` @@ -562,14 +568,23 @@ the module. submodules, to the parent package's name. See :pep:`366` for further details. - This attribute is used instead of ``__name__`` to calculate explicit - relative imports for main modules, as defined in :pep:`366`. It is - expected to have the same value as ``__spec__.parent``. + It is **strongly** recommended that you rely on :attr:`__spec__` + instead instead of this attribute. .. versionchanged:: 3.6 The value of ``__package__`` is expected to be the same as ``__spec__.parent``. + .. versionchanged:: 3.10 + :exc:`ImportWarning` is raised if import falls back to + ``__package__`` instead of + :attr:`~importlib.machinery.ModuleSpec.parent`. + + .. versionchanged:: 3.12 + Raise :exc:`DeprecationWarning` instead of :exc:`ImportWarning` + when falling back to ``__package__``. + + .. attribute:: __spec__ The ``__spec__`` attribute must be set to the module spec that was @@ -578,7 +593,7 @@ the module. interpreter startup `. The one exception is ``__main__``, where ``__spec__`` is :ref:`set to None in some cases `. - When ``__package__`` is not defined, ``__spec__.parent`` is used as + When ``__spec__.parent`` is not set, ``__package__`` is used as a fallback. .. versionadded:: 3.4 @@ -623,6 +638,9 @@ the module. if a loader can load from a cached module but otherwise does not load from a file, that atypical scenario may be appropriate. + It is **strongly** recommended that you rely on :attr:`__spec__` + instead instead of ``__cached__``. + .. _package-path-rules: module.__path__ diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 2e9515d036e7..507ba3522146 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -215,6 +215,11 @@ Deprecated may be removed in a future version of Python. Use the single-arg versions of these functions instead. (Contributed by Ofey Chan in :gh:`89874`.) +* :exc:`DeprecationWarning` is now raised when ``__package__`` on a + module differs from ``__spec__.parent`` (previously it was + :exc:`ImportWarning`). + (Contributed by Brett Cannon in :gh:`65961`.) + Pending Removal in Python 3.13 ------------------------------ @@ -275,6 +280,9 @@ Pending Removal in Python 3.14 * Creating :c:data:`immutable types ` with mutable bases using the C API. +* ``__package__`` will cease to be set or taken into consideration by + the import system (:gh:`97879`). + Pending Removal in Future Versions ---------------------------------- @@ -432,6 +440,10 @@ Removed * References to, and support for ``module_repr()`` has been eradicated. +* ``importlib.util.set_package`` has been removed. + (Contributed by Brett Cannon in :gh:`65961`.) + + Porting to Python 3.12 ====================== diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py index 5d3c9fe3fbd2..1c132106ce5a 100644 --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -1228,7 +1228,7 @@ def _calc___package__(globals): if spec is not None and package != spec.parent: _warnings.warn("__package__ != __spec__.parent " f"({package!r} != {spec.parent!r})", - ImportWarning, stacklevel=3) + DeprecationWarning, stacklevel=3) return package elif spec is not None: return spec.parent diff --git a/Lib/importlib/util.py b/Lib/importlib/util.py index 8623c89840c6..7f15b029b240 100644 --- a/Lib/importlib/util.py +++ b/Lib/importlib/util.py @@ -141,26 +141,6 @@ def _module_to_load(name): module.__initializing__ = False -def set_package(fxn): - """Set __package__ on the returned module. - - This function is deprecated. - - """ - @functools.wraps(fxn) - def set_package_wrapper(*args, **kwargs): - warnings.warn('The import system now takes care of this automatically; ' - 'this decorator is slated for removal in Python 3.12', - DeprecationWarning, stacklevel=2) - module = fxn(*args, **kwargs) - if getattr(module, '__package__', None) is None: - module.__package__ = module.__name__ - if not hasattr(module, '__path__'): - module.__package__ = module.__package__.rpartition('.')[0] - return module - return set_package_wrapper - - def set_loader(fxn): """Set __loader__ on the returned module. diff --git a/Lib/test/test_importlib/import_/test___package__.py b/Lib/test/test_importlib/import_/test___package__.py index 1ab5018a431d..ab1b35ee3c1a 100644 --- a/Lib/test/test_importlib/import_/test___package__.py +++ b/Lib/test/test_importlib/import_/test___package__.py @@ -74,8 +74,8 @@ def test_spec_fallback(self): self.assertEqual(module.__name__, 'pkg') def test_warn_when_package_and_spec_disagree(self): - # Raise an ImportWarning if __package__ != __spec__.parent. - with self.assertWarns(ImportWarning): + # Raise a DeprecationWarning if __package__ != __spec__.parent. + with self.assertWarns(DeprecationWarning): self.import_module({'__package__': 'pkg.fake', '__spec__': FakeSpec('pkg.fakefake')}) diff --git a/Lib/test/test_importlib/test_util.py b/Lib/test/test_importlib/test_util.py index a62d68fcd8b3..e70971e9d3bc 100644 --- a/Lib/test/test_importlib/test_util.py +++ b/Lib/test/test_importlib/test_util.py @@ -252,69 +252,6 @@ def load_module(self, module): ) = util.test_both(ModuleForLoaderTests, util=importlib_util) -class SetPackageTests: - - """Tests for importlib.util.set_package.""" - - def verify(self, module, expect): - """Verify the module has the expected value for __package__ after - passing through set_package.""" - fxn = lambda: module - wrapped = self.util.set_package(fxn) - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - wrapped() - self.assertTrue(hasattr(module, '__package__')) - self.assertEqual(expect, module.__package__) - - def test_top_level(self): - # __package__ should be set to the empty string if a top-level module. - # Implicitly tests when package is set to None. - module = types.ModuleType('module') - module.__package__ = None - self.verify(module, '') - - def test_package(self): - # Test setting __package__ for a package. - module = types.ModuleType('pkg') - module.__path__ = [''] - module.__package__ = None - self.verify(module, 'pkg') - - def test_submodule(self): - # Test __package__ for a module in a package. - module = types.ModuleType('pkg.mod') - module.__package__ = None - self.verify(module, 'pkg') - - def test_setting_if_missing(self): - # __package__ should be set if it is missing. - module = types.ModuleType('mod') - if hasattr(module, '__package__'): - delattr(module, '__package__') - self.verify(module, '') - - def test_leaving_alone(self): - # If __package__ is set and not None then leave it alone. - for value in (True, False): - module = types.ModuleType('mod') - module.__package__ = value - self.verify(module, value) - - def test_decorator_attrs(self): - def fxn(module): pass - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - wrapped = self.util.set_package(fxn) - self.assertEqual(wrapped.__name__, fxn.__name__) - self.assertEqual(wrapped.__qualname__, fxn.__qualname__) - - -(Frozen_SetPackageTests, - Source_SetPackageTests - ) = util.test_both(SetPackageTests, util=importlib_util) - - class SetLoaderTests: """Tests importlib.util.set_loader().""" diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-05-00-37-27.gh-issue-65961.z0Ys0y.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-05-00-37-27.gh-issue-65961.z0Ys0y.rst new file mode 100644 index 000000000000..0c034263c1a8 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-05-00-37-27.gh-issue-65961.z0Ys0y.rst @@ -0,0 +1,5 @@ +When ``__package__`` is different than ``__spec__.parent``, raise a +``DeprecationWarning`` instead of ``ImportWarning``. + +Also remove ``importlib.util.set_package()`` which was scheduled for +removal. diff --git a/Python/import.c b/Python/import.c index 54c21fa4a56a..698ef37ce0a1 100644 --- a/Python/import.c +++ b/Python/import.c @@ -1573,7 +1573,7 @@ resolve_name(PyThreadState *tstate, PyObject *name, PyObject *globals, int level goto error; } else if (equal == 0) { - if (PyErr_WarnEx(PyExc_ImportWarning, + if (PyErr_WarnEx(PyExc_DeprecationWarning, "__package__ != __spec__.parent", 1) < 0) { goto error; } From webhook-mailer at python.org Wed Oct 5 18:02:12 2022 From: webhook-mailer at python.org (ambv) Date: Wed, 05 Oct 2022 22:02:12 -0000 Subject: [Python-checkins] [3.11] gh-95987: Fix `repr` of `Any` type subclasses (GH-96412) (#96451) Message-ID: https://github.com/python/cpython/commit/c9eacc8d02a949b7539a24ce744786940864e270 commit: c9eacc8d02a949b7539a24ce744786940864e270 branch: 3.11 author: Shantanu <12621235+hauntsaninja at users.noreply.github.com> committer: ambv date: 2022-10-05T15:02:06-07:00 summary: [3.11] gh-95987: Fix `repr` of `Any` type subclasses (GH-96412) (#96451) (cherry picked from commit 4217393) Co-authored-by: Nikita Sobolev files: A Misc/NEWS.d/next/Library/2022-08-30-11-46-36.gh-issue-95987.CV7_u4.rst M Lib/test/test_typing.py M Lib/typing.py diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 1bcadf8753f9..71590449dc56 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -109,6 +109,12 @@ def test_any_instance_type_error(self): def test_repr(self): self.assertEqual(repr(Any), 'typing.Any') + class Sub(Any): pass + self.assertEqual( + repr(Sub), + ".Sub'>", + ) + def test_errors(self): with self.assertRaises(TypeError): issubclass(42, Any) diff --git a/Lib/typing.py b/Lib/typing.py index 354976caaaa0..1e335bb7204d 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -493,7 +493,9 @@ def __instancecheck__(self, obj): return super().__instancecheck__(obj) def __repr__(self): - return "typing.Any" + if self is Any: + return "typing.Any" + return super().__repr__() # respect to subclasses class Any(metaclass=_AnyMeta): diff --git a/Misc/NEWS.d/next/Library/2022-08-30-11-46-36.gh-issue-95987.CV7_u4.rst b/Misc/NEWS.d/next/Library/2022-08-30-11-46-36.gh-issue-95987.CV7_u4.rst new file mode 100644 index 000000000000..232bba1b9244 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-08-30-11-46-36.gh-issue-95987.CV7_u4.rst @@ -0,0 +1 @@ +Fix ``repr`` of ``Any`` subclasses. From webhook-mailer at python.org Wed Oct 5 18:03:24 2022 From: webhook-mailer at python.org (ambv) Date: Wed, 05 Oct 2022 22:03:24 -0000 Subject: [Python-checkins] [3.11] gh-96197: Fix expression when :func:`sys.breakpointhook is missing (gh-96293) (#96294) Message-ID: https://github.com/python/cpython/commit/19ec4d40a231f96870f728b4e2339410b86134ea commit: 19ec4d40a231f96870f728b4e2339410b86134ea branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-05T15:03:18-07:00 summary: [3.11] gh-96197: Fix expression when :func:`sys.breakpointhook is missing (gh-96293) (#96294) (cherry picked from commit 47d406ffc4946b023e38322c5235bec25f068481) Co-authored-by: Dong-hee Na files: M Doc/library/functions.rst diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 41fda9d85597..26ee302d2eab 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -164,7 +164,7 @@ are always available. They are listed here in alphabetical order. :func:`sys.breakpointhook` can be set to some other function and :func:`breakpoint` will automatically call that, allowing you to drop into the debugger of choice. - If :func:`sys.breakpointhook` is not available to be called, this function will + If :func:`sys.breakpointhook` is not accessible, this function will raise :exc:`RuntimeError`. .. audit-event:: builtins.breakpoint breakpointhook breakpoint From webhook-mailer at python.org Wed Oct 5 18:05:32 2022 From: webhook-mailer at python.org (ambv) Date: Wed, 05 Oct 2022 22:05:32 -0000 Subject: [Python-checkins] [3.11] gh-96017: Fix some compiler warnings (GH-96018) (#96106) Message-ID: https://github.com/python/cpython/commit/eecbeec083ca55ea22e544edba431c9b9023f692 commit: eecbeec083ca55ea22e544edba431c9b9023f692 branch: 3.11 author: Christian Heimes committer: ambv date: 2022-10-05T15:05:27-07:00 summary: [3.11] gh-96017: Fix some compiler warnings (GH-96018) (#96106) - only define recreate_gil with ifdef HAVE_FORK. (cherry picked from commit d9c1b746b5013f81d1724757bb3c6a1c87c4a8dc) Co-authored-by: Christian Heimes files: M Python/ceval_gil.h diff --git a/Python/ceval_gil.h b/Python/ceval_gil.h index 23f6fb26580e..476ed7f1a2dd 100644 --- a/Python/ceval_gil.h +++ b/Python/ceval_gil.h @@ -133,12 +133,14 @@ static void destroy_gil(struct _gil_runtime_state *gil) _Py_ANNOTATE_RWLOCK_DESTROY(&gil->locked); } +#ifdef HAVE_FORK static void recreate_gil(struct _gil_runtime_state *gil) { _Py_ANNOTATE_RWLOCK_DESTROY(&gil->locked); /* XXX should we destroy the old OS resources here? */ create_gil(gil); } +#endif static void drop_gil(struct _ceval_runtime_state *ceval, struct _ceval_state *ceval2, From webhook-mailer at python.org Wed Oct 5 18:26:03 2022 From: webhook-mailer at python.org (ethanfurman) Date: Wed, 05 Oct 2022 22:26:03 -0000 Subject: [Python-checkins] gh-96865: [Enum] fix Flag to use CONFORM boundary (GH-97528) Message-ID: https://github.com/python/cpython/commit/b44372e03c5461b6ad3d89763a9eb6cb82df07a4 commit: b44372e03c5461b6ad3d89763a9eb6cb82df07a4 branch: main author: Ethan Furman committer: ethanfurman date: 2022-10-05T15:25:55-07:00 summary: gh-96865: [Enum] fix Flag to use CONFORM boundary (GH-97528) files: A Misc/NEWS.d/next/Library/2022-09-24-18-56-23.gh-issue-96865.o9WUkW.rst M Lib/enum.py M Lib/test/test_enum.py diff --git a/Lib/enum.py b/Lib/enum.py index c3aafc283719..a66c344dbc3d 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -1269,7 +1269,7 @@ class FlagBoundary(StrEnum): STRICT, CONFORM, EJECT, KEEP = FlagBoundary -class Flag(Enum, boundary=STRICT): +class Flag(Enum, boundary=CONFORM): """ Support for flags """ diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index ad421f87d6d0..f50017d916f5 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -2927,7 +2927,7 @@ def test_bool(self): self.assertEqual(bool(f.value), bool(f)) def test_boundary(self): - self.assertIs(enum.Flag._boundary_, STRICT) + self.assertIs(enum.Flag._boundary_, CONFORM) class Iron(Flag, boundary=STRICT): ONE = 1 TWO = 2 diff --git a/Misc/NEWS.d/next/Library/2022-09-24-18-56-23.gh-issue-96865.o9WUkW.rst b/Misc/NEWS.d/next/Library/2022-09-24-18-56-23.gh-issue-96865.o9WUkW.rst new file mode 100644 index 000000000000..b054fdeee078 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-09-24-18-56-23.gh-issue-96865.o9WUkW.rst @@ -0,0 +1,9 @@ +fix Flag to use boundary CONFORM + +This restores previous Flag behavior of allowing flags with non-sequential values to be combined; e.g. + + class Skip(Flag): + TWO = 2 + EIGHT = 8 + + Skip.TWO | Skip.EIGHT -> From webhook-mailer at python.org Wed Oct 5 19:32:22 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 05 Oct 2022 23:32:22 -0000 Subject: [Python-checkins] gh-96865: [Enum] fix Flag to use CONFORM boundary (GH-97528) Message-ID: https://github.com/python/cpython/commit/c9480d5ad59b052ad3d3422fcf0ac8dd5fed7f6d commit: c9480d5ad59b052ad3d3422fcf0ac8dd5fed7f6d branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-05T16:32:16-07:00 summary: gh-96865: [Enum] fix Flag to use CONFORM boundary (GH-97528) (cherry picked from commit b44372e03c5461b6ad3d89763a9eb6cb82df07a4) Co-authored-by: Ethan Furman files: A Misc/NEWS.d/next/Library/2022-09-24-18-56-23.gh-issue-96865.o9WUkW.rst M Lib/enum.py M Lib/test/test_enum.py diff --git a/Lib/enum.py b/Lib/enum.py index dffb673f44f9..ae97334e220b 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -1292,7 +1292,7 @@ class FlagBoundary(StrEnum): STRICT, CONFORM, EJECT, KEEP = FlagBoundary -class Flag(Enum, boundary=STRICT): +class Flag(Enum, boundary=CONFORM): """ Support for flags """ diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index 3b1c77d688ec..d2cfc7f7cd4b 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -2878,7 +2878,7 @@ def test_bool(self): self.assertEqual(bool(f.value), bool(f)) def test_boundary(self): - self.assertIs(enum.Flag._boundary_, STRICT) + self.assertIs(enum.Flag._boundary_, CONFORM) class Iron(Flag, boundary=STRICT): ONE = 1 TWO = 2 diff --git a/Misc/NEWS.d/next/Library/2022-09-24-18-56-23.gh-issue-96865.o9WUkW.rst b/Misc/NEWS.d/next/Library/2022-09-24-18-56-23.gh-issue-96865.o9WUkW.rst new file mode 100644 index 000000000000..b054fdeee078 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-09-24-18-56-23.gh-issue-96865.o9WUkW.rst @@ -0,0 +1,9 @@ +fix Flag to use boundary CONFORM + +This restores previous Flag behavior of allowing flags with non-sequential values to be combined; e.g. + + class Skip(Flag): + TWO = 2 + EIGHT = 8 + + Skip.TWO | Skip.EIGHT -> From webhook-mailer at python.org Wed Oct 5 19:42:10 2022 From: webhook-mailer at python.org (gvanrossum) Date: Wed, 05 Oct 2022 23:42:10 -0000 Subject: [Python-checkins] GH-88968: Add notes about socket ownership transfers (#97936) Message-ID: https://github.com/python/cpython/commit/74ea204634f8eb4745afd5cb75c3fe7749cf38b5 commit: 74ea204634f8eb4745afd5cb75c3fe7749cf38b5 branch: main author: Guido van Rossum committer: gvanrossum date: 2022-10-05T16:42:01-07:00 summary: GH-88968: Add notes about socket ownership transfers (#97936) files: M Doc/library/asyncio-eventloop.rst M Doc/library/asyncio-stream.rst diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index 6fe95687c151..2f306b7edb8f 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -468,6 +468,12 @@ Opening network connections *happy_eyeballs_delay*, *interleave* and *local_addr* should be specified. + .. note:: + + The *sock* argument transfers ownership of the socket to the + transport created. To close the socket, call the transport's + :meth:`~asyncio.BaseTransport.close` method. + * *local_addr*, if given, is a ``(local_host, local_port)`` tuple used to bind the socket locally. The *local_host* and *local_port* are looked up using ``getaddrinfo()``, similarly to *host* and *port*. @@ -577,6 +583,12 @@ Opening network connections transport. If specified, *local_addr* and *remote_addr* should be omitted (must be :const:`None`). + .. note:: + + The *sock* argument transfers ownership of the socket to the + transport created. To close the socket, call the transport's + :meth:`~asyncio.BaseTransport.close` method. + See :ref:`UDP echo client protocol ` and :ref:`UDP echo server protocol ` examples. @@ -688,6 +700,12 @@ Creating network servers * *sock* can optionally be specified in order to use a preexisting socket object. If specified, *host* and *port* must not be specified. + .. note:: + + The *sock* argument transfers ownership of the socket to the + server created. To close the socket, call the server's + :meth:`~asyncio.Server.close` method. + * *backlog* is the maximum number of queued connections passed to :meth:`~socket.socket.listen` (defaults to 100). @@ -789,6 +807,12 @@ Creating network servers * *sock* is a preexisting socket object returned from :meth:`socket.accept `. + .. note:: + + The *sock* argument transfers ownership of the socket to the + transport created. To close the socket, call the transport's + :meth:`~asyncio.BaseTransport.close` method. + * *ssl* can be set to an :class:`~ssl.SSLContext` to enable SSL over the accepted connections. diff --git a/Doc/library/asyncio-stream.rst b/Doc/library/asyncio-stream.rst index 9b468670a252..ce88d70d6607 100644 --- a/Doc/library/asyncio-stream.rst +++ b/Doc/library/asyncio-stream.rst @@ -67,6 +67,12 @@ and work with streams: The rest of the arguments are passed directly to :meth:`loop.create_connection`. + .. note:: + + The *sock* argument transfers ownership of the socket to the + :class:`StreamWriter` created. To close the socket, call its + :meth:`~asyncio.StreamWriter.close` method. + .. versionchanged:: 3.7 Added the *ssl_handshake_timeout* parameter. @@ -103,6 +109,12 @@ and work with streams: The rest of the arguments are passed directly to :meth:`loop.create_server`. + .. note:: + + The *sock* argument transfers ownership of the socket to the + server created. To close the socket, call the server's + :meth:`~asyncio.Server.close` method. + .. versionchanged:: 3.7 Added the *ssl_handshake_timeout* and *start_serving* parameters. @@ -123,6 +135,12 @@ and work with streams: See also the documentation of :meth:`loop.create_unix_connection`. + .. note:: + + The *sock* argument transfers ownership of the socket to the + :class:`StreamWriter` created. To close the socket, call its + :meth:`~asyncio.StreamWriter.close` method. + .. availability:: Unix. .. versionchanged:: 3.7 @@ -143,6 +161,12 @@ and work with streams: See also the documentation of :meth:`loop.create_unix_server`. + .. note:: + + The *sock* argument transfers ownership of the socket to the + server created. To close the socket, call the server's + :meth:`~asyncio.Server.close` method. + .. availability:: Unix. .. versionchanged:: 3.7 From webhook-mailer at python.org Wed Oct 5 19:54:27 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 05 Oct 2022 23:54:27 -0000 Subject: [Python-checkins] GH-88968: Add notes about socket ownership transfers (GH-97936) Message-ID: https://github.com/python/cpython/commit/0c387bf978167ec8b90e6fe068803bb6165becf3 commit: 0c387bf978167ec8b90e6fe068803bb6165becf3 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-05T16:54:21-07:00 summary: GH-88968: Add notes about socket ownership transfers (GH-97936) (cherry picked from commit 74ea204634f8eb4745afd5cb75c3fe7749cf38b5) Co-authored-by: Guido van Rossum files: M Doc/library/asyncio-eventloop.rst M Doc/library/asyncio-stream.rst diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index b83e6ace5589..8125612de58a 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -458,6 +458,12 @@ Opening network connections *happy_eyeballs_delay*, *interleave* and *local_addr* should be specified. + .. note:: + + The *sock* argument transfers ownership of the socket to the + transport created. To close the socket, call the transport's + :meth:`~asyncio.BaseTransport.close` method. + * *local_addr*, if given, is a ``(local_host, local_port)`` tuple used to bind the socket locally. The *local_host* and *local_port* are looked up using ``getaddrinfo()``, similarly to *host* and *port*. @@ -556,6 +562,12 @@ Opening network connections transport. If specified, *local_addr* and *remote_addr* should be omitted (must be :const:`None`). + .. note:: + + The *sock* argument transfers ownership of the socket to the + transport created. To close the socket, call the transport's + :meth:`~asyncio.BaseTransport.close` method. + See :ref:`UDP echo client protocol ` and :ref:`UDP echo server protocol ` examples. @@ -667,6 +679,12 @@ Creating network servers * *sock* can optionally be specified in order to use a preexisting socket object. If specified, *host* and *port* must not be specified. + .. note:: + + The *sock* argument transfers ownership of the socket to the + server created. To close the socket, call the server's + :meth:`~asyncio.Server.close` method. + * *backlog* is the maximum number of queued connections passed to :meth:`~socket.socket.listen` (defaults to 100). @@ -768,6 +786,12 @@ Creating network servers * *sock* is a preexisting socket object returned from :meth:`socket.accept `. + .. note:: + + The *sock* argument transfers ownership of the socket to the + transport created. To close the socket, call the transport's + :meth:`~asyncio.BaseTransport.close` method. + * *ssl* can be set to an :class:`~ssl.SSLContext` to enable SSL over the accepted connections. diff --git a/Doc/library/asyncio-stream.rst b/Doc/library/asyncio-stream.rst index 9b468670a252..ce88d70d6607 100644 --- a/Doc/library/asyncio-stream.rst +++ b/Doc/library/asyncio-stream.rst @@ -67,6 +67,12 @@ and work with streams: The rest of the arguments are passed directly to :meth:`loop.create_connection`. + .. note:: + + The *sock* argument transfers ownership of the socket to the + :class:`StreamWriter` created. To close the socket, call its + :meth:`~asyncio.StreamWriter.close` method. + .. versionchanged:: 3.7 Added the *ssl_handshake_timeout* parameter. @@ -103,6 +109,12 @@ and work with streams: The rest of the arguments are passed directly to :meth:`loop.create_server`. + .. note:: + + The *sock* argument transfers ownership of the socket to the + server created. To close the socket, call the server's + :meth:`~asyncio.Server.close` method. + .. versionchanged:: 3.7 Added the *ssl_handshake_timeout* and *start_serving* parameters. @@ -123,6 +135,12 @@ and work with streams: See also the documentation of :meth:`loop.create_unix_connection`. + .. note:: + + The *sock* argument transfers ownership of the socket to the + :class:`StreamWriter` created. To close the socket, call its + :meth:`~asyncio.StreamWriter.close` method. + .. availability:: Unix. .. versionchanged:: 3.7 @@ -143,6 +161,12 @@ and work with streams: See also the documentation of :meth:`loop.create_unix_server`. + .. note:: + + The *sock* argument transfers ownership of the socket to the + server created. To close the socket, call the server's + :meth:`~asyncio.Server.close` method. + .. availability:: Unix. .. versionchanged:: 3.7 From webhook-mailer at python.org Wed Oct 5 19:54:51 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 05 Oct 2022 23:54:51 -0000 Subject: [Python-checkins] GH-88968: Add notes about socket ownership transfers (GH-97936) Message-ID: https://github.com/python/cpython/commit/c80c282d112b9771fc9ac652095c76cfdad9ace3 commit: c80c282d112b9771fc9ac652095c76cfdad9ace3 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-05T16:54:46-07:00 summary: GH-88968: Add notes about socket ownership transfers (GH-97936) (cherry picked from commit 74ea204634f8eb4745afd5cb75c3fe7749cf38b5) Co-authored-by: Guido van Rossum files: M Doc/library/asyncio-eventloop.rst M Doc/library/asyncio-stream.rst diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index d2f786990802..343672d350ab 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -450,6 +450,12 @@ Opening network connections *happy_eyeballs_delay*, *interleave* and *local_addr* should be specified. + .. note:: + + The *sock* argument transfers ownership of the socket to the + transport created. To close the socket, call the transport's + :meth:`~asyncio.BaseTransport.close` method. + * *local_addr*, if given, is a ``(local_host, local_port)`` tuple used to bind the socket locally. The *local_host* and *local_port* are looked up using ``getaddrinfo()``, similarly to *host* and *port*. @@ -555,6 +561,12 @@ Opening network connections transport. If specified, *local_addr* and *remote_addr* should be omitted (must be :const:`None`). + .. note:: + + The *sock* argument transfers ownership of the socket to the + transport created. To close the socket, call the transport's + :meth:`~asyncio.BaseTransport.close` method. + See :ref:`UDP echo client protocol ` and :ref:`UDP echo server protocol ` examples. @@ -644,6 +656,12 @@ Creating network servers * *sock* can optionally be specified in order to use a preexisting socket object. If specified, *host* and *port* must not be specified. + .. note:: + + The *sock* argument transfers ownership of the socket to the + server created. To close the socket, call the server's + :meth:`~asyncio.Server.close` method. + * *backlog* is the maximum number of queued connections passed to :meth:`~socket.socket.listen` (defaults to 100). @@ -729,6 +747,12 @@ Creating network servers * *sock* is a preexisting socket object returned from :meth:`socket.accept `. + .. note:: + + The *sock* argument transfers ownership of the socket to the + transport created. To close the socket, call the transport's + :meth:`~asyncio.BaseTransport.close` method. + * *ssl* can be set to an :class:`~ssl.SSLContext` to enable SSL over the accepted connections. diff --git a/Doc/library/asyncio-stream.rst b/Doc/library/asyncio-stream.rst index 65f3d5322db2..19210a556057 100644 --- a/Doc/library/asyncio-stream.rst +++ b/Doc/library/asyncio-stream.rst @@ -67,6 +67,12 @@ and work with streams: The rest of the arguments are passed directly to :meth:`loop.create_connection`. + .. note:: + + The *sock* argument transfers ownership of the socket to the + :class:`StreamWriter` created. To close the socket, call its + :meth:`~asyncio.StreamWriter.close` method. + .. versionchanged:: 3.7 Added the *ssl_handshake_timeout* parameter. @@ -103,6 +109,12 @@ and work with streams: The rest of the arguments are passed directly to :meth:`loop.create_server`. + .. note:: + + The *sock* argument transfers ownership of the socket to the + server created. To close the socket, call the server's + :meth:`~asyncio.Server.close` method. + .. versionchanged:: 3.7 Added the *ssl_handshake_timeout* and *start_serving* parameters. @@ -123,6 +135,12 @@ and work with streams: See also the documentation of :meth:`loop.create_unix_connection`. + .. note:: + + The *sock* argument transfers ownership of the socket to the + :class:`StreamWriter` created. To close the socket, call its + :meth:`~asyncio.StreamWriter.close` method. + .. availability:: Unix. .. versionchanged:: 3.7 @@ -143,6 +161,12 @@ and work with streams: See also the documentation of :meth:`loop.create_unix_server`. + .. note:: + + The *sock* argument transfers ownership of the socket to the + server created. To close the socket, call the server's + :meth:`~asyncio.Server.close` method. + .. availability:: Unix. .. versionchanged:: 3.7 From webhook-mailer at python.org Wed Oct 5 19:57:50 2022 From: webhook-mailer at python.org (nanjekyejoannah) Date: Wed, 05 Oct 2022 23:57:50 -0000 Subject: [Python-checkins] gh-95691: Doc BufferedWriter and BufferedReader (#95703) Message-ID: https://github.com/python/cpython/commit/0d68879104dfb392d31e52e25dcb0661801a0249 commit: 0d68879104dfb392d31e52e25dcb0661801a0249 branch: main author: 180909 <734461790 at qq.com> committer: nanjekyejoannah <33177550+nanjekyejoannah at users.noreply.github.com> date: 2022-10-05T16:57:42-07:00 summary: gh-95691: Doc BufferedWriter and BufferedReader (#95703) files: M Doc/library/io.rst diff --git a/Doc/library/io.rst b/Doc/library/io.rst index 7ec990c3212a..8fd6b3537019 100644 --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -272,7 +272,7 @@ to provide an interface to files in the machine's file system. The :class:`BufferedIOBase` ABC extends :class:`IOBase`. It deals with buffering on a raw binary stream (:class:`RawIOBase`). Its subclasses, :class:`BufferedWriter`, :class:`BufferedReader`, and :class:`BufferedRWPair` -buffer raw binary streams that are readable, writable, and both readable and writable, +buffer raw binary streams that are writable, readable, and both readable and writable, respectively. :class:`BufferedRandom` provides a buffered interface to seekable streams. Another :class:`BufferedIOBase` subclass, :class:`BytesIO`, is a stream of in-memory bytes. From webhook-mailer at python.org Wed Oct 5 20:22:01 2022 From: webhook-mailer at python.org (nanjekyejoannah) Date: Thu, 06 Oct 2022 00:22:01 -0000 Subject: [Python-checkins] [3.11] gh-95691: Doc BufferedWriter and BufferedReader (GH-95703) (#97947) Message-ID: https://github.com/python/cpython/commit/1144cf64d8d668bd6a6a8eebe5790eb47f654ec5 commit: 1144cf64d8d668bd6a6a8eebe5790eb47f654ec5 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: nanjekyejoannah <33177550+nanjekyejoannah at users.noreply.github.com> date: 2022-10-05T17:21:55-07:00 summary: [3.11] gh-95691: Doc BufferedWriter and BufferedReader (GH-95703) (#97947) gh-95691: Doc BufferedWriter and BufferedReader (GH-95703) (cherry picked from commit 0d68879104dfb392d31e52e25dcb0661801a0249) Co-authored-by: 180909 <734461790 at qq.com> Co-authored-by: 180909 <734461790 at qq.com> files: M Doc/library/io.rst diff --git a/Doc/library/io.rst b/Doc/library/io.rst index 7ec990c3212a..8fd6b3537019 100644 --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -272,7 +272,7 @@ to provide an interface to files in the machine's file system. The :class:`BufferedIOBase` ABC extends :class:`IOBase`. It deals with buffering on a raw binary stream (:class:`RawIOBase`). Its subclasses, :class:`BufferedWriter`, :class:`BufferedReader`, and :class:`BufferedRWPair` -buffer raw binary streams that are readable, writable, and both readable and writable, +buffer raw binary streams that are writable, readable, and both readable and writable, respectively. :class:`BufferedRandom` provides a buffered interface to seekable streams. Another :class:`BufferedIOBase` subclass, :class:`BytesIO`, is a stream of in-memory bytes. From webhook-mailer at python.org Wed Oct 5 20:22:47 2022 From: webhook-mailer at python.org (nanjekyejoannah) Date: Thu, 06 Oct 2022 00:22:47 -0000 Subject: [Python-checkins] [3.10] gh-95691: Doc BufferedWriter and BufferedReader (GH-95703) (#97948) Message-ID: https://github.com/python/cpython/commit/e2591e4f5eb717922b2b33e201daefe4f99463dc commit: e2591e4f5eb717922b2b33e201daefe4f99463dc branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: nanjekyejoannah <33177550+nanjekyejoannah at users.noreply.github.com> date: 2022-10-05T17:22:42-07:00 summary: [3.10] gh-95691: Doc BufferedWriter and BufferedReader (GH-95703) (#97948) gh-95691: Doc BufferedWriter and BufferedReader (GH-95703) (cherry picked from commit 0d68879104dfb392d31e52e25dcb0661801a0249) Co-authored-by: 180909 <734461790 at qq.com> Co-authored-by: 180909 <734461790 at qq.com> files: M Doc/library/io.rst diff --git a/Doc/library/io.rst b/Doc/library/io.rst index df812d63666c..5cf692e060cd 100644 --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -265,7 +265,7 @@ to provide an interface to files in the machine's file system. The :class:`BufferedIOBase` ABC extends :class:`IOBase`. It deals with buffering on a raw binary stream (:class:`RawIOBase`). Its subclasses, :class:`BufferedWriter`, :class:`BufferedReader`, and :class:`BufferedRWPair` -buffer raw binary streams that are readable, writable, and both readable and writable, +buffer raw binary streams that are writable, readable, and both readable and writable, respectively. :class:`BufferedRandom` provides a buffered interface to seekable streams. Another :class:`BufferedIOBase` subclass, :class:`BytesIO`, is a stream of in-memory bytes. From webhook-mailer at python.org Thu Oct 6 08:16:37 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Thu, 06 Oct 2022 12:16:37 -0000 Subject: [Python-checkins] gh-94808: Cover `PyObject_PyBytes` case with custom `__bytes__` method (#96610) Message-ID: https://github.com/python/cpython/commit/e39ae6bef2c357a88e232dcab2e4b4c0f367544b commit: e39ae6bef2c357a88e232dcab2e4b4c0f367544b branch: main author: Nikita Sobolev committer: JelleZijlstra date: 2022-10-06T05:16:16-07:00 summary: gh-94808: Cover `PyObject_PyBytes` case with custom `__bytes__` method (#96610) Co-authored-by: Jelle Zijlstra files: M Lib/test/test_long.py diff --git a/Lib/test/test_long.py b/Lib/test/test_long.py index d092e0176c26..b6407b5a7c88 100644 --- a/Lib/test/test_long.py +++ b/Lib/test/test_long.py @@ -1518,6 +1518,22 @@ def __init__(self, value): self.assertEqual(i, 1) self.assertEqual(getattr(i, 'foo', 'none'), 'bar') + class ValidBytes: + def __bytes__(self): + return b'\x01' + class InvalidBytes: + def __bytes__(self): + return 'abc' + class MissingBytes: ... + class RaisingBytes: + def __bytes__(self): + 1 / 0 + + self.assertEqual(int.from_bytes(ValidBytes()), 1) + self.assertRaises(TypeError, int.from_bytes, InvalidBytes()) + self.assertRaises(TypeError, int.from_bytes, MissingBytes()) + self.assertRaises(ZeroDivisionError, int.from_bytes, RaisingBytes()) + @support.cpython_only def test_from_bytes_small(self): # bpo-46361 From webhook-mailer at python.org Thu Oct 6 08:44:11 2022 From: webhook-mailer at python.org (miss-islington) Date: Thu, 06 Oct 2022 12:44:11 -0000 Subject: [Python-checkins] gh-94808: Cover `PyObject_PyBytes` case with custom `__bytes__` method (GH-96610) Message-ID: https://github.com/python/cpython/commit/4aa93afd6ef377c22cf9a8505a392f071ea4bc0e commit: 4aa93afd6ef377c22cf9a8505a392f071ea4bc0e branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-06T05:44:05-07:00 summary: gh-94808: Cover `PyObject_PyBytes` case with custom `__bytes__` method (GH-96610) Co-authored-by: Jelle Zijlstra (cherry picked from commit e39ae6bef2c357a88e232dcab2e4b4c0f367544b) Co-authored-by: Nikita Sobolev files: M Lib/test/test_long.py diff --git a/Lib/test/test_long.py b/Lib/test/test_long.py index d092e0176c26..b6407b5a7c88 100644 --- a/Lib/test/test_long.py +++ b/Lib/test/test_long.py @@ -1518,6 +1518,22 @@ def __init__(self, value): self.assertEqual(i, 1) self.assertEqual(getattr(i, 'foo', 'none'), 'bar') + class ValidBytes: + def __bytes__(self): + return b'\x01' + class InvalidBytes: + def __bytes__(self): + return 'abc' + class MissingBytes: ... + class RaisingBytes: + def __bytes__(self): + 1 / 0 + + self.assertEqual(int.from_bytes(ValidBytes()), 1) + self.assertRaises(TypeError, int.from_bytes, InvalidBytes()) + self.assertRaises(TypeError, int.from_bytes, MissingBytes()) + self.assertRaises(ZeroDivisionError, int.from_bytes, RaisingBytes()) + @support.cpython_only def test_from_bytes_small(self): # bpo-46361 From webhook-mailer at python.org Thu Oct 6 11:20:33 2022 From: webhook-mailer at python.org (encukou) Date: Thu, 06 Oct 2022 15:20:33 -0000 Subject: [Python-checkins] gh-94808: Cover `PyUnicode_Count` in CAPI (#96929) Message-ID: https://github.com/python/cpython/commit/e63d7dae90d15957303688285daeebc2e931e04b commit: e63d7dae90d15957303688285daeebc2e931e04b branch: main author: Nikita Sobolev committer: encukou date: 2022-10-06T17:20:22+02:00 summary: gh-94808: Cover `PyUnicode_Count` in CAPI (#96929) files: M Lib/test/test_unicode.py M Modules/_testcapi/unicode.c diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py index 63bccb72e046..30faaaf83bec 100644 --- a/Lib/test/test_unicode.py +++ b/Lib/test/test_unicode.py @@ -2945,6 +2945,44 @@ def test_asutf8andsize(self): self.assertEqual(unicode_asutf8andsize(nonbmp), (b'\xf4\x8f\xbf\xbf', 4)) self.assertRaises(UnicodeEncodeError, unicode_asutf8andsize, 'a\ud800b\udfffc') + # Test PyUnicode_Count() + @support.cpython_only + @unittest.skipIf(_testcapi is None, 'need _testcapi module') + def test_count(self): + from _testcapi import unicode_count + + st = 'abcabd' + self.assertEqual(unicode_count(st, 'a', 0, len(st)), 2) + self.assertEqual(unicode_count(st, 'ab', 0, len(st)), 2) + self.assertEqual(unicode_count(st, 'abc', 0, len(st)), 1) + self.assertEqual(unicode_count(st, '?', 0, len(st)), 0) # cyrillic "a" + # start < end + self.assertEqual(unicode_count(st, 'a', 3, len(st)), 1) + self.assertEqual(unicode_count(st, 'a', 4, len(st)), 0) + self.assertEqual(unicode_count(st, 'a', 0, sys.maxsize), 2) + # start >= end + self.assertEqual(unicode_count(st, 'abc', 0, 0), 0) + self.assertEqual(unicode_count(st, 'a', 3, 2), 0) + self.assertEqual(unicode_count(st, 'a', sys.maxsize, 5), 0) + # negative + self.assertEqual(unicode_count(st, 'ab', -len(st), -1), 2) + self.assertEqual(unicode_count(st, 'a', -len(st), -3), 1) + # wrong args + self.assertRaises(TypeError, unicode_count, 'a', 'a') + self.assertRaises(TypeError, unicode_count, 'a', 'a', 1) + self.assertRaises(TypeError, unicode_count, 1, 'a', 0, 1) + self.assertRaises(TypeError, unicode_count, 'a', 1, 0, 1) + # empty string + self.assertEqual(unicode_count('abc', '', 0, 3), 4) + self.assertEqual(unicode_count('abc', '', 1, 3), 3) + self.assertEqual(unicode_count('', '', 0, 1), 1) + self.assertEqual(unicode_count('', 'a', 0, 1), 0) + # different unicode kinds + for uni in "\xa1", "\u8000\u8080", "\ud800\udc02", "\U0001f100\U0001f1f1": + for ch in uni: + self.assertEqual(unicode_count(uni, ch, 0, len(uni)), 1) + self.assertEqual(unicode_count(st, ch, 0, len(st)), 0) + # Test PyUnicode_FindChar() @support.cpython_only @unittest.skipIf(_testcapi is None, 'need _testcapi module') diff --git a/Modules/_testcapi/unicode.c b/Modules/_testcapi/unicode.c index d0f1e2abdc82..d5c4a9e5b95e 100644 --- a/Modules/_testcapi/unicode.c +++ b/Modules/_testcapi/unicode.c @@ -223,6 +223,26 @@ unicode_asutf8andsize(PyObject *self, PyObject *args) return Py_BuildValue("(Nn)", result, utf8_len); } +static PyObject * +unicode_count(PyObject *self, PyObject *args) +{ + PyObject *str; + PyObject *substr; + Py_ssize_t result; + Py_ssize_t start, end; + + if (!PyArg_ParseTuple(args, "UUnn:unicode_count", &str, &substr, + &start, &end)) { + return NULL; + } + + result = PyUnicode_Count(str, substr, start, end); + if (result == -1) + return NULL; + else + return PyLong_FromSsize_t(result); +} + static PyObject * unicode_findchar(PyObject *self, PyObject *args) { @@ -696,6 +716,7 @@ static PyMethodDef TestMethods[] = { {"unicode_asucs4", unicode_asucs4, METH_VARARGS}, {"unicode_asutf8", unicode_asutf8, METH_VARARGS}, {"unicode_asutf8andsize", unicode_asutf8andsize, METH_VARARGS}, + {"unicode_count", unicode_count, METH_VARARGS}, {"unicode_findchar", unicode_findchar, METH_VARARGS}, {"unicode_copycharacters", unicode_copycharacters, METH_VARARGS}, {NULL}, From webhook-mailer at python.org Thu Oct 6 12:12:19 2022 From: webhook-mailer at python.org (ned-deily) Date: Thu, 06 Oct 2022 16:12:19 -0000 Subject: [Python-checkins] gh-97897: Prevent os.mkfifo and os.mknod segfaults with macOS 13 SDK (GH-97944) Message-ID: https://github.com/python/cpython/commit/6d0a0191a4e5477bd843e62c24d7f3bcad4fd5fc commit: 6d0a0191a4e5477bd843e62c24d7f3bcad4fd5fc branch: main author: Ned Deily committer: ned-deily date: 2022-10-06T09:11:47-07:00 summary: gh-97897: Prevent os.mkfifo and os.mknod segfaults with macOS 13 SDK (GH-97944) The macOS 13 SDK includes support for the `mkfifoat` and `mknodat` system calls. Using the `dir_fd` option with either `os.mkfifo` or `os.mknod` could result in a segfault if cpython is built with the macOS 13 SDK but run on an earlier version of macOS. Prevent this by adding runtime support for detection of these system calls ("weaklinking") as is done for other newer syscalls on macOS. files: A Misc/NEWS.d/next/macOS/2022-10-05-15-26-58.gh-issue-97897.Rf-C6u.rst M Lib/test/test_posix.py M Modules/posixmodule.c diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py index ae25ef55885d..e643d8e5a4ce 100644 --- a/Lib/test/test_posix.py +++ b/Lib/test/test_posix.py @@ -2090,6 +2090,28 @@ def test_mkdir(self): with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"): os.mkdir("dir", dir_fd=0) + def test_mkfifo(self): + self._verify_available("HAVE_MKFIFOAT") + if self.mac_ver >= (13, 0): + self.assertIn("HAVE_MKFIFOAT", posix._have_functions) + + else: + self.assertNotIn("HAVE_MKFIFOAT", posix._have_functions) + + with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"): + os.mkfifo("path", dir_fd=0) + + def test_mknod(self): + self._verify_available("HAVE_MKNODAT") + if self.mac_ver >= (13, 0): + self.assertIn("HAVE_MKNODAT", posix._have_functions) + + else: + self.assertNotIn("HAVE_MKNODAT", posix._have_functions) + + with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"): + os.mknod("path", dir_fd=0) + def test_rename_replace(self): self._verify_available("HAVE_RENAMEAT") if self.mac_ver >= (10, 10): diff --git a/Misc/NEWS.d/next/macOS/2022-10-05-15-26-58.gh-issue-97897.Rf-C6u.rst b/Misc/NEWS.d/next/macOS/2022-10-05-15-26-58.gh-issue-97897.Rf-C6u.rst new file mode 100644 index 000000000000..0d21e98b37c5 --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2022-10-05-15-26-58.gh-issue-97897.Rf-C6u.rst @@ -0,0 +1,6 @@ +The macOS 13 SDK includes support for the ``mkfifoat`` and ``mknodat`` system calls. +Using the ``dir_fd`` option with either :func:`os.mkfifo` or :func:`os.mknod` could result in a +segfault if cpython is built with the macOS 13 SDK but run on an earlier +version of macOS. Prevent this by adding runtime support for detection of +these system calls ("weaklinking") as is done for other newer syscalls on +macOS. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 3810bc87c1fb..cbdc25973758 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -91,6 +91,8 @@ # define HAVE_FUTIMENS_RUNTIME __builtin_available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *) # define HAVE_UTIMENSAT_RUNTIME __builtin_available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *) # define HAVE_PWRITEV_RUNTIME __builtin_available(macOS 11.0, iOS 14.0, tvOS 14.0, watchOS 7.0, *) +# define HAVE_MKFIFOAT_RUNTIME __builtin_available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) +# define HAVE_MKNODAT_RUNTIME __builtin_available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) # define HAVE_POSIX_SPAWN_SETSID_RUNTIME __builtin_available(macOS 10.15, *) @@ -175,6 +177,8 @@ # define HAVE_FUTIMENS_RUNTIME 1 # define HAVE_UTIMENSAT_RUNTIME 1 # define HAVE_PWRITEV_RUNTIME 1 +# define HAVE_MKFIFOAT_RUNTIME 1 +# define HAVE_MKNODAT_RUNTIME 1 #endif @@ -10619,18 +10623,35 @@ os_mkfifo_impl(PyObject *module, path_t *path, int mode, int dir_fd) { int result; int async_err = 0; +#ifdef HAVE_MKFIFOAT + int mkfifoat_unavailable = 0; +#endif do { Py_BEGIN_ALLOW_THREADS #ifdef HAVE_MKFIFOAT - if (dir_fd != DEFAULT_DIR_FD) - result = mkfifoat(dir_fd, path->narrow, mode); - else + if (dir_fd != DEFAULT_DIR_FD) { + if (HAVE_MKFIFOAT_RUNTIME) { + result = mkfifoat(dir_fd, path->narrow, mode); + + } else { + mkfifoat_unavailable = 1; + result = 0; + } + } else #endif result = mkfifo(path->narrow, mode); Py_END_ALLOW_THREADS } while (result != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + +#ifdef HAVE_MKFIFOAT + if (mkfifoat_unavailable) { + argument_unavailable_error(NULL, "dir_fd"); + return NULL; + } +#endif + if (result != 0) return (!async_err) ? posix_error() : NULL; @@ -10671,18 +10692,33 @@ os_mknod_impl(PyObject *module, path_t *path, int mode, dev_t device, { int result; int async_err = 0; +#ifdef HAVE_MKNODAT + int mknodat_unavailable = 0; +#endif do { Py_BEGIN_ALLOW_THREADS #ifdef HAVE_MKNODAT - if (dir_fd != DEFAULT_DIR_FD) - result = mknodat(dir_fd, path->narrow, mode, device); - else + if (dir_fd != DEFAULT_DIR_FD) { + if (HAVE_MKNODAT_RUNTIME) { + result = mknodat(dir_fd, path->narrow, mode, device); + + } else { + mknodat_unavailable = 1; + result = 0; + } + } else #endif result = mknod(path->narrow, mode, device); Py_END_ALLOW_THREADS } while (result != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); +#ifdef HAVE_MKNODAT + if (mknodat_unavailable) { + argument_unavailable_error(NULL, "dir_fd"); + return NULL; + } +#endif if (result != 0) return (!async_err) ? posix_error() : NULL; @@ -15525,6 +15561,14 @@ PROBE(probe_fdopendir, HAVE_FDOPENDIR_RUNTIME) PROBE(probe_mkdirat, HAVE_MKDIRAT_RUNTIME) #endif +#ifdef HAVE_MKFIFOAT +PROBE(probe_mkfifoat, HAVE_MKFIFOAT_RUNTIME) +#endif + +#ifdef HAVE_MKNODAT +PROBE(probe_mknodat, HAVE_MKNODAT_RUNTIME) +#endif + #ifdef HAVE_RENAMEAT PROBE(probe_renameat, HAVE_RENAMEAT_RUNTIME) #endif @@ -15658,11 +15702,11 @@ static const struct have_function { #endif #ifdef HAVE_MKFIFOAT - { "HAVE_MKFIFOAT", NULL }, + { "HAVE_MKFIFOAT", probe_mkfifoat }, #endif #ifdef HAVE_MKNODAT - { "HAVE_MKNODAT", NULL }, + { "HAVE_MKNODAT", probe_mknodat }, #endif #ifdef HAVE_OPENAT From webhook-mailer at python.org Thu Oct 6 12:52:36 2022 From: webhook-mailer at python.org (nanjekyejoannah) Date: Thu, 06 Oct 2022 16:52:36 -0000 Subject: [Python-checkins] gh-95986: Fix the example using match keyword (#95989) Message-ID: https://github.com/python/cpython/commit/cd0fde27f9657266a0fb5782a5234678f2cf4662 commit: cd0fde27f9657266a0fb5782a5234678f2cf4662 branch: main author: 180909 <734461790 at qq.com> committer: nanjekyejoannah <33177550+nanjekyejoannah at users.noreply.github.com> date: 2022-10-06T09:52:21-07:00 summary: gh-95986: Fix the example using match keyword (#95989) files: M Doc/whatsnew/3.10.rst diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index db8d9281b1f2..428a19453db5 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -669,6 +669,7 @@ Several other key features: GREEN = 1 BLUE = 2 + color = Color.GREEN match color: case Color.RED: print("I see red!") From webhook-mailer at python.org Thu Oct 6 13:11:46 2022 From: webhook-mailer at python.org (ambv) Date: Thu, 06 Oct 2022 17:11:46 -0000 Subject: [Python-checkins] gh-93738: Disallow pre-v3 syntax in the C domain (#97962) Message-ID: https://github.com/python/cpython/commit/f612565bd32d4ab0945798da775eea070f08b6fe commit: f612565bd32d4ab0945798da775eea070f08b6fe branch: main author: Adam Turner <9087854+AA-Turner at users.noreply.github.com> committer: ambv date: 2022-10-06T10:11:37-07:00 summary: gh-93738: Disallow pre-v3 syntax in the C domain (#97962) Also, disable using invalid sphinx-lint 0.6.2. files: M Doc/conf.py M Doc/extending/newtypes.rst M Doc/extending/newtypes_tutorial.rst M Doc/howto/isolating-extensions.rst M Doc/requirements.txt M Doc/whatsnew/2.2.rst M Doc/whatsnew/2.5.rst diff --git a/Doc/conf.py b/Doc/conf.py index 909f992d9d82..be1c9fff51a2 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -239,28 +239,3 @@ # Relative filename of the data files refcount_file = 'data/refcounts.dat' stable_abi_file = 'data/stable_abi.dat' - -# Sphinx 2 and Sphinx 3 compatibility -# ----------------------------------- - -# bpo-40204: Allow Sphinx 2 syntax in the C domain -c_allow_pre_v3 = True - -# bpo-40204: Disable warnings on Sphinx 2 syntax of the C domain since the -# documentation is built with -W (warnings treated as errors). -c_warn_on_allowed_pre_v3 = False - -# Fix '!' not working with C domain when pre_v3 is enabled -import sphinx - -if sphinx.version_info[:2] < (5, 3): - from sphinx.domains.c import CXRefRole - - original_run = CXRefRole.run - - def new_run(self): - if self.disabled: - return super(CXRefRole, self).run() - return original_run(self) - - CXRefRole.run = new_run diff --git a/Doc/extending/newtypes.rst b/Doc/extending/newtypes.rst index a076eae534b9..3de849ade788 100644 --- a/Doc/extending/newtypes.rst +++ b/Doc/extending/newtypes.rst @@ -208,7 +208,7 @@ a special case, for which the new value passed to the handler is ``NULL``. Python supports two pairs of attribute handlers; a type that supports attributes only needs to implement the functions for one pair. The difference is that one pair takes the name of the attribute as a :c:expr:`char\*`, while the other -accepts a :c:type:`PyObject\*`. Each type can use whichever pair makes more +accepts a :c:expr:`PyObject*`. Each type can use whichever pair makes more sense for the implementation's convenience. :: getattrfunc tp_getattr; /* char * version */ @@ -219,7 +219,7 @@ sense for the implementation's convenience. :: If accessing attributes of an object is always a simple operation (this will be explained shortly), there are generic implementations which can be used to -provide the :c:type:`PyObject\*` version of the attribute management functions. +provide the :c:expr:`PyObject*` version of the attribute management functions. The actual need for type-specific attribute handlers almost completely disappeared starting with Python 2.2, though there are many examples which have not been updated to use some of the new generic mechanism that is available. @@ -341,7 +341,7 @@ Type-specific Attribute Management For simplicity, only the :c:expr:`char\*` version will be demonstrated here; the type of the name parameter is the only difference between the :c:expr:`char\*` -and :c:type:`PyObject\*` flavors of the interface. This example effectively does +and :c:expr:`PyObject*` flavors of the interface. This example effectively does the same thing as the generic example above, but does not use the generic support added in Python 2.2. It explains how the handler functions are called, so that if you do need to extend their functionality, you'll understand diff --git a/Doc/extending/newtypes_tutorial.rst b/Doc/extending/newtypes_tutorial.rst index 34c25d1f6f19..5d4a3f06dd54 100644 --- a/Doc/extending/newtypes_tutorial.rst +++ b/Doc/extending/newtypes_tutorial.rst @@ -24,7 +24,7 @@ The Basics ========== The :term:`CPython` runtime sees all Python objects as variables of type -:c:type:`PyObject\*`, which serves as a "base type" for all Python objects. +:c:expr:`PyObject*`, which serves as a "base type" for all Python objects. The :c:type:`PyObject` structure itself only contains the object's :term:`reference count` and a pointer to the object's "type object". This is where the action is; the type object determines which (C) functions diff --git a/Doc/howto/isolating-extensions.rst b/Doc/howto/isolating-extensions.rst index 8ee7e5e28479..2657b4ec6aaf 100644 --- a/Doc/howto/isolating-extensions.rst +++ b/Doc/howto/isolating-extensions.rst @@ -411,7 +411,7 @@ that subclass, which may be defined in different module than yours. pass For a method to get its "defining class", it must use the -:c:data:`METH_METHOD | METH_FASTCALL | METH_KEYWORDS` +:data:`METH_METHOD | METH_FASTCALL | METH_KEYWORDS` :c:type:`calling convention ` and the corresponding :c:type:`PyCMethod` signature:: diff --git a/Doc/requirements.txt b/Doc/requirements.txt index f8a7f9db144c..be058733fcf4 100644 --- a/Doc/requirements.txt +++ b/Doc/requirements.txt @@ -7,7 +7,10 @@ sphinx==4.5.0 blurb -sphinx-lint<1 +# sphinx-lint 0.6.2 yields many default role errors due to the new regular +# expression used for default role detection, so we don't use the version +# until the errors are fixed. +sphinx-lint<1,!=0.6.2 # The theme used by the documentation is stored separately, so we need # to install that as well. diff --git a/Doc/whatsnew/2.2.rst b/Doc/whatsnew/2.2.rst index bfb2aacbc077..39997661bb96 100644 --- a/Doc/whatsnew/2.2.rst +++ b/Doc/whatsnew/2.2.rst @@ -1102,7 +1102,7 @@ code, none of the changes described here will affect you very much. * A different argument parsing function, :c:func:`PyArg_UnpackTuple`, has been added that's simpler and presumably faster. Instead of specifying a format string, the caller simply gives the minimum and maximum number of arguments - expected, and a set of pointers to :c:type:`PyObject\*` variables that will be + expected, and a set of pointers to :c:expr:`PyObject*` variables that will be filled in with argument values. * Two new flags :const:`METH_NOARGS` and :const:`METH_O` are available in method diff --git a/Doc/whatsnew/2.5.rst b/Doc/whatsnew/2.5.rst index 0aca2fe697cc..dcfaef6ed294 100644 --- a/Doc/whatsnew/2.5.rst +++ b/Doc/whatsnew/2.5.rst @@ -1725,7 +1725,7 @@ attribute of the function object to change this:: ``ctypes.pythonapi`` object. This object does *not* release the global interpreter lock before calling a function, because the lock must be held when calling into the interpreter's code. There's a :class:`py_object()` type -constructor that will create a :c:type:`PyObject \*` pointer. A simple usage:: +constructor that will create a :c:expr:`PyObject *` pointer. A simple usage:: import ctypes From webhook-mailer at python.org Thu Oct 6 13:18:29 2022 From: webhook-mailer at python.org (gvanrossum) Date: Thu, 06 Oct 2022 17:18:29 -0000 Subject: [Python-checkins] GH-88050: fix race in closing subprocess pipe in asyncio (#97951) Message-ID: https://github.com/python/cpython/commit/e2e6b95c0342247ed1a761b6e149ac579a8722dd commit: e2e6b95c0342247ed1a761b6e149ac579a8722dd branch: main author: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> committer: gvanrossum date: 2022-10-06T10:18:19-07:00 summary: GH-88050: fix race in closing subprocess pipe in asyncio (#97951) Check for None when iterating over `self._pipes.values()`. files: M Lib/asyncio/base_subprocess.py diff --git a/Lib/asyncio/base_subprocess.py b/Lib/asyncio/base_subprocess.py index c2ca4a2792f6..e15bb4141fc0 100644 --- a/Lib/asyncio/base_subprocess.py +++ b/Lib/asyncio/base_subprocess.py @@ -216,7 +216,9 @@ def _process_exited(self, returncode): self._proc.returncode = returncode self._call(self._protocol.process_exited) for p in self._pipes.values(): - p.pipe.close() + if p is not None: + p.pipe.close() + self._try_finish() async def _wait(self): From webhook-mailer at python.org Thu Oct 6 13:39:26 2022 From: webhook-mailer at python.org (nanjekyejoannah) Date: Thu, 06 Oct 2022 17:39:26 -0000 Subject: [Python-checkins] gh-94808: Coverage: Test that maximum indentation level is handled (#95926) Message-ID: https://github.com/python/cpython/commit/23e83a84651bbcf1f3778baf3ab0b4cbfead75e3 commit: 23e83a84651bbcf1f3778baf3ab0b4cbfead75e3 branch: main author: Michael Droettboom committer: nanjekyejoannah <33177550+nanjekyejoannah at users.noreply.github.com> date: 2022-10-06T10:39:17-07:00 summary: gh-94808: Coverage: Test that maximum indentation level is handled (#95926) * gh-94808: Coverage: Test that maximum indentation level is handled * Use "compile" rather than "exec" files: M Lib/test/test_tokenize.py diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py index 1272e1e9be00..47f2c06685bc 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -3,7 +3,7 @@ from tokenize import (tokenize, _tokenize, untokenize, NUMBER, NAME, OP, STRING, ENDMARKER, ENCODING, tok_name, detect_encoding, open as tokenize_open, Untokenizer, generate_tokens, - NEWLINE, _generate_tokens_from_c_tokenizer) + NEWLINE, _generate_tokens_from_c_tokenizer, DEDENT) from io import BytesIO, StringIO import unittest from textwrap import dedent @@ -2512,6 +2512,26 @@ def get_tokens(string): self.assertRaises(SyntaxError, get_tokens, "("*1000+"a"+")"*1000) self.assertRaises(SyntaxError, get_tokens, "]") + def test_max_indent(self): + MAXINDENT = 100 + + def generate_source(indents): + source = ''.join((' ' * x) + 'if True:\n' for x in range(indents)) + source += ' ' * indents + 'pass\n' + return source + + valid = generate_source(MAXINDENT - 1) + tokens = list(_generate_tokens_from_c_tokenizer(valid)) + self.assertEqual(tokens[-1].type, DEDENT) + compile(valid, "", "exec") + + invalid = generate_source(MAXINDENT) + tokens = list(_generate_tokens_from_c_tokenizer(invalid)) + self.assertEqual(tokens[-1].type, NEWLINE) + self.assertRaises( + IndentationError, compile, invalid, "", "exec" + ) + def test_continuation_lines_indentation(self): def get_tokens(string): return [(kind, string) for (kind, string, *_) in _generate_tokens_from_c_tokenizer(string)] From webhook-mailer at python.org Thu Oct 6 13:49:34 2022 From: webhook-mailer at python.org (ambv) Date: Thu, 06 Oct 2022 17:49:34 -0000 Subject: [Python-checkins] [3.11] gh-93738: Disallow pre-v3 syntax in the C domain (GH-97962) (#97976) Message-ID: https://github.com/python/cpython/commit/27a7fe319a46bb3e36f27a9efeaf061f2379dcd8 commit: 27a7fe319a46bb3e36f27a9efeaf061f2379dcd8 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-06T10:49:29-07:00 summary: [3.11] gh-93738: Disallow pre-v3 syntax in the C domain (GH-97962) (#97976) Also, disable using invalid sphinx-lint 0.6.2. (cherry picked from commit f612565bd32d4ab0945798da775eea070f08b6fe) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> Co-authored-by: ?ukasz Langa files: M Doc/c-api/unicode.rst M Doc/conf.py M Doc/extending/newtypes.rst M Doc/extending/newtypes_tutorial.rst M Doc/howto/isolating-extensions.rst M Doc/requirements.txt M Doc/whatsnew/2.2.rst M Doc/whatsnew/2.5.rst diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst index 26d34052972a..e72f151510cb 100644 --- a/Doc/c-api/unicode.rst +++ b/Doc/c-api/unicode.rst @@ -17,8 +17,8 @@ of Unicode characters while staying memory efficient. There are special cases for strings where all code points are below 128, 256, or 65536; otherwise, code points must be below 1114112 (which is the full Unicode range). -:c:type:`Py_UNICODE*` and UTF-8 representations are created on demand and cached -in the Unicode object. The :c:type:`Py_UNICODE*` representation is deprecated +:c:expr:`Py_UNICODE*` and UTF-8 representations are created on demand and cached +in the Unicode object. The :c:expr:`Py_UNICODE*` representation is deprecated and inefficient. Due to the transition between the old APIs and the new APIs, Unicode objects @@ -30,7 +30,7 @@ can internally be in two states depending on how they were created: * "legacy" Unicode objects have been created through one of the deprecated APIs (typically :c:func:`PyUnicode_FromUnicode`) and only bear the - :c:type:`Py_UNICODE*` representation; you will have to call + :c:expr:`Py_UNICODE*` representation; you will have to call :c:func:`PyUnicode_READY` on them before calling any other API. .. note:: @@ -236,7 +236,7 @@ access to internal read-only data of Unicode objects: returned buffer is always terminated with an extra null code point. It may also contain embedded null code points, which would cause the string to be truncated when used in most C functions. The ``AS_DATA`` form - casts the pointer to :c:type:`const char *`. The *o* argument has to be + casts the pointer to :c:expr:`const char *`. The *o* argument has to be a Unicode object (not checked). .. versionchanged:: 3.3 @@ -714,7 +714,7 @@ Extension modules can continue using them, as they will not be removed in Python Return a read-only pointer to the Unicode object's internal :c:type:`Py_UNICODE` buffer, or ``NULL`` on error. This will create the - :c:type:`Py_UNICODE*` representation of the object if it is not yet + :c:expr:`Py_UNICODE*` representation of the object if it is not yet available. The buffer is always terminated with an extra null code point. Note that the resulting :c:type:`Py_UNICODE` string may also contain embedded null code points, which would cause the string to be truncated when @@ -730,7 +730,7 @@ Extension modules can continue using them, as they will not be removed in Python Like :c:func:`PyUnicode_AsUnicode`, but also saves the :c:func:`Py_UNICODE` array length (excluding the extra null terminator) in *size*. - Note that the resulting :c:type:`Py_UNICODE*` string + Note that the resulting :c:expr:`Py_UNICODE*` string may contain embedded null code points, which would cause the string to be truncated when used in most C functions. diff --git a/Doc/conf.py b/Doc/conf.py index e5c989da0b36..fd4ee2d5eee8 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -234,28 +234,3 @@ # Relative filename of the data files refcount_file = 'data/refcounts.dat' stable_abi_file = 'data/stable_abi.dat' - -# Sphinx 2 and Sphinx 3 compatibility -# ----------------------------------- - -# bpo-40204: Allow Sphinx 2 syntax in the C domain -c_allow_pre_v3 = True - -# bpo-40204: Disable warnings on Sphinx 2 syntax of the C domain since the -# documentation is built with -W (warnings treated as errors). -c_warn_on_allowed_pre_v3 = False - -# Fix '!' not working with C domain when pre_v3 is enabled -import sphinx - -if sphinx.version_info[:2] < (5, 3): - from sphinx.domains.c import CXRefRole - - original_run = CXRefRole.run - - def new_run(self): - if self.disabled: - return super(CXRefRole, self).run() - return original_run(self) - - CXRefRole.run = new_run diff --git a/Doc/extending/newtypes.rst b/Doc/extending/newtypes.rst index 1eef7f6e8eb9..5ba6383640cc 100644 --- a/Doc/extending/newtypes.rst +++ b/Doc/extending/newtypes.rst @@ -208,7 +208,7 @@ a special case, for which the new value passed to the handler is ``NULL``. Python supports two pairs of attribute handlers; a type that supports attributes only needs to implement the functions for one pair. The difference is that one pair takes the name of the attribute as a :c:expr:`char\*`, while the other -accepts a :c:type:`PyObject\*`. Each type can use whichever pair makes more +accepts a :c:expr:`PyObject*`. Each type can use whichever pair makes more sense for the implementation's convenience. :: getattrfunc tp_getattr; /* char * version */ @@ -219,7 +219,7 @@ sense for the implementation's convenience. :: If accessing attributes of an object is always a simple operation (this will be explained shortly), there are generic implementations which can be used to -provide the :c:type:`PyObject\*` version of the attribute management functions. +provide the :c:expr:`PyObject*` version of the attribute management functions. The actual need for type-specific attribute handlers almost completely disappeared starting with Python 2.2, though there are many examples which have not been updated to use some of the new generic mechanism that is available. @@ -341,7 +341,7 @@ Type-specific Attribute Management For simplicity, only the :c:expr:`char\*` version will be demonstrated here; the type of the name parameter is the only difference between the :c:expr:`char\*` -and :c:type:`PyObject\*` flavors of the interface. This example effectively does +and :c:expr:`PyObject*` flavors of the interface. This example effectively does the same thing as the generic example above, but does not use the generic support added in Python 2.2. It explains how the handler functions are called, so that if you do need to extend their functionality, you'll understand @@ -572,7 +572,7 @@ performance-critical objects (such as numbers). For an object to be weakly referencable, the extension type must do two things: -#. Include a :c:type:`PyObject\*` field in the C object structure dedicated to +#. Include a :c:expr:`PyObject*` field in the C object structure dedicated to the weak reference mechanism. The object's constructor should leave it ``NULL`` (which is automatic when using the default :c:member:`~PyTypeObject.tp_alloc`). diff --git a/Doc/extending/newtypes_tutorial.rst b/Doc/extending/newtypes_tutorial.rst index 34c25d1f6f19..5d4a3f06dd54 100644 --- a/Doc/extending/newtypes_tutorial.rst +++ b/Doc/extending/newtypes_tutorial.rst @@ -24,7 +24,7 @@ The Basics ========== The :term:`CPython` runtime sees all Python objects as variables of type -:c:type:`PyObject\*`, which serves as a "base type" for all Python objects. +:c:expr:`PyObject*`, which serves as a "base type" for all Python objects. The :c:type:`PyObject` structure itself only contains the object's :term:`reference count` and a pointer to the object's "type object". This is where the action is; the type object determines which (C) functions diff --git a/Doc/howto/isolating-extensions.rst b/Doc/howto/isolating-extensions.rst index 8ee7e5e28479..2657b4ec6aaf 100644 --- a/Doc/howto/isolating-extensions.rst +++ b/Doc/howto/isolating-extensions.rst @@ -411,7 +411,7 @@ that subclass, which may be defined in different module than yours. pass For a method to get its "defining class", it must use the -:c:data:`METH_METHOD | METH_FASTCALL | METH_KEYWORDS` +:data:`METH_METHOD | METH_FASTCALL | METH_KEYWORDS` :c:type:`calling convention ` and the corresponding :c:type:`PyCMethod` signature:: diff --git a/Doc/requirements.txt b/Doc/requirements.txt index f8a7f9db144c..be058733fcf4 100644 --- a/Doc/requirements.txt +++ b/Doc/requirements.txt @@ -7,7 +7,10 @@ sphinx==4.5.0 blurb -sphinx-lint<1 +# sphinx-lint 0.6.2 yields many default role errors due to the new regular +# expression used for default role detection, so we don't use the version +# until the errors are fixed. +sphinx-lint<1,!=0.6.2 # The theme used by the documentation is stored separately, so we need # to install that as well. diff --git a/Doc/whatsnew/2.2.rst b/Doc/whatsnew/2.2.rst index bfb2aacbc077..39997661bb96 100644 --- a/Doc/whatsnew/2.2.rst +++ b/Doc/whatsnew/2.2.rst @@ -1102,7 +1102,7 @@ code, none of the changes described here will affect you very much. * A different argument parsing function, :c:func:`PyArg_UnpackTuple`, has been added that's simpler and presumably faster. Instead of specifying a format string, the caller simply gives the minimum and maximum number of arguments - expected, and a set of pointers to :c:type:`PyObject\*` variables that will be + expected, and a set of pointers to :c:expr:`PyObject*` variables that will be filled in with argument values. * Two new flags :const:`METH_NOARGS` and :const:`METH_O` are available in method diff --git a/Doc/whatsnew/2.5.rst b/Doc/whatsnew/2.5.rst index 0aca2fe697cc..dcfaef6ed294 100644 --- a/Doc/whatsnew/2.5.rst +++ b/Doc/whatsnew/2.5.rst @@ -1725,7 +1725,7 @@ attribute of the function object to change this:: ``ctypes.pythonapi`` object. This object does *not* release the global interpreter lock before calling a function, because the lock must be held when calling into the interpreter's code. There's a :class:`py_object()` type -constructor that will create a :c:type:`PyObject \*` pointer. A simple usage:: +constructor that will create a :c:expr:`PyObject *` pointer. A simple usage:: import ctypes From webhook-mailer at python.org Thu Oct 6 14:57:16 2022 From: webhook-mailer at python.org (ambv) Date: Thu, 06 Oct 2022 18:57:16 -0000 Subject: [Python-checkins] [3.10] gh-93738: Disallow pre-v3 syntax in the C domain (GH-97962) (#97977) Message-ID: https://github.com/python/cpython/commit/537c93ea3b822b4dc039c35ea1375046a9e95c7a commit: 537c93ea3b822b4dc039c35ea1375046a9e95c7a branch: 3.10 author: ?ukasz Langa committer: ambv date: 2022-10-06T11:56:52-07:00 summary: [3.10] gh-93738: Disallow pre-v3 syntax in the C domain (GH-97962) (#97977) Also, disable using invalid sphinx-lint 0.6.2. (cherry picked from commit f612565bd32d4ab0945798da775eea070f08b6fe) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> files: M .gitignore M Doc/c-api/unicode.rst M Doc/conf.py M Doc/extending/newtypes.rst M Doc/extending/newtypes_tutorial.rst M Doc/whatsnew/2.2.rst M Doc/whatsnew/2.5.rst diff --git a/.gitignore b/.gitignore index 09d08c8050cb..0400feb6d745 100644 --- a/.gitignore +++ b/.gitignore @@ -139,6 +139,8 @@ Tools/ssl/win32 # Artifacts generated by 3.11 lying around when switching branches: /_bootstrap_python +/Modules/Setup.bootstrap +/Modules/Setup.stdlib /Programs/_freeze_module /Python/deepfreeze/ /Python/frozen_modules/ \ No newline at end of file diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst index f82bc6ca27bc..0ef4ff9f288c 100644 --- a/Doc/c-api/unicode.rst +++ b/Doc/c-api/unicode.rst @@ -17,8 +17,8 @@ of Unicode characters while staying memory efficient. There are special cases for strings where all code points are below 128, 256, or 65536; otherwise, code points must be below 1114112 (which is the full Unicode range). -:c:type:`Py_UNICODE*` and UTF-8 representations are created on demand and cached -in the Unicode object. The :c:type:`Py_UNICODE*` representation is deprecated +:c:expr:`Py_UNICODE*` and UTF-8 representations are created on demand and cached +in the Unicode object. The :c:expr:`Py_UNICODE*` representation is deprecated and inefficient. Due to the transition between the old APIs and the new APIs, Unicode objects @@ -30,7 +30,7 @@ can internally be in two states depending on how they were created: * "legacy" Unicode objects have been created through one of the deprecated APIs (typically :c:func:`PyUnicode_FromUnicode`) and only bear the - :c:type:`Py_UNICODE*` representation; you will have to call + :c:expr:`Py_UNICODE*` representation; you will have to call :c:func:`PyUnicode_READY` on them before calling any other API. .. note:: @@ -235,7 +235,7 @@ access internal read-only data of Unicode objects: returned buffer is always terminated with an extra null code point. It may also contain embedded null code points, which would cause the string to be truncated when used in most C functions. The ``AS_DATA`` form - casts the pointer to :c:type:`const char *`. The *o* argument has to be + casts the pointer to :c:expr:`const char *`. The *o* argument has to be a Unicode object (not checked). .. versionchanged:: 3.3 @@ -707,7 +707,7 @@ Extension modules can continue using them, as they will not be removed in Python Return a read-only pointer to the Unicode object's internal :c:type:`Py_UNICODE` buffer, or ``NULL`` on error. This will create the - :c:type:`Py_UNICODE*` representation of the object if it is not yet + :c:expr:`Py_UNICODE*` representation of the object if it is not yet available. The buffer is always terminated with an extra null code point. Note that the resulting :c:type:`Py_UNICODE` string may also contain embedded null code points, which would cause the string to be truncated when @@ -734,7 +734,7 @@ Extension modules can continue using them, as they will not be removed in Python Like :c:func:`PyUnicode_AsUnicode`, but also saves the :c:func:`Py_UNICODE` array length (excluding the extra null terminator) in *size*. - Note that the resulting :c:type:`Py_UNICODE*` string + Note that the resulting :c:expr:`Py_UNICODE*` string may contain embedded null code points, which would cause the string to be truncated when used in most C functions. diff --git a/Doc/conf.py b/Doc/conf.py index aff26f9c9058..178e52033b67 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -234,28 +234,3 @@ # Relative filename of the data files refcount_file = 'data/refcounts.dat' stable_abi_file = 'data/stable_abi.dat' - -# Sphinx 2 and Sphinx 3 compatibility -# ----------------------------------- - -# bpo-40204: Allow Sphinx 2 syntax in the C domain -c_allow_pre_v3 = True - -# bpo-40204: Disable warnings on Sphinx 2 syntax of the C domain since the -# documentation is built with -W (warnings treated as errors). -c_warn_on_allowed_pre_v3 = False - -# Fix '!' not working with C domain when pre_v3 is enabled -import sphinx - -if sphinx.version_info[:2] < (5, 3): - from sphinx.domains.c import CXRefRole - - original_run = CXRefRole.run - - def new_run(self): - if self.disabled: - return super(CXRefRole, self).run() - return original_run(self) - - CXRefRole.run = new_run diff --git a/Doc/extending/newtypes.rst b/Doc/extending/newtypes.rst index 1eef7f6e8eb9..5ba6383640cc 100644 --- a/Doc/extending/newtypes.rst +++ b/Doc/extending/newtypes.rst @@ -208,7 +208,7 @@ a special case, for which the new value passed to the handler is ``NULL``. Python supports two pairs of attribute handlers; a type that supports attributes only needs to implement the functions for one pair. The difference is that one pair takes the name of the attribute as a :c:expr:`char\*`, while the other -accepts a :c:type:`PyObject\*`. Each type can use whichever pair makes more +accepts a :c:expr:`PyObject*`. Each type can use whichever pair makes more sense for the implementation's convenience. :: getattrfunc tp_getattr; /* char * version */ @@ -219,7 +219,7 @@ sense for the implementation's convenience. :: If accessing attributes of an object is always a simple operation (this will be explained shortly), there are generic implementations which can be used to -provide the :c:type:`PyObject\*` version of the attribute management functions. +provide the :c:expr:`PyObject*` version of the attribute management functions. The actual need for type-specific attribute handlers almost completely disappeared starting with Python 2.2, though there are many examples which have not been updated to use some of the new generic mechanism that is available. @@ -341,7 +341,7 @@ Type-specific Attribute Management For simplicity, only the :c:expr:`char\*` version will be demonstrated here; the type of the name parameter is the only difference between the :c:expr:`char\*` -and :c:type:`PyObject\*` flavors of the interface. This example effectively does +and :c:expr:`PyObject*` flavors of the interface. This example effectively does the same thing as the generic example above, but does not use the generic support added in Python 2.2. It explains how the handler functions are called, so that if you do need to extend their functionality, you'll understand @@ -572,7 +572,7 @@ performance-critical objects (such as numbers). For an object to be weakly referencable, the extension type must do two things: -#. Include a :c:type:`PyObject\*` field in the C object structure dedicated to +#. Include a :c:expr:`PyObject*` field in the C object structure dedicated to the weak reference mechanism. The object's constructor should leave it ``NULL`` (which is automatic when using the default :c:member:`~PyTypeObject.tp_alloc`). diff --git a/Doc/extending/newtypes_tutorial.rst b/Doc/extending/newtypes_tutorial.rst index 34c25d1f6f19..5d4a3f06dd54 100644 --- a/Doc/extending/newtypes_tutorial.rst +++ b/Doc/extending/newtypes_tutorial.rst @@ -24,7 +24,7 @@ The Basics ========== The :term:`CPython` runtime sees all Python objects as variables of type -:c:type:`PyObject\*`, which serves as a "base type" for all Python objects. +:c:expr:`PyObject*`, which serves as a "base type" for all Python objects. The :c:type:`PyObject` structure itself only contains the object's :term:`reference count` and a pointer to the object's "type object". This is where the action is; the type object determines which (C) functions diff --git a/Doc/whatsnew/2.2.rst b/Doc/whatsnew/2.2.rst index bfb2aacbc077..39997661bb96 100644 --- a/Doc/whatsnew/2.2.rst +++ b/Doc/whatsnew/2.2.rst @@ -1102,7 +1102,7 @@ code, none of the changes described here will affect you very much. * A different argument parsing function, :c:func:`PyArg_UnpackTuple`, has been added that's simpler and presumably faster. Instead of specifying a format string, the caller simply gives the minimum and maximum number of arguments - expected, and a set of pointers to :c:type:`PyObject\*` variables that will be + expected, and a set of pointers to :c:expr:`PyObject*` variables that will be filled in with argument values. * Two new flags :const:`METH_NOARGS` and :const:`METH_O` are available in method diff --git a/Doc/whatsnew/2.5.rst b/Doc/whatsnew/2.5.rst index 0aca2fe697cc..dcfaef6ed294 100644 --- a/Doc/whatsnew/2.5.rst +++ b/Doc/whatsnew/2.5.rst @@ -1725,7 +1725,7 @@ attribute of the function object to change this:: ``ctypes.pythonapi`` object. This object does *not* release the global interpreter lock before calling a function, because the lock must be held when calling into the interpreter's code. There's a :class:`py_object()` type -constructor that will create a :c:type:`PyObject \*` pointer. A simple usage:: +constructor that will create a :c:expr:`PyObject *` pointer. A simple usage:: import ctypes From webhook-mailer at python.org Thu Oct 6 15:06:54 2022 From: webhook-mailer at python.org (nanjekyejoannah) Date: Thu, 06 Oct 2022 19:06:54 -0000 Subject: [Python-checkins] [3.11] gh-94808: Coverage: Test that maximum indentation level is handled (GH-95926) (#97979) Message-ID: https://github.com/python/cpython/commit/1cd19f7ebfc2df2f4052e5dba0d548c4eb9caa45 commit: 1cd19f7ebfc2df2f4052e5dba0d548c4eb9caa45 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: nanjekyejoannah <33177550+nanjekyejoannah at users.noreply.github.com> date: 2022-10-06T12:06:49-07:00 summary: [3.11] gh-94808: Coverage: Test that maximum indentation level is handled (GH-95926) (#97979) gh-94808: Coverage: Test that maximum indentation level is handled (GH-95926) * gh-94808: Coverage: Test that maximum indentation level is handled * Use "compile" rather than "exec" (cherry picked from commit 23e83a84651bbcf1f3778baf3ab0b4cbfead75e3) Co-authored-by: Michael Droettboom Co-authored-by: Michael Droettboom files: M Lib/test/test_tokenize.py diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py index 1272e1e9be00..47f2c06685bc 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -3,7 +3,7 @@ from tokenize import (tokenize, _tokenize, untokenize, NUMBER, NAME, OP, STRING, ENDMARKER, ENCODING, tok_name, detect_encoding, open as tokenize_open, Untokenizer, generate_tokens, - NEWLINE, _generate_tokens_from_c_tokenizer) + NEWLINE, _generate_tokens_from_c_tokenizer, DEDENT) from io import BytesIO, StringIO import unittest from textwrap import dedent @@ -2512,6 +2512,26 @@ def get_tokens(string): self.assertRaises(SyntaxError, get_tokens, "("*1000+"a"+")"*1000) self.assertRaises(SyntaxError, get_tokens, "]") + def test_max_indent(self): + MAXINDENT = 100 + + def generate_source(indents): + source = ''.join((' ' * x) + 'if True:\n' for x in range(indents)) + source += ' ' * indents + 'pass\n' + return source + + valid = generate_source(MAXINDENT - 1) + tokens = list(_generate_tokens_from_c_tokenizer(valid)) + self.assertEqual(tokens[-1].type, DEDENT) + compile(valid, "", "exec") + + invalid = generate_source(MAXINDENT) + tokens = list(_generate_tokens_from_c_tokenizer(invalid)) + self.assertEqual(tokens[-1].type, NEWLINE) + self.assertRaises( + IndentationError, compile, invalid, "", "exec" + ) + def test_continuation_lines_indentation(self): def get_tokens(string): return [(kind, string) for (kind, string, *_) in _generate_tokens_from_c_tokenizer(string)] From webhook-mailer at python.org Thu Oct 6 15:09:56 2022 From: webhook-mailer at python.org (ambv) Date: Thu, 06 Oct 2022 19:09:56 -0000 Subject: [Python-checkins] [3.11] GH-88050: fix race in closing subprocess pipe in asyncio (GH-97951) (#97978) Message-ID: https://github.com/python/cpython/commit/bd3dcb3549e9c1c26495bc3cc1a45197079bdcaf commit: bd3dcb3549e9c1c26495bc3cc1a45197079bdcaf branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-06T12:09:50-07:00 summary: [3.11] GH-88050: fix race in closing subprocess pipe in asyncio (GH-97951) (#97978) Check for None when iterating over `self._pipes.values()`. (cherry picked from commit e2e6b95c0342247ed1a761b6e149ac579a8722dd) Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> files: M Lib/asyncio/base_subprocess.py diff --git a/Lib/asyncio/base_subprocess.py b/Lib/asyncio/base_subprocess.py index c2ca4a2792f6..e15bb4141fc0 100644 --- a/Lib/asyncio/base_subprocess.py +++ b/Lib/asyncio/base_subprocess.py @@ -216,7 +216,9 @@ def _process_exited(self, returncode): self._proc.returncode = returncode self._call(self._protocol.process_exited) for p in self._pipes.values(): - p.pipe.close() + if p is not None: + p.pipe.close() + self._try_finish() async def _wait(self): From webhook-mailer at python.org Thu Oct 6 15:13:52 2022 From: webhook-mailer at python.org (ambv) Date: Thu, 06 Oct 2022 19:13:52 -0000 Subject: [Python-checkins] [3.11] gh-97897: Prevent os.mkfifo and os.mknod segfaults with macOS 13 SDK (GH-97944) (#97969) Message-ID: https://github.com/python/cpython/commit/60570303e419a2c9185f219fb3265e3ca2f14d9d commit: 60570303e419a2c9185f219fb3265e3ca2f14d9d branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-06T12:13:46-07:00 summary: [3.11] gh-97897: Prevent os.mkfifo and os.mknod segfaults with macOS 13 SDK (GH-97944) (#97969) The macOS 13 SDK includes support for the `mkfifoat` and `mknodat` system calls. Using the `dir_fd` option with either `os.mkfifo` or `os.mknod` could result in a segfault if cpython is built with the macOS 13 SDK but run on an earlier version of macOS. Prevent this by adding runtime support for detection of these system calls ("weaklinking") as is done for other newer syscalls on macOS. (cherry picked from commit 6d0a0191a4e5477bd843e62c24d7f3bcad4fd5fc) Co-authored-by: Ned Deily files: A Misc/NEWS.d/next/macOS/2022-10-05-15-26-58.gh-issue-97897.Rf-C6u.rst M Lib/test/test_posix.py M Modules/posixmodule.c diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py index ae25ef55885d..e643d8e5a4ce 100644 --- a/Lib/test/test_posix.py +++ b/Lib/test/test_posix.py @@ -2090,6 +2090,28 @@ def test_mkdir(self): with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"): os.mkdir("dir", dir_fd=0) + def test_mkfifo(self): + self._verify_available("HAVE_MKFIFOAT") + if self.mac_ver >= (13, 0): + self.assertIn("HAVE_MKFIFOAT", posix._have_functions) + + else: + self.assertNotIn("HAVE_MKFIFOAT", posix._have_functions) + + with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"): + os.mkfifo("path", dir_fd=0) + + def test_mknod(self): + self._verify_available("HAVE_MKNODAT") + if self.mac_ver >= (13, 0): + self.assertIn("HAVE_MKNODAT", posix._have_functions) + + else: + self.assertNotIn("HAVE_MKNODAT", posix._have_functions) + + with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"): + os.mknod("path", dir_fd=0) + def test_rename_replace(self): self._verify_available("HAVE_RENAMEAT") if self.mac_ver >= (10, 10): diff --git a/Misc/NEWS.d/next/macOS/2022-10-05-15-26-58.gh-issue-97897.Rf-C6u.rst b/Misc/NEWS.d/next/macOS/2022-10-05-15-26-58.gh-issue-97897.Rf-C6u.rst new file mode 100644 index 000000000000..0d21e98b37c5 --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2022-10-05-15-26-58.gh-issue-97897.Rf-C6u.rst @@ -0,0 +1,6 @@ +The macOS 13 SDK includes support for the ``mkfifoat`` and ``mknodat`` system calls. +Using the ``dir_fd`` option with either :func:`os.mkfifo` or :func:`os.mknod` could result in a +segfault if cpython is built with the macOS 13 SDK but run on an earlier +version of macOS. Prevent this by adding runtime support for detection of +these system calls ("weaklinking") as is done for other newer syscalls on +macOS. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 378032501f9e..309982af824c 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -91,6 +91,8 @@ # define HAVE_FUTIMENS_RUNTIME __builtin_available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *) # define HAVE_UTIMENSAT_RUNTIME __builtin_available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *) # define HAVE_PWRITEV_RUNTIME __builtin_available(macOS 11.0, iOS 14.0, tvOS 14.0, watchOS 7.0, *) +# define HAVE_MKFIFOAT_RUNTIME __builtin_available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) +# define HAVE_MKNODAT_RUNTIME __builtin_available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) # define HAVE_POSIX_SPAWN_SETSID_RUNTIME __builtin_available(macOS 10.15, *) @@ -175,6 +177,8 @@ # define HAVE_FUTIMENS_RUNTIME 1 # define HAVE_UTIMENSAT_RUNTIME 1 # define HAVE_PWRITEV_RUNTIME 1 +# define HAVE_MKFIFOAT_RUNTIME 1 +# define HAVE_MKNODAT_RUNTIME 1 #endif @@ -10644,18 +10648,35 @@ os_mkfifo_impl(PyObject *module, path_t *path, int mode, int dir_fd) { int result; int async_err = 0; +#ifdef HAVE_MKFIFOAT + int mkfifoat_unavailable = 0; +#endif do { Py_BEGIN_ALLOW_THREADS #ifdef HAVE_MKFIFOAT - if (dir_fd != DEFAULT_DIR_FD) - result = mkfifoat(dir_fd, path->narrow, mode); - else + if (dir_fd != DEFAULT_DIR_FD) { + if (HAVE_MKFIFOAT_RUNTIME) { + result = mkfifoat(dir_fd, path->narrow, mode); + + } else { + mkfifoat_unavailable = 1; + result = 0; + } + } else #endif result = mkfifo(path->narrow, mode); Py_END_ALLOW_THREADS } while (result != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + +#ifdef HAVE_MKFIFOAT + if (mkfifoat_unavailable) { + argument_unavailable_error(NULL, "dir_fd"); + return NULL; + } +#endif + if (result != 0) return (!async_err) ? posix_error() : NULL; @@ -10696,18 +10717,33 @@ os_mknod_impl(PyObject *module, path_t *path, int mode, dev_t device, { int result; int async_err = 0; +#ifdef HAVE_MKNODAT + int mknodat_unavailable = 0; +#endif do { Py_BEGIN_ALLOW_THREADS #ifdef HAVE_MKNODAT - if (dir_fd != DEFAULT_DIR_FD) - result = mknodat(dir_fd, path->narrow, mode, device); - else + if (dir_fd != DEFAULT_DIR_FD) { + if (HAVE_MKNODAT_RUNTIME) { + result = mknodat(dir_fd, path->narrow, mode, device); + + } else { + mknodat_unavailable = 1; + result = 0; + } + } else #endif result = mknod(path->narrow, mode, device); Py_END_ALLOW_THREADS } while (result != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); +#ifdef HAVE_MKNODAT + if (mknodat_unavailable) { + argument_unavailable_error(NULL, "dir_fd"); + return NULL; + } +#endif if (result != 0) return (!async_err) ? posix_error() : NULL; @@ -15576,6 +15612,14 @@ PROBE(probe_fdopendir, HAVE_FDOPENDIR_RUNTIME) PROBE(probe_mkdirat, HAVE_MKDIRAT_RUNTIME) #endif +#ifdef HAVE_MKFIFOAT +PROBE(probe_mkfifoat, HAVE_MKFIFOAT_RUNTIME) +#endif + +#ifdef HAVE_MKNODAT +PROBE(probe_mknodat, HAVE_MKNODAT_RUNTIME) +#endif + #ifdef HAVE_RENAMEAT PROBE(probe_renameat, HAVE_RENAMEAT_RUNTIME) #endif @@ -15709,11 +15753,11 @@ static const struct have_function { #endif #ifdef HAVE_MKFIFOAT - { "HAVE_MKFIFOAT", NULL }, + { "HAVE_MKFIFOAT", probe_mkfifoat }, #endif #ifdef HAVE_MKNODAT - { "HAVE_MKNODAT", NULL }, + { "HAVE_MKNODAT", probe_mknodat }, #endif #ifdef HAVE_OPENAT From webhook-mailer at python.org Thu Oct 6 15:14:21 2022 From: webhook-mailer at python.org (ambv) Date: Thu, 06 Oct 2022 19:14:21 -0000 Subject: [Python-checkins] [3.10] gh-97897: Prevent os.mkfifo and os.mknod segfaults with macOS 13 SDK (GH-97944) (#97967) Message-ID: https://github.com/python/cpython/commit/3d89ac2f4c573f5facde11579db0791832f5b392 commit: 3d89ac2f4c573f5facde11579db0791832f5b392 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-06T12:14:16-07:00 summary: [3.10] gh-97897: Prevent os.mkfifo and os.mknod segfaults with macOS 13 SDK (GH-97944) (#97967) The macOS 13 SDK includes support for the `mkfifoat` and `mknodat` system calls. Using the `dir_fd` option with either `os.mkfifo` or `os.mknod` could result in a segfault if cpython is built with the macOS 13 SDK but run on an earlier version of macOS. Prevent this by adding runtime support for detection of these system calls ("weaklinking") as is done for other newer syscalls on macOS. (cherry picked from commit 6d0a0191a4e5477bd843e62c24d7f3bcad4fd5fc) Co-authored-by: Ned Deily files: A Misc/NEWS.d/next/macOS/2022-10-05-15-26-58.gh-issue-97897.Rf-C6u.rst M Lib/test/test_posix.py M Modules/posixmodule.c diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py index 701543bb6ac6..19bc88531596 100644 --- a/Lib/test/test_posix.py +++ b/Lib/test/test_posix.py @@ -2066,6 +2066,28 @@ def test_mkdir(self): with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"): os.mkdir("dir", dir_fd=0) + def test_mkfifo(self): + self._verify_available("HAVE_MKFIFOAT") + if self.mac_ver >= (13, 0): + self.assertIn("HAVE_MKFIFOAT", posix._have_functions) + + else: + self.assertNotIn("HAVE_MKFIFOAT", posix._have_functions) + + with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"): + os.mkfifo("path", dir_fd=0) + + def test_mknod(self): + self._verify_available("HAVE_MKNODAT") + if self.mac_ver >= (13, 0): + self.assertIn("HAVE_MKNODAT", posix._have_functions) + + else: + self.assertNotIn("HAVE_MKNODAT", posix._have_functions) + + with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"): + os.mknod("path", dir_fd=0) + def test_rename_replace(self): self._verify_available("HAVE_RENAMEAT") if self.mac_ver >= (10, 10): diff --git a/Misc/NEWS.d/next/macOS/2022-10-05-15-26-58.gh-issue-97897.Rf-C6u.rst b/Misc/NEWS.d/next/macOS/2022-10-05-15-26-58.gh-issue-97897.Rf-C6u.rst new file mode 100644 index 000000000000..0d21e98b37c5 --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2022-10-05-15-26-58.gh-issue-97897.Rf-C6u.rst @@ -0,0 +1,6 @@ +The macOS 13 SDK includes support for the ``mkfifoat`` and ``mknodat`` system calls. +Using the ``dir_fd`` option with either :func:`os.mkfifo` or :func:`os.mknod` could result in a +segfault if cpython is built with the macOS 13 SDK but run on an earlier +version of macOS. Prevent this by adding runtime support for detection of +these system calls ("weaklinking") as is done for other newer syscalls on +macOS. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 3d74b22f7288..0b8b41cb2ded 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -85,6 +85,8 @@ # define HAVE_FUTIMENS_RUNTIME __builtin_available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *) # define HAVE_UTIMENSAT_RUNTIME __builtin_available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *) # define HAVE_PWRITEV_RUNTIME __builtin_available(macOS 11.0, iOS 14.0, tvOS 14.0, watchOS 7.0, *) +# define HAVE_MKFIFOAT_RUNTIME __builtin_available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) +# define HAVE_MKNODAT_RUNTIME __builtin_available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) # define HAVE_POSIX_SPAWN_SETSID_RUNTIME __builtin_available(macOS 10.15, *) @@ -169,6 +171,8 @@ # define HAVE_FUTIMENS_RUNTIME 1 # define HAVE_UTIMENSAT_RUNTIME 1 # define HAVE_PWRITEV_RUNTIME 1 +# define HAVE_MKFIFOAT_RUNTIME 1 +# define HAVE_MKNODAT_RUNTIME 1 #endif @@ -10554,18 +10558,35 @@ os_mkfifo_impl(PyObject *module, path_t *path, int mode, int dir_fd) { int result; int async_err = 0; +#ifdef HAVE_MKFIFOAT + int mkfifoat_unavailable = 0; +#endif do { Py_BEGIN_ALLOW_THREADS #ifdef HAVE_MKFIFOAT - if (dir_fd != DEFAULT_DIR_FD) - result = mkfifoat(dir_fd, path->narrow, mode); - else + if (dir_fd != DEFAULT_DIR_FD) { + if (HAVE_MKFIFOAT_RUNTIME) { + result = mkfifoat(dir_fd, path->narrow, mode); + + } else { + mkfifoat_unavailable = 1; + result = 0; + } + } else #endif result = mkfifo(path->narrow, mode); Py_END_ALLOW_THREADS } while (result != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + +#ifdef HAVE_MKFIFOAT + if (mkfifoat_unavailable) { + argument_unavailable_error(NULL, "dir_fd"); + return NULL; + } +#endif + if (result != 0) return (!async_err) ? posix_error() : NULL; @@ -10606,18 +10627,33 @@ os_mknod_impl(PyObject *module, path_t *path, int mode, dev_t device, { int result; int async_err = 0; +#ifdef HAVE_MKNODAT + int mknodat_unavailable = 0; +#endif do { Py_BEGIN_ALLOW_THREADS #ifdef HAVE_MKNODAT - if (dir_fd != DEFAULT_DIR_FD) - result = mknodat(dir_fd, path->narrow, mode, device); - else + if (dir_fd != DEFAULT_DIR_FD) { + if (HAVE_MKNODAT_RUNTIME) { + result = mknodat(dir_fd, path->narrow, mode, device); + + } else { + mknodat_unavailable = 1; + result = 0; + } + } else #endif result = mknod(path->narrow, mode, device); Py_END_ALLOW_THREADS } while (result != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); +#ifdef HAVE_MKNODAT + if (mknodat_unavailable) { + argument_unavailable_error(NULL, "dir_fd"); + return NULL; + } +#endif if (result != 0) return (!async_err) ? posix_error() : NULL; @@ -15466,6 +15502,14 @@ PROBE(probe_fdopendir, HAVE_FDOPENDIR_RUNTIME) PROBE(probe_mkdirat, HAVE_MKDIRAT_RUNTIME) #endif +#ifdef HAVE_MKFIFOAT +PROBE(probe_mkfifoat, HAVE_MKFIFOAT_RUNTIME) +#endif + +#ifdef HAVE_MKNODAT +PROBE(probe_mknodat, HAVE_MKNODAT_RUNTIME) +#endif + #ifdef HAVE_RENAMEAT PROBE(probe_renameat, HAVE_RENAMEAT_RUNTIME) #endif @@ -15599,11 +15643,11 @@ static const struct have_function { #endif #ifdef HAVE_MKFIFOAT - { "HAVE_MKFIFOAT", NULL }, + { "HAVE_MKFIFOAT", probe_mkfifoat }, #endif #ifdef HAVE_MKNODAT - { "HAVE_MKNODAT", NULL }, + { "HAVE_MKNODAT", probe_mknodat }, #endif #ifdef HAVE_OPENAT From webhook-mailer at python.org Thu Oct 6 15:14:37 2022 From: webhook-mailer at python.org (ambv) Date: Thu, 06 Oct 2022 19:14:37 -0000 Subject: [Python-checkins] [3.9] gh-97897: Prevent os.mkfifo and os.mknod segfaults with macOS 13 SDK (GH-97944) (#97968) Message-ID: https://github.com/python/cpython/commit/77796d058e780083279994dfbfca71caf95d1e7d commit: 77796d058e780083279994dfbfca71caf95d1e7d branch: 3.9 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-06T12:14:32-07:00 summary: [3.9] gh-97897: Prevent os.mkfifo and os.mknod segfaults with macOS 13 SDK (GH-97944) (#97968) The macOS 13 SDK includes support for the `mkfifoat` and `mknodat` system calls. Using the `dir_fd` option with either `os.mkfifo` or `os.mknod` could result in a segfault if cpython is built with the macOS 13 SDK but run on an earlier version of macOS. Prevent this by adding runtime support for detection of these system calls ("weaklinking") as is done for other newer syscalls on macOS. (cherry picked from commit 6d0a0191a4e5477bd843e62c24d7f3bcad4fd5fc) Co-authored-by: Ned Deily files: A Misc/NEWS.d/next/macOS/2022-10-05-15-26-58.gh-issue-97897.Rf-C6u.rst M Lib/test/test_posix.py M Modules/posixmodule.c diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py index 6ba14547bdd6..3c0ddeb0037c 100644 --- a/Lib/test/test_posix.py +++ b/Lib/test/test_posix.py @@ -2040,6 +2040,28 @@ def test_mkdir(self): with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"): os.mkdir("dir", dir_fd=0) + def test_mkfifo(self): + self._verify_available("HAVE_MKFIFOAT") + if self.mac_ver >= (13, 0): + self.assertIn("HAVE_MKFIFOAT", posix._have_functions) + + else: + self.assertNotIn("HAVE_MKFIFOAT", posix._have_functions) + + with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"): + os.mkfifo("path", dir_fd=0) + + def test_mknod(self): + self._verify_available("HAVE_MKNODAT") + if self.mac_ver >= (13, 0): + self.assertIn("HAVE_MKNODAT", posix._have_functions) + + else: + self.assertNotIn("HAVE_MKNODAT", posix._have_functions) + + with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"): + os.mknod("path", dir_fd=0) + def test_rename_replace(self): self._verify_available("HAVE_RENAMEAT") if self.mac_ver >= (10, 10): diff --git a/Misc/NEWS.d/next/macOS/2022-10-05-15-26-58.gh-issue-97897.Rf-C6u.rst b/Misc/NEWS.d/next/macOS/2022-10-05-15-26-58.gh-issue-97897.Rf-C6u.rst new file mode 100644 index 000000000000..0d21e98b37c5 --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2022-10-05-15-26-58.gh-issue-97897.Rf-C6u.rst @@ -0,0 +1,6 @@ +The macOS 13 SDK includes support for the ``mkfifoat`` and ``mknodat`` system calls. +Using the ``dir_fd`` option with either :func:`os.mkfifo` or :func:`os.mknod` could result in a +segfault if cpython is built with the macOS 13 SDK but run on an earlier +version of macOS. Prevent this by adding runtime support for detection of +these system calls ("weaklinking") as is done for other newer syscalls on +macOS. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 1270af735e2b..bf4e648421d3 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -79,6 +79,8 @@ # define HAVE_FUTIMENS_RUNTIME __builtin_available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *) # define HAVE_UTIMENSAT_RUNTIME __builtin_available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *) # define HAVE_PWRITEV_RUNTIME __builtin_available(macOS 11.0, iOS 14.0, tvOS 14.0, watchOS 7.0, *) +# define HAVE_MKFIFOAT_RUNTIME __builtin_available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) +# define HAVE_MKNODAT_RUNTIME __builtin_available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) # define HAVE_POSIX_SPAWN_SETSID_RUNTIME __builtin_available(macOS 10.15, *) @@ -163,6 +165,8 @@ # define HAVE_FUTIMENS_RUNTIME 1 # define HAVE_UTIMENSAT_RUNTIME 1 # define HAVE_PWRITEV_RUNTIME 1 +# define HAVE_MKFIFOAT_RUNTIME 1 +# define HAVE_MKNODAT_RUNTIME 1 #endif @@ -10482,18 +10486,35 @@ os_mkfifo_impl(PyObject *module, path_t *path, int mode, int dir_fd) { int result; int async_err = 0; +#ifdef HAVE_MKFIFOAT + int mkfifoat_unavailable = 0; +#endif do { Py_BEGIN_ALLOW_THREADS #ifdef HAVE_MKFIFOAT - if (dir_fd != DEFAULT_DIR_FD) - result = mkfifoat(dir_fd, path->narrow, mode); - else + if (dir_fd != DEFAULT_DIR_FD) { + if (HAVE_MKFIFOAT_RUNTIME) { + result = mkfifoat(dir_fd, path->narrow, mode); + + } else { + mkfifoat_unavailable = 1; + result = 0; + } + } else #endif result = mkfifo(path->narrow, mode); Py_END_ALLOW_THREADS } while (result != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + +#ifdef HAVE_MKFIFOAT + if (mkfifoat_unavailable) { + argument_unavailable_error(NULL, "dir_fd"); + return NULL; + } +#endif + if (result != 0) return (!async_err) ? posix_error() : NULL; @@ -10534,18 +10555,33 @@ os_mknod_impl(PyObject *module, path_t *path, int mode, dev_t device, { int result; int async_err = 0; +#ifdef HAVE_MKNODAT + int mknodat_unavailable = 0; +#endif do { Py_BEGIN_ALLOW_THREADS #ifdef HAVE_MKNODAT - if (dir_fd != DEFAULT_DIR_FD) - result = mknodat(dir_fd, path->narrow, mode, device); - else + if (dir_fd != DEFAULT_DIR_FD) { + if (HAVE_MKNODAT_RUNTIME) { + result = mknodat(dir_fd, path->narrow, mode, device); + + } else { + mknodat_unavailable = 1; + result = 0; + } + } else #endif result = mknod(path->narrow, mode, device); Py_END_ALLOW_THREADS } while (result != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); +#ifdef HAVE_MKNODAT + if (mknodat_unavailable) { + argument_unavailable_error(NULL, "dir_fd"); + return NULL; + } +#endif if (result != 0) return (!async_err) ? posix_error() : NULL; @@ -15265,6 +15301,14 @@ PROBE(probe_fdopendir, HAVE_FDOPENDIR_RUNTIME) PROBE(probe_mkdirat, HAVE_MKDIRAT_RUNTIME) #endif +#ifdef HAVE_MKFIFOAT +PROBE(probe_mkfifoat, HAVE_MKFIFOAT_RUNTIME) +#endif + +#ifdef HAVE_MKNODAT +PROBE(probe_mknodat, HAVE_MKNODAT_RUNTIME) +#endif + #ifdef HAVE_RENAMEAT PROBE(probe_renameat, HAVE_RENAMEAT_RUNTIME) #endif @@ -15394,11 +15438,11 @@ static const struct have_function { #endif #ifdef HAVE_MKFIFOAT - { "HAVE_MKFIFOAT", NULL }, + { "HAVE_MKFIFOAT", probe_mkfifoat }, #endif #ifdef HAVE_MKNODAT - { "HAVE_MKNODAT", NULL }, + { "HAVE_MKNODAT", probe_mknodat }, #endif #ifdef HAVE_OPENAT From webhook-mailer at python.org Thu Oct 6 15:23:38 2022 From: webhook-mailer at python.org (pablogsal) Date: Thu, 06 Oct 2022 19:23:38 -0000 Subject: [Python-checkins] gh-97943: PyFunction_GetAnnotations should return a borrowed reference. (#97949) Message-ID: https://github.com/python/cpython/commit/6bfb0be80486c614cd60dce44c9fe7b3e6c76e3b commit: 6bfb0be80486c614cd60dce44c9fe7b3e6c76e3b branch: main author: larryhastings committer: pablogsal date: 2022-10-06T12:23:20-07:00 summary: gh-97943: PyFunction_GetAnnotations should return a borrowed reference. (#97949) files: A Misc/NEWS.d/next/Core and Builtins/2022-10-05-17-02-22.gh-issue-97943.LYAWlE.rst M Objects/funcobject.c diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-05-17-02-22.gh-issue-97943.LYAWlE.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-05-17-02-22.gh-issue-97943.LYAWlE.rst new file mode 100644 index 000000000000..9b4a421a9d47 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-05-17-02-22.gh-issue-97943.LYAWlE.rst @@ -0,0 +1,2 @@ +Bugfix: :func:`PyFunction_GetAnnotations` should return a borrowed +reference. It was returning a new reference. diff --git a/Objects/funcobject.c b/Objects/funcobject.c index 7f257a998698..ccc6d0b52eab 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -311,7 +311,6 @@ func_get_annotation_dict(PyFunctionObject *op) } Py_SETREF(op->func_annotations, ann_dict); } - Py_INCREF(op->func_annotations); assert(PyDict_Check(op->func_annotations)); return op->func_annotations; } @@ -543,7 +542,11 @@ func_get_annotations(PyFunctionObject *op, void *Py_UNUSED(ignored)) if (op->func_annotations == NULL) return NULL; } - return func_get_annotation_dict(op); + PyObject *d = func_get_annotation_dict(op); + if (d) { + Py_INCREF(d); + } + return d; } static int From webhook-mailer at python.org Thu Oct 6 15:24:25 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Thu, 06 Oct 2022 19:24:25 -0000 Subject: [Python-checkins] gh-86482: Document assignment expression need for ()s (#23291) Message-ID: https://github.com/python/cpython/commit/2b5f1360ead9aa72ae00de59edfd6c229d13933f commit: 2b5f1360ead9aa72ae00de59edfd6c229d13933f branch: main author: Terry Jan Reedy committer: JelleZijlstra date: 2022-10-06T12:24:17-07:00 summary: gh-86482: Document assignment expression need for ()s (#23291) Co-authored-by: Jelle Zijlstra files: A Misc/NEWS.d/next/Core and Builtins/2020-11-15-02-08-43.bpo-42316.LqdkWK.rst M Doc/reference/expressions.rst diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst index a6ca55dafe53..a661e03b1734 100644 --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -1766,6 +1766,13 @@ Or, when processing a file stream in chunks: while chunk := file.read(9000): process(chunk) +Assignment expressions must be surrounded by parentheses when used +as sub-expressions in slicing, conditional, lambda, +keyword-argument, and comprehension-if expressions +and in ``assert`` and ``with`` statements. +In all other places where they can be used, parentheses are not required, +including in ``if`` and ``while`` statements. + .. versionadded:: 3.8 See :pep:`572` for more details about assignment expressions. diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-11-15-02-08-43.bpo-42316.LqdkWK.rst b/Misc/NEWS.d/next/Core and Builtins/2020-11-15-02-08-43.bpo-42316.LqdkWK.rst new file mode 100644 index 000000000000..ea997800bf07 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2020-11-15-02-08-43.bpo-42316.LqdkWK.rst @@ -0,0 +1 @@ +Document some places where an assignment expression needs parentheses. From webhook-mailer at python.org Thu Oct 6 15:25:33 2022 From: webhook-mailer at python.org (jaraco) Date: Thu, 06 Oct 2022 19:25:33 -0000 Subject: [Python-checkins] gh-97781: Apply changes from importlib_metadata 5. (GH-97785) Message-ID: https://github.com/python/cpython/commit/8af04cdef202364541540ed67e204b71e2e759d0 commit: 8af04cdef202364541540ed67e204b71e2e759d0 branch: main author: Jason R. Coombs committer: jaraco date: 2022-10-06T15:25:24-04:00 summary: gh-97781: Apply changes from importlib_metadata 5. (GH-97785) * gh-97781: Apply changes from importlib_metadata 5. * Apply changes from upstream * Apply changes from upstream. files: A Misc/NEWS.d/next/Library/2022-10-03-13-25-19.gh-issue-97781.gCLLef.rst M Doc/library/importlib.metadata.rst M Lib/importlib/metadata/__init__.py M Lib/test/test_importlib/test_main.py M Lib/test/test_importlib/test_metadata_api.py diff --git a/Doc/library/importlib.metadata.rst b/Doc/library/importlib.metadata.rst index a1af7a754ba4..094c2688a8cd 100644 --- a/Doc/library/importlib.metadata.rst +++ b/Doc/library/importlib.metadata.rst @@ -13,21 +13,39 @@ **Source code:** :source:`Lib/importlib/metadata/__init__.py` -``importlib.metadata`` is a library that provides access to installed -package metadata, such as its entry points or its -top-level name. Built in part on Python's import system, this library +``importlib_metadata`` is a library that provides access to +the metadata of an installed `Distribution Package `_, +such as its entry points +or its top-level names (`Import Package `_\s, modules, if any). +Built in part on Python's import system, this library intends to replace similar functionality in the `entry point API`_ and `metadata API`_ of ``pkg_resources``. Along with :mod:`importlib.resources`, this package can eliminate the need to use the older and less efficient ``pkg_resources`` package. -By "installed package" we generally mean a third-party package installed into -Python's ``site-packages`` directory via tools such as `pip -`_. Specifically, -it means a package with either a discoverable ``dist-info`` or ``egg-info`` -directory, and metadata defined by :pep:`566` or its older specifications. -By default, package metadata can live on the file system or in zip archives on +``importlib_metadata`` operates on third-party *distribution packages* +installed into Python's ``site-packages`` directory via tools such as +`pip `_. +Specifically, it works with distributions with discoverable +``dist-info`` or ``egg-info`` directories, +and metadata defined by the `Core metadata specifications `_. + +.. important:: + + These are *not* necessarily equivalent to or correspond 1:1 with + the top-level *import package* names + that can be imported inside Python code. + One *distribution package* can contain multiple *import packages* + (and single modules), + and one top-level *import package* + may map to multiple *distribution packages* + if it is a namespace package. + You can use :ref:`package_distributions() ` + to get a mapping between them. + +By default, distribution metadata can live on the file system +or in zip archives on :data:`sys.path`. Through an extension mechanism, the metadata can live almost anywhere. @@ -37,12 +55,19 @@ anywhere. https://importlib-metadata.readthedocs.io/ The documentation for ``importlib_metadata``, which supplies a backport of ``importlib.metadata``. + This includes an `API reference + `__ + for this module's classes and functions, + as well as a `migration guide + `__ + for existing users of ``pkg_resources``. Overview ======== -Let's say you wanted to get the version string for a package you've installed +Let's say you wanted to get the version string for a +`Distribution Package `_ you've installed using ``pip``. We start by creating a virtual environment and installing something into it: @@ -151,11 +176,10 @@ for more information on entry points, their definition, and usage. The "selectable" entry points were introduced in ``importlib_metadata`` 3.6 and Python 3.10. Prior to those changes, ``entry_points`` accepted no parameters and always returned a dictionary of entry points, keyed -by group. For compatibility, if no parameters are passed to entry_points, -a ``SelectableGroups`` object is returned, implementing that dict -interface. In the future, calling ``entry_points`` with no parameters -will return an ``EntryPoints`` object. Users should rely on the selection -interface to retrieve entry points by group. +by group. With ``importlib_metadata`` 5.0 and Python 3.12, +``entry_points`` always returns an ``EntryPoints`` object. See +`backports.entry_points_selectable `_ +for compatibility options. .. _metadata: @@ -163,7 +187,8 @@ interface to retrieve entry points by group. Distribution metadata --------------------- -Every distribution includes some metadata, which you can extract using the +Every `Distribution Package `_ includes some metadata, +which you can extract using the ``metadata()`` function:: >>> wheel_metadata = metadata('wheel') # doctest: +SKIP @@ -201,7 +226,8 @@ all the metadata in a JSON-compatible form per :PEP:`566`:: Distribution versions --------------------- -The ``version()`` function is the quickest way to get a distribution's version +The ``version()`` function is the quickest way to get a +`Distribution Package `_'s version number, as a string:: >>> version('wheel') # doctest: +SKIP @@ -214,7 +240,8 @@ Distribution files ------------------ You can also get the full set of files contained within a distribution. The -``files()`` function takes a distribution package name and returns all of the +``files()`` function takes a `Distribution Package `_ name +and returns all of the files installed by this distribution. Each file object returned is a ``PackagePath``, a :class:`pathlib.PurePath` derived object with additional ``dist``, ``size``, and ``hash`` properties as indicated by the metadata. For example:: @@ -259,19 +286,24 @@ distribution is not known to have the metadata present. Distribution requirements ------------------------- -To get the full set of requirements for a distribution, use the ``requires()`` +To get the full set of requirements for a `Distribution Package `_, +use the ``requires()`` function:: >>> requires('wheel') # doctest: +SKIP ["pytest (>=3.0.0) ; extra == 'test'", "pytest-cov ; extra == 'test'"] -Package distributions ---------------------- +.. _package-distributions: +.. _import-distribution-package-mapping: + +Mapping import to distribution packages +--------------------------------------- -A convenience method to resolve the distribution or -distributions (in the case of a namespace package) for top-level -Python packages or modules:: +A convenience method to resolve the `Distribution Package `_ +name (or names, in the case of a namespace package) +that provide each importable top-level +Python module or `Import Package `_:: >>> packages_distributions() {'importlib_metadata': ['importlib-metadata'], 'yaml': ['PyYAML'], 'jaraco': ['jaraco.classes', 'jaraco.functools'], ...} @@ -285,7 +317,8 @@ Distributions While the above API is the most common and convenient usage, you can get all of that information from the ``Distribution`` class. A ``Distribution`` is an -abstract object that represents the metadata for a Python package. You can +abstract object that represents the metadata for +a Python `Distribution Package `_. You can get the ``Distribution`` instance:: >>> from importlib.metadata import distribution # doctest: +SKIP @@ -305,14 +338,16 @@ instance:: >>> dist.metadata['License'] # doctest: +SKIP 'MIT' -The full set of available metadata is not described here. See :pep:`566` -for additional details. +The full set of available metadata is not described here. +See the `Core metadata specifications `_ for additional details. Distribution Discovery ====================== -By default, this package provides built-in support for discovery of metadata for file system and zip file packages. This metadata finder search defaults to ``sys.path``, but varies slightly in how it interprets those values from how other import machinery does. In particular: +By default, this package provides built-in support for discovery of metadata +for file system and zip file `Distribution Package `_\s. +This metadata finder search defaults to ``sys.path``, but varies slightly in how it interprets those values from how other import machinery does. In particular: - ``importlib.metadata`` does not honor :class:`bytes` objects on ``sys.path``. - ``importlib.metadata`` will incidentally honor :py:class:`pathlib.Path` objects on ``sys.path`` even though such values will be ignored for imports. @@ -321,15 +356,18 @@ By default, this package provides built-in support for discovery of metadata for Extending the search algorithm ============================== -Because package metadata is not available through :data:`sys.path` searches, or -package loaders directly, the metadata for a package is found through import -system :ref:`finders `. To find a distribution package's metadata, +Because `Distribution Package `_ metadata +is not available through :data:`sys.path` searches, or +package loaders directly, +the metadata for a distribution is found through import +system `finders`_. To find a distribution package's metadata, ``importlib.metadata`` queries the list of :term:`meta path finders ` on :data:`sys.meta_path`. -The default ``PathFinder`` for Python includes a hook that calls into -``importlib.metadata.MetadataPathFinder`` for finding distributions -loaded from typical file-system-based paths. +By default ``importlib_metadata`` installs a finder for distribution packages +found on the file system. +This finder doesn't actually find any *distributions*, +but it can find their metadata. The abstract class :py:class:`importlib.abc.MetaPathFinder` defines the interface expected of finders by Python's import system. @@ -358,4 +396,4 @@ a custom finder, return instances of this derived ``Distribution`` in the .. _`entry point API`: https://setuptools.readthedocs.io/en/latest/pkg_resources.html#entry-points .. _`metadata API`: https://setuptools.readthedocs.io/en/latest/pkg_resources.html#metadata-api -.. _`importlib_resources`: https://importlib-resources.readthedocs.io/en/latest/index.html +.. _`finders`: https://docs.python.org/3/reference/import.html#finders-and-loaders diff --git a/Lib/importlib/metadata/__init__.py b/Lib/importlib/metadata/__init__.py index b01de145c336..40ab1a1aaac3 100644 --- a/Lib/importlib/metadata/__init__.py +++ b/Lib/importlib/metadata/__init__.py @@ -24,7 +24,7 @@ from importlib import import_module from importlib.abc import MetaPathFinder from itertools import starmap -from typing import List, Mapping, Optional, Union +from typing import List, Mapping, Optional __all__ = [ @@ -134,6 +134,7 @@ class DeprecatedTuple: 1 """ + # Do not remove prior to 2023-05-01 or Python 3.13 _warn = functools.partial( warnings.warn, "EntryPoint tuple interface is deprecated. Access members by name.", @@ -184,6 +185,10 @@ class EntryPoint(DeprecatedTuple): following the attr, and following any extras. """ + name: str + value: str + group: str + dist: Optional['Distribution'] = None def __init__(self, name, value, group): @@ -218,17 +223,6 @@ def _for(self, dist): vars(self).update(dist=dist) return self - def __iter__(self): - """ - Supply iter so one may construct dicts of EntryPoints by name. - """ - msg = ( - "Construction of dict of EntryPoints is deprecated in " - "favor of EntryPoints." - ) - warnings.warn(msg, DeprecationWarning) - return iter((self.name, self)) - def matches(self, **params): """ EntryPoint matches the given parameters. @@ -274,77 +268,7 @@ def __hash__(self): return hash(self._key()) -class DeprecatedList(list): - """ - Allow an otherwise immutable object to implement mutability - for compatibility. - - >>> recwarn = getfixture('recwarn') - >>> dl = DeprecatedList(range(3)) - >>> dl[0] = 1 - >>> dl.append(3) - >>> del dl[3] - >>> dl.reverse() - >>> dl.sort() - >>> dl.extend([4]) - >>> dl.pop(-1) - 4 - >>> dl.remove(1) - >>> dl += [5] - >>> dl + [6] - [1, 2, 5, 6] - >>> dl + (6,) - [1, 2, 5, 6] - >>> dl.insert(0, 0) - >>> dl - [0, 1, 2, 5] - >>> dl == [0, 1, 2, 5] - True - >>> dl == (0, 1, 2, 5) - True - >>> len(recwarn) - 1 - """ - - __slots__ = () - - _warn = functools.partial( - warnings.warn, - "EntryPoints list interface is deprecated. Cast to list if needed.", - DeprecationWarning, - stacklevel=2, - ) - - def _wrap_deprecated_method(method_name: str): # type: ignore - def wrapped(self, *args, **kwargs): - self._warn() - return getattr(super(), method_name)(*args, **kwargs) - - return method_name, wrapped - - locals().update( - map( - _wrap_deprecated_method, - '__setitem__ __delitem__ append reverse extend pop remove ' - '__iadd__ insert sort'.split(), - ) - ) - - def __add__(self, other): - if not isinstance(other, tuple): - self._warn() - other = tuple(other) - return self.__class__(tuple(self) + other) - - def __eq__(self, other): - if not isinstance(other, tuple): - self._warn() - other = tuple(other) - - return tuple(self).__eq__(other) - - -class EntryPoints(DeprecatedList): +class EntryPoints(tuple): """ An immutable collection of selectable EntryPoint objects. """ @@ -355,14 +279,6 @@ def __getitem__(self, name): # -> EntryPoint: """ Get the EntryPoint in self matching name. """ - if isinstance(name, int): - warnings.warn( - "Accessing entry points by index is deprecated. " - "Cast to tuple if needed.", - DeprecationWarning, - stacklevel=2, - ) - return super().__getitem__(name) try: return next(iter(self.select(name=name))) except StopIteration: @@ -386,10 +302,6 @@ def names(self): def groups(self): """ Return the set of all groups of all entry points. - - For coverage while SelectableGroups is present. - >>> EntryPoints().groups - set() """ return {ep.group for ep in self} @@ -405,101 +317,6 @@ def _from_text(text): ) -class Deprecated: - """ - Compatibility add-in for mapping to indicate that - mapping behavior is deprecated. - - >>> recwarn = getfixture('recwarn') - >>> class DeprecatedDict(Deprecated, dict): pass - >>> dd = DeprecatedDict(foo='bar') - >>> dd.get('baz', None) - >>> dd['foo'] - 'bar' - >>> list(dd) - ['foo'] - >>> list(dd.keys()) - ['foo'] - >>> 'foo' in dd - True - >>> list(dd.values()) - ['bar'] - >>> len(recwarn) - 1 - """ - - _warn = functools.partial( - warnings.warn, - "SelectableGroups dict interface is deprecated. Use select.", - DeprecationWarning, - stacklevel=2, - ) - - def __getitem__(self, name): - self._warn() - return super().__getitem__(name) - - def get(self, name, default=None): - self._warn() - return super().get(name, default) - - def __iter__(self): - self._warn() - return super().__iter__() - - def __contains__(self, *args): - self._warn() - return super().__contains__(*args) - - def keys(self): - self._warn() - return super().keys() - - def values(self): - self._warn() - return super().values() - - -class SelectableGroups(Deprecated, dict): - """ - A backward- and forward-compatible result from - entry_points that fully implements the dict interface. - """ - - @classmethod - def load(cls, eps): - by_group = operator.attrgetter('group') - ordered = sorted(eps, key=by_group) - grouped = itertools.groupby(ordered, by_group) - return cls((group, EntryPoints(eps)) for group, eps in grouped) - - @property - def _all(self): - """ - Reconstruct a list of all entrypoints from the groups. - """ - groups = super(Deprecated, self).values() - return EntryPoints(itertools.chain.from_iterable(groups)) - - @property - def groups(self): - return self._all.groups - - @property - def names(self): - """ - for coverage: - >>> SelectableGroups().names - set() - """ - return self._all.names - - def select(self, **params): - if not params: - return self - return self._all.select(**params) - - class PackagePath(pathlib.PurePosixPath): """A reference to a path in a package""" @@ -1013,27 +830,19 @@ def version(distribution_name): """ -def entry_points(**params) -> Union[EntryPoints, SelectableGroups]: +def entry_points(**params) -> EntryPoints: """Return EntryPoint objects for all installed packages. Pass selection parameters (group or name) to filter the result to entry points matching those properties (see EntryPoints.select()). - For compatibility, returns ``SelectableGroups`` object unless - selection parameters are supplied. In the future, this function - will return ``EntryPoints`` instead of ``SelectableGroups`` - even when no selection parameters are supplied. - - For maximum future compatibility, pass selection parameters - or invoke ``.select`` with parameters on the result. - - :return: EntryPoints or SelectableGroups for all installed packages. + :return: EntryPoints for all installed packages. """ eps = itertools.chain.from_iterable( dist.entry_points for dist in _unique(distributions()) ) - return SelectableGroups.load(eps).select(**params) + return EntryPoints(eps).select(**params) def files(distribution_name): diff --git a/Lib/test/test_importlib/test_main.py b/Lib/test/test_importlib/test_main.py index d9d067c4b23d..30b68b6ae7d8 100644 --- a/Lib/test/test_importlib/test_main.py +++ b/Lib/test/test_importlib/test_main.py @@ -1,8 +1,6 @@ import re -import json import pickle import unittest -import warnings import importlib.metadata try: @@ -260,14 +258,6 @@ def test_hashable(self): """EntryPoints should be hashable""" hash(self.ep) - def test_json_dump(self): - """ - json should not expect to be able to dump an EntryPoint - """ - with self.assertRaises(Exception): - with warnings.catch_warnings(record=True): - json.dumps(self.ep) - def test_module(self): assert self.ep.module == 'value' diff --git a/Lib/test/test_importlib/test_metadata_api.py b/Lib/test/test_importlib/test_metadata_api.py index 69c78e9820c0..71c47e62d271 100644 --- a/Lib/test/test_importlib/test_metadata_api.py +++ b/Lib/test/test_importlib/test_metadata_api.py @@ -124,62 +124,6 @@ def test_entry_points_missing_name(self): def test_entry_points_missing_group(self): assert entry_points(group='missing') == () - def test_entry_points_dict_construction(self): - """ - Prior versions of entry_points() returned simple lists and - allowed casting those lists into maps by name using ``dict()``. - Capture this now deprecated use-case. - """ - with suppress_known_deprecation() as caught: - eps = dict(entry_points(group='entries')) - - assert 'main' in eps - assert eps['main'] == entry_points(group='entries')['main'] - - # check warning - expected = next(iter(caught)) - assert expected.category is DeprecationWarning - assert "Construction of dict of EntryPoints is deprecated" in str(expected) - - def test_entry_points_by_index(self): - """ - Prior versions of Distribution.entry_points would return a - tuple that allowed access by index. - Capture this now deprecated use-case - See python/importlib_metadata#300 and bpo-44246. - """ - eps = distribution('distinfo-pkg').entry_points - with suppress_known_deprecation() as caught: - eps[0] - - # check warning - expected = next(iter(caught)) - assert expected.category is DeprecationWarning - assert "Accessing entry points by index is deprecated" in str(expected) - - def test_entry_points_groups_getitem(self): - """ - Prior versions of entry_points() returned a dict. Ensure - that callers using '.__getitem__()' are supported but warned to - migrate. - """ - with suppress_known_deprecation(): - entry_points()['entries'] == entry_points(group='entries') - - with self.assertRaises(KeyError): - entry_points()['missing'] - - def test_entry_points_groups_get(self): - """ - Prior versions of entry_points() returned a dict. Ensure - that callers using '.get()' are supported but warned to - migrate. - """ - with suppress_known_deprecation(): - entry_points().get('missing', 'default') == 'default' - entry_points().get('entries', 'default') == entry_points()['entries'] - entry_points().get('missing', ()) == () - def test_entry_points_allows_no_attributes(self): ep = entry_points().select(group='entries', name='main') with self.assertRaises(AttributeError): diff --git a/Misc/NEWS.d/next/Library/2022-10-03-13-25-19.gh-issue-97781.gCLLef.rst b/Misc/NEWS.d/next/Library/2022-10-03-13-25-19.gh-issue-97781.gCLLef.rst new file mode 100644 index 000000000000..8c36d9c3afd2 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-03-13-25-19.gh-issue-97781.gCLLef.rst @@ -0,0 +1,5 @@ +Removed deprecated interfaces in ``importlib.metadata`` (entry points +accessed as dictionary, implicit dictionary construction of sequence of +``EntryPoint`` objects, mutablility of ``EntryPoints`` result, access of +entry point by index). ``entry_points`` now has a simpler, more +straightforward API (returning ``EntryPoints``). From webhook-mailer at python.org Thu Oct 6 15:32:45 2022 From: webhook-mailer at python.org (miss-islington) Date: Thu, 06 Oct 2022 19:32:45 -0000 Subject: [Python-checkins] gh-86482: Document assignment expression need for ()s (GH-23291) Message-ID: https://github.com/python/cpython/commit/4aa2ebc01e63cf53c2c152eb4e0ea82bc932c3d5 commit: 4aa2ebc01e63cf53c2c152eb4e0ea82bc932c3d5 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-06T12:32:39-07:00 summary: gh-86482: Document assignment expression need for ()s (GH-23291) Co-authored-by: Jelle Zijlstra (cherry picked from commit 2b5f1360ead9aa72ae00de59edfd6c229d13933f) Co-authored-by: Terry Jan Reedy files: A Misc/NEWS.d/next/Core and Builtins/2020-11-15-02-08-43.bpo-42316.LqdkWK.rst M Doc/reference/expressions.rst diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst index 6d23e473cdcd..fd43e6c161f7 100644 --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -1755,6 +1755,13 @@ Or, when processing a file stream in chunks: while chunk := file.read(9000): process(chunk) +Assignment expressions must be surrounded by parentheses when used +as sub-expressions in slicing, conditional, lambda, +keyword-argument, and comprehension-if expressions +and in ``assert`` and ``with`` statements. +In all other places where they can be used, parentheses are not required, +including in ``if`` and ``while`` statements. + .. versionadded:: 3.8 See :pep:`572` for more details about assignment expressions. diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-11-15-02-08-43.bpo-42316.LqdkWK.rst b/Misc/NEWS.d/next/Core and Builtins/2020-11-15-02-08-43.bpo-42316.LqdkWK.rst new file mode 100644 index 000000000000..ea997800bf07 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2020-11-15-02-08-43.bpo-42316.LqdkWK.rst @@ -0,0 +1 @@ +Document some places where an assignment expression needs parentheses. From webhook-mailer at python.org Thu Oct 6 15:33:28 2022 From: webhook-mailer at python.org (miss-islington) Date: Thu, 06 Oct 2022 19:33:28 -0000 Subject: [Python-checkins] gh-86482: Document assignment expression need for ()s (GH-23291) Message-ID: https://github.com/python/cpython/commit/b7487dff302767bd2aed92df04d440f15c2eca14 commit: b7487dff302767bd2aed92df04d440f15c2eca14 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-06T12:33:23-07:00 summary: gh-86482: Document assignment expression need for ()s (GH-23291) Co-authored-by: Jelle Zijlstra (cherry picked from commit 2b5f1360ead9aa72ae00de59edfd6c229d13933f) Co-authored-by: Terry Jan Reedy files: A Misc/NEWS.d/next/Core and Builtins/2020-11-15-02-08-43.bpo-42316.LqdkWK.rst M Doc/reference/expressions.rst diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst index 0a9e7141d397..1e76b25f4880 100644 --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -1748,6 +1748,13 @@ Or, when processing a file stream in chunks: while chunk := file.read(9000): process(chunk) +Assignment expressions must be surrounded by parentheses when used +as sub-expressions in slicing, conditional, lambda, +keyword-argument, and comprehension-if expressions +and in ``assert`` and ``with`` statements. +In all other places where they can be used, parentheses are not required, +including in ``if`` and ``while`` statements. + .. versionadded:: 3.8 See :pep:`572` for more details about assignment expressions. diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-11-15-02-08-43.bpo-42316.LqdkWK.rst b/Misc/NEWS.d/next/Core and Builtins/2020-11-15-02-08-43.bpo-42316.LqdkWK.rst new file mode 100644 index 000000000000..ea997800bf07 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2020-11-15-02-08-43.bpo-42316.LqdkWK.rst @@ -0,0 +1 @@ +Document some places where an assignment expression needs parentheses. From webhook-mailer at python.org Thu Oct 6 16:03:43 2022 From: webhook-mailer at python.org (miss-islington) Date: Thu, 06 Oct 2022 20:03:43 -0000 Subject: [Python-checkins] gh-97943: PyFunction_GetAnnotations should return a borrowed reference. (GH-97949) Message-ID: https://github.com/python/cpython/commit/33cf0a604c111fc291dffaa0fb104336cb7d0add commit: 33cf0a604c111fc291dffaa0fb104336cb7d0add branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-06T13:03:32-07:00 summary: gh-97943: PyFunction_GetAnnotations should return a borrowed reference. (GH-97949) (cherry picked from commit 6bfb0be80486c614cd60dce44c9fe7b3e6c76e3b) Co-authored-by: larryhastings files: A Misc/NEWS.d/next/Core and Builtins/2022-10-05-17-02-22.gh-issue-97943.LYAWlE.rst M Objects/funcobject.c diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-05-17-02-22.gh-issue-97943.LYAWlE.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-05-17-02-22.gh-issue-97943.LYAWlE.rst new file mode 100644 index 000000000000..9b4a421a9d47 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-05-17-02-22.gh-issue-97943.LYAWlE.rst @@ -0,0 +1,2 @@ +Bugfix: :func:`PyFunction_GetAnnotations` should return a borrowed +reference. It was returning a new reference. diff --git a/Objects/funcobject.c b/Objects/funcobject.c index 32b4155c03e6..63074634747f 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -300,7 +300,6 @@ func_get_annotation_dict(PyFunctionObject *op) } Py_SETREF(op->func_annotations, ann_dict); } - Py_INCREF(op->func_annotations); assert(PyDict_Check(op->func_annotations)); return op->func_annotations; } @@ -532,7 +531,11 @@ func_get_annotations(PyFunctionObject *op, void *Py_UNUSED(ignored)) if (op->func_annotations == NULL) return NULL; } - return func_get_annotation_dict(op); + PyObject *d = func_get_annotation_dict(op); + if (d) { + Py_INCREF(d); + } + return d; } static int From webhook-mailer at python.org Thu Oct 6 16:30:01 2022 From: webhook-mailer at python.org (warsaw) Date: Thu, 06 Oct 2022 20:30:01 -0000 Subject: [Python-checkins] Add Pynche's move to the What's new in 3.11 (#97974) Message-ID: https://github.com/python/cpython/commit/effc25f7f25ae1ac053415addc584b050c022dcb commit: effc25f7f25ae1ac053415addc584b050c022dcb branch: main author: Barry Warsaw committer: warsaw date: 2022-10-06T13:29:52-07:00 summary: Add Pynche's move to the What's new in 3.11 (#97974) * Add Pynche's move to the What's new in 3.11 * Update Doc/whatsnew/3.11.rst Co-authored-by: Ezio Melotti Co-authored-by: Ezio Melotti files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index dafbbb673f0e..6103da76a34d 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1667,6 +1667,10 @@ Removed Python's test suite." (Contributed by Victor Stinner in :issue:`46852`.) +* Pynche --- The Pythonically Natural Color and Hue Editor --- has been moved out + of ``Tools/scripts`` and is `being developed independently + `_ from the Python source tree. + Porting to Python 3.11 ====================== From webhook-mailer at python.org Thu Oct 6 16:36:02 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Thu, 06 Oct 2022 20:36:02 -0000 Subject: [Python-checkins] gh-94590: add signatures to operator itemgetter, attrgetter, methodcaller (#94591) Message-ID: https://github.com/python/cpython/commit/1c4728cc299953c61e0e1cdb077eefccfd555b87 commit: 1c4728cc299953c61e0e1cdb077eefccfd555b87 branch: main author: Erik Welch committer: JelleZijlstra date: 2022-10-06T13:35:53-07:00 summary: gh-94590: add signatures to operator itemgetter, attrgetter, methodcaller (#94591) These were intentionally skipped when operator was updated to use the argument clinic: https://github.com/python/cpython/issues/64385#issuecomment-1093641466 However, by not using the argument clinic, they missed out on getting signatures. This is a narrow PR to update the docstrings so that `__text_signature__` can be extracted from them. Updating to use the argument clinic is beyond scope. `methodcaller` uses `*args, **kwargs` to match variadic names used elsewhere, including in `operator.call`. files: M Modules/_operator.c diff --git a/Modules/_operator.c b/Modules/_operator.c index 51ca74eeeaee..77eabdb57af9 100644 --- a/Modules/_operator.c +++ b/Modules/_operator.c @@ -1162,8 +1162,7 @@ static PyMemberDef itemgetter_members[] = { }; PyDoc_STRVAR(itemgetter_doc, -"itemgetter(item, ...) --> itemgetter object\n\ -\n\ +"itemgetter(item, /, *items)\n--\n\n\ Return a callable object that fetches the given item(s) from its operand.\n\ After f = itemgetter(2), the call f(r) returns r[2].\n\ After g = itemgetter(2, 5, 3), the call g(r) returns (r[2], r[5], r[3])"); @@ -1523,8 +1522,7 @@ static PyMemberDef attrgetter_members[] = { }; PyDoc_STRVAR(attrgetter_doc, -"attrgetter(attr, ...) --> attrgetter object\n\ -\n\ +"attrgetter(attr, /, *attrs)\n--\n\n\ Return a callable object that fetches the given attribute(s) from its operand.\n\ After f = attrgetter('name'), the call f(r) returns r.name.\n\ After g = attrgetter('name', 'date'), the call g(r) returns (r.name, r.date).\n\ @@ -1775,8 +1773,7 @@ static PyMethodDef methodcaller_methods[] = { {NULL} }; PyDoc_STRVAR(methodcaller_doc, -"methodcaller(name, ...) --> methodcaller object\n\ -\n\ +"methodcaller(name, /, *args, **kwargs)\n--\n\n\ Return a callable object that calls the given method on its operand.\n\ After f = methodcaller('name'), the call f(r) returns r.name().\n\ After g = methodcaller('name', 'date', foo=1), the call g(r) returns\n\ From webhook-mailer at python.org Thu Oct 6 16:47:38 2022 From: webhook-mailer at python.org (warsaw) Date: Thu, 06 Oct 2022 20:47:38 -0000 Subject: [Python-checkins] [3.11] Backport effc25f 3.11 (#97991) Message-ID: https://github.com/python/cpython/commit/930adfa503e93134551f0e32b5abcf580e6285a5 commit: 930adfa503e93134551f0e32b5abcf580e6285a5 branch: 3.11 author: Barry Warsaw committer: warsaw date: 2022-10-06T13:47:33-07:00 summary: [3.11] Backport effc25f 3.11 (#97991) * Add Pynche's move to the What's new in 3.11 (#97974) * Add Pynche's move to the What's new in 3.11 * Update Doc/whatsnew/3.11.rst Co-authored-by: Ezio Melotti Co-authored-by: Ezio Melotti (cherry picked from commit effc25f7f25ae1ac053415addc584b050c022dcb) * [3.11] Add Pynche's move to the What's new in 3.11 (GH-97974) * Add Pynche's move to the What's new in 3.11 * Update Doc/whatsnew/3.11.rst Co-authored-by: Ezio Melotti Co-authored-by: Ezio Melotti . (cherry picked from commit effc25f7f25ae1ac053415addc584b050c022dcb) Co-authored-by: Barry Warsaw files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 1e8fb14b3cd4..24ee491d28e2 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1682,6 +1682,9 @@ Removed (and corresponding ``EXPERIMENTAL_ISOLATED_SUBINTERPRETERS``) have been removed. +* Pynche --- The Pythonically Natural Color and Hue Editor --- has been moved out + of ``Tools/scripts`` and is `being developed independently + `_ from the Python source tree. Porting to Python 3.11 ====================== From webhook-mailer at python.org Thu Oct 6 16:58:54 2022 From: webhook-mailer at python.org (ned-deily) Date: Thu, 06 Oct 2022 20:58:54 -0000 Subject: [Python-checkins] Docs: pin sphinx-lint (GH-97992) Message-ID: https://github.com/python/cpython/commit/993de50e44ce275ad96857e73e144c556eea68b0 commit: 993de50e44ce275ad96857e73e144c556eea68b0 branch: main author: Hugo van Kemenade committer: ned-deily date: 2022-10-06T13:58:41-07:00 summary: Docs: pin sphinx-lint (GH-97992) files: M Doc/requirements.txt diff --git a/Doc/requirements.txt b/Doc/requirements.txt index be058733fcf4..960ac54d7b91 100644 --- a/Doc/requirements.txt +++ b/Doc/requirements.txt @@ -10,7 +10,7 @@ blurb # sphinx-lint 0.6.2 yields many default role errors due to the new regular # expression used for default role detection, so we don't use the version # until the errors are fixed. -sphinx-lint<1,!=0.6.2 +sphinx-lint==0.6.1 # The theme used by the documentation is stored separately, so we need # to install that as well. From webhook-mailer at python.org Thu Oct 6 17:01:15 2022 From: webhook-mailer at python.org (brettcannon) Date: Thu, 06 Oct 2022 21:01:15 -0000 Subject: [Python-checkins] gh-97850: Remove the open issues section from the import reference (#97935) Message-ID: https://github.com/python/cpython/commit/f8edc6ff531bb98858185857513371f14519ed1d commit: f8edc6ff531bb98858185857513371f14519ed1d branch: main author: Brett Cannon committer: brettcannon date: 2022-10-06T14:01:06-07:00 summary: gh-97850: Remove the open issues section from the import reference (#97935) Remove the open issues section from the import reference Tracking in https://github.com/python/cpython/issues/97850 instead. files: M Doc/reference/import.rst diff --git a/Doc/reference/import.rst b/Doc/reference/import.rst index 58f4ef897bdb..b7a53cd0886f 100644 --- a/Doc/reference/import.rst +++ b/Doc/reference/import.rst @@ -1025,25 +1025,6 @@ and ``__main__.__spec__`` is set accordingly, they're still considered to populate the ``__main__`` namespace, and not during normal import. -Open issues -=========== - -XXX It would be really nice to have a diagram. - -XXX * (import_machinery.rst) how about a section devoted just to the -attributes of modules and packages, perhaps expanding upon or supplanting the -related entries in the data model reference page? - -XXX runpy, pkgutil, et al in the library manual should all get "See Also" -links at the top pointing to the new import system section. - -XXX Add more explanation regarding the different ways in which -``__main__`` is initialized? - -XXX Add more info on ``__main__`` quirks/pitfalls (i.e. copy from -:pep:`395`). - - References ========== From webhook-mailer at python.org Thu Oct 6 17:01:32 2022 From: webhook-mailer at python.org (ned-deily) Date: Thu, 06 Oct 2022 21:01:32 -0000 Subject: [Python-checkins] [3.11] Docs: pin sphinx-lint (GH-97992) (GH-97993) Message-ID: https://github.com/python/cpython/commit/cd05379a7dbabf17602eebdd4fab9e489fde7568 commit: cd05379a7dbabf17602eebdd4fab9e489fde7568 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ned-deily date: 2022-10-06T14:01:27-07:00 summary: [3.11] Docs: pin sphinx-lint (GH-97992) (GH-97993) files: M Doc/requirements.txt diff --git a/Doc/requirements.txt b/Doc/requirements.txt index be058733fcf4..960ac54d7b91 100644 --- a/Doc/requirements.txt +++ b/Doc/requirements.txt @@ -10,7 +10,7 @@ blurb # sphinx-lint 0.6.2 yields many default role errors due to the new regular # expression used for default role detection, so we don't use the version # until the errors are fixed. -sphinx-lint<1,!=0.6.2 +sphinx-lint==0.6.1 # The theme used by the documentation is stored separately, so we need # to install that as well. From webhook-mailer at python.org Thu Oct 6 17:07:40 2022 From: webhook-mailer at python.org (miss-islington) Date: Thu, 06 Oct 2022 21:07:40 -0000 Subject: [Python-checkins] gh-97850: Remove the open issues section from the import reference (GH-97935) Message-ID: https://github.com/python/cpython/commit/bc03bf42e70b111e4125bc6d08cd5943f8560c64 commit: bc03bf42e70b111e4125bc6d08cd5943f8560c64 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-06T14:07:34-07:00 summary: gh-97850: Remove the open issues section from the import reference (GH-97935) Remove the open issues section from the import reference Tracking in https://github.com/python/cpython/issues/97850 instead. (cherry picked from commit f8edc6ff531bb98858185857513371f14519ed1d) Co-authored-by: Brett Cannon files: M Doc/reference/import.rst diff --git a/Doc/reference/import.rst b/Doc/reference/import.rst index 92ae9fd3cf39..383797501397 100644 --- a/Doc/reference/import.rst +++ b/Doc/reference/import.rst @@ -1015,25 +1015,6 @@ and ``__main__.__spec__`` is set accordingly, they're still considered to populate the ``__main__`` namespace, and not during normal import. -Open issues -=========== - -XXX It would be really nice to have a diagram. - -XXX * (import_machinery.rst) how about a section devoted just to the -attributes of modules and packages, perhaps expanding upon or supplanting the -related entries in the data model reference page? - -XXX runpy, pkgutil, et al in the library manual should all get "See Also" -links at the top pointing to the new import system section. - -XXX Add more explanation regarding the different ways in which -``__main__`` is initialized? - -XXX Add more info on ``__main__`` quirks/pitfalls (i.e. copy from -:pep:`395`). - - References ========== From webhook-mailer at python.org Thu Oct 6 17:10:12 2022 From: webhook-mailer at python.org (miss-islington) Date: Thu, 06 Oct 2022 21:10:12 -0000 Subject: [Python-checkins] [3.11] gh-97850: Remove the open issues section from the import reference (GH-97935) (GH-97994) Message-ID: https://github.com/python/cpython/commit/ae2ab478205921cd2f006388c8300bc9272515f3 commit: ae2ab478205921cd2f006388c8300bc9272515f3 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-06T14:10:06-07:00 summary: [3.11] gh-97850: Remove the open issues section from the import reference (GH-97935) (GH-97994) Remove the open issues section from the import reference Tracking in https://github.com/python/cpython/issues/97850 instead. (cherry picked from commit f8edc6ff531bb98858185857513371f14519ed1d) Co-authored-by: Brett Cannon Automerge-Triggered-By: GH:brettcannon files: M Doc/reference/import.rst diff --git a/Doc/reference/import.rst b/Doc/reference/import.rst index 1e6b08f32a7a..0d8c02955008 100644 --- a/Doc/reference/import.rst +++ b/Doc/reference/import.rst @@ -1019,25 +1019,6 @@ and ``__main__.__spec__`` is set accordingly, they're still considered to populate the ``__main__`` namespace, and not during normal import. -Open issues -=========== - -XXX It would be really nice to have a diagram. - -XXX * (import_machinery.rst) how about a section devoted just to the -attributes of modules and packages, perhaps expanding upon or supplanting the -related entries in the data model reference page? - -XXX runpy, pkgutil, et al in the library manual should all get "See Also" -links at the top pointing to the new import system section. - -XXX Add more explanation regarding the different ways in which -``__main__`` is initialized? - -XXX Add more info on ``__main__`` quirks/pitfalls (i.e. copy from -:pep:`395`). - - References ========== From webhook-mailer at python.org Thu Oct 6 18:40:31 2022 From: webhook-mailer at python.org (brettcannon) Date: Thu, 06 Oct 2022 22:40:31 -0000 Subject: [Python-checkins] gh-65961: Do not rely solely on `__cached__` (GH-97990) Message-ID: https://github.com/python/cpython/commit/e1c4d56fdde28728c37de855edbb463fa0d7f95d commit: e1c4d56fdde28728c37de855edbb463fa0d7f95d branch: main author: Brett Cannon committer: brettcannon date: 2022-10-06T15:40:22-07:00 summary: gh-65961: Do not rely solely on `__cached__` (GH-97990) Make sure `__spec__.cached` (at minimum) can be used. files: A Lib/test/test_importlib/import_/test_helpers.py A Misc/NEWS.d/next/Library/2022-10-06-17-59-22.gh-issue-65961.SXlQnI.rst M Doc/c-api/import.rst M Doc/library/runpy.rst M Doc/whatsnew/3.12.rst M Lib/cProfile.py M Lib/importlib/_bootstrap_external.py M Lib/inspect.py M Lib/profile.py M Lib/test/test_inspect.py M Lib/test/test_pydoc.py diff --git a/Doc/c-api/import.rst b/Doc/c-api/import.rst index 0922956c607b..a51619db6d3d 100644 --- a/Doc/c-api/import.rst +++ b/Doc/c-api/import.rst @@ -150,6 +150,11 @@ Importing Modules See also :c:func:`PyImport_ExecCodeModuleEx` and :c:func:`PyImport_ExecCodeModuleWithPathnames`. + .. versionchanged:: 3.12 + The setting of :attr:`__cached__` and :attr:`__loader__` is + deprecated. See :class:`~importlib.machinery.ModuleSpec` for + alternatives. + .. c:function:: PyObject* PyImport_ExecCodeModuleEx(const char *name, PyObject *co, const char *pathname) @@ -167,6 +172,10 @@ Importing Modules .. versionadded:: 3.3 + .. versionchanged:: 3.12 + Setting :attr:`__cached__` is deprecated. See + :class:`~importlib.machinery.ModuleSpec` for alternatives. + .. c:function:: PyObject* PyImport_ExecCodeModuleWithPathnames(const char *name, PyObject *co, const char *pathname, const char *cpathname) diff --git a/Doc/library/runpy.rst b/Doc/library/runpy.rst index 26a4f1435214..501f4ddf5a3e 100644 --- a/Doc/library/runpy.rst +++ b/Doc/library/runpy.rst @@ -93,6 +93,11 @@ The :mod:`runpy` module provides two functions: run this way, as well as ensuring the real module name is always accessible as ``__spec__.name``. + .. versionchanged:: 3.12 + The setting of ``__cached__``, ``__loader__``, and + ``__package__`` are deprecated. See + :class:`~importlib.machinery.ModuleSpec` for alternatives. + .. function:: run_path(path_name, init_globals=None, run_name=None) .. index:: @@ -163,6 +168,10 @@ The :mod:`runpy` module provides two functions: case where ``__main__`` is imported from a valid sys.path entry rather than being executed directly. + .. versionchanged:: 3.12 + The setting of ``__cached__``, ``__loader__``, and + ``__package__`` are deprecated. + .. seealso:: :pep:`338` -- Executing modules as scripts diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 507ba3522146..d18c31fbe986 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -280,8 +280,8 @@ Pending Removal in Python 3.14 * Creating :c:data:`immutable types ` with mutable bases using the C API. -* ``__package__`` will cease to be set or taken into consideration by - the import system (:gh:`97879`). +* ``__package__`` and ``__cached__`` will cease to be set or taken + into consideration by the import system (:gh:`97879`). Pending Removal in Future Versions diff --git a/Lib/cProfile.py b/Lib/cProfile.py index 9fc978830208..f7000a8bfa0d 100755 --- a/Lib/cProfile.py +++ b/Lib/cProfile.py @@ -7,6 +7,7 @@ __all__ = ["run", "runctx", "Profile"] import _lsprof +import importlib.machinery import profile as _pyprofile # ____________________________________________________________ @@ -169,9 +170,12 @@ def main(): sys.path.insert(0, os.path.dirname(progname)) with open(progname, 'rb') as fp: code = compile(fp.read(), progname, 'exec') + spec = importlib.machinery.ModuleSpec(name='__main__', loader=None, + origin=progname) globs = { - '__file__': progname, - '__name__': '__main__', + '__spec__': spec, + '__file__': spec.origin, + '__name__': spec.name, '__package__': None, '__cached__': None, } diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index b3c31b9659d8..efda49382540 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -182,6 +182,16 @@ def _path_isabs(path): return path.startswith(path_separators) +def _path_abspath(path): + """Replacement for os.path.abspath.""" + if not _path_isabs(path): + for sep in path_separators: + path = path.removeprefix(f".{sep}") + return _path_join(_os.getcwd(), path) + else: + return path + + def _write_atomic(path, data, mode=0o666): """Best-effort function to write data to a path atomically. Be prepared to handle a FileExistsError if concurrent writing of the @@ -494,8 +504,7 @@ def cache_from_source(path, debug_override=None, *, optimization=None): # make it absolute (`C:\Somewhere\Foo\Bar`), then make it root-relative # (`Somewhere\Foo\Bar`), so we end up placing the bytecode file in an # unambiguous `C:\Bytecode\Somewhere\Foo\Bar\`. - if not _path_isabs(head): - head = _path_join(_os.getcwd(), head) + head = _path_abspath(head) # Strip initial drive from a Windows path. We know we have an absolute # path here, so the second part of the check rules out a POSIX path that @@ -808,11 +817,10 @@ def spec_from_file_location(name, location=None, *, loader=None, pass else: location = _os.fspath(location) - if not _path_isabs(location): - try: - location = _path_join(_os.getcwd(), location) - except OSError: - pass + try: + location = _path_abspath(location) + except OSError: + pass # If the location is on the filesystem, but doesn't actually exist, # we could return None here, indicating that the location is not @@ -1564,10 +1572,8 @@ def __init__(self, path, *loader_details): # Base (directory) path if not path or path == '.': self.path = _os.getcwd() - elif not _path_isabs(path): - self.path = _path_join(_os.getcwd(), path) else: - self.path = path + self.path = _path_abspath(path) self._path_mtime = -1 self._path_cache = set() self._relaxed_path_cache = set() @@ -1717,6 +1723,8 @@ def _fix_up_module(ns, name, pathname, cpathname=None): loader = SourceFileLoader(name, pathname) if not spec: spec = spec_from_file_location(name, pathname, loader=loader) + if cpathname: + spec.cached = _path_abspath(cpathname) try: ns['__spec__'] = spec ns['__loader__'] = loader diff --git a/Lib/inspect.py b/Lib/inspect.py index 498ee7ab9eaf..8a107a894909 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -281,30 +281,15 @@ def get_annotations(obj, *, globals=None, locals=None, eval_str=False): # ----------------------------------------------------------- type-checking def ismodule(object): - """Return true if the object is a module. - - Module objects provide these attributes: - __cached__ pathname to byte compiled file - __doc__ documentation string - __file__ filename (missing for built-in modules)""" + """Return true if the object is a module.""" return isinstance(object, types.ModuleType) def isclass(object): - """Return true if the object is a class. - - Class objects provide these attributes: - __doc__ documentation string - __module__ name of module in which this class was defined""" + """Return true if the object is a class.""" return isinstance(object, type) def ismethod(object): - """Return true if the object is an instance method. - - Instance method objects provide these attributes: - __doc__ documentation string - __name__ name with which this method was defined - __func__ function object containing implementation of method - __self__ instance to which this method is bound""" + """Return true if the object is an instance method.""" return isinstance(object, types.MethodType) def ismethoddescriptor(object): diff --git a/Lib/profile.py b/Lib/profile.py index d8599fb4eebd..453e56285c51 100755 --- a/Lib/profile.py +++ b/Lib/profile.py @@ -24,6 +24,7 @@ # governing permissions and limitations under the License. +import importlib.machinery import sys import time import marshal @@ -589,9 +590,12 @@ def main(): sys.path.insert(0, os.path.dirname(progname)) with open(progname, 'rb') as fp: code = compile(fp.read(), progname, 'exec') + spec = importlib.machinery.ModuleSpec(name='__main__', loader=None, + origin=progname) globs = { - '__file__': progname, - '__name__': '__main__', + '__spec__': spec, + '__file__': spec.origin, + '__name__': spec.name, '__package__': None, '__cached__': None, } diff --git a/Lib/test/test_importlib/import_/test_helpers.py b/Lib/test/test_importlib/import_/test_helpers.py new file mode 100644 index 000000000000..90df56f09fe5 --- /dev/null +++ b/Lib/test/test_importlib/import_/test_helpers.py @@ -0,0 +1,71 @@ +"""Tests for helper functions used by import.c .""" + +from importlib import _bootstrap_external, machinery +import os.path +import unittest + +from .. import util + + +class FixUpModuleTests: + + def test_no_loader_but_spec(self): + loader = object() + name = "hello" + path = "hello.py" + spec = machinery.ModuleSpec(name, loader) + ns = {"__spec__": spec} + _bootstrap_external._fix_up_module(ns, name, path) + + expected = {"__spec__": spec, "__loader__": loader, "__file__": path, + "__cached__": None} + self.assertEqual(ns, expected) + + def test_no_loader_no_spec_but_sourceless(self): + name = "hello" + path = "hello.py" + ns = {} + _bootstrap_external._fix_up_module(ns, name, path, path) + + expected = {"__file__": path, "__cached__": path} + + for key, val in expected.items(): + with self.subTest(f"{key}: {val}"): + self.assertEqual(ns[key], val) + + spec = ns["__spec__"] + self.assertIsInstance(spec, machinery.ModuleSpec) + self.assertEqual(spec.name, name) + self.assertEqual(spec.origin, os.path.abspath(path)) + self.assertEqual(spec.cached, os.path.abspath(path)) + self.assertIsInstance(spec.loader, machinery.SourcelessFileLoader) + self.assertEqual(spec.loader.name, name) + self.assertEqual(spec.loader.path, path) + self.assertEqual(spec.loader, ns["__loader__"]) + + def test_no_loader_no_spec_but_source(self): + name = "hello" + path = "hello.py" + ns = {} + _bootstrap_external._fix_up_module(ns, name, path) + + expected = {"__file__": path, "__cached__": None} + + for key, val in expected.items(): + with self.subTest(f"{key}: {val}"): + self.assertEqual(ns[key], val) + + spec = ns["__spec__"] + self.assertIsInstance(spec, machinery.ModuleSpec) + self.assertEqual(spec.name, name) + self.assertEqual(spec.origin, os.path.abspath(path)) + self.assertIsInstance(spec.loader, machinery.SourceFileLoader) + self.assertEqual(spec.loader.name, name) + self.assertEqual(spec.loader.path, path) + self.assertEqual(spec.loader, ns["__loader__"]) + + +FrozenFixUpModuleTests, SourceFixUpModuleTests = util.test_both(FixUpModuleTests) + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index be9f29e04ae1..710b609ce550 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -4358,8 +4358,11 @@ def test_details(self): 'unittest', '--details') output = out.decode() # Just a quick sanity check on the output + self.assertIn(module.__spec__.name, output) self.assertIn(module.__name__, output) + self.assertIn(module.__spec__.origin, output) self.assertIn(module.__file__, output) + self.assertIn(module.__spec__.cached, output) self.assertIn(module.__cached__, output) self.assertEqual(err, b'') diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py index 8ab3289dd740..cefc71cb5a7f 100644 --- a/Lib/test/test_pydoc.py +++ b/Lib/test/test_pydoc.py @@ -702,7 +702,7 @@ def test_synopsis(self): def test_synopsis_sourceless(self): os = import_helper.import_fresh_module('os') expected = os.__doc__.splitlines()[0] - filename = os.__cached__ + filename = os.__spec__.cached synopsis = pydoc.synopsis(filename) self.assertEqual(synopsis, expected) diff --git a/Misc/NEWS.d/next/Library/2022-10-06-17-59-22.gh-issue-65961.SXlQnI.rst b/Misc/NEWS.d/next/Library/2022-10-06-17-59-22.gh-issue-65961.SXlQnI.rst new file mode 100644 index 000000000000..f708a75a5045 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-06-17-59-22.gh-issue-65961.SXlQnI.rst @@ -0,0 +1,2 @@ +Do not rely solely on ``__cached__`` on modules; code will also support +``__spec__.cached``. From webhook-mailer at python.org Thu Oct 6 18:57:46 2022 From: webhook-mailer at python.org (benjaminp) Date: Thu, 06 Oct 2022 22:57:46 -0000 Subject: [Python-checkins] fixes gh-96078: os.sched_yield release the GIL while calling sched_yield(2). (gh-97965) Message-ID: https://github.com/python/cpython/commit/b9d2e8171696514e9226164005f7bf24bf69e66d commit: b9d2e8171696514e9226164005f7bf24bf69e66d branch: main author: Dong-hee Na committer: benjaminp date: 2022-10-06T15:57:37-07:00 summary: fixes gh-96078: os.sched_yield release the GIL while calling sched_yield(2). (gh-97965) files: A Misc/NEWS.d/next/Core and Builtins/2022-10-06-15-45-57.gh-issue-96078.fS-6mU.rst M Modules/posixmodule.c diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-06-15-45-57.gh-issue-96078.fS-6mU.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-06-15-45-57.gh-issue-96078.fS-6mU.rst new file mode 100644 index 000000000000..d1f949c6e13a --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-06-15-45-57.gh-issue-96078.fS-6mU.rst @@ -0,0 +1,2 @@ +:func:`os.sched_yield` now release the GIL while calling sched_yield(2). +Patch by Dong-hee Na. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index cbdc25973758..a72d57771c22 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -7075,8 +7075,13 @@ static PyObject * os_sched_yield_impl(PyObject *module) /*[clinic end generated code: output=902323500f222cac input=e54d6f98189391d4]*/ { - if (sched_yield()) + int result; + Py_BEGIN_ALLOW_THREADS + result = sched_yield(); + Py_END_ALLOW_THREADS + if (result < 0) { return posix_error(); + } Py_RETURN_NONE; } From webhook-mailer at python.org Thu Oct 6 19:07:25 2022 From: webhook-mailer at python.org (lysnikolaou) Date: Thu, 06 Oct 2022 23:07:25 -0000 Subject: [Python-checkins] gh-97973: Return all necessary information from the tokenizer (GH-97984) Message-ID: https://github.com/python/cpython/commit/cbf0afd8a1474d68310331af9218606959d4cc22 commit: cbf0afd8a1474d68310331af9218606959d4cc22 branch: main author: Lysandros Nikolaou committer: lysnikolaou date: 2022-10-06T16:07:17-07:00 summary: gh-97973: Return all necessary information from the tokenizer (GH-97984) Right now, the tokenizer only returns type and two pointers to the start and end of the token. This PR modifies the tokenizer to return the type and set all of the necessary information, so that the parser does not have to this. files: A Misc/NEWS.d/next/Core and Builtins/2022-10-06-20-41-29.gh-issue-97973.gB-xWi.rst M Parser/pegen.c M Parser/pegen_errors.c M Parser/tokenizer.c M Parser/tokenizer.h M Python/Python-tokenize.c diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-06-20-41-29.gh-issue-97973.gB-xWi.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-06-20-41-29.gh-issue-97973.gB-xWi.rst new file mode 100644 index 000000000000..a0095a61ec32 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-06-20-41-29.gh-issue-97973.gB-xWi.rst @@ -0,0 +1 @@ +Modify the tokenizer to return all necessary information the parser needs to set location information in the AST nodes, so that the parser does not have to calculate those doing pointer arithmetic. diff --git a/Parser/pegen.c b/Parser/pegen.c index a5d123da5129..1317606749b8 100644 --- a/Parser/pegen.c +++ b/Parser/pegen.c @@ -123,16 +123,18 @@ growable_comment_array_deallocate(growable_comment_array *arr) { } static int -_get_keyword_or_name_type(Parser *p, const char *name, int name_len) +_get_keyword_or_name_type(Parser *p, struct token *new_token) { + int name_len = new_token->end_col_offset - new_token->col_offset; assert(name_len > 0); + if (name_len >= p->n_keyword_lists || p->keywords[name_len] == NULL || p->keywords[name_len]->type == -1) { return NAME; } for (KeywordToken *k = p->keywords[name_len]; k != NULL && k->type != -1; k++) { - if (strncmp(k->str, name, name_len) == 0) { + if (strncmp(k->str, new_token->start, name_len) == 0) { return k->type; } } @@ -140,33 +142,26 @@ _get_keyword_or_name_type(Parser *p, const char *name, int name_len) } static int -initialize_token(Parser *p, Token *token, const char *start, const char *end, int token_type) { - assert(token != NULL); +initialize_token(Parser *p, Token *parser_token, struct token *new_token, int token_type) { + assert(parser_token != NULL); - token->type = (token_type == NAME) ? _get_keyword_or_name_type(p, start, (int)(end - start)) : token_type; - token->bytes = PyBytes_FromStringAndSize(start, end - start); - if (token->bytes == NULL) { + parser_token->type = (token_type == NAME) ? _get_keyword_or_name_type(p, new_token) : token_type; + parser_token->bytes = PyBytes_FromStringAndSize(new_token->start, new_token->end - new_token->start); + if (parser_token->bytes == NULL) { return -1; } - - if (_PyArena_AddPyObject(p->arena, token->bytes) < 0) { - Py_DECREF(token->bytes); + if (_PyArena_AddPyObject(p->arena, parser_token->bytes) < 0) { + Py_DECREF(parser_token->bytes); return -1; } - token->level = p->tok->level; - - const char *line_start = token_type == STRING ? p->tok->multi_line_start : p->tok->line_start; - int lineno = token_type == STRING ? p->tok->first_lineno : p->tok->lineno; - int end_lineno = p->tok->lineno; - - int col_offset = (start != NULL && start >= line_start) ? (int)(start - line_start) : -1; - int end_col_offset = (end != NULL && end >= p->tok->line_start) ? (int)(end - p->tok->line_start) : -1; - - token->lineno = lineno; - token->col_offset = p->tok->lineno == p->starting_lineno ? p->starting_col_offset + col_offset : col_offset; - token->end_lineno = end_lineno; - token->end_col_offset = p->tok->lineno == p->starting_lineno ? p->starting_col_offset + end_col_offset : end_col_offset; + parser_token->level = new_token->level; + parser_token->lineno = new_token->lineno; + parser_token->col_offset = p->tok->lineno == p->starting_lineno ? p->starting_col_offset + new_token->col_offset + : new_token->col_offset; + parser_token->end_lineno = new_token->end_lineno; + parser_token->end_col_offset = p->tok->lineno == p->starting_lineno ? p->starting_col_offset + new_token->end_col_offset + : new_token->end_col_offset; p->fill += 1; @@ -202,26 +197,25 @@ _resize_tokens_array(Parser *p) { int _PyPegen_fill_token(Parser *p) { - const char *start; - const char *end; - int type = _PyTokenizer_Get(p->tok, &start, &end); + struct token new_token; + int type = _PyTokenizer_Get(p->tok, &new_token); // Record and skip '# type: ignore' comments while (type == TYPE_IGNORE) { - Py_ssize_t len = end - start; + Py_ssize_t len = new_token.end_col_offset - new_token.col_offset; char *tag = PyMem_Malloc(len + 1); if (tag == NULL) { PyErr_NoMemory(); return -1; } - strncpy(tag, start, len); + strncpy(tag, new_token.start, len); tag[len] = '\0'; // Ownership of tag passes to the growable array if (!growable_comment_array_add(&p->type_ignore_comments, p->tok->lineno, tag)) { PyErr_NoMemory(); return -1; } - type = _PyTokenizer_Get(p->tok, &start, &end); + type = _PyTokenizer_Get(p->tok, &new_token); } // If we have reached the end and we are in single input mode we need to insert a newline and reset the parsing @@ -244,7 +238,7 @@ _PyPegen_fill_token(Parser *p) } Token *t = p->tokens[p->fill]; - return initialize_token(p, t, start, end, type); + return initialize_token(p, t, &new_token, type); } #if defined(Py_DEBUG) diff --git a/Parser/pegen_errors.c b/Parser/pegen_errors.c index 95bbd43dc326..7738cbaf9ef3 100644 --- a/Parser/pegen_errors.c +++ b/Parser/pegen_errors.c @@ -164,11 +164,10 @@ _PyPegen_tokenize_full_source_to_check_for_errors(Parser *p) { Py_ssize_t current_err_line = current_token->lineno; int ret = 0; + struct token new_token; for (;;) { - const char *start; - const char *end; - switch (_PyTokenizer_Get(p->tok, &start, &end)) { + switch (_PyTokenizer_Get(p->tok, &new_token)) { case ERRORTOKEN: if (p->tok->level != 0) { int error_lineno = p->tok->parenlinenostack[p->tok->level-1]; diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index 3c37fd9c45a4..c5d3e580247c 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -36,6 +36,8 @@ /* Don't ever change this -- it would break the portability of Python code */ #define TABSIZE 8 +#define MAKE_TOKEN(token_type) token_setup(tok, token, token_type, p_start, p_end) + /* Forward */ static struct tok_state *tok_new(void); static int tok_nextc(struct tok_state *tok); @@ -1174,8 +1176,6 @@ syntaxerror_known_range(struct tok_state *tok, return ret; } - - static int indenterror(struct tok_state *tok) { @@ -1391,12 +1391,32 @@ tok_continuation_line(struct tok_state *tok) { } static int -tok_get(struct tok_state *tok, const char **p_start, const char **p_end) +token_setup(struct tok_state *tok, struct token *token, int type, const char *start, const char *end) +{ + assert((start == NULL && end == NULL) || (start != NULL && end != NULL)); + token->level = tok->level; + token->lineno = type == STRING ? tok->first_lineno : tok->lineno; + token->end_lineno = tok->lineno; + token->col_offset = -1; + token->end_col_offset = -1; + token->start = start; + token->end = end; + if (start != NULL && end != NULL) { + const char *line_start = type == STRING ? tok->multi_line_start : tok->line_start; + token->col_offset = (start >= line_start) ? (int)(start - line_start) : -1; + token->end_col_offset = (end >= tok->line_start) ? (int)(end - tok->line_start) : -1; + } + return type; +} + +static int +tok_get(struct tok_state *tok, struct token *token) { int c; int blankline, nonascii; - *p_start = *p_end = NULL; + const char *p_start = NULL; + const char *p_end = NULL; nextline: tok->start = NULL; blankline = 0; @@ -1426,7 +1446,7 @@ tok_get(struct tok_state *tok, const char **p_start, const char **p_end) // the level of indentation of whatever comes next. cont_line_col = cont_line_col ? cont_line_col : col; if ((c = tok_continuation_line(tok)) == -1) { - return ERRORTOKEN; + return MAKE_TOKEN(ERRORTOKEN); } } else { @@ -1461,7 +1481,7 @@ tok_get(struct tok_state *tok, const char **p_start, const char **p_end) if (col == tok->indstack[tok->indent]) { /* No change */ if (altcol != tok->altindstack[tok->indent]) { - return indenterror(tok); + return MAKE_TOKEN(indenterror(tok)); } } else if (col > tok->indstack[tok->indent]) { @@ -1469,10 +1489,10 @@ tok_get(struct tok_state *tok, const char **p_start, const char **p_end) if (tok->indent+1 >= MAXINDENT) { tok->done = E_TOODEEP; tok->cur = tok->inp; - return ERRORTOKEN; + return MAKE_TOKEN(ERRORTOKEN); } if (altcol <= tok->altindstack[tok->indent]) { - return indenterror(tok); + return MAKE_TOKEN(indenterror(tok)); } tok->pendin++; tok->indstack[++tok->indent] = col; @@ -1488,10 +1508,10 @@ tok_get(struct tok_state *tok, const char **p_start, const char **p_end) if (col != tok->indstack[tok->indent]) { tok->done = E_DEDENT; tok->cur = tok->inp; - return ERRORTOKEN; + return MAKE_TOKEN(ERRORTOKEN); } if (altcol != tok->altindstack[tok->indent]) { - return indenterror(tok); + return MAKE_TOKEN(indenterror(tok)); } } } @@ -1503,11 +1523,11 @@ tok_get(struct tok_state *tok, const char **p_start, const char **p_end) if (tok->pendin != 0) { if (tok->pendin < 0) { tok->pendin++; - return DEDENT; + return MAKE_TOKEN(DEDENT); } else { tok->pendin--; - return INDENT; + return MAKE_TOKEN(INDENT); } } @@ -1587,34 +1607,34 @@ tok_get(struct tok_state *tok, const char **p_start, const char **p_end) && ((unsigned char)ignore_end[0] >= 128 || Py_ISALNUM(ignore_end[0])))); if (is_type_ignore) { - *p_start = ignore_end; - *p_end = tok->cur; + p_start = ignore_end; + p_end = tok->cur; /* If this type ignore is the only thing on the line, consume the newline also. */ if (blankline) { tok_nextc(tok); tok->atbol = 1; } - return TYPE_IGNORE; + return MAKE_TOKEN(TYPE_IGNORE); } else { - *p_start = type_start; /* after type_comment_prefix */ - *p_end = tok->cur; - return TYPE_COMMENT; + p_start = type_start; + p_end = tok->cur; + return MAKE_TOKEN(TYPE_COMMENT); } } } } if (tok->done == E_INTERACT_STOP) { - return ENDMARKER; + return MAKE_TOKEN(ENDMARKER); } /* Check for EOF and errors now */ if (c == EOF) { if (tok->level) { - return ERRORTOKEN; + return MAKE_TOKEN(ERRORTOKEN); } - return tok->done == E_EOF ? ENDMARKER : ERRORTOKEN; + return MAKE_TOKEN(tok->done == E_EOF ? ENDMARKER : ERRORTOKEN); } /* Identifier (most frequent token!) */ @@ -1654,11 +1674,11 @@ tok_get(struct tok_state *tok, const char **p_start, const char **p_end) } tok_backup(tok, c); if (nonascii && !verify_identifier(tok)) { - return ERRORTOKEN; + return MAKE_TOKEN(ERRORTOKEN); } - *p_start = tok->start; - *p_end = tok->cur; + p_start = tok->start; + p_end = tok->cur; /* async/await parsing block. */ if (tok->cur - tok->start == 5 && tok->start[0] == 'a') { @@ -1673,10 +1693,10 @@ tok_get(struct tok_state *tok, const char **p_start, const char **p_end) if (!tok->async_hacks || tok->async_def) { /* Always recognize the keywords. */ if (memcmp(tok->start, "async", 5) == 0) { - return ASYNC; + return MAKE_TOKEN(ASYNC); } if (memcmp(tok->start, "await", 5) == 0) { - return AWAIT; + return MAKE_TOKEN(AWAIT); } } else if (memcmp(tok->start, "async", 5) == 0) { @@ -1684,13 +1704,11 @@ tok_get(struct tok_state *tok, const char **p_start, const char **p_end) Look ahead one token to see if that is 'def'. */ struct tok_state ahead_tok; - const char *ahead_tok_start = NULL; - const char *ahead_tok_end = NULL; + struct token ahead_token; int ahead_tok_kind; memcpy(&ahead_tok, tok, sizeof(ahead_tok)); - ahead_tok_kind = tok_get(&ahead_tok, &ahead_tok_start, - &ahead_tok_end); + ahead_tok_kind = tok_get(&ahead_tok, &ahead_token); if (ahead_tok_kind == NAME && ahead_tok.cur - ahead_tok.start == 3 @@ -1700,12 +1718,12 @@ tok_get(struct tok_state *tok, const char **p_start, const char **p_end) returning a plain NAME token, return ASYNC. */ tok->async_def_indent = tok->indent; tok->async_def = 1; - return ASYNC; + return MAKE_TOKEN(ASYNC); } } } - return NAME; + return MAKE_TOKEN(NAME); } /* Newline */ @@ -1714,15 +1732,15 @@ tok_get(struct tok_state *tok, const char **p_start, const char **p_end) if (blankline || tok->level > 0) { goto nextline; } - *p_start = tok->start; - *p_end = tok->cur - 1; /* Leave '\n' out of the string */ + p_start = tok->start; + p_end = tok->cur - 1; /* Leave '\n' out of the string */ tok->cont_line = 0; if (tok->async_def) { /* We're somewhere inside an 'async def' function, and we've encountered a NEWLINE after its signature. */ tok->async_def_nl = 1; } - return NEWLINE; + return MAKE_TOKEN(NEWLINE); } /* Period or number starting with period? */ @@ -1733,9 +1751,9 @@ tok_get(struct tok_state *tok, const char **p_start, const char **p_end) } else if (c == '.') { c = tok_nextc(tok); if (c == '.') { - *p_start = tok->start; - *p_end = tok->cur; - return ELLIPSIS; + p_start = tok->start; + p_end = tok->cur; + return MAKE_TOKEN(ELLIPSIS); } else { tok_backup(tok, c); @@ -1745,9 +1763,9 @@ tok_get(struct tok_state *tok, const char **p_start, const char **p_end) else { tok_backup(tok, c); } - *p_start = tok->start; - *p_end = tok->cur; - return DOT; + p_start = tok->start; + p_end = tok->cur; + return MAKE_TOKEN(DOT); } /* Number */ @@ -1764,14 +1782,14 @@ tok_get(struct tok_state *tok, const char **p_start, const char **p_end) } if (!isxdigit(c)) { tok_backup(tok, c); - return syntaxerror(tok, "invalid hexadecimal literal"); + return MAKE_TOKEN(syntaxerror(tok, "invalid hexadecimal literal")); } do { c = tok_nextc(tok); } while (isxdigit(c)); } while (c == '_'); if (!verify_end_of_number(tok, c, "hexadecimal")) { - return ERRORTOKEN; + return MAKE_TOKEN(ERRORTOKEN); } } else if (c == 'o' || c == 'O') { @@ -1783,12 +1801,12 @@ tok_get(struct tok_state *tok, const char **p_start, const char **p_end) } if (c < '0' || c >= '8') { if (isdigit(c)) { - return syntaxerror(tok, - "invalid digit '%c' in octal literal", c); + return MAKE_TOKEN(syntaxerror(tok, + "invalid digit '%c' in octal literal", c)); } else { tok_backup(tok, c); - return syntaxerror(tok, "invalid octal literal"); + return MAKE_TOKEN(syntaxerror(tok, "invalid octal literal")); } } do { @@ -1796,11 +1814,11 @@ tok_get(struct tok_state *tok, const char **p_start, const char **p_end) } while ('0' <= c && c < '8'); } while (c == '_'); if (isdigit(c)) { - return syntaxerror(tok, - "invalid digit '%c' in octal literal", c); + return MAKE_TOKEN(syntaxerror(tok, + "invalid digit '%c' in octal literal", c)); } if (!verify_end_of_number(tok, c, "octal")) { - return ERRORTOKEN; + return MAKE_TOKEN(ERRORTOKEN); } } else if (c == 'b' || c == 'B') { @@ -1812,12 +1830,11 @@ tok_get(struct tok_state *tok, const char **p_start, const char **p_end) } if (c != '0' && c != '1') { if (isdigit(c)) { - return syntaxerror(tok, - "invalid digit '%c' in binary literal", c); + return MAKE_TOKEN(syntaxerror(tok, "invalid digit '%c' in binary literal", c)); } else { tok_backup(tok, c); - return syntaxerror(tok, "invalid binary literal"); + return MAKE_TOKEN(syntaxerror(tok, "invalid binary literal")); } } do { @@ -1825,11 +1842,10 @@ tok_get(struct tok_state *tok, const char **p_start, const char **p_end) } while (c == '0' || c == '1'); } while (c == '_'); if (isdigit(c)) { - return syntaxerror(tok, - "invalid digit '%c' in binary literal", c); + return MAKE_TOKEN(syntaxerror(tok, "invalid digit '%c' in binary literal", c)); } if (!verify_end_of_number(tok, c, "binary")) { - return ERRORTOKEN; + return MAKE_TOKEN(ERRORTOKEN); } } else { @@ -1841,7 +1857,7 @@ tok_get(struct tok_state *tok, const char **p_start, const char **p_end) c = tok_nextc(tok); if (!isdigit(c)) { tok_backup(tok, c); - return syntaxerror(tok, "invalid decimal literal"); + return MAKE_TOKEN(syntaxerror(tok, "invalid decimal literal")); } } if (c != '0') { @@ -1854,7 +1870,7 @@ tok_get(struct tok_state *tok, const char **p_start, const char **p_end) nonzero = 1; c = tok_decimal_tail(tok); if (c == 0) { - return ERRORTOKEN; + return MAKE_TOKEN(ERRORTOKEN); } } if (c == '.') { @@ -1870,15 +1886,15 @@ tok_get(struct tok_state *tok, const char **p_start, const char **p_end) else if (nonzero) { /* Old-style octal: now disallowed. */ tok_backup(tok, c); - return syntaxerror_known_range( + return MAKE_TOKEN(syntaxerror_known_range( tok, (int)(tok->start + 1 - tok->line_start), (int)(zeros_end - tok->line_start), "leading zeros in decimal integer " "literals are not permitted; " - "use an 0o prefix for octal integers"); + "use an 0o prefix for octal integers")); } if (!verify_end_of_number(tok, c, "decimal")) { - return ERRORTOKEN; + return MAKE_TOKEN(ERRORTOKEN); } } } @@ -1886,7 +1902,7 @@ tok_get(struct tok_state *tok, const char **p_start, const char **p_end) /* Decimal */ c = tok_decimal_tail(tok); if (c == 0) { - return ERRORTOKEN; + return MAKE_TOKEN(ERRORTOKEN); } { /* Accept floating point numbers. */ @@ -1897,7 +1913,7 @@ tok_get(struct tok_state *tok, const char **p_start, const char **p_end) if (isdigit(c)) { c = tok_decimal_tail(tok); if (c == 0) { - return ERRORTOKEN; + return MAKE_TOKEN(ERRORTOKEN); } } } @@ -1911,21 +1927,21 @@ tok_get(struct tok_state *tok, const char **p_start, const char **p_end) c = tok_nextc(tok); if (!isdigit(c)) { tok_backup(tok, c); - return syntaxerror(tok, "invalid decimal literal"); + return MAKE_TOKEN(syntaxerror(tok, "invalid decimal literal")); } } else if (!isdigit(c)) { tok_backup(tok, c); if (!verify_end_of_number(tok, e, "decimal")) { - return ERRORTOKEN; + return MAKE_TOKEN(ERRORTOKEN); } tok_backup(tok, e); - *p_start = tok->start; - *p_end = tok->cur; - return NUMBER; + p_start = tok->start; + p_end = tok->cur; + return MAKE_TOKEN(NUMBER); } c = tok_decimal_tail(tok); if (c == 0) { - return ERRORTOKEN; + return MAKE_TOKEN(ERRORTOKEN); } } if (c == 'j' || c == 'J') { @@ -1933,18 +1949,18 @@ tok_get(struct tok_state *tok, const char **p_start, const char **p_end) imaginary: c = tok_nextc(tok); if (!verify_end_of_number(tok, c, "imaginary")) { - return ERRORTOKEN; + return MAKE_TOKEN(ERRORTOKEN); } } else if (!verify_end_of_number(tok, c, "decimal")) { - return ERRORTOKEN; + return MAKE_TOKEN(ERRORTOKEN); } } } tok_backup(tok, c); - *p_start = tok->start; - *p_end = tok->cur; - return NUMBER; + p_start = tok->start; + p_end = tok->cur; + return MAKE_TOKEN(NUMBER); } letter_quote: @@ -1997,7 +2013,7 @@ tok_get(struct tok_state *tok, const char **p_start, const char **p_end) if (c != '\n') { tok->done = E_EOFS; } - return ERRORTOKEN; + return MAKE_TOKEN(ERRORTOKEN); } else { syntaxerror(tok, "unterminated string literal (detected at" @@ -2005,7 +2021,7 @@ tok_get(struct tok_state *tok, const char **p_start, const char **p_end) if (c != '\n') { tok->done = E_EOLS; } - return ERRORTOKEN; + return MAKE_TOKEN(ERRORTOKEN); } } if (c == quote) { @@ -2019,15 +2035,15 @@ tok_get(struct tok_state *tok, const char **p_start, const char **p_end) } } - *p_start = tok->start; - *p_end = tok->cur; - return STRING; + p_start = tok->start; + p_end = tok->cur; + return MAKE_TOKEN(STRING); } /* Line continuation */ if (c == '\\') { if ((c = tok_continuation_line(tok)) == -1) { - return ERRORTOKEN; + return MAKE_TOKEN(ERRORTOKEN); } tok->cont_line = 1; goto again; /* Read next line */ @@ -2036,19 +2052,19 @@ tok_get(struct tok_state *tok, const char **p_start, const char **p_end) /* Check for two-character token */ { int c2 = tok_nextc(tok); - int token = _PyToken_TwoChars(c, c2); - if (token != OP) { + int current_token = _PyToken_TwoChars(c, c2); + if (current_token != OP) { int c3 = tok_nextc(tok); - int token3 = _PyToken_ThreeChars(c, c2, c3); - if (token3 != OP) { - token = token3; + int current_token3 = _PyToken_ThreeChars(c, c2, c3); + if (current_token3 != OP) { + current_token = current_token3; } else { tok_backup(tok, c3); } - *p_start = tok->start; - *p_end = tok->cur; - return token; + p_start = tok->start; + p_end = tok->cur; + return MAKE_TOKEN(current_token); } tok_backup(tok, c2); } @@ -2059,7 +2075,7 @@ tok_get(struct tok_state *tok, const char **p_start, const char **p_end) case '[': case '{': if (tok->level >= MAXLEVEL) { - return syntaxerror(tok, "too many nested parentheses"); + return MAKE_TOKEN(syntaxerror(tok, "too many nested parentheses")); } tok->parenstack[tok->level] = c; tok->parenlinenostack[tok->level] = tok->lineno; @@ -2070,7 +2086,7 @@ tok_get(struct tok_state *tok, const char **p_start, const char **p_end) case ']': case '}': if (!tok->level) { - return syntaxerror(tok, "unmatched '%c'", c); + return MAKE_TOKEN(syntaxerror(tok, "unmatched '%c'", c)); } tok->level--; int opening = tok->parenstack[tok->level]; @@ -2079,16 +2095,16 @@ tok_get(struct tok_state *tok, const char **p_start, const char **p_end) (opening == '{' && c == '}'))) { if (tok->parenlinenostack[tok->level] != tok->lineno) { - return syntaxerror(tok, + return MAKE_TOKEN(syntaxerror(tok, "closing parenthesis '%c' does not match " "opening parenthesis '%c' on line %d", - c, opening, tok->parenlinenostack[tok->level]); + c, opening, tok->parenlinenostack[tok->level])); } else { - return syntaxerror(tok, + return MAKE_TOKEN(syntaxerror(tok, "closing parenthesis '%c' does not match " "opening parenthesis '%c'", - c, opening); + c, opening)); } } break; @@ -2097,20 +2113,19 @@ tok_get(struct tok_state *tok, const char **p_start, const char **p_end) if (!Py_UNICODE_ISPRINTABLE(c)) { char hex[9]; (void)PyOS_snprintf(hex, sizeof(hex), "%04X", c); - return syntaxerror(tok, "invalid non-printable character U+%s", hex); + return MAKE_TOKEN(syntaxerror(tok, "invalid non-printable character U+%s", hex)); } /* Punctuation character */ - *p_start = tok->start; - *p_end = tok->cur; - return _PyToken_OneChar(c); + p_start = tok->start; + p_end = tok->cur; + return MAKE_TOKEN(_PyToken_OneChar(c)); } int -_PyTokenizer_Get(struct tok_state *tok, - const char **p_start, const char **p_end) +_PyTokenizer_Get(struct tok_state *tok, struct token *token) { - int result = tok_get(tok, p_start, p_end); + int result = tok_get(tok, token); if (tok->decoding_erred) { result = ERRORTOKEN; tok->done = E_DECODE; @@ -2166,8 +2181,6 @@ _PyTokenizer_FindEncodingFilename(int fd, PyObject *filename) { struct tok_state *tok; FILE *fp; - const char *p_start = NULL; - const char *p_end = NULL; char *encoding = NULL; fp = fdopen_borrow(fd); @@ -2191,8 +2204,9 @@ _PyTokenizer_FindEncodingFilename(int fd, PyObject *filename) return encoding; } } + struct token token; while (tok->lineno < 2 && tok->done == E_OK) { - _PyTokenizer_Get(tok, &p_start, &p_end); + _PyTokenizer_Get(tok, &token); } fclose(fp); if (tok->encoding) { diff --git a/Parser/tokenizer.h b/Parser/tokenizer.h index 5ac64a99b7d6..5b8c7f314386 100644 --- a/Parser/tokenizer.h +++ b/Parser/tokenizer.h @@ -27,6 +27,12 @@ enum interactive_underflow_t { IUNDERFLOW_STOP, }; +struct token { + int level; + int lineno, col_offset, end_lineno, end_col_offset; + const char *start, *end; +}; + /* Tokenizer state */ struct tok_state { /* Input state; buf <= cur <= inp <= end */ @@ -94,7 +100,7 @@ extern struct tok_state *_PyTokenizer_FromUTF8(const char *, int); extern struct tok_state *_PyTokenizer_FromFile(FILE *, const char*, const char *, const char *); extern void _PyTokenizer_Free(struct tok_state *); -extern int _PyTokenizer_Get(struct tok_state *, const char **, const char **); +extern int _PyTokenizer_Get(struct tok_state *, struct token *); #define tok_dump _Py_tok_dump diff --git a/Python/Python-tokenize.c b/Python/Python-tokenize.c index c5124a6942e7..8daa9877254e 100644 --- a/Python/Python-tokenize.c +++ b/Python/Python-tokenize.c @@ -60,9 +60,8 @@ tokenizeriter_new_impl(PyTypeObject *type, const char *source) static PyObject * tokenizeriter_next(tokenizeriterobject *it) { - const char *start; - const char *end; - int type = _PyTokenizer_Get(it->tok, &start, &end); + struct token token; + int type = _PyTokenizer_Get(it->tok, &token); if (type == ERRORTOKEN && PyErr_Occurred()) { return NULL; } @@ -71,11 +70,11 @@ tokenizeriter_next(tokenizeriterobject *it) return NULL; } PyObject *str = NULL; - if (start == NULL || end == NULL) { + if (token.start == NULL || token.end == NULL) { str = PyUnicode_FromString(""); } else { - str = PyUnicode_FromStringAndSize(start, end - start); + str = PyUnicode_FromStringAndSize(token.start, token.end - token.start); } if (str == NULL) { return NULL; @@ -92,11 +91,11 @@ tokenizeriter_next(tokenizeriterobject *it) int end_lineno = it->tok->lineno; int col_offset = -1; int end_col_offset = -1; - if (start != NULL && start >= line_start) { - col_offset = (int)(start - line_start); + if (token.start != NULL && token.start >= line_start) { + col_offset = (int)(token.start - line_start); } - if (end != NULL && end >= it->tok->line_start) { - end_col_offset = (int)(end - it->tok->line_start); + if (token.end != NULL && token.end >= it->tok->line_start) { + end_col_offset = (int)(token.end - it->tok->line_start); } return Py_BuildValue("(NiiiiiN)", str, type, lineno, end_lineno, col_offset, end_col_offset, line); From webhook-mailer at python.org Thu Oct 6 19:20:10 2022 From: webhook-mailer at python.org (markshannon) Date: Thu, 06 Oct 2022 23:20:10 -0000 Subject: [Python-checkins] GH-97002: Prevent `_PyInterpreterFrame`s from backing more than one `PyFrameObject` (GH-97996) Message-ID: https://github.com/python/cpython/commit/21a2d9ff550977f2668e2cf1cc15793bf27fa109 commit: 21a2d9ff550977f2668e2cf1cc15793bf27fa109 branch: main author: Brandt Bucher committer: markshannon date: 2022-10-07T00:20:01+01:00 summary: GH-97002: Prevent `_PyInterpreterFrame`s from backing more than one `PyFrameObject` (GH-97996) files: A Misc/NEWS.d/next/Core and Builtins/2022-10-06-02-11-34.gh-issue-97002.Zvsk71.rst M Lib/test/test_frame.py M Python/frame.c diff --git a/Lib/test/test_frame.py b/Lib/test/test_frame.py index 5dda2fbfac37..4b86a60d2f4c 100644 --- a/Lib/test/test_frame.py +++ b/Lib/test/test_frame.py @@ -1,3 +1,4 @@ +import gc import re import sys import textwrap @@ -261,5 +262,69 @@ def gen(): """) assert_python_ok("-c", code) + @support.cpython_only + def test_sneaky_frame_object(self): + + def trace(frame, event, arg): + """ + Don't actually do anything, just force a frame object to be created. + """ + + def callback(phase, info): + """ + Yo dawg, I heard you like frames, so I'm allocating a frame while + you're allocating a frame, so you can have a frame while you have a + frame! + """ + nonlocal sneaky_frame_object + sneaky_frame_object = sys._getframe().f_back + # We're done here: + gc.callbacks.remove(callback) + + def f(): + while True: + yield + + old_threshold = gc.get_threshold() + old_callbacks = gc.callbacks[:] + old_enabled = gc.isenabled() + old_trace = sys.gettrace() + try: + # Stop the GC for a second while we set things up: + gc.disable() + # Create a paused generator: + g = f() + next(g) + # Move all objects to the oldest generation, and tell the GC to run + # on the *very next* allocation: + gc.collect() + gc.set_threshold(1, 0, 0) + # Okay, so here's the nightmare scenario: + # - We're tracing the resumption of a generator, which creates a new + # frame object. + # - The allocation of this frame object triggers a collection + # *before* the frame object is actually created. + # - During the collection, we request the exact same frame object. + # This test does it with a GC callback, but in real code it would + # likely be a trace function, weakref callback, or finalizer. + # - The collection finishes, and the original frame object is + # created. We now have two frame objects fighting over ownership + # of the same interpreter frame! + sys.settrace(trace) + gc.callbacks.append(callback) + sneaky_frame_object = None + gc.enable() + next(g) + # g.gi_frame should be the the frame object from the callback (the + # one that was *requested* second, but *created* first): + self.assertIs(g.gi_frame, sneaky_frame_object) + finally: + gc.set_threshold(*old_threshold) + gc.callbacks[:] = old_callbacks + sys.settrace(old_trace) + if old_enabled: + gc.enable() + + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-06-02-11-34.gh-issue-97002.Zvsk71.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-06-02-11-34.gh-issue-97002.Zvsk71.rst new file mode 100644 index 000000000000..1f577e02e1fd --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-06-02-11-34.gh-issue-97002.Zvsk71.rst @@ -0,0 +1,3 @@ +Fix an issue where several frame objects could be backed by the same +interpreter frame, possibly leading to corrupted memory and hard crashes of +the interpreter. diff --git a/Python/frame.c b/Python/frame.c index 96566de63a78..89f084b110cb 100644 --- a/Python/frame.c +++ b/Python/frame.c @@ -37,14 +37,31 @@ _PyFrame_MakeAndSetFrameObject(_PyInterpreterFrame *frame) Py_XDECREF(error_type); Py_XDECREF(error_value); Py_XDECREF(error_traceback); + return NULL; } - else { - assert(frame->owner != FRAME_OWNED_BY_FRAME_OBJECT); - assert(frame->owner != FRAME_CLEARED); - f->f_frame = frame; - frame->frame_obj = f; - PyErr_Restore(error_type, error_value, error_traceback); + PyErr_Restore(error_type, error_value, error_traceback); + if (frame->frame_obj) { + // GH-97002: How did we get into this horrible situation? Most likely, + // allocating f triggered a GC collection, which ran some code that + // *also* created the same frame... while we were in the middle of + // creating it! See test_sneaky_frame_object in test_frame.py for a + // concrete example. + // + // Regardless, just throw f away and use that frame instead, since it's + // already been exposed to user code. It's actually a bit tricky to do + // this, since we aren't backed by a real _PyInterpreterFrame anymore. + // Just pretend that we have an owned, cleared frame so frame_dealloc + // doesn't make the situation worse: + f->f_frame = (_PyInterpreterFrame *)f->_f_frame_data; + f->f_frame->owner = FRAME_CLEARED; + f->f_frame->frame_obj = f; + Py_DECREF(f); + return frame->frame_obj; } + assert(frame->owner != FRAME_OWNED_BY_FRAME_OBJECT); + assert(frame->owner != FRAME_CLEARED); + f->f_frame = frame; + frame->frame_obj = f; return f; } From webhook-mailer at python.org Thu Oct 6 19:43:24 2022 From: webhook-mailer at python.org (gpshead) Date: Thu, 06 Oct 2022 23:43:24 -0000 Subject: [Python-checkins] bpo-38693: Use f-strings instead of str.format() within importlib (#17058) Message-ID: https://github.com/python/cpython/commit/683ab859554c34831fcecc854de35745d7fd603c commit: 683ab859554c34831fcecc854de35745d7fd603c branch: main author: Gregory P. Smith committer: gpshead date: 2022-10-06T16:43:16-07:00 summary: bpo-38693: Use f-strings instead of str.format() within importlib (#17058) This is a small performance improvement, especially for one or two hot places such as _handle_fromlist() that are called a lot and the .format() method was being used just to join two strings with a dot. Otherwise it is merely a readability improvement. We keep `_ERR_MSG` and `_ERR_MSG_PREFIX` as those may be used elsewhere for canonical looking error messages. files: A Misc/NEWS.d/next/Library/2019-11-04-22-21-27.bpo-38693.w_OAov.rst A Python/importlib.h M Lib/importlib/_bootstrap.py diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py index 1c132106ce5a..e0110e701d6c 100644 --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -136,7 +136,7 @@ def release(self): self.wakeup.release() def __repr__(self): - return '_ModuleLock({!r}) at {}'.format(self.name, id(self)) + return f'_ModuleLock({self.name!r}) at {id(self)}' class _DummyModuleLock: @@ -157,7 +157,7 @@ def release(self): self.count -= 1 def __repr__(self): - return '_DummyModuleLock({!r}) at {}'.format(self.name, id(self)) + return f'_DummyModuleLock({self.name!r}) at {id(self)}' class _ModuleLockManager: @@ -253,7 +253,7 @@ def _requires_builtin(fxn): """Decorator to verify the named module is built-in.""" def _requires_builtin_wrapper(self, fullname): if fullname not in sys.builtin_module_names: - raise ImportError('{!r} is not a built-in module'.format(fullname), + raise ImportError(f'{fullname!r} is not a built-in module', name=fullname) return fxn(self, fullname) _wrap(_requires_builtin_wrapper, fxn) @@ -264,7 +264,7 @@ def _requires_frozen(fxn): """Decorator to verify the named module is frozen.""" def _requires_frozen_wrapper(self, fullname): if not _imp.is_frozen(fullname): - raise ImportError('{!r} is not a frozen module'.format(fullname), + raise ImportError(f'{fullname!r} is not a frozen module', name=fullname) return fxn(self, fullname) _wrap(_requires_frozen_wrapper, fxn) @@ -305,11 +305,11 @@ def _module_repr(module): filename = module.__file__ except AttributeError: if loader is None: - return ''.format(name) + return f'' else: - return ''.format(name, loader) + return f'' else: - return ''.format(name, filename) + return f'' class ModuleSpec: @@ -363,14 +363,12 @@ def __init__(self, name, loader, *, origin=None, loader_state=None, self._cached = None def __repr__(self): - args = ['name={!r}'.format(self.name), - 'loader={!r}'.format(self.loader)] + args = [f'name={self.name!r}', f'loader={self.loader!r}'] if self.origin is not None: - args.append('origin={!r}'.format(self.origin)) + args.append(f'origin={self.origin!r}') if self.submodule_search_locations is not None: - args.append('submodule_search_locations={}' - .format(self.submodule_search_locations)) - return '{}({})'.format(self.__class__.__name__, ', '.join(args)) + args.append(f'submodule_search_locations={self.submodule_search_locations}') + return f'{self.__class__.__name__}({", ".join(args)})' def __eq__(self, other): smsl = self.submodule_search_locations @@ -580,14 +578,14 @@ def _module_repr_from_spec(spec): name = '?' if spec.name is None else spec.name if spec.origin is None: if spec.loader is None: - return ''.format(name) + return f'' else: - return ''.format(name, spec.loader) + return f'' else: if spec.has_location: - return ''.format(name, spec.origin) + return f'' else: - return ''.format(spec.name, spec.origin) + return f'' # Used by importlib.reload() and _load_module_shim(). @@ -596,7 +594,7 @@ def _exec(spec, module): name = spec.name with _ModuleLockManager(name): if sys.modules.get(name) is not module: - msg = 'module {!r} not in sys.modules'.format(name) + msg = f'module {name!r} not in sys.modules' raise ImportError(msg, name=name) try: if spec.loader is None: @@ -756,7 +754,7 @@ def find_module(cls, fullname, path=None): def create_module(spec): """Create a built-in module""" if spec.name not in sys.builtin_module_names: - raise ImportError('{!r} is not a built-in module'.format(spec.name), + raise ImportError(f'{spec.name!r} is not a built-in module', name=spec.name) return _call_with_frames_removed(_imp.create_builtin, spec) @@ -1012,7 +1010,7 @@ def _resolve_name(name, package, level): if len(bits) < level: raise ImportError('attempted relative import beyond top-level package') base = bits[0] - return '{}.{}'.format(base, name) if name else base + return f'{base}.{name}' if name else base def _find_spec_legacy(finder, name, path): @@ -1075,7 +1073,7 @@ def _find_spec(name, path, target=None): def _sanity_check(name, package, level): """Verify arguments are "sane".""" if not isinstance(name, str): - raise TypeError('module name must be str, not {}'.format(type(name))) + raise TypeError(f'module name must be str, not {type(name)}') if level < 0: raise ValueError('level must be >= 0') if level > 0: @@ -1105,13 +1103,13 @@ def _find_and_load_unlocked(name, import_): try: path = parent_module.__path__ except AttributeError: - msg = (_ERR_MSG + '; {!r} is not a package').format(name, parent) + msg = f'{_ERR_MSG_PREFIX} {name!r}; {parent!r} is not a package' raise ModuleNotFoundError(msg, name=name) from None parent_spec = parent_module.__spec__ child = name.rpartition('.')[2] spec = _find_spec(name, path) if spec is None: - raise ModuleNotFoundError(_ERR_MSG.format(name), name=name) + raise ModuleNotFoundError(f'{_ERR_MSG_PREFIX}{name!r}', name=name) else: if parent_spec: # Temporarily add child we are currently importing to parent's @@ -1156,8 +1154,7 @@ def _find_and_load(name, import_): _lock_unlock_module(name) if module is None: - message = ('import of {} halted; ' - 'None in sys.modules'.format(name)) + message = f'import of {name} halted; None in sys.modules' raise ModuleNotFoundError(message, name=name) return module @@ -1201,7 +1198,7 @@ def _handle_fromlist(module, fromlist, import_, *, recursive=False): _handle_fromlist(module, module.__all__, import_, recursive=True) elif not hasattr(module, x): - from_name = '{}.{}'.format(module.__name__, x) + from_name = f'{module.__name__}.{x}' try: _call_with_frames_removed(import_, from_name) except ModuleNotFoundError as exc: diff --git a/Misc/NEWS.d/next/Library/2019-11-04-22-21-27.bpo-38693.w_OAov.rst b/Misc/NEWS.d/next/Library/2019-11-04-22-21-27.bpo-38693.w_OAov.rst new file mode 100644 index 000000000000..6d0ad36809ee --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-11-04-22-21-27.bpo-38693.w_OAov.rst @@ -0,0 +1 @@ +importlib now uses f-strings internally instead of str.format(). diff --git a/Python/importlib.h b/Python/importlib.h new file mode 100644 index 000000000000..586f3b21f462 --- /dev/null +++ b/Python/importlib.h @@ -0,0 +1,1783 @@ +/* Auto-generated by Programs/_freeze_importlib.c */ +const unsigned char _Py_M__importlib_bootstrap[] = { + 99,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,4,0,0,0,64,0,0,0,115,194,1,0,0,100,0, + 90,0,100,1,97,1,100,2,100,3,132,0,90,2,100,4, + 100,5,132,0,90,3,105,0,90,4,105,0,90,5,71,0, + 100,6,100,7,132,0,100,7,101,6,131,3,90,7,71,0, + 100,8,100,9,132,0,100,9,131,2,90,8,71,0,100,10, + 100,11,132,0,100,11,131,2,90,9,71,0,100,12,100,13, + 132,0,100,13,131,2,90,10,100,14,100,15,132,0,90,11, + 100,16,100,17,132,0,90,12,100,18,100,19,132,0,90,13, + 100,20,100,21,156,1,100,22,100,23,132,2,90,14,100,24, + 100,25,132,0,90,15,100,26,100,27,132,0,90,16,100,28, + 100,29,132,0,90,17,100,30,100,31,132,0,90,18,71,0, + 100,32,100,33,132,0,100,33,131,2,90,19,100,1,100,1, + 100,34,156,2,100,35,100,36,132,2,90,20,100,94,100,37, + 100,38,132,1,90,21,100,39,100,40,156,1,100,41,100,42, + 132,2,90,22,100,43,100,44,132,0,90,23,100,45,100,46, + 132,0,90,24,100,47,100,48,132,0,90,25,100,49,100,50, + 132,0,90,26,100,51,100,52,132,0,90,27,100,53,100,54, + 132,0,90,28,71,0,100,55,100,56,132,0,100,56,131,2, + 90,29,71,0,100,57,100,58,132,0,100,58,131,2,90,30, + 71,0,100,59,100,60,132,0,100,60,131,2,90,31,100,61, + 100,62,132,0,90,32,100,63,100,64,132,0,90,33,100,95, + 100,65,100,66,132,1,90,34,100,67,100,68,132,0,90,35, + 100,69,90,36,101,36,100,70,23,0,90,37,100,71,100,72, + 132,0,90,38,101,39,131,0,90,40,100,73,100,74,132,0, + 90,41,100,96,100,76,100,77,132,1,90,42,100,39,100,78, + 156,1,100,79,100,80,132,2,90,43,100,81,100,82,132,0, + 90,44,100,97,100,84,100,85,132,1,90,45,100,86,100,87, + 132,0,90,46,100,88,100,89,132,0,90,47,100,90,100,91, + 132,0,90,48,100,92,100,93,132,0,90,49,100,1,83,0, + 41,98,97,83,1,0,0,67,111,114,101,32,105,109,112,108, + 101,109,101,110,116,97,116,105,111,110,32,111,102,32,105,109, + 112,111,114,116,46,10,10,84,104,105,115,32,109,111,100,117, + 108,101,32,105,115,32,78,79,84,32,109,101,97,110,116,32, + 116,111,32,98,101,32,100,105,114,101,99,116,108,121,32,105, + 109,112,111,114,116,101,100,33,32,73,116,32,104,97,115,32, + 98,101,101,110,32,100,101,115,105,103,110,101,100,32,115,117, + 99,104,10,116,104,97,116,32,105,116,32,99,97,110,32,98, + 101,32,98,111,111,116,115,116,114,97,112,112,101,100,32,105, + 110,116,111,32,80,121,116,104,111,110,32,97,115,32,116,104, + 101,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110, + 32,111,102,32,105,109,112,111,114,116,46,32,65,115,10,115, + 117,99,104,32,105,116,32,114,101,113,117,105,114,101,115,32, + 116,104,101,32,105,110,106,101,99,116,105,111,110,32,111,102, + 32,115,112,101,99,105,102,105,99,32,109,111,100,117,108,101, + 115,32,97,110,100,32,97,116,116,114,105,98,117,116,101,115, + 32,105,110,32,111,114,100,101,114,32,116,111,10,119,111,114, + 107,46,32,79,110,101,32,115,104,111,117,108,100,32,117,115, + 101,32,105,109,112,111,114,116,108,105,98,32,97,115,32,116, + 104,101,32,112,117,98,108,105,99,45,102,97,99,105,110,103, + 32,118,101,114,115,105,111,110,32,111,102,32,116,104,105,115, + 32,109,111,100,117,108,101,46,10,10,78,99,2,0,0,0, + 0,0,0,0,0,0,0,0,3,0,0,0,7,0,0,0, + 67,0,0,0,115,56,0,0,0,100,1,68,0,93,32,125, + 2,116,0,124,1,124,2,131,2,114,4,116,1,124,0,124, + 2,116,2,124,1,124,2,131,2,131,3,1,0,113,4,124, + 0,106,3,160,4,124,1,106,3,161,1,1,0,100,2,83, + 0,41,3,122,47,83,105,109,112,108,101,32,115,117,98,115, + 116,105,116,117,116,101,32,102,111,114,32,102,117,110,99,116, + 111,111,108,115,46,117,112,100,97,116,101,95,119,114,97,112, + 112,101,114,46,41,4,218,10,95,95,109,111,100,117,108,101, + 95,95,218,8,95,95,110,97,109,101,95,95,218,12,95,95, + 113,117,97,108,110,97,109,101,95,95,218,7,95,95,100,111, + 99,95,95,78,41,5,218,7,104,97,115,97,116,116,114,218, + 7,115,101,116,97,116,116,114,218,7,103,101,116,97,116,116, + 114,218,8,95,95,100,105,99,116,95,95,218,6,117,112,100, + 97,116,101,41,3,90,3,110,101,119,90,3,111,108,100,218, + 7,114,101,112,108,97,99,101,169,0,114,10,0,0,0,250, + 29,60,102,114,111,122,101,110,32,105,109,112,111,114,116,108, + 105,98,46,95,98,111,111,116,115,116,114,97,112,62,218,5, + 95,119,114,97,112,27,0,0,0,115,8,0,0,0,0,2, + 8,1,10,1,20,1,114,12,0,0,0,99,1,0,0,0, + 0,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0, + 67,0,0,0,115,12,0,0,0,116,0,116,1,131,1,124, + 0,131,1,83,0,169,1,78,41,2,218,4,116,121,112,101, + 218,3,115,121,115,169,1,218,4,110,97,109,101,114,10,0, + 0,0,114,10,0,0,0,114,11,0,0,0,218,11,95,110, + 101,119,95,109,111,100,117,108,101,35,0,0,0,115,2,0, + 0,0,0,1,114,18,0,0,0,99,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,1,0,0,0,64,0, + 0,0,115,12,0,0,0,101,0,90,1,100,0,90,2,100, + 1,83,0,41,2,218,14,95,68,101,97,100,108,111,99,107, + 69,114,114,111,114,78,41,3,114,1,0,0,0,114,0,0, + 0,0,114,2,0,0,0,114,10,0,0,0,114,10,0,0, + 0,114,10,0,0,0,114,11,0,0,0,114,19,0,0,0, + 48,0,0,0,115,2,0,0,0,8,1,114,19,0,0,0, + 99,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,2,0,0,0,64,0,0,0,115,56,0,0,0,101,0, + 90,1,100,0,90,2,100,1,90,3,100,2,100,3,132,0, + 90,4,100,4,100,5,132,0,90,5,100,6,100,7,132,0, + 90,6,100,8,100,9,132,0,90,7,100,10,100,11,132,0, + 90,8,100,12,83,0,41,13,218,11,95,77,111,100,117,108, + 101,76,111,99,107,122,169,65,32,114,101,99,117,114,115,105, + 118,101,32,108,111,99,107,32,105,109,112,108,101,109,101,110, + 116,97,116,105,111,110,32,119,104,105,99,104,32,105,115,32, + 97,98,108,101,32,116,111,32,100,101,116,101,99,116,32,100, + 101,97,100,108,111,99,107,115,10,32,32,32,32,40,101,46, + 103,46,32,116,104,114,101,97,100,32,49,32,116,114,121,105, + 110,103,32,116,111,32,116,97,107,101,32,108,111,99,107,115, + 32,65,32,116,104,101,110,32,66,44,32,97,110,100,32,116, + 104,114,101,97,100,32,50,32,116,114,121,105,110,103,32,116, + 111,10,32,32,32,32,116,97,107,101,32,108,111,99,107,115, + 32,66,32,116,104,101,110,32,65,41,46,10,32,32,32,32, + 99,2,0,0,0,0,0,0,0,0,0,0,0,2,0,0, + 0,2,0,0,0,67,0,0,0,115,48,0,0,0,116,0, + 160,1,161,0,124,0,95,2,116,0,160,1,161,0,124,0, + 95,3,124,1,124,0,95,4,100,0,124,0,95,5,100,1, + 124,0,95,6,100,1,124,0,95,7,100,0,83,0,169,2, + 78,233,0,0,0,0,41,8,218,7,95,116,104,114,101,97, + 100,90,13,97,108,108,111,99,97,116,101,95,108,111,99,107, + 218,4,108,111,99,107,218,6,119,97,107,101,117,112,114,17, + 0,0,0,218,5,111,119,110,101,114,218,5,99,111,117,110, + 116,218,7,119,97,105,116,101,114,115,169,2,218,4,115,101, + 108,102,114,17,0,0,0,114,10,0,0,0,114,10,0,0, + 0,114,11,0,0,0,218,8,95,95,105,110,105,116,95,95, + 58,0,0,0,115,12,0,0,0,0,1,10,1,10,1,6, + 1,6,1,6,1,122,20,95,77,111,100,117,108,101,76,111, + 99,107,46,95,95,105,110,105,116,95,95,99,1,0,0,0, + 0,0,0,0,0,0,0,0,4,0,0,0,3,0,0,0, + 67,0,0,0,115,60,0,0,0,116,0,160,1,161,0,125, + 1,124,0,106,2,125,2,116,3,160,4,124,2,161,1,125, + 3,124,3,100,0,107,8,114,36,100,1,83,0,124,3,106, + 2,125,2,124,2,124,1,107,2,114,14,100,2,83,0,113, + 14,100,0,83,0,41,3,78,70,84,41,5,114,23,0,0, + 0,218,9,103,101,116,95,105,100,101,110,116,114,26,0,0, + 0,218,12,95,98,108,111,99,107,105,110,103,95,111,110,218, + 3,103,101,116,41,4,114,30,0,0,0,90,2,109,101,218, + 3,116,105,100,114,24,0,0,0,114,10,0,0,0,114,10, + 0,0,0,114,11,0,0,0,218,12,104,97,115,95,100,101, + 97,100,108,111,99,107,66,0,0,0,115,16,0,0,0,0, + 2,8,1,6,2,10,1,8,1,4,1,6,1,8,1,122, + 24,95,77,111,100,117,108,101,76,111,99,107,46,104,97,115, + 95,100,101,97,100,108,111,99,107,99,1,0,0,0,0,0, + 0,0,0,0,0,0,2,0,0,0,9,0,0,0,67,0, + 0,0,115,178,0,0,0,116,0,160,1,161,0,125,1,124, + 0,116,2,124,1,60,0,122,148,124,0,106,3,143,110,1, + 0,124,0,106,4,100,1,107,2,115,46,124,0,106,5,124, + 1,107,2,114,84,124,1,124,0,95,5,124,0,4,0,106, + 4,100,2,55,0,2,0,95,4,87,0,53,0,81,0,82, + 0,163,0,87,0,162,86,100,3,83,0,124,0,160,6,161, + 0,114,104,116,7,100,4,124,0,22,0,131,1,130,1,124, + 0,106,8,160,9,100,5,161,1,114,130,124,0,4,0,106, + 10,100,2,55,0,2,0,95,10,87,0,53,0,81,0,82, + 0,88,0,124,0,106,8,160,9,161,0,1,0,124,0,106, + 8,160,11,161,0,1,0,113,18,87,0,53,0,116,2,124, + 1,61,0,88,0,100,6,83,0,41,7,122,185,10,32,32, + 32,32,32,32,32,32,65,99,113,117,105,114,101,32,116,104, + 101,32,109,111,100,117,108,101,32,108,111,99,107,46,32,32, + 73,102,32,97,32,112,111,116,101,110,116,105,97,108,32,100, + 101,97,100,108,111,99,107,32,105,115,32,100,101,116,101,99, + 116,101,100,44,10,32,32,32,32,32,32,32,32,97,32,95, + 68,101,97,100,108,111,99,107,69,114,114,111,114,32,105,115, + 32,114,97,105,115,101,100,46,10,32,32,32,32,32,32,32, + 32,79,116,104,101,114,119,105,115,101,44,32,116,104,101,32, + 108,111,99,107,32,105,115,32,97,108,119,97,121,115,32,97, + 99,113,117,105,114,101,100,32,97,110,100,32,84,114,117,101, + 32,105,115,32,114,101,116,117,114,110,101,100,46,10,32,32, + 32,32,32,32,32,32,114,22,0,0,0,233,1,0,0,0, + 84,122,23,100,101,97,100,108,111,99,107,32,100,101,116,101, + 99,116,101,100,32,98,121,32,37,114,70,78,41,12,114,23, + 0,0,0,114,32,0,0,0,114,33,0,0,0,114,24,0, + 0,0,114,27,0,0,0,114,26,0,0,0,114,36,0,0, + 0,114,19,0,0,0,114,25,0,0,0,218,7,97,99,113, + 117,105,114,101,114,28,0,0,0,218,7,114,101,108,101,97, + 115,101,169,2,114,30,0,0,0,114,35,0,0,0,114,10, + 0,0,0,114,10,0,0,0,114,11,0,0,0,114,38,0, + 0,0,78,0,0,0,115,30,0,0,0,0,6,8,1,8, + 1,2,2,8,1,20,1,6,1,14,1,18,1,8,1,12, + 1,12,1,24,2,10,1,16,2,122,19,95,77,111,100,117, + 108,101,76,111,99,107,46,97,99,113,117,105,114,101,99,1, + 0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,9, + 0,0,0,67,0,0,0,115,122,0,0,0,116,0,160,1, + 161,0,125,1,124,0,106,2,143,98,1,0,124,0,106,3, + 124,1,107,3,114,34,116,4,100,1,131,1,130,1,124,0, + 106,5,100,2,107,4,115,48,74,0,130,1,124,0,4,0, + 106,5,100,3,56,0,2,0,95,5,124,0,106,5,100,2, + 107,2,114,108,100,0,124,0,95,3,124,0,106,6,114,108, + 124,0,4,0,106,6,100,3,56,0,2,0,95,6,124,0, + 106,7,160,8,161,0,1,0,87,0,53,0,81,0,82,0, + 88,0,100,0,83,0,41,4,78,250,31,99,97,110,110,111, + 116,32,114,101,108,101,97,115,101,32,117,110,45,97,99,113, + 117,105,114,101,100,32,108,111,99,107,114,22,0,0,0,114, + 37,0,0,0,41,9,114,23,0,0,0,114,32,0,0,0, + 114,24,0,0,0,114,26,0,0,0,218,12,82,117,110,116, + 105,109,101,69,114,114,111,114,114,27,0,0,0,114,28,0, + 0,0,114,25,0,0,0,114,39,0,0,0,114,40,0,0, + 0,114,10,0,0,0,114,10,0,0,0,114,11,0,0,0, + 114,39,0,0,0,103,0,0,0,115,22,0,0,0,0,1, + 8,1,8,1,10,1,8,1,14,1,14,1,10,1,6,1, + 6,1,14,1,122,19,95,77,111,100,117,108,101,76,111,99, + 107,46,114,101,108,101,97,115,101,99,1,0,0,0,0,0, + 0,0,0,0,0,0,1,0,0,0,5,0,0,0,67,0, + 0,0,115,22,0,0,0,100,1,124,0,106,0,155,2,100, + 2,116,1,124,0,131,1,155,0,157,4,83,0,41,3,78, + 122,12,95,77,111,100,117,108,101,76,111,99,107,40,250,5, + 41,32,97,116,32,169,2,114,17,0,0,0,218,2,105,100, + 169,1,114,30,0,0,0,114,10,0,0,0,114,10,0,0, + 0,114,11,0,0,0,218,8,95,95,114,101,112,114,95,95, + 116,0,0,0,115,2,0,0,0,0,1,122,20,95,77,111, + 100,117,108,101,76,111,99,107,46,95,95,114,101,112,114,95, + 95,78,41,9,114,1,0,0,0,114,0,0,0,0,114,2, + 0,0,0,114,3,0,0,0,114,31,0,0,0,114,36,0, + 0,0,114,38,0,0,0,114,39,0,0,0,114,47,0,0, + 0,114,10,0,0,0,114,10,0,0,0,114,10,0,0,0, + 114,11,0,0,0,114,20,0,0,0,52,0,0,0,115,12, + 0,0,0,8,1,4,5,8,8,8,12,8,25,8,13,114, + 20,0,0,0,99,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,2,0,0,0,64,0,0,0,115,48,0, + 0,0,101,0,90,1,100,0,90,2,100,1,90,3,100,2, + 100,3,132,0,90,4,100,4,100,5,132,0,90,5,100,6, + 100,7,132,0,90,6,100,8,100,9,132,0,90,7,100,10, + 83,0,41,11,218,16,95,68,117,109,109,121,77,111,100,117, + 108,101,76,111,99,107,122,86,65,32,115,105,109,112,108,101, + 32,95,77,111,100,117,108,101,76,111,99,107,32,101,113,117, + 105,118,97,108,101,110,116,32,102,111,114,32,80,121,116,104, + 111,110,32,98,117,105,108,100,115,32,119,105,116,104,111,117, + 116,10,32,32,32,32,109,117,108,116,105,45,116,104,114,101, + 97,100,105,110,103,32,115,117,112,112,111,114,116,46,99,2, + 0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,2, + 0,0,0,67,0,0,0,115,16,0,0,0,124,1,124,0, + 95,0,100,1,124,0,95,1,100,0,83,0,114,21,0,0, + 0,41,2,114,17,0,0,0,114,27,0,0,0,114,29,0, + 0,0,114,10,0,0,0,114,10,0,0,0,114,11,0,0, + 0,114,31,0,0,0,124,0,0,0,115,4,0,0,0,0, + 1,6,1,122,25,95,68,117,109,109,121,77,111,100,117,108, + 101,76,111,99,107,46,95,95,105,110,105,116,95,95,99,1, + 0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,3, + 0,0,0,67,0,0,0,115,18,0,0,0,124,0,4,0, + 106,0,100,1,55,0,2,0,95,0,100,2,83,0,41,3, + 78,114,37,0,0,0,84,41,1,114,27,0,0,0,114,46, + 0,0,0,114,10,0,0,0,114,10,0,0,0,114,11,0, + 0,0,114,38,0,0,0,128,0,0,0,115,4,0,0,0, + 0,1,14,1,122,24,95,68,117,109,109,121,77,111,100,117, + 108,101,76,111,99,107,46,97,99,113,117,105,114,101,99,1, + 0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,3, + 0,0,0,67,0,0,0,115,36,0,0,0,124,0,106,0, + 100,1,107,2,114,18,116,1,100,2,131,1,130,1,124,0, + 4,0,106,0,100,3,56,0,2,0,95,0,100,0,83,0, + 41,4,78,114,22,0,0,0,114,41,0,0,0,114,37,0, + 0,0,41,2,114,27,0,0,0,114,42,0,0,0,114,46, + 0,0,0,114,10,0,0,0,114,10,0,0,0,114,11,0, + 0,0,114,39,0,0,0,132,0,0,0,115,6,0,0,0, + 0,1,10,1,8,1,122,24,95,68,117,109,109,121,77,111, + 100,117,108,101,76,111,99,107,46,114,101,108,101,97,115,101, + 99,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0, + 0,5,0,0,0,67,0,0,0,115,22,0,0,0,100,1, + 124,0,106,0,155,2,100,2,116,1,124,0,131,1,155,0, + 157,4,83,0,41,3,78,122,17,95,68,117,109,109,121,77, + 111,100,117,108,101,76,111,99,107,40,114,43,0,0,0,114, + 44,0,0,0,114,46,0,0,0,114,10,0,0,0,114,10, + 0,0,0,114,11,0,0,0,114,47,0,0,0,137,0,0, + 0,115,2,0,0,0,0,1,122,25,95,68,117,109,109,121, + 77,111,100,117,108,101,76,111,99,107,46,95,95,114,101,112, + 114,95,95,78,41,8,114,1,0,0,0,114,0,0,0,0, + 114,2,0,0,0,114,3,0,0,0,114,31,0,0,0,114, + 38,0,0,0,114,39,0,0,0,114,47,0,0,0,114,10, + 0,0,0,114,10,0,0,0,114,10,0,0,0,114,11,0, + 0,0,114,48,0,0,0,120,0,0,0,115,10,0,0,0, + 8,1,4,3,8,4,8,4,8,5,114,48,0,0,0,99, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,0,0,0,64,0,0,0,115,36,0,0,0,101,0,90, + 1,100,0,90,2,100,1,100,2,132,0,90,3,100,3,100, + 4,132,0,90,4,100,5,100,6,132,0,90,5,100,7,83, + 0,41,8,218,18,95,77,111,100,117,108,101,76,111,99,107, + 77,97,110,97,103,101,114,99,2,0,0,0,0,0,0,0, + 0,0,0,0,2,0,0,0,2,0,0,0,67,0,0,0, + 115,16,0,0,0,124,1,124,0,95,0,100,0,124,0,95, + 1,100,0,83,0,114,13,0,0,0,41,2,218,5,95,110, + 97,109,101,218,5,95,108,111,99,107,114,29,0,0,0,114, + 10,0,0,0,114,10,0,0,0,114,11,0,0,0,114,31, + 0,0,0,143,0,0,0,115,4,0,0,0,0,1,6,1, + 122,27,95,77,111,100,117,108,101,76,111,99,107,77,97,110, + 97,103,101,114,46,95,95,105,110,105,116,95,95,99,1,0, + 0,0,0,0,0,0,0,0,0,0,1,0,0,0,2,0, + 0,0,67,0,0,0,115,26,0,0,0,116,0,124,0,106, + 1,131,1,124,0,95,2,124,0,106,2,160,3,161,0,1, + 0,100,0,83,0,114,13,0,0,0,41,4,218,16,95,103, + 101,116,95,109,111,100,117,108,101,95,108,111,99,107,114,50, + 0,0,0,114,51,0,0,0,114,38,0,0,0,114,46,0, + 0,0,114,10,0,0,0,114,10,0,0,0,114,11,0,0, + 0,218,9,95,95,101,110,116,101,114,95,95,147,0,0,0, + 115,4,0,0,0,0,1,12,1,122,28,95,77,111,100,117, + 108,101,76,111,99,107,77,97,110,97,103,101,114,46,95,95, + 101,110,116,101,114,95,95,99,1,0,0,0,0,0,0,0, + 0,0,0,0,3,0,0,0,2,0,0,0,79,0,0,0, + 115,14,0,0,0,124,0,106,0,160,1,161,0,1,0,100, + 0,83,0,114,13,0,0,0,41,2,114,51,0,0,0,114, + 39,0,0,0,41,3,114,30,0,0,0,218,4,97,114,103, + 115,90,6,107,119,97,114,103,115,114,10,0,0,0,114,10, + 0,0,0,114,11,0,0,0,218,8,95,95,101,120,105,116, + 95,95,151,0,0,0,115,2,0,0,0,0,1,122,27,95, + 77,111,100,117,108,101,76,111,99,107,77,97,110,97,103,101, + 114,46,95,95,101,120,105,116,95,95,78,41,6,114,1,0, + 0,0,114,0,0,0,0,114,2,0,0,0,114,31,0,0, + 0,114,53,0,0,0,114,55,0,0,0,114,10,0,0,0, + 114,10,0,0,0,114,10,0,0,0,114,11,0,0,0,114, + 49,0,0,0,141,0,0,0,115,6,0,0,0,8,2,8, + 4,8,4,114,49,0,0,0,99,1,0,0,0,0,0,0, + 0,0,0,0,0,3,0,0,0,8,0,0,0,67,0,0, + 0,115,130,0,0,0,116,0,160,1,161,0,1,0,122,106, + 122,14,116,3,124,0,25,0,131,0,125,1,87,0,110,24, + 4,0,116,4,107,10,114,48,1,0,1,0,1,0,100,1, + 125,1,89,0,110,2,88,0,124,1,100,1,107,8,114,112, + 116,5,100,1,107,8,114,76,116,6,124,0,131,1,125,1, + 110,8,116,7,124,0,131,1,125,1,124,0,102,1,100,2, + 100,3,132,1,125,2,116,8,160,9,124,1,124,2,161,2, + 116,3,124,0,60,0,87,0,53,0,116,0,160,2,161,0, + 1,0,88,0,124,1,83,0,41,4,122,139,71,101,116,32, + 111,114,32,99,114,101,97,116,101,32,116,104,101,32,109,111, + 100,117,108,101,32,108,111,99,107,32,102,111,114,32,97,32, + 103,105,118,101,110,32,109,111,100,117,108,101,32,110,97,109, + 101,46,10,10,32,32,32,32,65,99,113,117,105,114,101,47, + 114,101,108,101,97,115,101,32,105,110,116,101,114,110,97,108, + 108,121,32,116,104,101,32,103,108,111,98,97,108,32,105,109, + 112,111,114,116,32,108,111,99,107,32,116,111,32,112,114,111, + 116,101,99,116,10,32,32,32,32,95,109,111,100,117,108,101, + 95,108,111,99,107,115,46,78,99,2,0,0,0,0,0,0, + 0,0,0,0,0,2,0,0,0,8,0,0,0,83,0,0, + 0,115,48,0,0,0,116,0,160,1,161,0,1,0,122,24, + 116,3,160,4,124,1,161,1,124,0,107,8,114,30,116,3, + 124,1,61,0,87,0,53,0,116,0,160,2,161,0,1,0, + 88,0,100,0,83,0,114,13,0,0,0,41,5,218,4,95, + 105,109,112,218,12,97,99,113,117,105,114,101,95,108,111,99, + 107,218,12,114,101,108,101,97,115,101,95,108,111,99,107,218, + 13,95,109,111,100,117,108,101,95,108,111,99,107,115,114,34, + 0,0,0,41,2,218,3,114,101,102,114,17,0,0,0,114, + 10,0,0,0,114,10,0,0,0,114,11,0,0,0,218,2, + 99,98,176,0,0,0,115,10,0,0,0,0,1,8,1,2, + 4,14,1,10,2,122,28,95,103,101,116,95,109,111,100,117, + 108,101,95,108,111,99,107,46,60,108,111,99,97,108,115,62, + 46,99,98,41,10,114,56,0,0,0,114,57,0,0,0,114, + 58,0,0,0,114,59,0,0,0,218,8,75,101,121,69,114, + 114,111,114,114,23,0,0,0,114,48,0,0,0,114,20,0, + 0,0,218,8,95,119,101,97,107,114,101,102,114,60,0,0, + 0,41,3,114,17,0,0,0,114,24,0,0,0,114,61,0, + 0,0,114,10,0,0,0,114,10,0,0,0,114,11,0,0, + 0,114,52,0,0,0,157,0,0,0,115,28,0,0,0,0, + 6,8,1,2,1,2,1,14,1,14,1,10,2,8,1,8, + 1,10,2,8,2,12,11,20,2,10,2,114,52,0,0,0, + 99,1,0,0,0,0,0,0,0,0,0,0,0,2,0,0, + 0,8,0,0,0,67,0,0,0,115,54,0,0,0,116,0, + 124,0,131,1,125,1,122,12,124,1,160,1,161,0,1,0, + 87,0,110,20,4,0,116,2,107,10,114,40,1,0,1,0, + 1,0,89,0,110,10,88,0,124,1,160,3,161,0,1,0, + 100,1,83,0,41,2,122,189,65,99,113,117,105,114,101,115, + 32,116,104,101,110,32,114,101,108,101,97,115,101,115,32,116, + 104,101,32,109,111,100,117,108,101,32,108,111,99,107,32,102, + 111,114,32,97,32,103,105,118,101,110,32,109,111,100,117,108, + 101,32,110,97,109,101,46,10,10,32,32,32,32,84,104,105, + 115,32,105,115,32,117,115,101,100,32,116,111,32,101,110,115, + 117,114,101,32,97,32,109,111,100,117,108,101,32,105,115,32, + 99,111,109,112,108,101,116,101,108,121,32,105,110,105,116,105, + 97,108,105,122,101,100,44,32,105,110,32,116,104,101,10,32, + 32,32,32,101,118,101,110,116,32,105,116,32,105,115,32,98, + 101,105,110,103,32,105,109,112,111,114,116,101,100,32,98,121, + 32,97,110,111,116,104,101,114,32,116,104,114,101,97,100,46, + 10,32,32,32,32,78,41,4,114,52,0,0,0,114,38,0, + 0,0,114,19,0,0,0,114,39,0,0,0,41,2,114,17, + 0,0,0,114,24,0,0,0,114,10,0,0,0,114,10,0, + 0,0,114,11,0,0,0,218,19,95,108,111,99,107,95,117, + 110,108,111,99,107,95,109,111,100,117,108,101,194,0,0,0, + 115,12,0,0,0,0,6,8,1,2,1,12,1,14,3,6, + 2,114,64,0,0,0,99,1,0,0,0,0,0,0,0,0, + 0,0,0,3,0,0,0,3,0,0,0,79,0,0,0,115, + 10,0,0,0,124,0,124,1,124,2,142,1,83,0,41,1, + 97,46,1,0,0,114,101,109,111,118,101,95,105,109,112,111, + 114,116,108,105,98,95,102,114,97,109,101,115,32,105,110,32, + 105,109,112,111,114,116,46,99,32,119,105,108,108,32,97,108, + 119,97,121,115,32,114,101,109,111,118,101,32,115,101,113,117, + 101,110,99,101,115,10,32,32,32,32,111,102,32,105,109,112, + 111,114,116,108,105,98,32,102,114,97,109,101,115,32,116,104, + 97,116,32,101,110,100,32,119,105,116,104,32,97,32,99,97, + 108,108,32,116,111,32,116,104,105,115,32,102,117,110,99,116, + 105,111,110,10,10,32,32,32,32,85,115,101,32,105,116,32, + 105,110,115,116,101,97,100,32,111,102,32,97,32,110,111,114, + 109,97,108,32,99,97,108,108,32,105,110,32,112,108,97,99, + 101,115,32,119,104,101,114,101,32,105,110,99,108,117,100,105, + 110,103,32,116,104,101,32,105,109,112,111,114,116,108,105,98, + 10,32,32,32,32,102,114,97,109,101,115,32,105,110,116,114, + 111,100,117,99,101,115,32,117,110,119,97,110,116,101,100,32, + 110,111,105,115,101,32,105,110,116,111,32,116,104,101,32,116, + 114,97,99,101,98,97,99,107,32,40,101,46,103,46,32,119, + 104,101,110,32,101,120,101,99,117,116,105,110,103,10,32,32, + 32,32,109,111,100,117,108,101,32,99,111,100,101,41,10,32, + 32,32,32,114,10,0,0,0,41,3,218,1,102,114,54,0, + 0,0,90,4,107,119,100,115,114,10,0,0,0,114,10,0, + 0,0,114,11,0,0,0,218,25,95,99,97,108,108,95,119, + 105,116,104,95,102,114,97,109,101,115,95,114,101,109,111,118, + 101,100,211,0,0,0,115,2,0,0,0,0,8,114,66,0, + 0,0,114,37,0,0,0,41,1,218,9,118,101,114,98,111, + 115,105,116,121,99,1,0,0,0,0,0,0,0,1,0,0, + 0,3,0,0,0,4,0,0,0,71,0,0,0,115,54,0, + 0,0,116,0,106,1,106,2,124,1,107,5,114,50,124,0, + 160,3,100,1,161,1,115,30,100,2,124,0,23,0,125,0, + 116,4,124,0,106,5,124,2,142,0,116,0,106,6,100,3, + 141,2,1,0,100,4,83,0,41,5,122,61,80,114,105,110, + 116,32,116,104,101,32,109,101,115,115,97,103,101,32,116,111, + 32,115,116,100,101,114,114,32,105,102,32,45,118,47,80,89, + 84,72,79,78,86,69,82,66,79,83,69,32,105,115,32,116, + 117,114,110,101,100,32,111,110,46,41,2,250,1,35,122,7, + 105,109,112,111,114,116,32,122,2,35,32,41,1,90,4,102, + 105,108,101,78,41,7,114,15,0,0,0,218,5,102,108,97, + 103,115,218,7,118,101,114,98,111,115,101,218,10,115,116,97, + 114,116,115,119,105,116,104,218,5,112,114,105,110,116,218,6, + 102,111,114,109,97,116,218,6,115,116,100,101,114,114,41,3, + 218,7,109,101,115,115,97,103,101,114,67,0,0,0,114,54, + 0,0,0,114,10,0,0,0,114,10,0,0,0,114,11,0, + 0,0,218,16,95,118,101,114,98,111,115,101,95,109,101,115, + 115,97,103,101,222,0,0,0,115,8,0,0,0,0,2,12, + 1,10,1,8,1,114,76,0,0,0,99,1,0,0,0,0, + 0,0,0,0,0,0,0,2,0,0,0,3,0,0,0,3, + 0,0,0,115,26,0,0,0,135,0,102,1,100,1,100,2, + 132,8,125,1,116,0,124,1,136,0,131,2,1,0,124,1, + 83,0,41,3,122,49,68,101,99,111,114,97,116,111,114,32, + 116,111,32,118,101,114,105,102,121,32,116,104,101,32,110,97, + 109,101,100,32,109,111,100,117,108,101,32,105,115,32,98,117, + 105,108,116,45,105,110,46,99,2,0,0,0,0,0,0,0, + 0,0,0,0,2,0,0,0,4,0,0,0,19,0,0,0, + 115,38,0,0,0,124,1,116,0,106,1,107,7,114,28,116, + 2,124,1,155,2,100,1,157,2,124,1,100,2,141,2,130, + 1,136,0,124,0,124,1,131,2,83,0,41,3,78,250,25, + 32,105,115,32,110,111,116,32,97,32,98,117,105,108,116,45, + 105,110,32,109,111,100,117,108,101,114,16,0,0,0,41,3, + 114,15,0,0,0,218,20,98,117,105,108,116,105,110,95,109, + 111,100,117,108,101,95,110,97,109,101,115,218,11,73,109,112, + 111,114,116,69,114,114,111,114,169,2,114,30,0,0,0,218, + 8,102,117,108,108,110,97,109,101,169,1,218,3,102,120,110, + 114,10,0,0,0,114,11,0,0,0,218,25,95,114,101,113, + 117,105,114,101,115,95,98,117,105,108,116,105,110,95,119,114, + 97,112,112,101,114,232,0,0,0,115,10,0,0,0,0,1, + 10,1,10,1,2,255,6,2,122,52,95,114,101,113,117,105, + 114,101,115,95,98,117,105,108,116,105,110,46,60,108,111,99, + 97,108,115,62,46,95,114,101,113,117,105,114,101,115,95,98, + 117,105,108,116,105,110,95,119,114,97,112,112,101,114,169,1, + 114,12,0,0,0,41,2,114,83,0,0,0,114,84,0,0, + 0,114,10,0,0,0,114,82,0,0,0,114,11,0,0,0, + 218,17,95,114,101,113,117,105,114,101,115,95,98,117,105,108, + 116,105,110,230,0,0,0,115,6,0,0,0,0,2,12,5, + 10,1,114,86,0,0,0,99,1,0,0,0,0,0,0,0, + 0,0,0,0,2,0,0,0,3,0,0,0,3,0,0,0, + 115,26,0,0,0,135,0,102,1,100,1,100,2,132,8,125, + 1,116,0,124,1,136,0,131,2,1,0,124,1,83,0,41, + 3,122,47,68,101,99,111,114,97,116,111,114,32,116,111,32, + 118,101,114,105,102,121,32,116,104,101,32,110,97,109,101,100, + 32,109,111,100,117,108,101,32,105,115,32,102,114,111,122,101, + 110,46,99,2,0,0,0,0,0,0,0,0,0,0,0,2, + 0,0,0,4,0,0,0,19,0,0,0,115,38,0,0,0, + 116,0,160,1,124,1,161,1,115,28,116,2,124,1,155,2, + 100,1,157,2,124,1,100,2,141,2,130,1,136,0,124,0, + 124,1,131,2,83,0,169,3,78,122,23,32,105,115,32,110, + 111,116,32,97,32,102,114,111,122,101,110,32,109,111,100,117, + 108,101,114,16,0,0,0,41,3,114,56,0,0,0,218,9, + 105,115,95,102,114,111,122,101,110,114,79,0,0,0,114,80, + 0,0,0,114,82,0,0,0,114,10,0,0,0,114,11,0, + 0,0,218,24,95,114,101,113,117,105,114,101,115,95,102,114, + 111,122,101,110,95,119,114,97,112,112,101,114,243,0,0,0, + 115,10,0,0,0,0,1,10,1,10,1,2,255,6,2,122, + 50,95,114,101,113,117,105,114,101,115,95,102,114,111,122,101, + 110,46,60,108,111,99,97,108,115,62,46,95,114,101,113,117, + 105,114,101,115,95,102,114,111,122,101,110,95,119,114,97,112, + 112,101,114,114,85,0,0,0,41,2,114,83,0,0,0,114, + 89,0,0,0,114,10,0,0,0,114,82,0,0,0,114,11, + 0,0,0,218,16,95,114,101,113,117,105,114,101,115,95,102, + 114,111,122,101,110,241,0,0,0,115,6,0,0,0,0,2, + 12,5,10,1,114,90,0,0,0,99,2,0,0,0,0,0, + 0,0,0,0,0,0,4,0,0,0,3,0,0,0,67,0, + 0,0,115,62,0,0,0,116,0,124,1,124,0,131,2,125, + 2,124,1,116,1,106,2,107,6,114,50,116,1,106,2,124, + 1,25,0,125,3,116,3,124,2,124,3,131,2,1,0,116, + 1,106,2,124,1,25,0,83,0,116,4,124,2,131,1,83, + 0,100,1,83,0,41,2,122,128,76,111,97,100,32,116,104, + 101,32,115,112,101,99,105,102,105,101,100,32,109,111,100,117, + 108,101,32,105,110,116,111,32,115,121,115,46,109,111,100,117, + 108,101,115,32,97,110,100,32,114,101,116,117,114,110,32,105, + 116,46,10,10,32,32,32,32,84,104,105,115,32,109,101,116, + 104,111,100,32,105,115,32,100,101,112,114,101,99,97,116,101, + 100,46,32,32,85,115,101,32,108,111,97,100,101,114,46,101, + 120,101,99,95,109,111,100,117,108,101,32,105,110,115,116,101, + 97,100,46,10,10,32,32,32,32,78,41,5,218,16,115,112, + 101,99,95,102,114,111,109,95,108,111,97,100,101,114,114,15, + 0,0,0,218,7,109,111,100,117,108,101,115,218,5,95,101, + 120,101,99,218,5,95,108,111,97,100,41,4,114,30,0,0, + 0,114,81,0,0,0,218,4,115,112,101,99,218,6,109,111, + 100,117,108,101,114,10,0,0,0,114,10,0,0,0,114,11, + 0,0,0,218,17,95,108,111,97,100,95,109,111,100,117,108, + 101,95,115,104,105,109,253,0,0,0,115,12,0,0,0,0, + 6,10,1,10,1,10,1,10,1,10,2,114,97,0,0,0, + 99,1,0,0,0,0,0,0,0,0,0,0,0,5,0,0, + 0,8,0,0,0,67,0,0,0,115,240,0,0,0,116,0, + 124,0,100,1,100,0,131,3,125,1,116,1,124,1,100,2, + 131,2,114,56,122,12,124,1,160,2,124,0,161,1,87,0, + 83,0,4,0,116,3,107,10,114,54,1,0,1,0,1,0, + 89,0,110,2,88,0,122,10,124,0,106,4,125,2,87,0, + 110,20,4,0,116,5,107,10,114,86,1,0,1,0,1,0, + 89,0,110,18,88,0,124,2,100,0,107,9,114,104,116,6, + 124,2,131,1,83,0,122,10,124,0,106,7,125,3,87,0, + 110,24,4,0,116,5,107,10,114,138,1,0,1,0,1,0, + 100,3,125,3,89,0,110,2,88,0,122,10,124,0,106,8, + 125,4,87,0,110,66,4,0,116,5,107,10,114,216,1,0, + 1,0,1,0,124,1,100,0,107,8,114,190,100,4,124,3, + 155,2,100,5,157,3,6,0,89,0,83,0,100,4,124,3, + 155,2,100,6,124,1,155,2,100,7,157,5,6,0,89,0, + 83,0,89,0,110,20,88,0,100,4,124,3,155,2,100,8, + 124,4,155,2,100,5,157,5,83,0,100,0,83,0,41,9, + 78,218,10,95,95,108,111,97,100,101,114,95,95,218,11,109, + 111,100,117,108,101,95,114,101,112,114,250,1,63,250,8,60, + 109,111,100,117,108,101,32,250,1,62,250,2,32,40,250,2, + 41,62,250,6,32,102,114,111,109,32,41,9,114,6,0,0, + 0,114,4,0,0,0,114,99,0,0,0,218,9,69,120,99, + 101,112,116,105,111,110,218,8,95,95,115,112,101,99,95,95, + 218,14,65,116,116,114,105,98,117,116,101,69,114,114,111,114, + 218,22,95,109,111,100,117,108,101,95,114,101,112,114,95,102, + 114,111,109,95,115,112,101,99,114,1,0,0,0,218,8,95, + 95,102,105,108,101,95,95,41,5,114,96,0,0,0,218,6, + 108,111,97,100,101,114,114,95,0,0,0,114,17,0,0,0, + 218,8,102,105,108,101,110,97,109,101,114,10,0,0,0,114, + 10,0,0,0,114,11,0,0,0,218,12,95,109,111,100,117, + 108,101,95,114,101,112,114,13,1,0,0,115,46,0,0,0, + 0,2,12,1,10,4,2,1,12,1,14,1,6,1,2,1, + 10,1,14,1,6,2,8,1,8,4,2,1,10,1,14,1, + 10,1,2,1,10,1,14,1,8,1,16,2,28,2,114,113, + 0,0,0,99,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,4,0,0,0,64,0,0,0,115,114,0,0, + 0,101,0,90,1,100,0,90,2,100,1,90,3,100,2,100, + 2,100,2,100,3,156,3,100,4,100,5,132,2,90,4,100, + 6,100,7,132,0,90,5,100,8,100,9,132,0,90,6,101, + 7,100,10,100,11,132,0,131,1,90,8,101,8,106,9,100, + 12,100,11,132,0,131,1,90,8,101,7,100,13,100,14,132, + 0,131,1,90,10,101,7,100,15,100,16,132,0,131,1,90, + 11,101,11,106,9,100,17,100,16,132,0,131,1,90,11,100, + 2,83,0,41,18,218,10,77,111,100,117,108,101,83,112,101, + 99,97,208,5,0,0,84,104,101,32,115,112,101,99,105,102, + 105,99,97,116,105,111,110,32,102,111,114,32,97,32,109,111, + 100,117,108,101,44,32,117,115,101,100,32,102,111,114,32,108, + 111,97,100,105,110,103,46,10,10,32,32,32,32,65,32,109, + 111,100,117,108,101,39,115,32,115,112,101,99,32,105,115,32, + 116,104,101,32,115,111,117,114,99,101,32,102,111,114,32,105, + 110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116, + 32,116,104,101,32,109,111,100,117,108,101,46,32,32,70,111, + 114,10,32,32,32,32,100,97,116,97,32,97,115,115,111,99, + 105,97,116,101,100,32,119,105,116,104,32,116,104,101,32,109, + 111,100,117,108,101,44,32,105,110,99,108,117,100,105,110,103, + 32,115,111,117,114,99,101,44,32,117,115,101,32,116,104,101, + 32,115,112,101,99,39,115,10,32,32,32,32,108,111,97,100, + 101,114,46,10,10,32,32,32,32,96,110,97,109,101,96,32, + 105,115,32,116,104,101,32,97,98,115,111,108,117,116,101,32, + 110,97,109,101,32,111,102,32,116,104,101,32,109,111,100,117, + 108,101,46,32,32,96,108,111,97,100,101,114,96,32,105,115, + 32,116,104,101,32,108,111,97,100,101,114,10,32,32,32,32, + 116,111,32,117,115,101,32,119,104,101,110,32,108,111,97,100, + 105,110,103,32,116,104,101,32,109,111,100,117,108,101,46,32, + 32,96,112,97,114,101,110,116,96,32,105,115,32,116,104,101, + 32,110,97,109,101,32,111,102,32,116,104,101,10,32,32,32, + 32,112,97,99,107,97,103,101,32,116,104,101,32,109,111,100, + 117,108,101,32,105,115,32,105,110,46,32,32,84,104,101,32, + 112,97,114,101,110,116,32,105,115,32,100,101,114,105,118,101, + 100,32,102,114,111,109,32,116,104,101,32,110,97,109,101,46, + 10,10,32,32,32,32,96,105,115,95,112,97,99,107,97,103, + 101,96,32,100,101,116,101,114,109,105,110,101,115,32,105,102, + 32,116,104,101,32,109,111,100,117,108,101,32,105,115,32,99, + 111,110,115,105,100,101,114,101,100,32,97,32,112,97,99,107, + 97,103,101,32,111,114,10,32,32,32,32,110,111,116,46,32, + 32,79,110,32,109,111,100,117,108,101,115,32,116,104,105,115, + 32,105,115,32,114,101,102,108,101,99,116,101,100,32,98,121, + 32,116,104,101,32,96,95,95,112,97,116,104,95,95,96,32, + 97,116,116,114,105,98,117,116,101,46,10,10,32,32,32,32, + 96,111,114,105,103,105,110,96,32,105,115,32,116,104,101,32, + 115,112,101,99,105,102,105,99,32,108,111,99,97,116,105,111, + 110,32,117,115,101,100,32,98,121,32,116,104,101,32,108,111, + 97,100,101,114,32,102,114,111,109,32,119,104,105,99,104,32, + 116,111,10,32,32,32,32,108,111,97,100,32,116,104,101,32, + 109,111,100,117,108,101,44,32,105,102,32,116,104,97,116,32, + 105,110,102,111,114,109,97,116,105,111,110,32,105,115,32,97, + 118,97,105,108,97,98,108,101,46,32,32,87,104,101,110,32, + 102,105,108,101,110,97,109,101,32,105,115,10,32,32,32,32, + 115,101,116,44,32,111,114,105,103,105,110,32,119,105,108,108, + 32,109,97,116,99,104,46,10,10,32,32,32,32,96,104,97, + 115,95,108,111,99,97,116,105,111,110,96,32,105,110,100,105, + 99,97,116,101,115,32,116,104,97,116,32,97,32,115,112,101, + 99,39,115,32,34,111,114,105,103,105,110,34,32,114,101,102, + 108,101,99,116,115,32,97,32,108,111,99,97,116,105,111,110, + 46,10,32,32,32,32,87,104,101,110,32,116,104,105,115,32, + 105,115,32,84,114,117,101,44,32,96,95,95,102,105,108,101, + 95,95,96,32,97,116,116,114,105,98,117,116,101,32,111,102, + 32,116,104,101,32,109,111,100,117,108,101,32,105,115,32,115, + 101,116,46,10,10,32,32,32,32,96,99,97,99,104,101,100, + 96,32,105,115,32,116,104,101,32,108,111,99,97,116,105,111, + 110,32,111,102,32,116,104,101,32,99,97,99,104,101,100,32, + 98,121,116,101,99,111,100,101,32,102,105,108,101,44,32,105, + 102,32,97,110,121,46,32,32,73,116,10,32,32,32,32,99, + 111,114,114,101,115,112,111,110,100,115,32,116,111,32,116,104, + 101,32,96,95,95,99,97,99,104,101,100,95,95,96,32,97, + 116,116,114,105,98,117,116,101,46,10,10,32,32,32,32,96, + 115,117,98,109,111,100,117,108,101,95,115,101,97,114,99,104, + 95,108,111,99,97,116,105,111,110,115,96,32,105,115,32,116, + 104,101,32,115,101,113,117,101,110,99,101,32,111,102,32,112, + 97,116,104,32,101,110,116,114,105,101,115,32,116,111,10,32, + 32,32,32,115,101,97,114,99,104,32,119,104,101,110,32,105, + 109,112,111,114,116,105,110,103,32,115,117,98,109,111,100,117, + 108,101,115,46,32,32,73,102,32,115,101,116,44,32,105,115, + 95,112,97,99,107,97,103,101,32,115,104,111,117,108,100,32, + 98,101,10,32,32,32,32,84,114,117,101,45,45,97,110,100, + 32,70,97,108,115,101,32,111,116,104,101,114,119,105,115,101, + 46,10,10,32,32,32,32,80,97,99,107,97,103,101,115,32, + 97,114,101,32,115,105,109,112,108,121,32,109,111,100,117,108, + 101,115,32,116,104,97,116,32,40,109,97,121,41,32,104,97, + 118,101,32,115,117,98,109,111,100,117,108,101,115,46,32,32, + 73,102,32,97,32,115,112,101,99,10,32,32,32,32,104,97, + 115,32,97,32,110,111,110,45,78,111,110,101,32,118,97,108, + 117,101,32,105,110,32,96,115,117,98,109,111,100,117,108,101, + 95,115,101,97,114,99,104,95,108,111,99,97,116,105,111,110, + 115,96,44,32,116,104,101,32,105,109,112,111,114,116,10,32, + 32,32,32,115,121,115,116,101,109,32,119,105,108,108,32,99, + 111,110,115,105,100,101,114,32,109,111,100,117,108,101,115,32, + 108,111,97,100,101,100,32,102,114,111,109,32,116,104,101,32, + 115,112,101,99,32,97,115,32,112,97,99,107,97,103,101,115, + 46,10,10,32,32,32,32,79,110,108,121,32,102,105,110,100, + 101,114,115,32,40,115,101,101,32,105,109,112,111,114,116,108, + 105,98,46,97,98,99,46,77,101,116,97,80,97,116,104,70, + 105,110,100,101,114,32,97,110,100,10,32,32,32,32,105,109, + 112,111,114,116,108,105,98,46,97,98,99,46,80,97,116,104, + 69,110,116,114,121,70,105,110,100,101,114,41,32,115,104,111, + 117,108,100,32,109,111,100,105,102,121,32,77,111,100,117,108, + 101,83,112,101,99,32,105,110,115,116,97,110,99,101,115,46, + 10,10,32,32,32,32,78,41,3,218,6,111,114,105,103,105, + 110,218,12,108,111,97,100,101,114,95,115,116,97,116,101,218, + 10,105,115,95,112,97,99,107,97,103,101,99,3,0,0,0, + 0,0,0,0,3,0,0,0,6,0,0,0,2,0,0,0, + 67,0,0,0,115,54,0,0,0,124,1,124,0,95,0,124, + 2,124,0,95,1,124,3,124,0,95,2,124,4,124,0,95, + 3,124,5,114,32,103,0,110,2,100,0,124,0,95,4,100, + 1,124,0,95,5,100,0,124,0,95,6,100,0,83,0,41, + 2,78,70,41,7,114,17,0,0,0,114,111,0,0,0,114, + 115,0,0,0,114,116,0,0,0,218,26,115,117,98,109,111, + 100,117,108,101,95,115,101,97,114,99,104,95,108,111,99,97, + 116,105,111,110,115,218,13,95,115,101,116,95,102,105,108,101, + 97,116,116,114,218,7,95,99,97,99,104,101,100,41,6,114, + 30,0,0,0,114,17,0,0,0,114,111,0,0,0,114,115, + 0,0,0,114,116,0,0,0,114,117,0,0,0,114,10,0, + 0,0,114,10,0,0,0,114,11,0,0,0,114,31,0,0, + 0,86,1,0,0,115,14,0,0,0,0,2,6,1,6,1, + 6,1,6,1,14,3,6,1,122,19,77,111,100,117,108,101, + 83,112,101,99,46,95,95,105,110,105,116,95,95,99,1,0, + 0,0,0,0,0,0,0,0,0,0,2,0,0,0,5,0, + 0,0,67,0,0,0,115,106,0,0,0,100,1,124,0,106, + 0,155,2,157,2,100,2,124,0,106,1,155,2,157,2,103, + 2,125,1,124,0,106,2,100,0,107,9,114,52,124,1,160, + 3,100,3,124,0,106,2,155,2,157,2,161,1,1,0,124, + 0,106,4,100,0,107,9,114,80,124,1,160,3,100,4,124, + 0,106,4,155,0,157,2,161,1,1,0,124,0,106,5,106, + 6,155,0,100,5,100,6,160,7,124,1,161,1,155,0,100, + 7,157,4,83,0,41,8,78,122,5,110,97,109,101,61,122, + 7,108,111,97,100,101,114,61,122,7,111,114,105,103,105,110, + 61,122,27,115,117,98,109,111,100,117,108,101,95,115,101,97, + 114,99,104,95,108,111,99,97,116,105,111,110,115,61,250,1, + 40,122,2,44,32,250,1,41,41,8,114,17,0,0,0,114, + 111,0,0,0,114,115,0,0,0,218,6,97,112,112,101,110, + 100,114,118,0,0,0,218,9,95,95,99,108,97,115,115,95, + 95,114,1,0,0,0,218,4,106,111,105,110,41,2,114,30, + 0,0,0,114,54,0,0,0,114,10,0,0,0,114,10,0, + 0,0,114,11,0,0,0,114,47,0,0,0,98,1,0,0, + 115,16,0,0,0,0,1,10,1,10,255,4,2,10,1,18, + 1,10,1,18,1,122,19,77,111,100,117,108,101,83,112,101, + 99,46,95,95,114,101,112,114,95,95,99,2,0,0,0,0, + 0,0,0,0,0,0,0,3,0,0,0,8,0,0,0,67, + 0,0,0,115,108,0,0,0,124,0,106,0,125,2,122,72, + 124,0,106,1,124,1,106,1,107,2,111,76,124,0,106,2, + 124,1,106,2,107,2,111,76,124,0,106,3,124,1,106,3, + 107,2,111,76,124,2,124,1,106,0,107,2,111,76,124,0, + 106,4,124,1,106,4,107,2,111,76,124,0,106,5,124,1, + 106,5,107,2,87,0,83,0,4,0,116,6,107,10,114,102, + 1,0,1,0,1,0,116,7,6,0,89,0,83,0,88,0, + 100,0,83,0,114,13,0,0,0,41,8,114,118,0,0,0, + 114,17,0,0,0,114,111,0,0,0,114,115,0,0,0,218, + 6,99,97,99,104,101,100,218,12,104,97,115,95,108,111,99, + 97,116,105,111,110,114,108,0,0,0,218,14,78,111,116,73, + 109,112,108,101,109,101,110,116,101,100,41,3,114,30,0,0, + 0,90,5,111,116,104,101,114,90,4,115,109,115,108,114,10, + 0,0,0,114,10,0,0,0,114,11,0,0,0,218,6,95, + 95,101,113,95,95,107,1,0,0,115,30,0,0,0,0,1, + 6,1,2,1,12,1,10,255,2,2,10,254,2,3,8,253, + 2,4,10,252,2,5,10,251,4,6,14,1,122,17,77,111, + 100,117,108,101,83,112,101,99,46,95,95,101,113,95,95,99, + 1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0, + 3,0,0,0,67,0,0,0,115,58,0,0,0,124,0,106, + 0,100,0,107,8,114,52,124,0,106,1,100,0,107,9,114, + 52,124,0,106,2,114,52,116,3,100,0,107,8,114,38,116, + 4,130,1,116,3,160,5,124,0,106,1,161,1,124,0,95, + 0,124,0,106,0,83,0,114,13,0,0,0,41,6,114,120, + 0,0,0,114,115,0,0,0,114,119,0,0,0,218,19,95, + 98,111,111,116,115,116,114,97,112,95,101,120,116,101,114,110, + 97,108,218,19,78,111,116,73,109,112,108,101,109,101,110,116, + 101,100,69,114,114,111,114,90,11,95,103,101,116,95,99,97, + 99,104,101,100,114,46,0,0,0,114,10,0,0,0,114,10, + 0,0,0,114,11,0,0,0,114,126,0,0,0,119,1,0, + 0,115,12,0,0,0,0,2,10,1,16,1,8,1,4,1, + 14,1,122,17,77,111,100,117,108,101,83,112,101,99,46,99, + 97,99,104,101,100,99,2,0,0,0,0,0,0,0,0,0, + 0,0,2,0,0,0,2,0,0,0,67,0,0,0,115,10, + 0,0,0,124,1,124,0,95,0,100,0,83,0,114,13,0, + 0,0,41,1,114,120,0,0,0,41,2,114,30,0,0,0, + 114,126,0,0,0,114,10,0,0,0,114,10,0,0,0,114, + 11,0,0,0,114,126,0,0,0,128,1,0,0,115,2,0, + 0,0,0,2,99,1,0,0,0,0,0,0,0,0,0,0, + 0,1,0,0,0,3,0,0,0,67,0,0,0,115,36,0, + 0,0,124,0,106,0,100,1,107,8,114,26,124,0,106,1, + 160,2,100,2,161,1,100,3,25,0,83,0,124,0,106,1, + 83,0,100,1,83,0,41,4,122,32,84,104,101,32,110,97, + 109,101,32,111,102,32,116,104,101,32,109,111,100,117,108,101, + 39,115,32,112,97,114,101,110,116,46,78,218,1,46,114,22, + 0,0,0,41,3,114,118,0,0,0,114,17,0,0,0,218, + 10,114,112,97,114,116,105,116,105,111,110,114,46,0,0,0, + 114,10,0,0,0,114,10,0,0,0,114,11,0,0,0,218, + 6,112,97,114,101,110,116,132,1,0,0,115,6,0,0,0, + 0,3,10,1,16,2,122,17,77,111,100,117,108,101,83,112, + 101,99,46,112,97,114,101,110,116,99,1,0,0,0,0,0, + 0,0,0,0,0,0,1,0,0,0,1,0,0,0,67,0, + 0,0,115,6,0,0,0,124,0,106,0,83,0,114,13,0, + 0,0,41,1,114,119,0,0,0,114,46,0,0,0,114,10, + 0,0,0,114,10,0,0,0,114,11,0,0,0,114,127,0, + 0,0,140,1,0,0,115,2,0,0,0,0,2,122,23,77, + 111,100,117,108,101,83,112,101,99,46,104,97,115,95,108,111, + 99,97,116,105,111,110,99,2,0,0,0,0,0,0,0,0, + 0,0,0,2,0,0,0,2,0,0,0,67,0,0,0,115, + 14,0,0,0,116,0,124,1,131,1,124,0,95,1,100,0, + 83,0,114,13,0,0,0,41,2,218,4,98,111,111,108,114, + 119,0,0,0,41,2,114,30,0,0,0,218,5,118,97,108, + 117,101,114,10,0,0,0,114,10,0,0,0,114,11,0,0, + 0,114,127,0,0,0,144,1,0,0,115,2,0,0,0,0, + 2,41,12,114,1,0,0,0,114,0,0,0,0,114,2,0, + 0,0,114,3,0,0,0,114,31,0,0,0,114,47,0,0, + 0,114,129,0,0,0,218,8,112,114,111,112,101,114,116,121, + 114,126,0,0,0,218,6,115,101,116,116,101,114,114,134,0, + 0,0,114,127,0,0,0,114,10,0,0,0,114,10,0,0, + 0,114,10,0,0,0,114,11,0,0,0,114,114,0,0,0, + 49,1,0,0,115,32,0,0,0,8,1,4,36,4,1,2, + 255,12,12,8,9,8,12,2,1,10,8,4,1,10,3,2, + 1,10,7,2,1,10,3,4,1,114,114,0,0,0,169,2, + 114,115,0,0,0,114,117,0,0,0,99,2,0,0,0,0, + 0,0,0,2,0,0,0,6,0,0,0,8,0,0,0,67, + 0,0,0,115,154,0,0,0,116,0,124,1,100,1,131,2, + 114,74,116,1,100,2,107,8,114,22,116,2,130,1,116,1, + 106,3,125,4,124,3,100,2,107,8,114,48,124,4,124,0, + 124,1,100,3,141,2,83,0,124,3,114,56,103,0,110,2, + 100,2,125,5,124,4,124,0,124,1,124,5,100,4,141,3, + 83,0,124,3,100,2,107,8,114,138,116,0,124,1,100,5, + 131,2,114,134,122,14,124,1,160,4,124,0,161,1,125,3, + 87,0,113,138,4,0,116,5,107,10,114,130,1,0,1,0, + 1,0,100,2,125,3,89,0,113,138,88,0,110,4,100,6, + 125,3,116,6,124,0,124,1,124,2,124,3,100,7,141,4, + 83,0,41,8,122,53,82,101,116,117,114,110,32,97,32,109, + 111,100,117,108,101,32,115,112,101,99,32,98,97,115,101,100, + 32,111,110,32,118,97,114,105,111,117,115,32,108,111,97,100, + 101,114,32,109,101,116,104,111,100,115,46,90,12,103,101,116, + 95,102,105,108,101,110,97,109,101,78,41,1,114,111,0,0, + 0,41,2,114,111,0,0,0,114,118,0,0,0,114,117,0, + 0,0,70,114,139,0,0,0,41,7,114,4,0,0,0,114, + 130,0,0,0,114,131,0,0,0,218,23,115,112,101,99,95, + 102,114,111,109,95,102,105,108,101,95,108,111,99,97,116,105, + 111,110,114,117,0,0,0,114,79,0,0,0,114,114,0,0, + 0,41,6,114,17,0,0,0,114,111,0,0,0,114,115,0, + 0,0,114,117,0,0,0,114,140,0,0,0,90,6,115,101, + 97,114,99,104,114,10,0,0,0,114,10,0,0,0,114,11, + 0,0,0,114,91,0,0,0,149,1,0,0,115,36,0,0, + 0,0,2,10,1,8,1,4,1,6,2,8,1,12,1,12, + 1,6,1,2,255,6,3,8,1,10,1,2,1,14,1,14, + 1,12,3,4,2,114,91,0,0,0,99,3,0,0,0,0, + 0,0,0,0,0,0,0,8,0,0,0,8,0,0,0,67, + 0,0,0,115,56,1,0,0,122,10,124,0,106,0,125,3, + 87,0,110,20,4,0,116,1,107,10,114,30,1,0,1,0, + 1,0,89,0,110,14,88,0,124,3,100,0,107,9,114,44, + 124,3,83,0,124,0,106,2,125,4,124,1,100,0,107,8, + 114,90,122,10,124,0,106,3,125,1,87,0,110,20,4,0, + 116,1,107,10,114,88,1,0,1,0,1,0,89,0,110,2, + 88,0,122,10,124,0,106,4,125,5,87,0,110,24,4,0, + 116,1,107,10,114,124,1,0,1,0,1,0,100,0,125,5, + 89,0,110,2,88,0,124,2,100,0,107,8,114,184,124,5, + 100,0,107,8,114,180,122,10,124,1,106,5,125,2,87,0, + 113,184,4,0,116,1,107,10,114,176,1,0,1,0,1,0, + 100,0,125,2,89,0,113,184,88,0,110,4,124,5,125,2, + 122,10,124,0,106,6,125,6,87,0,110,24,4,0,116,1, + 107,10,114,218,1,0,1,0,1,0,100,0,125,6,89,0, + 110,2,88,0,122,14,116,7,124,0,106,8,131,1,125,7, + 87,0,110,26,4,0,116,1,107,10,144,1,114,4,1,0, + 1,0,1,0,100,0,125,7,89,0,110,2,88,0,116,9, + 124,4,124,1,124,2,100,1,141,3,125,3,124,5,100,0, + 107,8,144,1,114,34,100,2,110,2,100,3,124,3,95,10, + 124,6,124,3,95,11,124,7,124,3,95,12,124,3,83,0, + 41,4,78,169,1,114,115,0,0,0,70,84,41,13,114,107, + 0,0,0,114,108,0,0,0,114,1,0,0,0,114,98,0, + 0,0,114,110,0,0,0,218,7,95,79,82,73,71,73,78, + 218,10,95,95,99,97,99,104,101,100,95,95,218,4,108,105, + 115,116,218,8,95,95,112,97,116,104,95,95,114,114,0,0, + 0,114,119,0,0,0,114,126,0,0,0,114,118,0,0,0, + 41,8,114,96,0,0,0,114,111,0,0,0,114,115,0,0, + 0,114,95,0,0,0,114,17,0,0,0,90,8,108,111,99, + 97,116,105,111,110,114,126,0,0,0,114,118,0,0,0,114, + 10,0,0,0,114,10,0,0,0,114,11,0,0,0,218,17, + 95,115,112,101,99,95,102,114,111,109,95,109,111,100,117,108, + 101,175,1,0,0,115,72,0,0,0,0,2,2,1,10,1, + 14,1,6,2,8,1,4,2,6,1,8,1,2,1,10,1, + 14,2,6,1,2,1,10,1,14,1,10,1,8,1,8,1, + 2,1,10,1,14,1,12,2,4,1,2,1,10,1,14,1, + 10,1,2,1,14,1,16,1,10,2,14,1,20,1,6,1, + 6,1,114,146,0,0,0,70,169,1,218,8,111,118,101,114, + 114,105,100,101,99,2,0,0,0,0,0,0,0,1,0,0, + 0,5,0,0,0,8,0,0,0,67,0,0,0,115,226,1, + 0,0,124,2,115,20,116,0,124,1,100,1,100,0,131,3, + 100,0,107,8,114,54,122,12,124,0,106,1,124,1,95,2, + 87,0,110,20,4,0,116,3,107,10,114,52,1,0,1,0, + 1,0,89,0,110,2,88,0,124,2,115,74,116,0,124,1, + 100,2,100,0,131,3,100,0,107,8,114,178,124,0,106,4, + 125,3,124,3,100,0,107,8,114,146,124,0,106,5,100,0, + 107,9,114,146,116,6,100,0,107,8,114,110,116,7,130,1, + 116,6,106,8,125,4,124,4,160,9,124,4,161,1,125,3, + 124,0,106,5,124,3,95,10,124,3,124,0,95,4,100,0, + 124,1,95,11,122,10,124,3,124,1,95,12,87,0,110,20, + 4,0,116,3,107,10,114,176,1,0,1,0,1,0,89,0, + 110,2,88,0,124,2,115,198,116,0,124,1,100,3,100,0, + 131,3,100,0,107,8,114,232,122,12,124,0,106,13,124,1, + 95,14,87,0,110,20,4,0,116,3,107,10,114,230,1,0, + 1,0,1,0,89,0,110,2,88,0,122,10,124,0,124,1, + 95,15,87,0,110,22,4,0,116,3,107,10,144,1,114,8, + 1,0,1,0,1,0,89,0,110,2,88,0,124,2,144,1, + 115,34,116,0,124,1,100,4,100,0,131,3,100,0,107,8, + 144,1,114,82,124,0,106,5,100,0,107,9,144,1,114,82, + 122,12,124,0,106,5,124,1,95,16,87,0,110,22,4,0, + 116,3,107,10,144,1,114,80,1,0,1,0,1,0,89,0, + 110,2,88,0,124,0,106,17,144,1,114,222,124,2,144,1, + 115,114,116,0,124,1,100,5,100,0,131,3,100,0,107,8, + 144,1,114,150,122,12,124,0,106,18,124,1,95,11,87,0, + 110,22,4,0,116,3,107,10,144,1,114,148,1,0,1,0, + 1,0,89,0,110,2,88,0,124,2,144,1,115,174,116,0, + 124,1,100,6,100,0,131,3,100,0,107,8,144,1,114,222, + 124,0,106,19,100,0,107,9,144,1,114,222,122,12,124,0, + 106,19,124,1,95,20,87,0,110,22,4,0,116,3,107,10, + 144,1,114,220,1,0,1,0,1,0,89,0,110,2,88,0, + 124,1,83,0,41,7,78,114,1,0,0,0,114,98,0,0, + 0,218,11,95,95,112,97,99,107,97,103,101,95,95,114,145, + 0,0,0,114,110,0,0,0,114,143,0,0,0,41,21,114, + 6,0,0,0,114,17,0,0,0,114,1,0,0,0,114,108, + 0,0,0,114,111,0,0,0,114,118,0,0,0,114,130,0, + 0,0,114,131,0,0,0,218,16,95,78,97,109,101,115,112, + 97,99,101,76,111,97,100,101,114,218,7,95,95,110,101,119, + 95,95,90,5,95,112,97,116,104,114,110,0,0,0,114,98, + 0,0,0,114,134,0,0,0,114,149,0,0,0,114,107,0, + 0,0,114,145,0,0,0,114,127,0,0,0,114,115,0,0, + 0,114,126,0,0,0,114,143,0,0,0,41,5,114,95,0, + 0,0,114,96,0,0,0,114,148,0,0,0,114,111,0,0, + 0,114,150,0,0,0,114,10,0,0,0,114,10,0,0,0, + 114,11,0,0,0,218,18,95,105,110,105,116,95,109,111,100, + 117,108,101,95,97,116,116,114,115,220,1,0,0,115,96,0, + 0,0,0,4,20,1,2,1,12,1,14,1,6,2,20,1, + 6,1,8,2,10,1,8,1,4,1,6,2,10,1,8,1, + 6,11,6,1,2,1,10,1,14,1,6,2,20,1,2,1, + 12,1,14,1,6,2,2,1,10,1,16,1,6,2,24,1, + 12,1,2,1,12,1,16,1,6,2,8,1,24,1,2,1, + 12,1,16,1,6,2,24,1,12,1,2,1,12,1,16,1, + 6,1,114,152,0,0,0,99,1,0,0,0,0,0,0,0, + 0,0,0,0,2,0,0,0,3,0,0,0,67,0,0,0, + 115,82,0,0,0,100,1,125,1,116,0,124,0,106,1,100, + 2,131,2,114,30,124,0,106,1,160,2,124,0,161,1,125, + 1,110,20,116,0,124,0,106,1,100,3,131,2,114,50,116, + 3,100,4,131,1,130,1,124,1,100,1,107,8,114,68,116, + 4,124,0,106,5,131,1,125,1,116,6,124,0,124,1,131, + 2,1,0,124,1,83,0,41,5,122,43,67,114,101,97,116, + 101,32,97,32,109,111,100,117,108,101,32,98,97,115,101,100, + 32,111,110,32,116,104,101,32,112,114,111,118,105,100,101,100, + 32,115,112,101,99,46,78,218,13,99,114,101,97,116,101,95, + 109,111,100,117,108,101,218,11,101,120,101,99,95,109,111,100, + 117,108,101,122,66,108,111,97,100,101,114,115,32,116,104,97, + 116,32,100,101,102,105,110,101,32,101,120,101,99,95,109,111, + 100,117,108,101,40,41,32,109,117,115,116,32,97,108,115,111, + 32,100,101,102,105,110,101,32,99,114,101,97,116,101,95,109, + 111,100,117,108,101,40,41,41,7,114,4,0,0,0,114,111, + 0,0,0,114,153,0,0,0,114,79,0,0,0,114,18,0, + 0,0,114,17,0,0,0,114,152,0,0,0,169,2,114,95, + 0,0,0,114,96,0,0,0,114,10,0,0,0,114,10,0, + 0,0,114,11,0,0,0,218,16,109,111,100,117,108,101,95, + 102,114,111,109,95,115,112,101,99,36,2,0,0,115,18,0, + 0,0,0,3,4,1,12,3,14,1,12,1,8,2,8,1, + 10,1,10,1,114,156,0,0,0,99,1,0,0,0,0,0, + 0,0,0,0,0,0,2,0,0,0,5,0,0,0,67,0, + 0,0,115,126,0,0,0,124,0,106,0,100,1,107,8,114, + 14,100,2,110,4,124,0,106,0,125,1,124,0,106,1,100, + 1,107,8,114,74,124,0,106,2,100,1,107,8,114,52,100, + 3,124,1,155,2,100,4,157,3,83,0,100,3,124,1,155, + 2,100,5,124,0,106,2,155,2,100,6,157,5,83,0,110, + 48,124,0,106,3,114,100,100,3,124,1,155,2,100,7,124, + 0,106,1,155,2,100,4,157,5,83,0,100,3,124,0,106, + 0,155,2,100,5,124,0,106,1,155,0,100,6,157,5,83, + 0,100,1,83,0,41,8,122,38,82,101,116,117,114,110,32, + 116,104,101,32,114,101,112,114,32,116,111,32,117,115,101,32, + 102,111,114,32,116,104,101,32,109,111,100,117,108,101,46,78, + 114,100,0,0,0,114,101,0,0,0,114,102,0,0,0,114, + 103,0,0,0,114,104,0,0,0,114,105,0,0,0,41,4, + 114,17,0,0,0,114,115,0,0,0,114,111,0,0,0,114, + 127,0,0,0,41,2,114,95,0,0,0,114,17,0,0,0, + 114,10,0,0,0,114,10,0,0,0,114,11,0,0,0,114, + 109,0,0,0,53,2,0,0,115,16,0,0,0,0,3,20, + 1,10,1,10,1,12,2,22,2,6,1,20,2,114,109,0, + 0,0,99,2,0,0,0,0,0,0,0,0,0,0,0,4, + 0,0,0,10,0,0,0,67,0,0,0,115,206,0,0,0, + 124,0,106,0,125,2,116,1,124,2,131,1,143,182,1,0, + 116,2,106,3,160,4,124,2,161,1,124,1,107,9,114,56, + 100,1,124,2,155,2,100,2,157,3,125,3,116,5,124,3, + 124,2,100,3,141,2,130,1,122,106,124,0,106,7,100,4, + 107,8,114,108,124,0,106,8,100,4,107,8,114,92,116,5, + 100,5,124,0,106,0,100,3,141,2,130,1,116,9,124,0, + 124,1,100,6,100,7,141,3,1,0,110,52,116,9,124,0, + 124,1,100,6,100,7,141,3,1,0,116,10,124,0,106,7, + 100,8,131,2,115,148,124,0,106,7,160,11,124,2,161,1, + 1,0,110,12,124,0,106,7,160,12,124,1,161,1,1,0, + 87,0,53,0,116,2,106,3,160,6,124,0,106,0,161,1, + 125,1,124,1,116,2,106,3,124,0,106,0,60,0,88,0, + 87,0,53,0,81,0,82,0,88,0,124,1,83,0,41,9, + 122,70,69,120,101,99,117,116,101,32,116,104,101,32,115,112, + 101,99,39,115,32,115,112,101,99,105,102,105,101,100,32,109, + 111,100,117,108,101,32,105,110,32,97,110,32,101,120,105,115, + 116,105,110,103,32,109,111,100,117,108,101,39,115,32,110,97, + 109,101,115,112,97,99,101,46,122,7,109,111,100,117,108,101, + 32,122,19,32,110,111,116,32,105,110,32,115,121,115,46,109, + 111,100,117,108,101,115,114,16,0,0,0,78,250,14,109,105, + 115,115,105,110,103,32,108,111,97,100,101,114,84,114,147,0, + 0,0,114,154,0,0,0,41,13,114,17,0,0,0,114,49, + 0,0,0,114,15,0,0,0,114,92,0,0,0,114,34,0, + 0,0,114,79,0,0,0,218,3,112,111,112,114,111,0,0, + 0,114,118,0,0,0,114,152,0,0,0,114,4,0,0,0, + 218,11,108,111,97,100,95,109,111,100,117,108,101,114,154,0, + 0,0,41,4,114,95,0,0,0,114,96,0,0,0,114,17, + 0,0,0,218,3,109,115,103,114,10,0,0,0,114,10,0, + 0,0,114,11,0,0,0,114,93,0,0,0,70,2,0,0, + 115,34,0,0,0,0,2,6,1,10,1,16,1,12,1,12, + 1,2,1,10,1,10,1,14,2,16,2,14,1,12,4,14, + 2,16,4,14,1,24,1,114,93,0,0,0,99,1,0,0, + 0,0,0,0,0,0,0,0,0,2,0,0,0,8,0,0, + 0,67,0,0,0,115,26,1,0,0,122,18,124,0,106,0, + 160,1,124,0,106,2,161,1,1,0,87,0,110,52,1,0, + 1,0,1,0,124,0,106,2,116,3,106,4,107,6,114,64, + 116,3,106,4,160,5,124,0,106,2,161,1,125,1,124,1, + 116,3,106,4,124,0,106,2,60,0,130,0,89,0,110,2, + 88,0,116,3,106,4,160,5,124,0,106,2,161,1,125,1, + 124,1,116,3,106,4,124,0,106,2,60,0,116,6,124,1, + 100,1,100,0,131,3,100,0,107,8,114,148,122,12,124,0, + 106,0,124,1,95,7,87,0,110,20,4,0,116,8,107,10, + 114,146,1,0,1,0,1,0,89,0,110,2,88,0,116,6, + 124,1,100,2,100,0,131,3,100,0,107,8,114,226,122,40, + 124,1,106,9,124,1,95,10,116,11,124,1,100,3,131,2, + 115,202,124,0,106,2,160,12,100,4,161,1,100,5,25,0, + 124,1,95,10,87,0,110,20,4,0,116,8,107,10,114,224, + 1,0,1,0,1,0,89,0,110,2,88,0,116,6,124,1, + 100,6,100,0,131,3,100,0,107,8,144,1,114,22,122,10, + 124,0,124,1,95,13,87,0,110,22,4,0,116,8,107,10, + 144,1,114,20,1,0,1,0,1,0,89,0,110,2,88,0, + 124,1,83,0,41,7,78,114,98,0,0,0,114,149,0,0, + 0,114,145,0,0,0,114,132,0,0,0,114,22,0,0,0, + 114,107,0,0,0,41,14,114,111,0,0,0,114,159,0,0, + 0,114,17,0,0,0,114,15,0,0,0,114,92,0,0,0, + 114,158,0,0,0,114,6,0,0,0,114,98,0,0,0,114, + 108,0,0,0,114,1,0,0,0,114,149,0,0,0,114,4, + 0,0,0,114,133,0,0,0,114,107,0,0,0,114,155,0, + 0,0,114,10,0,0,0,114,10,0,0,0,114,11,0,0, + 0,218,25,95,108,111,97,100,95,98,97,99,107,119,97,114, + 100,95,99,111,109,112,97,116,105,98,108,101,100,2,0,0, + 115,54,0,0,0,0,4,2,1,18,1,6,1,12,1,14, + 1,12,1,8,3,14,1,12,1,16,1,2,1,12,1,14, + 1,6,1,16,1,2,4,8,1,10,1,22,1,14,1,6, + 1,18,1,2,1,10,1,16,1,6,1,114,161,0,0,0, + 99,1,0,0,0,0,0,0,0,0,0,0,0,2,0,0, + 0,11,0,0,0,67,0,0,0,115,220,0,0,0,124,0, + 106,0,100,0,107,9,114,30,116,1,124,0,106,0,100,1, + 131,2,115,30,116,2,124,0,131,1,83,0,116,3,124,0, + 131,1,125,1,100,2,124,0,95,4,122,162,124,1,116,5, + 106,6,124,0,106,7,60,0,122,52,124,0,106,0,100,0, + 107,8,114,96,124,0,106,8,100,0,107,8,114,108,116,9, + 100,4,124,0,106,7,100,5,141,2,130,1,110,12,124,0, + 106,0,160,10,124,1,161,1,1,0,87,0,110,50,1,0, + 1,0,1,0,122,14,116,5,106,6,124,0,106,7,61,0, + 87,0,110,20,4,0,116,11,107,10,114,152,1,0,1,0, + 1,0,89,0,110,2,88,0,130,0,89,0,110,2,88,0, + 116,5,106,6,160,12,124,0,106,7,161,1,125,1,124,1, + 116,5,106,6,124,0,106,7,60,0,116,13,100,6,124,0, + 106,7,124,0,106,0,131,3,1,0,87,0,53,0,100,3, + 124,0,95,4,88,0,124,1,83,0,41,7,78,114,154,0, + 0,0,84,70,114,157,0,0,0,114,16,0,0,0,122,18, + 105,109,112,111,114,116,32,123,33,114,125,32,35,32,123,33, + 114,125,41,14,114,111,0,0,0,114,4,0,0,0,114,161, + 0,0,0,114,156,0,0,0,90,13,95,105,110,105,116,105, + 97,108,105,122,105,110,103,114,15,0,0,0,114,92,0,0, + 0,114,17,0,0,0,114,118,0,0,0,114,79,0,0,0, + 114,154,0,0,0,114,62,0,0,0,114,158,0,0,0,114, + 76,0,0,0,114,155,0,0,0,114,10,0,0,0,114,10, + 0,0,0,114,11,0,0,0,218,14,95,108,111,97,100,95, + 117,110,108,111,99,107,101,100,137,2,0,0,115,46,0,0, + 0,0,2,10,2,12,1,8,2,8,5,6,1,2,1,12, + 1,2,1,10,1,10,1,16,3,16,1,6,1,2,1,14, + 1,14,1,6,1,8,5,14,1,12,1,20,2,8,2,114, + 162,0,0,0,99,1,0,0,0,0,0,0,0,0,0,0, + 0,1,0,0,0,10,0,0,0,67,0,0,0,115,42,0, + 0,0,116,0,124,0,106,1,131,1,143,22,1,0,116,2, + 124,0,131,1,87,0,2,0,53,0,81,0,82,0,163,0, + 83,0,81,0,82,0,88,0,100,1,83,0,41,2,122,191, + 82,101,116,117,114,110,32,97,32,110,101,119,32,109,111,100, + 117,108,101,32,111,98,106,101,99,116,44,32,108,111,97,100, + 101,100,32,98,121,32,116,104,101,32,115,112,101,99,39,115, + 32,108,111,97,100,101,114,46,10,10,32,32,32,32,84,104, + 101,32,109,111,100,117,108,101,32,105,115,32,110,111,116,32, + 97,100,100,101,100,32,116,111,32,105,116,115,32,112,97,114, + 101,110,116,46,10,10,32,32,32,32,73,102,32,97,32,109, + 111,100,117,108,101,32,105,115,32,97,108,114,101,97,100,121, + 32,105,110,32,115,121,115,46,109,111,100,117,108,101,115,44, + 32,116,104,97,116,32,101,120,105,115,116,105,110,103,32,109, + 111,100,117,108,101,32,103,101,116,115,10,32,32,32,32,99, + 108,111,98,98,101,114,101,100,46,10,10,32,32,32,32,78, + 41,3,114,49,0,0,0,114,17,0,0,0,114,162,0,0, + 0,41,1,114,95,0,0,0,114,10,0,0,0,114,10,0, + 0,0,114,11,0,0,0,114,94,0,0,0,179,2,0,0, + 115,4,0,0,0,0,9,12,1,114,94,0,0,0,99,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4, + 0,0,0,64,0,0,0,115,140,0,0,0,101,0,90,1, + 100,0,90,2,100,1,90,3,100,2,90,4,101,5,100,3, + 100,4,132,0,131,1,90,6,101,7,100,20,100,6,100,7, + 132,1,131,1,90,8,101,7,100,21,100,8,100,9,132,1, + 131,1,90,9,101,7,100,10,100,11,132,0,131,1,90,10, + 101,7,100,12,100,13,132,0,131,1,90,11,101,7,101,12, + 100,14,100,15,132,0,131,1,131,1,90,13,101,7,101,12, + 100,16,100,17,132,0,131,1,131,1,90,14,101,7,101,12, + 100,18,100,19,132,0,131,1,131,1,90,15,101,7,101,16, + 131,1,90,17,100,5,83,0,41,22,218,15,66,117,105,108, + 116,105,110,73,109,112,111,114,116,101,114,122,144,77,101,116, + 97,32,112,97,116,104,32,105,109,112,111,114,116,32,102,111, + 114,32,98,117,105,108,116,45,105,110,32,109,111,100,117,108, + 101,115,46,10,10,32,32,32,32,65,108,108,32,109,101,116, + 104,111,100,115,32,97,114,101,32,101,105,116,104,101,114,32, + 99,108,97,115,115,32,111,114,32,115,116,97,116,105,99,32, + 109,101,116,104,111,100,115,32,116,111,32,97,118,111,105,100, + 32,116,104,101,32,110,101,101,100,32,116,111,10,32,32,32, + 32,105,110,115,116,97,110,116,105,97,116,101,32,116,104,101, + 32,99,108,97,115,115,46,10,10,32,32,32,32,122,8,98, + 117,105,108,116,45,105,110,99,1,0,0,0,0,0,0,0, + 0,0,0,0,1,0,0,0,5,0,0,0,67,0,0,0, + 115,22,0,0,0,100,1,124,0,106,0,155,2,100,2,116, + 1,106,2,155,0,100,3,157,5,83,0,169,4,122,115,82, + 101,116,117,114,110,32,114,101,112,114,32,102,111,114,32,116, + 104,101,32,109,111,100,117,108,101,46,10,10,32,32,32,32, + 32,32,32,32,84,104,101,32,109,101,116,104,111,100,32,105, + 115,32,100,101,112,114,101,99,97,116,101,100,46,32,32,84, + 104,101,32,105,109,112,111,114,116,32,109,97,99,104,105,110, + 101,114,121,32,100,111,101,115,32,116,104,101,32,106,111,98, + 32,105,116,115,101,108,102,46,10,10,32,32,32,32,32,32, + 32,32,114,101,0,0,0,114,103,0,0,0,114,104,0,0, + 0,41,3,114,1,0,0,0,114,163,0,0,0,114,142,0, + 0,0,41,1,114,96,0,0,0,114,10,0,0,0,114,10, + 0,0,0,114,11,0,0,0,114,99,0,0,0,205,2,0, + 0,115,2,0,0,0,0,7,122,27,66,117,105,108,116,105, + 110,73,109,112,111,114,116,101,114,46,109,111,100,117,108,101, + 95,114,101,112,114,78,99,4,0,0,0,0,0,0,0,0, + 0,0,0,4,0,0,0,5,0,0,0,67,0,0,0,115, + 46,0,0,0,124,2,100,0,107,9,114,12,100,0,83,0, + 116,0,160,1,124,1,161,1,114,38,116,2,124,1,124,0, + 124,0,106,3,100,1,141,3,83,0,100,0,83,0,100,0, + 83,0,169,2,78,114,141,0,0,0,41,4,114,56,0,0, + 0,90,10,105,115,95,98,117,105,108,116,105,110,114,91,0, + 0,0,114,142,0,0,0,169,4,218,3,99,108,115,114,81, + 0,0,0,218,4,112,97,116,104,218,6,116,97,114,103,101, + 116,114,10,0,0,0,114,10,0,0,0,114,11,0,0,0, + 218,9,102,105,110,100,95,115,112,101,99,214,2,0,0,115, + 10,0,0,0,0,2,8,1,4,1,10,1,16,2,122,25, + 66,117,105,108,116,105,110,73,109,112,111,114,116,101,114,46, + 102,105,110,100,95,115,112,101,99,99,3,0,0,0,0,0, + 0,0,0,0,0,0,4,0,0,0,4,0,0,0,67,0, + 0,0,115,30,0,0,0,124,0,160,0,124,1,124,2,161, + 2,125,3,124,3,100,1,107,9,114,26,124,3,106,1,83, + 0,100,1,83,0,41,2,122,175,70,105,110,100,32,116,104, + 101,32,98,117,105,108,116,45,105,110,32,109,111,100,117,108, + 101,46,10,10,32,32,32,32,32,32,32,32,73,102,32,39, + 112,97,116,104,39,32,105,115,32,101,118,101,114,32,115,112, + 101,99,105,102,105,101,100,32,116,104,101,110,32,116,104,101, + 32,115,101,97,114,99,104,32,105,115,32,99,111,110,115,105, + 100,101,114,101,100,32,97,32,102,97,105,108,117,114,101,46, + 10,10,32,32,32,32,32,32,32,32,84,104,105,115,32,109, + 101,116,104,111,100,32,105,115,32,100,101,112,114,101,99,97, + 116,101,100,46,32,32,85,115,101,32,102,105,110,100,95,115, + 112,101,99,40,41,32,105,110,115,116,101,97,100,46,10,10, + 32,32,32,32,32,32,32,32,78,41,2,114,170,0,0,0, + 114,111,0,0,0,41,4,114,167,0,0,0,114,81,0,0, + 0,114,168,0,0,0,114,95,0,0,0,114,10,0,0,0, + 114,10,0,0,0,114,11,0,0,0,218,11,102,105,110,100, + 95,109,111,100,117,108,101,223,2,0,0,115,4,0,0,0, + 0,9,12,1,122,27,66,117,105,108,116,105,110,73,109,112, + 111,114,116,101,114,46,102,105,110,100,95,109,111,100,117,108, + 101,99,2,0,0,0,0,0,0,0,0,0,0,0,2,0, + 0,0,4,0,0,0,67,0,0,0,115,46,0,0,0,124, + 1,106,0,116,1,106,2,107,7,114,34,116,3,124,1,106, + 0,155,2,100,1,157,2,124,1,106,0,100,2,141,2,130, + 1,116,4,116,5,106,6,124,1,131,2,83,0,41,3,122, + 24,67,114,101,97,116,101,32,97,32,98,117,105,108,116,45, + 105,110,32,109,111,100,117,108,101,114,77,0,0,0,114,16, + 0,0,0,41,7,114,17,0,0,0,114,15,0,0,0,114, + 78,0,0,0,114,79,0,0,0,114,66,0,0,0,114,56, + 0,0,0,90,14,99,114,101,97,116,101,95,98,117,105,108, + 116,105,110,41,2,114,30,0,0,0,114,95,0,0,0,114, + 10,0,0,0,114,10,0,0,0,114,11,0,0,0,114,153, + 0,0,0,235,2,0,0,115,10,0,0,0,0,3,12,1, + 12,1,4,255,6,2,122,29,66,117,105,108,116,105,110,73, + 109,112,111,114,116,101,114,46,99,114,101,97,116,101,95,109, + 111,100,117,108,101,99,2,0,0,0,0,0,0,0,0,0, + 0,0,2,0,0,0,3,0,0,0,67,0,0,0,115,16, + 0,0,0,116,0,116,1,106,2,124,1,131,2,1,0,100, + 1,83,0,41,2,122,22,69,120,101,99,32,97,32,98,117, + 105,108,116,45,105,110,32,109,111,100,117,108,101,78,41,3, + 114,66,0,0,0,114,56,0,0,0,90,12,101,120,101,99, + 95,98,117,105,108,116,105,110,41,2,114,30,0,0,0,114, + 96,0,0,0,114,10,0,0,0,114,10,0,0,0,114,11, + 0,0,0,114,154,0,0,0,243,2,0,0,115,2,0,0, + 0,0,3,122,27,66,117,105,108,116,105,110,73,109,112,111, + 114,116,101,114,46,101,120,101,99,95,109,111,100,117,108,101, + 99,2,0,0,0,0,0,0,0,0,0,0,0,2,0,0, + 0,1,0,0,0,67,0,0,0,115,4,0,0,0,100,1, + 83,0,41,2,122,57,82,101,116,117,114,110,32,78,111,110, + 101,32,97,115,32,98,117,105,108,116,45,105,110,32,109,111, + 100,117,108,101,115,32,100,111,32,110,111,116,32,104,97,118, + 101,32,99,111,100,101,32,111,98,106,101,99,116,115,46,78, + 114,10,0,0,0,169,2,114,167,0,0,0,114,81,0,0, + 0,114,10,0,0,0,114,10,0,0,0,114,11,0,0,0, + 218,8,103,101,116,95,99,111,100,101,248,2,0,0,115,2, + 0,0,0,0,4,122,24,66,117,105,108,116,105,110,73,109, + 112,111,114,116,101,114,46,103,101,116,95,99,111,100,101,99, + 2,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0, + 1,0,0,0,67,0,0,0,115,4,0,0,0,100,1,83, + 0,41,2,122,56,82,101,116,117,114,110,32,78,111,110,101, + 32,97,115,32,98,117,105,108,116,45,105,110,32,109,111,100, + 117,108,101,115,32,100,111,32,110,111,116,32,104,97,118,101, + 32,115,111,117,114,99,101,32,99,111,100,101,46,78,114,10, + 0,0,0,114,172,0,0,0,114,10,0,0,0,114,10,0, + 0,0,114,11,0,0,0,218,10,103,101,116,95,115,111,117, + 114,99,101,254,2,0,0,115,2,0,0,0,0,4,122,26, + 66,117,105,108,116,105,110,73,109,112,111,114,116,101,114,46, + 103,101,116,95,115,111,117,114,99,101,99,2,0,0,0,0, + 0,0,0,0,0,0,0,2,0,0,0,1,0,0,0,67, + 0,0,0,115,4,0,0,0,100,1,83,0,41,2,122,52, + 82,101,116,117,114,110,32,70,97,108,115,101,32,97,115,32, + 98,117,105,108,116,45,105,110,32,109,111,100,117,108,101,115, + 32,97,114,101,32,110,101,118,101,114,32,112,97,99,107,97, + 103,101,115,46,70,114,10,0,0,0,114,172,0,0,0,114, + 10,0,0,0,114,10,0,0,0,114,11,0,0,0,114,117, + 0,0,0,4,3,0,0,115,2,0,0,0,0,4,122,26, + 66,117,105,108,116,105,110,73,109,112,111,114,116,101,114,46, + 105,115,95,112,97,99,107,97,103,101,41,2,78,78,41,1, + 78,41,18,114,1,0,0,0,114,0,0,0,0,114,2,0, + 0,0,114,3,0,0,0,114,142,0,0,0,218,12,115,116, + 97,116,105,99,109,101,116,104,111,100,114,99,0,0,0,218, + 11,99,108,97,115,115,109,101,116,104,111,100,114,170,0,0, + 0,114,171,0,0,0,114,153,0,0,0,114,154,0,0,0, + 114,86,0,0,0,114,173,0,0,0,114,174,0,0,0,114, + 117,0,0,0,114,97,0,0,0,114,159,0,0,0,114,10, + 0,0,0,114,10,0,0,0,114,10,0,0,0,114,11,0, + 0,0,114,163,0,0,0,194,2,0,0,115,44,0,0,0, + 8,2,4,7,4,2,2,1,10,8,2,1,12,8,2,1, + 12,11,2,1,10,7,2,1,10,4,2,1,2,1,12,4, + 2,1,2,1,12,4,2,1,2,1,12,4,114,163,0,0, + 0,99,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,4,0,0,0,64,0,0,0,115,144,0,0,0,101, + 0,90,1,100,0,90,2,100,1,90,3,100,2,90,4,101, + 5,100,3,100,4,132,0,131,1,90,6,101,7,100,22,100, + 6,100,7,132,1,131,1,90,8,101,7,100,23,100,8,100, + 9,132,1,131,1,90,9,101,7,100,10,100,11,132,0,131, + 1,90,10,101,5,100,12,100,13,132,0,131,1,90,11,101, + 7,100,14,100,15,132,0,131,1,90,12,101,7,101,13,100, + 16,100,17,132,0,131,1,131,1,90,14,101,7,101,13,100, + 18,100,19,132,0,131,1,131,1,90,15,101,7,101,13,100, + 20,100,21,132,0,131,1,131,1,90,16,100,5,83,0,41, + 24,218,14,70,114,111,122,101,110,73,109,112,111,114,116,101, + 114,122,142,77,101,116,97,32,112,97,116,104,32,105,109,112, + 111,114,116,32,102,111,114,32,102,114,111,122,101,110,32,109, + 111,100,117,108,101,115,46,10,10,32,32,32,32,65,108,108, + 32,109,101,116,104,111,100,115,32,97,114,101,32,101,105,116, + 104,101,114,32,99,108,97,115,115,32,111,114,32,115,116,97, + 116,105,99,32,109,101,116,104,111,100,115,32,116,111,32,97, + 118,111,105,100,32,116,104,101,32,110,101,101,100,32,116,111, + 10,32,32,32,32,105,110,115,116,97,110,116,105,97,116,101, + 32,116,104,101,32,99,108,97,115,115,46,10,10,32,32,32, + 32,90,6,102,114,111,122,101,110,99,1,0,0,0,0,0, + 0,0,0,0,0,0,1,0,0,0,5,0,0,0,67,0, + 0,0,115,22,0,0,0,100,1,124,0,106,0,155,2,100, + 2,116,1,106,2,155,0,100,3,157,5,83,0,114,164,0, + 0,0,41,3,114,1,0,0,0,114,177,0,0,0,114,142, + 0,0,0,41,1,218,1,109,114,10,0,0,0,114,10,0, + 0,0,114,11,0,0,0,114,99,0,0,0,24,3,0,0, + 115,2,0,0,0,0,7,122,26,70,114,111,122,101,110,73, + 109,112,111,114,116,101,114,46,109,111,100,117,108,101,95,114, + 101,112,114,78,99,4,0,0,0,0,0,0,0,0,0,0, + 0,4,0,0,0,5,0,0,0,67,0,0,0,115,34,0, + 0,0,116,0,160,1,124,1,161,1,114,26,116,2,124,1, + 124,0,124,0,106,3,100,1,141,3,83,0,100,0,83,0, + 100,0,83,0,114,165,0,0,0,41,4,114,56,0,0,0, + 114,88,0,0,0,114,91,0,0,0,114,142,0,0,0,114, + 166,0,0,0,114,10,0,0,0,114,10,0,0,0,114,11, + 0,0,0,114,170,0,0,0,33,3,0,0,115,6,0,0, + 0,0,2,10,1,16,2,122,24,70,114,111,122,101,110,73, + 109,112,111,114,116,101,114,46,102,105,110,100,95,115,112,101, + 99,99,3,0,0,0,0,0,0,0,0,0,0,0,3,0, + 0,0,3,0,0,0,67,0,0,0,115,18,0,0,0,116, + 0,160,1,124,1,161,1,114,14,124,0,83,0,100,1,83, + 0,41,2,122,93,70,105,110,100,32,97,32,102,114,111,122, + 101,110,32,109,111,100,117,108,101,46,10,10,32,32,32,32, + 32,32,32,32,84,104,105,115,32,109,101,116,104,111,100,32, + 105,115,32,100,101,112,114,101,99,97,116,101,100,46,32,32, + 85,115,101,32,102,105,110,100,95,115,112,101,99,40,41,32, + 105,110,115,116,101,97,100,46,10,10,32,32,32,32,32,32, + 32,32,78,41,2,114,56,0,0,0,114,88,0,0,0,41, + 3,114,167,0,0,0,114,81,0,0,0,114,168,0,0,0, + 114,10,0,0,0,114,10,0,0,0,114,11,0,0,0,114, + 171,0,0,0,40,3,0,0,115,2,0,0,0,0,7,122, + 26,70,114,111,122,101,110,73,109,112,111,114,116,101,114,46, + 102,105,110,100,95,109,111,100,117,108,101,99,2,0,0,0, + 0,0,0,0,0,0,0,0,2,0,0,0,1,0,0,0, + 67,0,0,0,115,4,0,0,0,100,1,83,0,41,2,122, + 42,85,115,101,32,100,101,102,97,117,108,116,32,115,101,109, + 97,110,116,105,99,115,32,102,111,114,32,109,111,100,117,108, + 101,32,99,114,101,97,116,105,111,110,46,78,114,10,0,0, + 0,41,2,114,167,0,0,0,114,95,0,0,0,114,10,0, + 0,0,114,10,0,0,0,114,11,0,0,0,114,153,0,0, + 0,49,3,0,0,115,2,0,0,0,0,2,122,28,70,114, + 111,122,101,110,73,109,112,111,114,116,101,114,46,99,114,101, + 97,116,101,95,109,111,100,117,108,101,99,1,0,0,0,0, + 0,0,0,0,0,0,0,3,0,0,0,4,0,0,0,67, + 0,0,0,115,64,0,0,0,124,0,106,0,106,1,125,1, + 116,2,160,3,124,1,161,1,115,36,116,4,124,1,155,2, + 100,1,157,2,124,1,100,2,141,2,130,1,116,5,116,2, + 106,6,124,1,131,2,125,2,116,7,124,2,124,0,106,8, + 131,2,1,0,100,0,83,0,114,87,0,0,0,41,9,114, + 107,0,0,0,114,17,0,0,0,114,56,0,0,0,114,88, + 0,0,0,114,79,0,0,0,114,66,0,0,0,218,17,103, + 101,116,95,102,114,111,122,101,110,95,111,98,106,101,99,116, + 218,4,101,120,101,99,114,7,0,0,0,41,3,114,96,0, + 0,0,114,17,0,0,0,218,4,99,111,100,101,114,10,0, + 0,0,114,10,0,0,0,114,11,0,0,0,114,154,0,0, + 0,53,3,0,0,115,10,0,0,0,0,2,8,1,10,1, + 18,1,12,1,122,26,70,114,111,122,101,110,73,109,112,111, + 114,116,101,114,46,101,120,101,99,95,109,111,100,117,108,101, + 99,2,0,0,0,0,0,0,0,0,0,0,0,2,0,0, + 0,3,0,0,0,67,0,0,0,115,10,0,0,0,116,0, + 124,0,124,1,131,2,83,0,41,1,122,95,76,111,97,100, + 32,97,32,102,114,111,122,101,110,32,109,111,100,117,108,101, + 46,10,10,32,32,32,32,32,32,32,32,84,104,105,115,32, + 109,101,116,104,111,100,32,105,115,32,100,101,112,114,101,99, + 97,116,101,100,46,32,32,85,115,101,32,101,120,101,99,95, + 109,111,100,117,108,101,40,41,32,105,110,115,116,101,97,100, + 46,10,10,32,32,32,32,32,32,32,32,41,1,114,97,0, + 0,0,114,172,0,0,0,114,10,0,0,0,114,10,0,0, + 0,114,11,0,0,0,114,159,0,0,0,61,3,0,0,115, + 2,0,0,0,0,7,122,26,70,114,111,122,101,110,73,109, + 112,111,114,116,101,114,46,108,111,97,100,95,109,111,100,117, + 108,101,99,2,0,0,0,0,0,0,0,0,0,0,0,2, + 0,0,0,3,0,0,0,67,0,0,0,115,10,0,0,0, + 116,0,160,1,124,1,161,1,83,0,41,1,122,45,82,101, + 116,117,114,110,32,116,104,101,32,99,111,100,101,32,111,98, + 106,101,99,116,32,102,111,114,32,116,104,101,32,102,114,111, + 122,101,110,32,109,111,100,117,108,101,46,41,2,114,56,0, + 0,0,114,179,0,0,0,114,172,0,0,0,114,10,0,0, + 0,114,10,0,0,0,114,11,0,0,0,114,173,0,0,0, + 70,3,0,0,115,2,0,0,0,0,4,122,23,70,114,111, + 122,101,110,73,109,112,111,114,116,101,114,46,103,101,116,95, + 99,111,100,101,99,2,0,0,0,0,0,0,0,0,0,0, + 0,2,0,0,0,1,0,0,0,67,0,0,0,115,4,0, + 0,0,100,1,83,0,41,2,122,54,82,101,116,117,114,110, + 32,78,111,110,101,32,97,115,32,102,114,111,122,101,110,32, + 109,111,100,117,108,101,115,32,100,111,32,110,111,116,32,104, + 97,118,101,32,115,111,117,114,99,101,32,99,111,100,101,46, + 78,114,10,0,0,0,114,172,0,0,0,114,10,0,0,0, + 114,10,0,0,0,114,11,0,0,0,114,174,0,0,0,76, + 3,0,0,115,2,0,0,0,0,4,122,25,70,114,111,122, + 101,110,73,109,112,111,114,116,101,114,46,103,101,116,95,115, + 111,117,114,99,101,99,2,0,0,0,0,0,0,0,0,0, + 0,0,2,0,0,0,3,0,0,0,67,0,0,0,115,10, + 0,0,0,116,0,160,1,124,1,161,1,83,0,41,1,122, + 46,82,101,116,117,114,110,32,84,114,117,101,32,105,102,32, + 116,104,101,32,102,114,111,122,101,110,32,109,111,100,117,108, + 101,32,105,115,32,97,32,112,97,99,107,97,103,101,46,41, + 2,114,56,0,0,0,90,17,105,115,95,102,114,111,122,101, + 110,95,112,97,99,107,97,103,101,114,172,0,0,0,114,10, + 0,0,0,114,10,0,0,0,114,11,0,0,0,114,117,0, + 0,0,82,3,0,0,115,2,0,0,0,0,4,122,25,70, + 114,111,122,101,110,73,109,112,111,114,116,101,114,46,105,115, + 95,112,97,99,107,97,103,101,41,2,78,78,41,1,78,41, + 17,114,1,0,0,0,114,0,0,0,0,114,2,0,0,0, + 114,3,0,0,0,114,142,0,0,0,114,175,0,0,0,114, + 99,0,0,0,114,176,0,0,0,114,170,0,0,0,114,171, + 0,0,0,114,153,0,0,0,114,154,0,0,0,114,159,0, + 0,0,114,90,0,0,0,114,173,0,0,0,114,174,0,0, + 0,114,117,0,0,0,114,10,0,0,0,114,10,0,0,0, + 114,10,0,0,0,114,11,0,0,0,114,177,0,0,0,13, + 3,0,0,115,46,0,0,0,8,2,4,7,4,2,2,1, + 10,8,2,1,12,6,2,1,12,8,2,1,10,3,2,1, + 10,7,2,1,10,8,2,1,2,1,12,4,2,1,2,1, + 12,4,2,1,2,1,114,177,0,0,0,99,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0, + 64,0,0,0,115,32,0,0,0,101,0,90,1,100,0,90, + 2,100,1,90,3,100,2,100,3,132,0,90,4,100,4,100, + 5,132,0,90,5,100,6,83,0,41,7,218,18,95,73,109, + 112,111,114,116,76,111,99,107,67,111,110,116,101,120,116,122, + 36,67,111,110,116,101,120,116,32,109,97,110,97,103,101,114, + 32,102,111,114,32,116,104,101,32,105,109,112,111,114,116,32, + 108,111,99,107,46,99,1,0,0,0,0,0,0,0,0,0, + 0,0,1,0,0,0,2,0,0,0,67,0,0,0,115,12, + 0,0,0,116,0,160,1,161,0,1,0,100,1,83,0,41, + 2,122,24,65,99,113,117,105,114,101,32,116,104,101,32,105, + 109,112,111,114,116,32,108,111,99,107,46,78,41,2,114,56, + 0,0,0,114,57,0,0,0,114,46,0,0,0,114,10,0, + 0,0,114,10,0,0,0,114,11,0,0,0,114,53,0,0, + 0,95,3,0,0,115,2,0,0,0,0,2,122,28,95,73, + 109,112,111,114,116,76,111,99,107,67,111,110,116,101,120,116, + 46,95,95,101,110,116,101,114,95,95,99,4,0,0,0,0, + 0,0,0,0,0,0,0,4,0,0,0,2,0,0,0,67, + 0,0,0,115,12,0,0,0,116,0,160,1,161,0,1,0, + 100,1,83,0,41,2,122,60,82,101,108,101,97,115,101,32, + 116,104,101,32,105,109,112,111,114,116,32,108,111,99,107,32, + 114,101,103,97,114,100,108,101,115,115,32,111,102,32,97,110, + 121,32,114,97,105,115,101,100,32,101,120,99,101,112,116,105, + 111,110,115,46,78,41,2,114,56,0,0,0,114,58,0,0, + 0,41,4,114,30,0,0,0,218,8,101,120,99,95,116,121, + 112,101,218,9,101,120,99,95,118,97,108,117,101,218,13,101, + 120,99,95,116,114,97,99,101,98,97,99,107,114,10,0,0, + 0,114,10,0,0,0,114,11,0,0,0,114,55,0,0,0, + 99,3,0,0,115,2,0,0,0,0,2,122,27,95,73,109, + 112,111,114,116,76,111,99,107,67,111,110,116,101,120,116,46, + 95,95,101,120,105,116,95,95,78,41,6,114,1,0,0,0, + 114,0,0,0,0,114,2,0,0,0,114,3,0,0,0,114, + 53,0,0,0,114,55,0,0,0,114,10,0,0,0,114,10, + 0,0,0,114,10,0,0,0,114,11,0,0,0,114,182,0, + 0,0,91,3,0,0,115,6,0,0,0,8,2,4,2,8, + 4,114,182,0,0,0,99,3,0,0,0,0,0,0,0,0, + 0,0,0,5,0,0,0,5,0,0,0,67,0,0,0,115, + 66,0,0,0,124,1,160,0,100,1,124,2,100,2,24,0, + 161,2,125,3,116,1,124,3,131,1,124,2,107,0,114,36, + 116,2,100,3,131,1,130,1,124,3,100,4,25,0,125,4, + 124,0,114,62,124,4,155,0,100,1,124,0,155,0,157,3, + 83,0,124,4,83,0,41,5,122,50,82,101,115,111,108,118, + 101,32,97,32,114,101,108,97,116,105,118,101,32,109,111,100, + 117,108,101,32,110,97,109,101,32,116,111,32,97,110,32,97, + 98,115,111,108,117,116,101,32,111,110,101,46,114,132,0,0, + 0,114,37,0,0,0,122,50,97,116,116,101,109,112,116,101, + 100,32,114,101,108,97,116,105,118,101,32,105,109,112,111,114, + 116,32,98,101,121,111,110,100,32,116,111,112,45,108,101,118, + 101,108,32,112,97,99,107,97,103,101,114,22,0,0,0,41, + 3,218,6,114,115,112,108,105,116,218,3,108,101,110,114,79, + 0,0,0,41,5,114,17,0,0,0,218,7,112,97,99,107, + 97,103,101,218,5,108,101,118,101,108,90,4,98,105,116,115, + 90,4,98,97,115,101,114,10,0,0,0,114,10,0,0,0, + 114,11,0,0,0,218,13,95,114,101,115,111,108,118,101,95, + 110,97,109,101,104,3,0,0,115,10,0,0,0,0,2,16, + 1,12,1,8,1,8,1,114,190,0,0,0,99,3,0,0, + 0,0,0,0,0,0,0,0,0,4,0,0,0,4,0,0, + 0,67,0,0,0,115,34,0,0,0,124,0,160,0,124,1, + 124,2,161,2,125,3,124,3,100,0,107,8,114,24,100,0, + 83,0,116,1,124,1,124,3,131,2,83,0,114,13,0,0, + 0,41,2,114,171,0,0,0,114,91,0,0,0,41,4,218, + 6,102,105,110,100,101,114,114,17,0,0,0,114,168,0,0, + 0,114,111,0,0,0,114,10,0,0,0,114,10,0,0,0, + 114,11,0,0,0,218,17,95,102,105,110,100,95,115,112,101, + 99,95,108,101,103,97,99,121,113,3,0,0,115,8,0,0, + 0,0,3,12,1,8,1,4,1,114,192,0,0,0,99,3, + 0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,10, + 0,0,0,67,0,0,0,115,12,1,0,0,116,0,106,1, + 125,3,124,3,100,1,107,8,114,22,116,2,100,2,131,1, + 130,1,124,3,115,38,116,3,160,4,100,3,116,5,161,2, + 1,0,124,0,116,0,106,6,107,6,125,4,124,3,68,0, + 93,210,125,5,116,7,131,0,143,84,1,0,122,10,124,5, + 106,8,125,6,87,0,110,54,4,0,116,9,107,10,114,128, + 1,0,1,0,1,0,116,10,124,5,124,0,124,1,131,3, + 125,7,124,7,100,1,107,8,114,124,89,0,87,0,53,0, + 81,0,82,0,163,0,113,52,89,0,110,14,88,0,124,6, + 124,0,124,1,124,2,131,3,125,7,87,0,53,0,81,0, + 82,0,88,0,124,7,100,1,107,9,114,52,124,4,144,0, + 115,254,124,0,116,0,106,6,107,6,144,0,114,254,116,0, + 106,6,124,0,25,0,125,8,122,10,124,8,106,11,125,9, + 87,0,110,28,4,0,116,9,107,10,114,226,1,0,1,0, + 1,0,124,7,6,0,89,0,2,0,1,0,83,0,88,0, + 124,9,100,1,107,8,114,244,124,7,2,0,1,0,83,0, + 124,9,2,0,1,0,83,0,113,52,124,7,2,0,1,0, + 83,0,113,52,100,1,83,0,41,4,122,21,70,105,110,100, + 32,97,32,109,111,100,117,108,101,39,115,32,115,112,101,99, + 46,78,122,53,115,121,115,46,109,101,116,97,95,112,97,116, + 104,32,105,115,32,78,111,110,101,44,32,80,121,116,104,111, + 110,32,105,115,32,108,105,107,101,108,121,32,115,104,117,116, + 116,105,110,103,32,100,111,119,110,122,22,115,121,115,46,109, + 101,116,97,95,112,97,116,104,32,105,115,32,101,109,112,116, + 121,41,12,114,15,0,0,0,218,9,109,101,116,97,95,112, + 97,116,104,114,79,0,0,0,218,9,95,119,97,114,110,105, + 110,103,115,218,4,119,97,114,110,218,13,73,109,112,111,114, + 116,87,97,114,110,105,110,103,114,92,0,0,0,114,182,0, + 0,0,114,170,0,0,0,114,108,0,0,0,114,192,0,0, + 0,114,107,0,0,0,41,10,114,17,0,0,0,114,168,0, + 0,0,114,169,0,0,0,114,193,0,0,0,90,9,105,115, + 95,114,101,108,111,97,100,114,191,0,0,0,114,170,0,0, + 0,114,95,0,0,0,114,96,0,0,0,114,107,0,0,0, + 114,10,0,0,0,114,10,0,0,0,114,11,0,0,0,218, + 10,95,102,105,110,100,95,115,112,101,99,122,3,0,0,115, + 54,0,0,0,0,2,6,1,8,2,8,3,4,1,12,5, + 10,1,8,1,8,1,2,1,10,1,14,1,12,1,8,1, + 20,2,22,1,8,2,18,1,10,1,2,1,10,1,14,4, + 14,2,8,1,8,2,10,2,10,2,114,197,0,0,0,99, + 3,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0, + 4,0,0,0,67,0,0,0,115,108,0,0,0,116,0,124, + 0,116,1,131,2,115,28,116,2,100,1,116,3,124,0,131, + 1,155,0,157,2,131,1,130,1,124,2,100,2,107,0,114, + 44,116,4,100,3,131,1,130,1,124,2,100,2,107,4,114, + 84,116,0,124,1,116,1,131,2,115,72,116,2,100,4,131, + 1,130,1,110,12,124,1,115,84,116,5,100,5,131,1,130, + 1,124,0,115,104,124,2,100,2,107,2,114,104,116,4,100, + 6,131,1,130,1,100,7,83,0,41,8,122,28,86,101,114, + 105,102,121,32,97,114,103,117,109,101,110,116,115,32,97,114, + 101,32,34,115,97,110,101,34,46,122,29,109,111,100,117,108, + 101,32,110,97,109,101,32,109,117,115,116,32,98,101,32,115, + 116,114,44,32,110,111,116,32,114,22,0,0,0,122,18,108, + 101,118,101,108,32,109,117,115,116,32,98,101,32,62,61,32, + 48,122,31,95,95,112,97,99,107,97,103,101,95,95,32,110, + 111,116,32,115,101,116,32,116,111,32,97,32,115,116,114,105, + 110,103,122,54,97,116,116,101,109,112,116,101,100,32,114,101, + 108,97,116,105,118,101,32,105,109,112,111,114,116,32,119,105, + 116,104,32,110,111,32,107,110,111,119,110,32,112,97,114,101, + 110,116,32,112,97,99,107,97,103,101,122,17,69,109,112,116, + 121,32,109,111,100,117,108,101,32,110,97,109,101,78,41,6, + 218,10,105,115,105,110,115,116,97,110,99,101,218,3,115,116, + 114,218,9,84,121,112,101,69,114,114,111,114,114,14,0,0, + 0,218,10,86,97,108,117,101,69,114,114,111,114,114,79,0, + 0,0,169,3,114,17,0,0,0,114,188,0,0,0,114,189, + 0,0,0,114,10,0,0,0,114,10,0,0,0,114,11,0, + 0,0,218,13,95,115,97,110,105,116,121,95,99,104,101,99, + 107,169,3,0,0,115,22,0,0,0,0,2,10,1,18,1, + 8,1,8,1,8,1,10,1,10,1,4,1,8,2,12,1, + 114,203,0,0,0,250,16,78,111,32,109,111,100,117,108,101, + 32,110,97,109,101,100,32,122,4,123,33,114,125,99,2,0, + 0,0,0,0,0,0,0,0,0,0,8,0,0,0,8,0, + 0,0,67,0,0,0,115,222,0,0,0,100,0,125,2,124, + 0,160,0,100,1,161,1,100,2,25,0,125,3,124,3,114, + 136,124,3,116,1,106,2,107,7,114,42,116,3,124,1,124, + 3,131,2,1,0,124,0,116,1,106,2,107,6,114,62,116, + 1,106,2,124,0,25,0,83,0,116,1,106,2,124,3,25, + 0,125,4,122,10,124,4,106,4,125,2,87,0,110,52,4, + 0,116,5,107,10,114,134,1,0,1,0,1,0,100,3,124, + 0,155,2,100,4,124,3,155,2,100,5,157,5,125,5,116, + 6,124,5,124,0,100,6,141,2,100,0,130,2,89,0,110, + 2,88,0,116,7,124,0,124,2,131,2,125,6,124,6,100, + 0,107,8,114,174,116,6,100,3,124,0,155,2,157,2,124, + 0,100,6,141,2,130,1,110,8,116,8,124,6,131,1,125, + 7,124,3,114,218,116,1,106,2,124,3,25,0,125,4,116, + 9,124,4,124,0,160,0,100,1,161,1,100,7,25,0,124, + 7,131,3,1,0,124,7,83,0,41,8,78,114,132,0,0, + 0,114,22,0,0,0,114,204,0,0,0,122,2,59,32,122, + 17,32,105,115,32,110,111,116,32,97,32,112,97,99,107,97, + 103,101,114,16,0,0,0,233,2,0,0,0,41,10,114,133, + 0,0,0,114,15,0,0,0,114,92,0,0,0,114,66,0, + 0,0,114,145,0,0,0,114,108,0,0,0,218,19,77,111, + 100,117,108,101,78,111,116,70,111,117,110,100,69,114,114,111, + 114,114,197,0,0,0,114,162,0,0,0,114,5,0,0,0, + 41,8,114,17,0,0,0,218,7,105,109,112,111,114,116,95, + 114,168,0,0,0,114,134,0,0,0,90,13,112,97,114,101, + 110,116,95,109,111,100,117,108,101,114,160,0,0,0,114,95, + 0,0,0,114,96,0,0,0,114,10,0,0,0,114,10,0, + 0,0,114,11,0,0,0,218,23,95,102,105,110,100,95,97, + 110,100,95,108,111,97,100,95,117,110,108,111,99,107,101,100, + 188,3,0,0,115,42,0,0,0,0,1,4,1,14,1,4, + 1,10,1,10,2,10,1,10,1,10,1,2,1,10,1,14, + 1,18,1,20,1,10,1,8,1,20,2,8,1,4,2,10, + 1,22,1,114,208,0,0,0,99,2,0,0,0,0,0,0, + 0,0,0,0,0,4,0,0,0,10,0,0,0,67,0,0, + 0,115,108,0,0,0,116,0,124,0,131,1,143,50,1,0, + 116,1,106,2,160,3,124,0,116,4,161,2,125,2,124,2, + 116,4,107,8,114,54,116,5,124,0,124,1,131,2,87,0, + 2,0,53,0,81,0,82,0,163,0,83,0,87,0,53,0, + 81,0,82,0,88,0,124,2,100,1,107,8,114,96,100,2, + 124,0,155,0,100,3,157,3,125,3,116,6,124,3,124,0, + 100,4,141,2,130,1,116,7,124,0,131,1,1,0,124,2, + 83,0,41,5,122,25,70,105,110,100,32,97,110,100,32,108, + 111,97,100,32,116,104,101,32,109,111,100,117,108,101,46,78, + 122,10,105,109,112,111,114,116,32,111,102,32,122,28,32,104, + 97,108,116,101,100,59,32,78,111,110,101,32,105,110,32,115, + 121,115,46,109,111,100,117,108,101,115,114,16,0,0,0,41, + 8,114,49,0,0,0,114,15,0,0,0,114,92,0,0,0, + 114,34,0,0,0,218,14,95,78,69,69,68,83,95,76,79, + 65,68,73,78,71,114,208,0,0,0,114,206,0,0,0,114, + 64,0,0,0,41,4,114,17,0,0,0,114,207,0,0,0, + 114,96,0,0,0,114,75,0,0,0,114,10,0,0,0,114, + 10,0,0,0,114,11,0,0,0,218,14,95,102,105,110,100, + 95,97,110,100,95,108,111,97,100,218,3,0,0,115,18,0, + 0,0,0,2,10,1,14,1,8,1,32,2,8,1,12,2, + 12,2,8,1,114,210,0,0,0,114,22,0,0,0,99,3, + 0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,4, + 0,0,0,67,0,0,0,115,42,0,0,0,116,0,124,0, + 124,1,124,2,131,3,1,0,124,2,100,1,107,4,114,32, + 116,1,124,0,124,1,124,2,131,3,125,0,116,2,124,0, + 116,3,131,2,83,0,41,2,97,50,1,0,0,73,109,112, + 111,114,116,32,97,110,100,32,114,101,116,117,114,110,32,116, + 104,101,32,109,111,100,117,108,101,32,98,97,115,101,100,32, + 111,110,32,105,116,115,32,110,97,109,101,44,32,116,104,101, + 32,112,97,99,107,97,103,101,32,116,104,101,32,99,97,108, + 108,32,105,115,10,32,32,32,32,98,101,105,110,103,32,109, + 97,100,101,32,102,114,111,109,44,32,97,110,100,32,116,104, + 101,32,108,101,118,101,108,32,97,100,106,117,115,116,109,101, + 110,116,46,10,10,32,32,32,32,84,104,105,115,32,102,117, + 110,99,116,105,111,110,32,114,101,112,114,101,115,101,110,116, + 115,32,116,104,101,32,103,114,101,97,116,101,115,116,32,99, + 111,109,109,111,110,32,100,101,110,111,109,105,110,97,116,111, + 114,32,111,102,32,102,117,110,99,116,105,111,110,97,108,105, + 116,121,10,32,32,32,32,98,101,116,119,101,101,110,32,105, + 109,112,111,114,116,95,109,111,100,117,108,101,32,97,110,100, + 32,95,95,105,109,112,111,114,116,95,95,46,32,84,104,105, + 115,32,105,110,99,108,117,100,101,115,32,115,101,116,116,105, + 110,103,32,95,95,112,97,99,107,97,103,101,95,95,32,105, + 102,10,32,32,32,32,116,104,101,32,108,111,97,100,101,114, + 32,100,105,100,32,110,111,116,46,10,10,32,32,32,32,114, + 22,0,0,0,41,4,114,203,0,0,0,114,190,0,0,0, + 114,210,0,0,0,218,11,95,103,99,100,95,105,109,112,111, + 114,116,114,202,0,0,0,114,10,0,0,0,114,10,0,0, + 0,114,11,0,0,0,114,211,0,0,0,234,3,0,0,115, + 8,0,0,0,0,9,12,1,8,1,12,1,114,211,0,0, + 0,169,1,218,9,114,101,99,117,114,115,105,118,101,99,3, + 0,0,0,0,0,0,0,1,0,0,0,8,0,0,0,11, + 0,0,0,67,0,0,0,115,228,0,0,0,124,1,68,0, + 93,218,125,4,116,0,124,4,116,1,131,2,115,66,124,3, + 114,34,124,0,106,2,100,1,23,0,125,5,110,4,100,2, + 125,5,116,3,100,3,124,5,155,0,100,4,116,4,124,4, + 131,1,106,2,155,0,157,4,131,1,130,1,113,4,124,4, + 100,5,107,2,114,108,124,3,115,222,116,5,124,0,100,6, + 131,2,114,222,116,6,124,0,124,0,106,7,124,2,100,7, + 100,8,141,4,1,0,113,4,116,5,124,0,124,4,131,2, + 115,4,124,0,106,2,155,0,100,9,124,4,155,0,157,3, + 125,6,122,14,116,8,124,2,124,6,131,2,1,0,87,0, + 113,4,4,0,116,9,107,10,114,220,1,0,125,7,1,0, + 122,42,124,7,106,10,124,6,107,2,114,202,116,11,106,12, + 160,13,124,6,116,14,161,2,100,10,107,9,114,202,87,0, + 89,0,162,8,113,4,130,0,87,0,53,0,100,10,125,7, + 126,7,88,0,89,0,113,4,88,0,113,4,124,0,83,0, + 41,11,122,238,70,105,103,117,114,101,32,111,117,116,32,119, + 104,97,116,32,95,95,105,109,112,111,114,116,95,95,32,115, + 104,111,117,108,100,32,114,101,116,117,114,110,46,10,10,32, + 32,32,32,84,104,101,32,105,109,112,111,114,116,95,32,112, + 97,114,97,109,101,116,101,114,32,105,115,32,97,32,99,97, + 108,108,97,98,108,101,32,119,104,105,99,104,32,116,97,107, + 101,115,32,116,104,101,32,110,97,109,101,32,111,102,32,109, + 111,100,117,108,101,32,116,111,10,32,32,32,32,105,109,112, + 111,114,116,46,32,73,116,32,105,115,32,114,101,113,117,105, + 114,101,100,32,116,111,32,100,101,99,111,117,112,108,101,32, + 116,104,101,32,102,117,110,99,116,105,111,110,32,102,114,111, + 109,32,97,115,115,117,109,105,110,103,32,105,109,112,111,114, + 116,108,105,98,39,115,10,32,32,32,32,105,109,112,111,114, + 116,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110, + 32,105,115,32,100,101,115,105,114,101,100,46,10,10,32,32, + 32,32,122,8,46,95,95,97,108,108,95,95,122,13,96,96, + 102,114,111,109,32,108,105,115,116,39,39,122,8,73,116,101, + 109,32,105,110,32,122,18,32,109,117,115,116,32,98,101,32, + 115,116,114,44,32,110,111,116,32,250,1,42,218,7,95,95, + 97,108,108,95,95,84,114,212,0,0,0,114,132,0,0,0, + 78,41,15,114,198,0,0,0,114,199,0,0,0,114,1,0, + 0,0,114,200,0,0,0,114,14,0,0,0,114,4,0,0, + 0,218,16,95,104,97,110,100,108,101,95,102,114,111,109,108, + 105,115,116,114,215,0,0,0,114,66,0,0,0,114,206,0, + 0,0,114,17,0,0,0,114,15,0,0,0,114,92,0,0, + 0,114,34,0,0,0,114,209,0,0,0,41,8,114,96,0, + 0,0,218,8,102,114,111,109,108,105,115,116,114,207,0,0, + 0,114,213,0,0,0,218,1,120,90,5,119,104,101,114,101, + 90,9,102,114,111,109,95,110,97,109,101,90,3,101,120,99, + 114,10,0,0,0,114,10,0,0,0,114,11,0,0,0,114, + 216,0,0,0,249,3,0,0,115,44,0,0,0,0,10,8, + 1,10,1,4,1,12,2,4,1,28,2,8,1,14,1,10, + 1,2,255,8,2,10,1,16,1,2,1,14,1,16,4,10, + 1,16,255,2,2,8,1,22,1,114,216,0,0,0,99,1, + 0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,6, + 0,0,0,67,0,0,0,115,146,0,0,0,124,0,160,0, + 100,1,161,1,125,1,124,0,160,0,100,2,161,1,125,2, + 124,1,100,3,107,9,114,82,124,2,100,3,107,9,114,78, + 124,1,124,2,106,1,107,3,114,78,116,2,106,3,100,4, + 124,1,155,2,100,5,124,2,106,1,155,2,100,6,157,5, + 116,4,100,7,100,8,141,3,1,0,124,1,83,0,124,2, + 100,3,107,9,114,96,124,2,106,1,83,0,116,2,106,3, + 100,9,116,4,100,7,100,8,141,3,1,0,124,0,100,10, + 25,0,125,1,100,11,124,0,107,7,114,142,124,1,160,5, + 100,12,161,1,100,13,25,0,125,1,124,1,83,0,41,14, + 122,167,67,97,108,99,117,108,97,116,101,32,119,104,97,116, + 32,95,95,112,97,99,107,97,103,101,95,95,32,115,104,111, + 117,108,100,32,98,101,46,10,10,32,32,32,32,95,95,112, + 97,99,107,97,103,101,95,95,32,105,115,32,110,111,116,32, + 103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101, + 32,100,101,102,105,110,101,100,32,111,114,32,99,111,117,108, + 100,32,98,101,32,115,101,116,32,116,111,32,78,111,110,101, + 10,32,32,32,32,116,111,32,114,101,112,114,101,115,101,110, + 116,32,116,104,97,116,32,105,116,115,32,112,114,111,112,101, + 114,32,118,97,108,117,101,32,105,115,32,117,110,107,110,111, + 119,110,46,10,10,32,32,32,32,114,149,0,0,0,114,107, + 0,0,0,78,122,32,95,95,112,97,99,107,97,103,101,95, + 95,32,33,61,32,95,95,115,112,101,99,95,95,46,112,97, + 114,101,110,116,32,40,122,4,32,33,61,32,114,122,0,0, + 0,233,3,0,0,0,41,1,90,10,115,116,97,99,107,108, + 101,118,101,108,122,89,99,97,110,39,116,32,114,101,115,111, + 108,118,101,32,112,97,99,107,97,103,101,32,102,114,111,109, + 32,95,95,115,112,101,99,95,95,32,111,114,32,95,95,112, + 97,99,107,97,103,101,95,95,44,32,102,97,108,108,105,110, + 103,32,98,97,99,107,32,111,110,32,95,95,110,97,109,101, + 95,95,32,97,110,100,32,95,95,112,97,116,104,95,95,114, + 1,0,0,0,114,145,0,0,0,114,132,0,0,0,114,22, + 0,0,0,41,6,114,34,0,0,0,114,134,0,0,0,114, + 194,0,0,0,114,195,0,0,0,114,196,0,0,0,114,133, + 0,0,0,41,3,218,7,103,108,111,98,97,108,115,114,188, + 0,0,0,114,95,0,0,0,114,10,0,0,0,114,10,0, + 0,0,114,11,0,0,0,218,17,95,99,97,108,99,95,95, + 95,112,97,99,107,97,103,101,95,95,30,4,0,0,115,38, + 0,0,0,0,7,10,1,10,1,8,1,18,1,22,2,2, + 0,2,254,6,3,4,1,8,1,6,2,6,2,2,0,2, + 254,6,3,8,1,8,1,14,1,114,221,0,0,0,114,10, + 0,0,0,99,5,0,0,0,0,0,0,0,0,0,0,0, + 9,0,0,0,5,0,0,0,67,0,0,0,115,180,0,0, + 0,124,4,100,1,107,2,114,18,116,0,124,0,131,1,125, + 5,110,36,124,1,100,2,107,9,114,30,124,1,110,2,105, + 0,125,6,116,1,124,6,131,1,125,7,116,0,124,0,124, + 7,124,4,131,3,125,5,124,3,115,150,124,4,100,1,107, + 2,114,84,116,0,124,0,160,2,100,3,161,1,100,1,25, + 0,131,1,83,0,124,0,115,92,124,5,83,0,116,3,124, + 0,131,1,116,3,124,0,160,2,100,3,161,1,100,1,25, + 0,131,1,24,0,125,8,116,4,106,5,124,5,106,6,100, + 2,116,3,124,5,106,6,131,1,124,8,24,0,133,2,25, + 0,25,0,83,0,110,26,116,7,124,5,100,4,131,2,114, + 172,116,8,124,5,124,3,116,0,131,3,83,0,124,5,83, + 0,100,2,83,0,41,5,97,215,1,0,0,73,109,112,111, + 114,116,32,97,32,109,111,100,117,108,101,46,10,10,32,32, + 32,32,84,104,101,32,39,103,108,111,98,97,108,115,39,32, + 97,114,103,117,109,101,110,116,32,105,115,32,117,115,101,100, + 32,116,111,32,105,110,102,101,114,32,119,104,101,114,101,32, + 116,104,101,32,105,109,112,111,114,116,32,105,115,32,111,99, + 99,117,114,114,105,110,103,32,102,114,111,109,10,32,32,32, + 32,116,111,32,104,97,110,100,108,101,32,114,101,108,97,116, + 105,118,101,32,105,109,112,111,114,116,115,46,32,84,104,101, + 32,39,108,111,99,97,108,115,39,32,97,114,103,117,109,101, + 110,116,32,105,115,32,105,103,110,111,114,101,100,46,32,84, + 104,101,10,32,32,32,32,39,102,114,111,109,108,105,115,116, + 39,32,97,114,103,117,109,101,110,116,32,115,112,101,99,105, + 102,105,101,115,32,119,104,97,116,32,115,104,111,117,108,100, + 32,101,120,105,115,116,32,97,115,32,97,116,116,114,105,98, + 117,116,101,115,32,111,110,32,116,104,101,32,109,111,100,117, + 108,101,10,32,32,32,32,98,101,105,110,103,32,105,109,112, + 111,114,116,101,100,32,40,101,46,103,46,32,96,96,102,114, + 111,109,32,109,111,100,117,108,101,32,105,109,112,111,114,116, + 32,60,102,114,111,109,108,105,115,116,62,96,96,41,46,32, + 32,84,104,101,32,39,108,101,118,101,108,39,10,32,32,32, + 32,97,114,103,117,109,101,110,116,32,114,101,112,114,101,115, + 101,110,116,115,32,116,104,101,32,112,97,99,107,97,103,101, + 32,108,111,99,97,116,105,111,110,32,116,111,32,105,109,112, + 111,114,116,32,102,114,111,109,32,105,110,32,97,32,114,101, + 108,97,116,105,118,101,10,32,32,32,32,105,109,112,111,114, + 116,32,40,101,46,103,46,32,96,96,102,114,111,109,32,46, + 46,112,107,103,32,105,109,112,111,114,116,32,109,111,100,96, + 96,32,119,111,117,108,100,32,104,97,118,101,32,97,32,39, + 108,101,118,101,108,39,32,111,102,32,50,41,46,10,10,32, + 32,32,32,114,22,0,0,0,78,114,132,0,0,0,114,145, + 0,0,0,41,9,114,211,0,0,0,114,221,0,0,0,218, + 9,112,97,114,116,105,116,105,111,110,114,187,0,0,0,114, + 15,0,0,0,114,92,0,0,0,114,1,0,0,0,114,4, + 0,0,0,114,216,0,0,0,41,9,114,17,0,0,0,114, + 220,0,0,0,218,6,108,111,99,97,108,115,114,217,0,0, + 0,114,189,0,0,0,114,96,0,0,0,90,8,103,108,111, + 98,97,108,115,95,114,188,0,0,0,90,7,99,117,116,95, + 111,102,102,114,10,0,0,0,114,10,0,0,0,114,11,0, + 0,0,218,10,95,95,105,109,112,111,114,116,95,95,57,4, + 0,0,115,30,0,0,0,0,11,8,1,10,2,16,1,8, + 1,12,1,4,3,8,1,18,1,4,1,4,4,26,3,32, + 1,10,1,12,2,114,224,0,0,0,99,1,0,0,0,0, + 0,0,0,0,0,0,0,2,0,0,0,3,0,0,0,67, + 0,0,0,115,38,0,0,0,116,0,160,1,124,0,161,1, + 125,1,124,1,100,0,107,8,114,30,116,2,100,1,124,0, + 23,0,131,1,130,1,116,3,124,1,131,1,83,0,41,2, + 78,122,25,110,111,32,98,117,105,108,116,45,105,110,32,109, + 111,100,117,108,101,32,110,97,109,101,100,32,41,4,114,163, + 0,0,0,114,170,0,0,0,114,79,0,0,0,114,162,0, + 0,0,41,2,114,17,0,0,0,114,95,0,0,0,114,10, + 0,0,0,114,10,0,0,0,114,11,0,0,0,218,18,95, + 98,117,105,108,116,105,110,95,102,114,111,109,95,110,97,109, + 101,94,4,0,0,115,8,0,0,0,0,1,10,1,8,1, + 12,1,114,225,0,0,0,99,2,0,0,0,0,0,0,0, + 0,0,0,0,10,0,0,0,5,0,0,0,67,0,0,0, + 115,166,0,0,0,124,1,97,0,124,0,97,1,116,2,116, + 1,131,1,125,2,116,1,106,3,160,4,161,0,68,0,93, + 72,92,2,125,3,125,4,116,5,124,4,124,2,131,2,114, + 26,124,3,116,1,106,6,107,6,114,60,116,7,125,5,110, + 18,116,0,160,8,124,3,161,1,114,26,116,9,125,5,110, + 2,113,26,116,10,124,4,124,5,131,2,125,6,116,11,124, + 6,124,4,131,2,1,0,113,26,116,1,106,3,116,12,25, + 0,125,7,100,1,68,0,93,46,125,8,124,8,116,1,106, + 3,107,7,114,138,116,13,124,8,131,1,125,9,110,10,116, + 1,106,3,124,8,25,0,125,9,116,14,124,7,124,8,124, + 9,131,3,1,0,113,114,100,2,83,0,41,3,122,250,83, + 101,116,117,112,32,105,109,112,111,114,116,108,105,98,32,98, + 121,32,105,109,112,111,114,116,105,110,103,32,110,101,101,100, + 101,100,32,98,117,105,108,116,45,105,110,32,109,111,100,117, + 108,101,115,32,97,110,100,32,105,110,106,101,99,116,105,110, + 103,32,116,104,101,109,10,32,32,32,32,105,110,116,111,32, + 116,104,101,32,103,108,111,98,97,108,32,110,97,109,101,115, + 112,97,99,101,46,10,10,32,32,32,32,65,115,32,115,121, + 115,32,105,115,32,110,101,101,100,101,100,32,102,111,114,32, + 115,121,115,46,109,111,100,117,108,101,115,32,97,99,99,101, + 115,115,32,97,110,100,32,95,105,109,112,32,105,115,32,110, + 101,101,100,101,100,32,116,111,32,108,111,97,100,32,98,117, + 105,108,116,45,105,110,10,32,32,32,32,109,111,100,117,108, + 101,115,44,32,116,104,111,115,101,32,116,119,111,32,109,111, + 100,117,108,101,115,32,109,117,115,116,32,98,101,32,101,120, + 112,108,105,99,105,116,108,121,32,112,97,115,115,101,100,32, + 105,110,46,10,10,32,32,32,32,41,3,114,23,0,0,0, + 114,194,0,0,0,114,63,0,0,0,78,41,15,114,56,0, + 0,0,114,15,0,0,0,114,14,0,0,0,114,92,0,0, + 0,218,5,105,116,101,109,115,114,198,0,0,0,114,78,0, + 0,0,114,163,0,0,0,114,88,0,0,0,114,177,0,0, + 0,114,146,0,0,0,114,152,0,0,0,114,1,0,0,0, + 114,225,0,0,0,114,5,0,0,0,41,10,218,10,115,121, + 115,95,109,111,100,117,108,101,218,11,95,105,109,112,95,109, + 111,100,117,108,101,90,11,109,111,100,117,108,101,95,116,121, + 112,101,114,17,0,0,0,114,96,0,0,0,114,111,0,0, + 0,114,95,0,0,0,90,11,115,101,108,102,95,109,111,100, + 117,108,101,90,12,98,117,105,108,116,105,110,95,110,97,109, + 101,90,14,98,117,105,108,116,105,110,95,109,111,100,117,108, + 101,114,10,0,0,0,114,10,0,0,0,114,11,0,0,0, + 218,6,95,115,101,116,117,112,101,4,0,0,115,36,0,0, + 0,0,9,4,1,4,3,8,1,18,1,10,1,10,1,6, + 1,10,1,6,2,2,1,10,1,12,3,10,1,8,1,10, + 1,10,2,10,1,114,229,0,0,0,99,2,0,0,0,0, + 0,0,0,0,0,0,0,2,0,0,0,3,0,0,0,67, + 0,0,0,115,38,0,0,0,116,0,124,0,124,1,131,2, + 1,0,116,1,106,2,160,3,116,4,161,1,1,0,116,1, + 106,2,160,3,116,5,161,1,1,0,100,1,83,0,41,2, + 122,48,73,110,115,116,97,108,108,32,105,109,112,111,114,116, + 101,114,115,32,102,111,114,32,98,117,105,108,116,105,110,32, + 97,110,100,32,102,114,111,122,101,110,32,109,111,100,117,108, + 101,115,78,41,6,114,229,0,0,0,114,15,0,0,0,114, + 193,0,0,0,114,123,0,0,0,114,163,0,0,0,114,177, + 0,0,0,41,2,114,227,0,0,0,114,228,0,0,0,114, + 10,0,0,0,114,10,0,0,0,114,11,0,0,0,218,8, + 95,105,110,115,116,97,108,108,136,4,0,0,115,6,0,0, + 0,0,2,10,2,12,1,114,230,0,0,0,99,0,0,0, + 0,0,0,0,0,0,0,0,0,1,0,0,0,4,0,0, + 0,67,0,0,0,115,32,0,0,0,100,1,100,2,108,0, + 125,0,124,0,97,1,124,0,160,2,116,3,106,4,116,5, + 25,0,161,1,1,0,100,2,83,0,41,3,122,57,73,110, + 115,116,97,108,108,32,105,109,112,111,114,116,101,114,115,32, + 116,104,97,116,32,114,101,113,117,105,114,101,32,101,120,116, + 101,114,110,97,108,32,102,105,108,101,115,121,115,116,101,109, + 32,97,99,99,101,115,115,114,22,0,0,0,78,41,6,218, + 26,95,102,114,111,122,101,110,95,105,109,112,111,114,116,108, + 105,98,95,101,120,116,101,114,110,97,108,114,130,0,0,0, + 114,230,0,0,0,114,15,0,0,0,114,92,0,0,0,114, + 1,0,0,0,41,1,114,231,0,0,0,114,10,0,0,0, + 114,10,0,0,0,114,11,0,0,0,218,27,95,105,110,115, + 116,97,108,108,95,101,120,116,101,114,110,97,108,95,105,109, + 112,111,114,116,101,114,115,144,4,0,0,115,6,0,0,0, + 0,3,8,1,4,1,114,232,0,0,0,41,2,78,78,41, + 1,78,41,2,78,114,22,0,0,0,41,4,78,78,114,10, + 0,0,0,114,22,0,0,0,41,50,114,3,0,0,0,114, + 130,0,0,0,114,12,0,0,0,114,18,0,0,0,114,59, + 0,0,0,114,33,0,0,0,114,42,0,0,0,114,19,0, + 0,0,114,20,0,0,0,114,48,0,0,0,114,49,0,0, + 0,114,52,0,0,0,114,64,0,0,0,114,66,0,0,0, + 114,76,0,0,0,114,86,0,0,0,114,90,0,0,0,114, + 97,0,0,0,114,113,0,0,0,114,114,0,0,0,114,91, + 0,0,0,114,146,0,0,0,114,152,0,0,0,114,156,0, + 0,0,114,109,0,0,0,114,93,0,0,0,114,161,0,0, + 0,114,162,0,0,0,114,94,0,0,0,114,163,0,0,0, + 114,177,0,0,0,114,182,0,0,0,114,190,0,0,0,114, + 192,0,0,0,114,197,0,0,0,114,203,0,0,0,90,15, + 95,69,82,82,95,77,83,71,95,80,82,69,70,73,88,90, + 8,95,69,82,82,95,77,83,71,114,208,0,0,0,218,6, + 111,98,106,101,99,116,114,209,0,0,0,114,210,0,0,0, + 114,211,0,0,0,114,216,0,0,0,114,221,0,0,0,114, + 224,0,0,0,114,225,0,0,0,114,229,0,0,0,114,230, + 0,0,0,114,232,0,0,0,114,10,0,0,0,114,10,0, + 0,0,114,10,0,0,0,114,11,0,0,0,218,8,60,109, + 111,100,117,108,101,62,1,0,0,0,115,94,0,0,0,4, + 24,4,2,8,8,8,8,4,2,4,3,16,4,14,68,14, + 21,14,16,8,37,8,17,8,11,14,8,8,11,8,12,8, + 16,8,36,14,100,16,26,10,45,14,72,8,17,8,17,8, + 30,8,37,8,42,8,15,14,75,14,78,14,13,8,9,8, + 9,10,47,8,16,4,1,8,2,8,27,6,3,8,16,10, + 15,14,37,8,27,10,37,8,7,8,35,8,8, +}; From webhook-mailer at python.org Thu Oct 6 20:08:10 2022 From: webhook-mailer at python.org (markshannon) Date: Fri, 07 Oct 2022 00:08:10 -0000 Subject: [Python-checkins] GH-91052: Add C API for watching dictionaries (GH-31787) Message-ID: https://github.com/python/cpython/commit/a4b7794887929f82c532fcd055326954ff1197ce commit: a4b7794887929f82c532fcd055326954ff1197ce branch: main author: Carl Meyer committer: markshannon date: 2022-10-07T01:08:00+01:00 summary: GH-91052: Add C API for watching dictionaries (GH-31787) files: A Misc/NEWS.d/next/Core and Builtins/2022-10-03-16-12-39.gh-issue-91052.MsYL9d.rst M Doc/c-api/dict.rst M Include/cpython/dictobject.h M Include/internal/pycore_dict.h M Include/internal/pycore_interp.h M Lib/test/test_capi.py M Modules/_testcapimodule.c M Objects/dictobject.c M Python/ceval.c M Python/pystate.c diff --git a/Doc/c-api/dict.rst b/Doc/c-api/dict.rst index 819168d48707..7bebea0c97de 100644 --- a/Doc/c-api/dict.rst +++ b/Doc/c-api/dict.rst @@ -238,3 +238,54 @@ Dictionary Objects for key, value in seq2: if override or key not in a: a[key] = value + +.. c:function:: int PyDict_AddWatcher(PyDict_WatchCallback callback) + + Register *callback* as a dictionary watcher. Return a non-negative integer + id which must be passed to future calls to :c:func:`PyDict_Watch`. In case + of error (e.g. no more watcher IDs available), return ``-1`` and set an + exception. + +.. c:function:: int PyDict_ClearWatcher(int watcher_id) + + Clear watcher identified by *watcher_id* previously returned from + :c:func:`PyDict_AddWatcher`. Return ``0`` on success, ``-1`` on error (e.g. + if the given *watcher_id* was never registered.) + +.. c:function:: int PyDict_Watch(int watcher_id, PyObject *dict) + + Mark dictionary *dict* as watched. The callback granted *watcher_id* by + :c:func:`PyDict_AddWatcher` will be called when *dict* is modified or + deallocated. + +.. c:type:: PyDict_WatchEvent + + Enumeration of possible dictionary watcher events: ``PyDict_EVENT_ADDED``, + ``PyDict_EVENT_MODIFIED``, ``PyDict_EVENT_DELETED``, ``PyDict_EVENT_CLONED``, + ``PyDict_EVENT_CLEARED``, or ``PyDict_EVENT_DEALLOCATED``. + +.. c:type:: int (*PyDict_WatchCallback)(PyDict_WatchEvent event, PyObject *dict, PyObject *key, PyObject *new_value) + + Type of a dict watcher callback function. + + If *event* is ``PyDict_EVENT_CLEARED`` or ``PyDict_EVENT_DEALLOCATED``, both + *key* and *new_value* will be ``NULL``. If *event* is ``PyDict_EVENT_ADDED`` + or ``PyDict_EVENT_MODIFIED``, *new_value* will be the new value for *key*. + If *event* is ``PyDict_EVENT_DELETED``, *key* is being deleted from the + dictionary and *new_value* will be ``NULL``. + + ``PyDict_EVENT_CLONED`` occurs when *dict* was previously empty and another + dict is merged into it. To maintain efficiency of this operation, per-key + ``PyDict_EVENT_ADDED`` events are not issued in this case; instead a + single ``PyDict_EVENT_CLONED`` is issued, and *key* will be the source + dictionary. + + The callback may inspect but must not modify *dict*; doing so could have + unpredictable effects, including infinite recursion. + + Callbacks occur before the notified modification to *dict* takes place, so + the prior state of *dict* can be inspected. + + If the callback returns with an exception set, it must return ``-1``; this + exception will be printed as an unraisable exception using + :c:func:`PyErr_WriteUnraisable`. Otherwise it should return ``0``. diff --git a/Include/cpython/dictobject.h b/Include/cpython/dictobject.h index 565ad791a6cb..f8a74a597b0e 100644 --- a/Include/cpython/dictobject.h +++ b/Include/cpython/dictobject.h @@ -83,3 +83,26 @@ typedef struct { PyAPI_FUNC(PyObject *) _PyDictView_New(PyObject *, PyTypeObject *); PyAPI_FUNC(PyObject *) _PyDictView_Intersect(PyObject* self, PyObject *other); + +/* Dictionary watchers */ + +typedef enum { + PyDict_EVENT_ADDED, + PyDict_EVENT_MODIFIED, + PyDict_EVENT_DELETED, + PyDict_EVENT_CLONED, + PyDict_EVENT_CLEARED, + PyDict_EVENT_DEALLOCATED, +} PyDict_WatchEvent; + +// Callback to be invoked when a watched dict is cleared, dealloced, or modified. +// In clear/dealloc case, key and new_value will be NULL. Otherwise, new_value will be the +// new value for key, NULL if key is being deleted. +typedef int(*PyDict_WatchCallback)(PyDict_WatchEvent event, PyObject* dict, PyObject* key, PyObject* new_value); + +// Register/unregister a dict-watcher callback +PyAPI_FUNC(int) PyDict_AddWatcher(PyDict_WatchCallback callback); +PyAPI_FUNC(int) PyDict_ClearWatcher(int watcher_id); + +// Mark given dictionary as "watched" (callback will be called if it is modified) +PyAPI_FUNC(int) PyDict_Watch(int watcher_id, PyObject* dict); diff --git a/Include/internal/pycore_dict.h b/Include/internal/pycore_dict.h index 464092996cae..ae4094a095d8 100644 --- a/Include/internal/pycore_dict.h +++ b/Include/internal/pycore_dict.h @@ -154,7 +154,32 @@ struct _dictvalues { extern uint64_t _pydict_global_version; -#define DICT_NEXT_VERSION() (++_pydict_global_version) +#define DICT_MAX_WATCHERS 8 +#define DICT_VERSION_INCREMENT (1 << DICT_MAX_WATCHERS) +#define DICT_VERSION_MASK (DICT_VERSION_INCREMENT - 1) + +#define DICT_NEXT_VERSION() (_pydict_global_version += DICT_VERSION_INCREMENT) + +void +_PyDict_SendEvent(int watcher_bits, + PyDict_WatchEvent event, + PyDictObject *mp, + PyObject *key, + PyObject *value); + +static inline uint64_t +_PyDict_NotifyEvent(PyDict_WatchEvent event, + PyDictObject *mp, + PyObject *key, + PyObject *value) +{ + int watcher_bits = mp->ma_version_tag & DICT_VERSION_MASK; + if (watcher_bits) { + _PyDict_SendEvent(watcher_bits, event, mp, key, value); + return DICT_NEXT_VERSION() | watcher_bits; + } + return DICT_NEXT_VERSION(); +} extern PyObject *_PyObject_MakeDictFromInstanceAttributes(PyObject *obj, PyDictValues *values); extern PyObject *_PyDict_FromItems( diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index b21708a388b3..8cecd5ab3e54 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -144,6 +144,8 @@ struct _is { // Initialized to _PyEval_EvalFrameDefault(). _PyFrameEvalFunction eval_frame; + PyDict_WatchCallback dict_watchers[DICT_MAX_WATCHERS]; + Py_ssize_t co_extra_user_count; freefunc co_extra_freefuncs[MAX_CO_EXTRA_USERS]; diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py index 2c6fe34d3b78..cb90d55941ca 100644 --- a/Lib/test/test_capi.py +++ b/Lib/test/test_capi.py @@ -2,6 +2,7 @@ # these are all functions _testcapi exports whose name begins with 'test_'. from collections import OrderedDict +from contextlib import contextmanager import _thread import importlib.machinery import importlib.util @@ -1393,5 +1394,136 @@ def func2(x=None): self.do_test(func2) +class TestDictWatchers(unittest.TestCase): + # types of watchers testcapimodule can add: + EVENTS = 0 # appends dict events as strings to global event list + ERROR = 1 # unconditionally sets and signals a RuntimeException + SECOND = 2 # always appends "second" to global event list + + def add_watcher(self, kind=EVENTS): + return _testcapi.add_dict_watcher(kind) + + def clear_watcher(self, watcher_id): + _testcapi.clear_dict_watcher(watcher_id) + + @contextmanager + def watcher(self, kind=EVENTS): + wid = self.add_watcher(kind) + try: + yield wid + finally: + self.clear_watcher(wid) + + def assert_events(self, expected): + actual = _testcapi.get_dict_watcher_events() + self.assertEqual(actual, expected) + + def watch(self, wid, d): + _testcapi.watch_dict(wid, d) + + def test_set_new_item(self): + d = {} + with self.watcher() as wid: + self.watch(wid, d) + d["foo"] = "bar" + self.assert_events(["new:foo:bar"]) + + def test_set_existing_item(self): + d = {"foo": "bar"} + with self.watcher() as wid: + self.watch(wid, d) + d["foo"] = "baz" + self.assert_events(["mod:foo:baz"]) + + def test_clone(self): + d = {} + d2 = {"foo": "bar"} + with self.watcher() as wid: + self.watch(wid, d) + d.update(d2) + self.assert_events(["clone"]) + + def test_no_event_if_not_watched(self): + d = {} + with self.watcher() as wid: + d["foo"] = "bar" + self.assert_events([]) + + def test_del(self): + d = {"foo": "bar"} + with self.watcher() as wid: + self.watch(wid, d) + del d["foo"] + self.assert_events(["del:foo"]) + + def test_pop(self): + d = {"foo": "bar"} + with self.watcher() as wid: + self.watch(wid, d) + d.pop("foo") + self.assert_events(["del:foo"]) + + def test_clear(self): + d = {"foo": "bar"} + with self.watcher() as wid: + self.watch(wid, d) + d.clear() + self.assert_events(["clear"]) + + def test_dealloc(self): + d = {"foo": "bar"} + with self.watcher() as wid: + self.watch(wid, d) + del d + self.assert_events(["dealloc"]) + + def test_error(self): + d = {} + unraisables = [] + def unraisable_hook(unraisable): + unraisables.append(unraisable) + with self.watcher(kind=self.ERROR) as wid: + self.watch(wid, d) + orig_unraisable_hook = sys.unraisablehook + sys.unraisablehook = unraisable_hook + try: + d["foo"] = "bar" + finally: + sys.unraisablehook = orig_unraisable_hook + self.assert_events([]) + self.assertEqual(len(unraisables), 1) + unraisable = unraisables[0] + self.assertIs(unraisable.object, d) + self.assertEqual(str(unraisable.exc_value), "boom!") + + def test_two_watchers(self): + d1 = {} + d2 = {} + with self.watcher() as wid1: + with self.watcher(kind=self.SECOND) as wid2: + self.watch(wid1, d1) + self.watch(wid2, d2) + d1["foo"] = "bar" + d2["hmm"] = "baz" + self.assert_events(["new:foo:bar", "second"]) + + def test_watch_non_dict(self): + with self.watcher() as wid: + with self.assertRaisesRegex(ValueError, r"Cannot watch non-dictionary"): + self.watch(wid, 1) + + def test_watch_out_of_range_watcher_id(self): + d = {} + with self.assertRaisesRegex(ValueError, r"Invalid dict watcher ID -1"): + self.watch(-1, d) + with self.assertRaisesRegex(ValueError, r"Invalid dict watcher ID 8"): + self.watch(8, d) # DICT_MAX_WATCHERS = 8 + + def test_unassigned_watcher_id(self): + d = {} + with self.assertRaisesRegex(ValueError, r"No dict watcher set for ID 1"): + self.watch(1, d) + + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-03-16-12-39.gh-issue-91052.MsYL9d.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-03-16-12-39.gh-issue-91052.MsYL9d.rst new file mode 100644 index 000000000000..c7db4da494fe --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-03-16-12-39.gh-issue-91052.MsYL9d.rst @@ -0,0 +1 @@ +Add API for subscribing to modification events on selected dictionaries. diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 3d6535f50be9..c57dba4a5bf3 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -5169,6 +5169,142 @@ test_tstate_capi(PyObject *self, PyObject *Py_UNUSED(args)) } +// Test dict watching +static PyObject *g_dict_watch_events; +static int g_dict_watchers_installed; + +static int +dict_watch_callback(PyDict_WatchEvent event, + PyObject *dict, + PyObject *key, + PyObject *new_value) +{ + PyObject *msg; + switch(event) { + case PyDict_EVENT_CLEARED: + msg = PyUnicode_FromString("clear"); + break; + case PyDict_EVENT_DEALLOCATED: + msg = PyUnicode_FromString("dealloc"); + break; + case PyDict_EVENT_CLONED: + msg = PyUnicode_FromString("clone"); + break; + case PyDict_EVENT_ADDED: + msg = PyUnicode_FromFormat("new:%S:%S", key, new_value); + break; + case PyDict_EVENT_MODIFIED: + msg = PyUnicode_FromFormat("mod:%S:%S", key, new_value); + break; + case PyDict_EVENT_DELETED: + msg = PyUnicode_FromFormat("del:%S", key); + break; + default: + msg = PyUnicode_FromString("unknown"); + } + if (!msg) { + return -1; + } + assert(PyList_Check(g_dict_watch_events)); + if (PyList_Append(g_dict_watch_events, msg) < 0) { + Py_DECREF(msg); + return -1; + } + return 0; +} + +static int +dict_watch_callback_second(PyDict_WatchEvent event, + PyObject *dict, + PyObject *key, + PyObject *new_value) +{ + PyObject *msg = PyUnicode_FromString("second"); + if (!msg) { + return -1; + } + if (PyList_Append(g_dict_watch_events, msg) < 0) { + return -1; + } + return 0; +} + +static int +dict_watch_callback_error(PyDict_WatchEvent event, + PyObject *dict, + PyObject *key, + PyObject *new_value) +{ + PyErr_SetString(PyExc_RuntimeError, "boom!"); + return -1; +} + +static PyObject * +add_dict_watcher(PyObject *self, PyObject *kind) +{ + int watcher_id; + assert(PyLong_Check(kind)); + long kind_l = PyLong_AsLong(kind); + if (kind_l == 2) { + watcher_id = PyDict_AddWatcher(dict_watch_callback_second); + } else if (kind_l == 1) { + watcher_id = PyDict_AddWatcher(dict_watch_callback_error); + } else { + watcher_id = PyDict_AddWatcher(dict_watch_callback); + } + if (watcher_id < 0) { + return NULL; + } + if (!g_dict_watchers_installed) { + assert(!g_dict_watch_events); + if (!(g_dict_watch_events = PyList_New(0))) { + return NULL; + } + } + g_dict_watchers_installed++; + return PyLong_FromLong(watcher_id); +} + +static PyObject * +clear_dict_watcher(PyObject *self, PyObject *watcher_id) +{ + if (PyDict_ClearWatcher(PyLong_AsLong(watcher_id))) { + return NULL; + } + g_dict_watchers_installed--; + if (!g_dict_watchers_installed) { + assert(g_dict_watch_events); + Py_CLEAR(g_dict_watch_events); + } + Py_RETURN_NONE; +} + +static PyObject * +watch_dict(PyObject *self, PyObject *args) +{ + PyObject *dict; + int watcher_id; + if (!PyArg_ParseTuple(args, "iO", &watcher_id, &dict)) { + return NULL; + } + if (PyDict_Watch(watcher_id, dict)) { + return NULL; + } + Py_RETURN_NONE; +} + +static PyObject * +get_dict_watcher_events(PyObject *self, PyObject *Py_UNUSED(args)) +{ + if (!g_dict_watch_events) { + PyErr_SetString(PyExc_RuntimeError, "no watchers active"); + return NULL; + } + Py_INCREF(g_dict_watch_events); + return g_dict_watch_events; +} + + // Test PyFloat_Pack2(), PyFloat_Pack4() and PyFloat_Pack8() static PyObject * test_float_pack(PyObject *self, PyObject *args) @@ -5762,6 +5898,10 @@ static PyMethodDef TestMethods[] = { {"settrace_to_record", settrace_to_record, METH_O, NULL}, {"test_macros", test_macros, METH_NOARGS, NULL}, {"clear_managed_dict", clear_managed_dict, METH_O, NULL}, + {"add_dict_watcher", add_dict_watcher, METH_O, NULL}, + {"clear_dict_watcher", clear_dict_watcher, METH_O, NULL}, + {"watch_dict", watch_dict, METH_VARARGS, NULL}, + {"get_dict_watcher_events", get_dict_watcher_events, METH_NOARGS, NULL}, {NULL, NULL} /* sentinel */ }; diff --git a/Objects/dictobject.c b/Objects/dictobject.c index fecdfa863701..6542b1803ffa 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -1240,6 +1240,7 @@ insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value) MAINTAIN_TRACKING(mp, key, value); if (ix == DKIX_EMPTY) { + uint64_t new_version = _PyDict_NotifyEvent(PyDict_EVENT_ADDED, mp, key, value); /* Insert into new slot. */ mp->ma_keys->dk_version = 0; assert(old_value == NULL); @@ -1274,7 +1275,7 @@ insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value) ep->me_value = value; } mp->ma_used++; - mp->ma_version_tag = DICT_NEXT_VERSION(); + mp->ma_version_tag = new_version; mp->ma_keys->dk_usable--; mp->ma_keys->dk_nentries++; assert(mp->ma_keys->dk_usable >= 0); @@ -1283,6 +1284,7 @@ insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value) } if (old_value != value) { + uint64_t new_version = _PyDict_NotifyEvent(PyDict_EVENT_MODIFIED, mp, key, value); if (_PyDict_HasSplitTable(mp)) { mp->ma_values->values[ix] = value; if (old_value == NULL) { @@ -1299,7 +1301,7 @@ insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value) DK_ENTRIES(mp->ma_keys)[ix].me_value = value; } } - mp->ma_version_tag = DICT_NEXT_VERSION(); + mp->ma_version_tag = new_version; } Py_XDECREF(old_value); /* which **CAN** re-enter (see issue #22653) */ ASSERT_CONSISTENT(mp); @@ -1320,6 +1322,8 @@ insert_to_emptydict(PyDictObject *mp, PyObject *key, Py_hash_t hash, { assert(mp->ma_keys == Py_EMPTY_KEYS); + uint64_t new_version = _PyDict_NotifyEvent(PyDict_EVENT_ADDED, mp, key, value); + int unicode = PyUnicode_CheckExact(key); PyDictKeysObject *newkeys = new_keys_object(PyDict_LOG_MINSIZE, unicode); if (newkeys == NULL) { @@ -1347,7 +1351,7 @@ insert_to_emptydict(PyDictObject *mp, PyObject *key, Py_hash_t hash, ep->me_value = value; } mp->ma_used++; - mp->ma_version_tag = DICT_NEXT_VERSION(); + mp->ma_version_tag = new_version; mp->ma_keys->dk_usable--; mp->ma_keys->dk_nentries++; return 0; @@ -1910,7 +1914,7 @@ delete_index_from_values(PyDictValues *values, Py_ssize_t ix) static int delitem_common(PyDictObject *mp, Py_hash_t hash, Py_ssize_t ix, - PyObject *old_value) + PyObject *old_value, uint64_t new_version) { PyObject *old_key; @@ -1918,7 +1922,7 @@ delitem_common(PyDictObject *mp, Py_hash_t hash, Py_ssize_t ix, assert(hashpos >= 0); mp->ma_used--; - mp->ma_version_tag = DICT_NEXT_VERSION(); + mp->ma_version_tag = new_version; if (mp->ma_values) { assert(old_value == mp->ma_values->values[ix]); mp->ma_values->values[ix] = NULL; @@ -1987,7 +1991,8 @@ _PyDict_DelItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash) return -1; } - return delitem_common(mp, hash, ix, old_value); + uint64_t new_version = _PyDict_NotifyEvent(PyDict_EVENT_DELETED, mp, key, NULL); + return delitem_common(mp, hash, ix, old_value, new_version); } /* This function promises that the predicate -> deletion sequence is atomic @@ -2028,10 +2033,12 @@ _PyDict_DelItemIf(PyObject *op, PyObject *key, hashpos = lookdict_index(mp->ma_keys, hash, ix); assert(hashpos >= 0); - if (res > 0) - return delitem_common(mp, hashpos, ix, old_value); - else + if (res > 0) { + uint64_t new_version = _PyDict_NotifyEvent(PyDict_EVENT_DELETED, mp, key, NULL); + return delitem_common(mp, hashpos, ix, old_value, new_version); + } else { return 0; + } } @@ -2052,11 +2059,12 @@ PyDict_Clear(PyObject *op) return; } /* Empty the dict... */ + uint64_t new_version = _PyDict_NotifyEvent(PyDict_EVENT_CLEARED, mp, NULL, NULL); dictkeys_incref(Py_EMPTY_KEYS); mp->ma_keys = Py_EMPTY_KEYS; mp->ma_values = NULL; mp->ma_used = 0; - mp->ma_version_tag = DICT_NEXT_VERSION(); + mp->ma_version_tag = new_version; /* ...then clear the keys and values */ if (oldvalues != NULL) { n = oldkeys->dk_nentries; @@ -2196,7 +2204,8 @@ _PyDict_Pop_KnownHash(PyObject *dict, PyObject *key, Py_hash_t hash, PyObject *d } assert(old_value != NULL); Py_INCREF(old_value); - delitem_common(mp, hash, ix, old_value); + uint64_t new_version = _PyDict_NotifyEvent(PyDict_EVENT_DELETED, mp, key, NULL); + delitem_common(mp, hash, ix, old_value, new_version); ASSERT_CONSISTENT(mp); return old_value; @@ -2321,6 +2330,7 @@ _PyDict_FromKeys(PyObject *cls, PyObject *iterable, PyObject *value) static void dict_dealloc(PyDictObject *mp) { + _PyDict_NotifyEvent(PyDict_EVENT_DEALLOCATED, mp, NULL, NULL); PyDictValues *values = mp->ma_values; PyDictKeysObject *keys = mp->ma_keys; Py_ssize_t i, n; @@ -2809,6 +2819,7 @@ dict_merge(PyObject *a, PyObject *b, int override) other->ma_used == okeys->dk_nentries && (DK_LOG_SIZE(okeys) == PyDict_LOG_MINSIZE || USABLE_FRACTION(DK_SIZE(okeys)/2) < other->ma_used)) { + uint64_t new_version = _PyDict_NotifyEvent(PyDict_EVENT_CLONED, mp, b, NULL); PyDictKeysObject *keys = clone_combined_dict_keys(other); if (keys == NULL) { return -1; @@ -2822,7 +2833,7 @@ dict_merge(PyObject *a, PyObject *b, int override) } mp->ma_used = other->ma_used; - mp->ma_version_tag = DICT_NEXT_VERSION(); + mp->ma_version_tag = new_version; ASSERT_CONSISTENT(mp); if (_PyObject_GC_IS_TRACKED(other) && !_PyObject_GC_IS_TRACKED(mp)) { @@ -3294,6 +3305,7 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj) return NULL; if (ix == DKIX_EMPTY) { + uint64_t new_version = _PyDict_NotifyEvent(PyDict_EVENT_ADDED, mp, key, defaultobj); mp->ma_keys->dk_version = 0; value = defaultobj; if (mp->ma_keys->dk_usable <= 0) { @@ -3328,12 +3340,13 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj) Py_INCREF(value); MAINTAIN_TRACKING(mp, key, value); mp->ma_used++; - mp->ma_version_tag = DICT_NEXT_VERSION(); + mp->ma_version_tag = new_version; mp->ma_keys->dk_usable--; mp->ma_keys->dk_nentries++; assert(mp->ma_keys->dk_usable >= 0); } else if (value == NULL) { + uint64_t new_version = _PyDict_NotifyEvent(PyDict_EVENT_ADDED, mp, key, defaultobj); value = defaultobj; assert(_PyDict_HasSplitTable(mp)); assert(mp->ma_values->values[ix] == NULL); @@ -3342,7 +3355,7 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj) mp->ma_values->values[ix] = value; _PyDictValues_AddToInsertionOrder(mp->ma_values, ix); mp->ma_used++; - mp->ma_version_tag = DICT_NEXT_VERSION(); + mp->ma_version_tag = new_version; } ASSERT_CONSISTENT(mp); @@ -3415,6 +3428,7 @@ dict_popitem_impl(PyDictObject *self) { Py_ssize_t i, j; PyObject *res; + uint64_t new_version; /* Allocate the result tuple before checking the size. Believe it * or not, this allocation could trigger a garbage collection which @@ -3454,6 +3468,7 @@ dict_popitem_impl(PyDictObject *self) assert(i >= 0); key = ep0[i].me_key; + new_version = _PyDict_NotifyEvent(PyDict_EVENT_DELETED, self, key, NULL); hash = unicode_get_hash(key); value = ep0[i].me_value; ep0[i].me_key = NULL; @@ -3468,6 +3483,7 @@ dict_popitem_impl(PyDictObject *self) assert(i >= 0); key = ep0[i].me_key; + new_version = _PyDict_NotifyEvent(PyDict_EVENT_DELETED, self, key, NULL); hash = ep0[i].me_hash; value = ep0[i].me_value; ep0[i].me_key = NULL; @@ -3485,7 +3501,7 @@ dict_popitem_impl(PyDictObject *self) /* We can't dk_usable++ since there is DKIX_DUMMY in indices */ self->ma_keys->dk_nentries = i; self->ma_used--; - self->ma_version_tag = DICT_NEXT_VERSION(); + self->ma_version_tag = new_version; ASSERT_CONSISTENT(self); return res; } @@ -5703,3 +5719,76 @@ uint32_t _PyDictKeys_GetVersionForCurrentState(PyDictKeysObject *dictkeys) dictkeys->dk_version = v; return v; } + +int +PyDict_Watch(int watcher_id, PyObject* dict) +{ + if (!PyDict_Check(dict)) { + PyErr_SetString(PyExc_ValueError, "Cannot watch non-dictionary"); + return -1; + } + if (watcher_id < 0 || watcher_id >= DICT_MAX_WATCHERS) { + PyErr_Format(PyExc_ValueError, "Invalid dict watcher ID %d", watcher_id); + return -1; + } + PyInterpreterState *interp = _PyInterpreterState_GET(); + if (!interp->dict_watchers[watcher_id]) { + PyErr_Format(PyExc_ValueError, "No dict watcher set for ID %d", watcher_id); + return -1; + } + ((PyDictObject*)dict)->ma_version_tag |= (1LL << watcher_id); + return 0; +} + +int +PyDict_AddWatcher(PyDict_WatchCallback callback) +{ + PyInterpreterState *interp = _PyInterpreterState_GET(); + + for (int i = 0; i < DICT_MAX_WATCHERS; i++) { + if (!interp->dict_watchers[i]) { + interp->dict_watchers[i] = callback; + return i; + } + } + + PyErr_SetString(PyExc_RuntimeError, "no more dict watcher IDs available"); + return -1; +} + +int +PyDict_ClearWatcher(int watcher_id) +{ + if (watcher_id < 0 || watcher_id >= DICT_MAX_WATCHERS) { + PyErr_Format(PyExc_ValueError, "Invalid dict watcher ID %d", watcher_id); + return -1; + } + PyInterpreterState *interp = _PyInterpreterState_GET(); + if (!interp->dict_watchers[watcher_id]) { + PyErr_Format(PyExc_ValueError, "No dict watcher set for ID %d", watcher_id); + return -1; + } + interp->dict_watchers[watcher_id] = NULL; + return 0; +} + +void +_PyDict_SendEvent(int watcher_bits, + PyDict_WatchEvent event, + PyDictObject *mp, + PyObject *key, + PyObject *value) +{ + PyInterpreterState *interp = _PyInterpreterState_GET(); + for (int i = 0; i < DICT_MAX_WATCHERS; i++) { + if (watcher_bits & 1) { + PyDict_WatchCallback cb = interp->dict_watchers[i]; + if (cb && (cb(event, (PyObject*)mp, key, value) < 0)) { + // some dict modification paths (e.g. PyDict_Clear) can't raise, so we + // can't propagate exceptions from dict watchers. + PyErr_WriteUnraisable((PyObject *)mp); + } + } + watcher_bits >>= 1; + } +} diff --git a/Python/ceval.c b/Python/ceval.c index c08c794005d1..ee1babaaf444 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -3252,6 +3252,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int uint16_t hint = cache->index; DEOPT_IF(hint >= (size_t)dict->ma_keys->dk_nentries, STORE_ATTR); PyObject *value, *old_value; + uint64_t new_version; if (DK_IS_UNICODE(dict->ma_keys)) { PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint; DEOPT_IF(ep->me_key != name, STORE_ATTR); @@ -3259,6 +3260,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int DEOPT_IF(old_value == NULL, STORE_ATTR); STACK_SHRINK(1); value = POP(); + new_version = _PyDict_NotifyEvent(PyDict_EVENT_MODIFIED, dict, name, value); ep->me_value = value; } else { @@ -3268,6 +3270,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int DEOPT_IF(old_value == NULL, STORE_ATTR); STACK_SHRINK(1); value = POP(); + new_version = _PyDict_NotifyEvent(PyDict_EVENT_MODIFIED, dict, name, value); ep->me_value = value; } Py_DECREF(old_value); @@ -3277,7 +3280,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int _PyObject_GC_TRACK(dict); } /* PEP 509 */ - dict->ma_version_tag = DICT_NEXT_VERSION(); + dict->ma_version_tag = new_version; Py_DECREF(owner); JUMPBY(INLINE_CACHE_ENTRIES_STORE_ATTR); DISPATCH(); diff --git a/Python/pystate.c b/Python/pystate.c index 50ae0ce68217..c74868ddfa20 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -451,6 +451,10 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate) Py_CLEAR(interp->sysdict); Py_CLEAR(interp->builtins); + for (int i=0; i < DICT_MAX_WATCHERS; i++) { + interp->dict_watchers[i] = NULL; + } + // XXX Once we have one allocator per interpreter (i.e. // per-interpreter GC) we must ensure that all of the interpreter's // objects have been cleaned up at the point. From webhook-mailer at python.org Thu Oct 6 20:12:08 2022 From: webhook-mailer at python.org (ericvsmith) Date: Fri, 07 Oct 2022 00:12:08 -0000 Subject: [Python-checkins] bpo-35540 dataclasses.asdict now supports defaultdict fields (gh-32056) Message-ID: https://github.com/python/cpython/commit/c46a423a520b797c3f8c81fef19293864742755d commit: c46a423a520b797c3f8c81fef19293864742755d branch: main author: Tiger committer: ericvsmith date: 2022-10-06T17:11:59-07:00 summary: bpo-35540 dataclasses.asdict now supports defaultdict fields (gh-32056) files: A Misc/NEWS.d/next/Library/2022-03-22-18-28-55.bpo-35540.nyijX9.rst M Lib/dataclasses.py M Lib/test/test_dataclasses.py diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index 65fb8f251861..bf7f290af162 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -1325,6 +1325,14 @@ def _asdict_inner(obj, dict_factory): # generator (which is not true for namedtuples, handled # above). return type(obj)(_asdict_inner(v, dict_factory) for v in obj) + elif isinstance(obj, dict) and hasattr(type(obj), 'default_factory'): + # obj is a defaultdict, which has a different constructor from + # dict as it requires the default_factory as its first arg. + # https://bugs.python.org/issue35540 + result = type(obj)(getattr(obj, 'default_factory')) + for k, v in obj.items(): + result[_asdict_inner(k, dict_factory)] = _asdict_inner(v, dict_factory) + return result elif isinstance(obj, dict): return type(obj)((_asdict_inner(k, dict_factory), _asdict_inner(v, dict_factory)) diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py index 328dcdcb0bce..637c456dd49e 100644 --- a/Lib/test/test_dataclasses.py +++ b/Lib/test/test_dataclasses.py @@ -12,9 +12,9 @@ import weakref import unittest from unittest.mock import Mock -from typing import ClassVar, Any, List, Union, Tuple, Dict, Generic, TypeVar, Optional, Protocol +from typing import ClassVar, Any, List, Union, Tuple, Dict, Generic, TypeVar, Optional, Protocol, DefaultDict from typing import get_type_hints -from collections import deque, OrderedDict, namedtuple +from collections import deque, OrderedDict, namedtuple, defaultdict from functools import total_ordering import typing # Needed for the string "typing.ClassVar[int]" to work as an annotation. @@ -1677,6 +1677,23 @@ class C: self.assertIsNot(d['f'], t) self.assertEqual(d['f'].my_a(), 6) + def test_helper_asdict_defaultdict(self): + # Ensure asdict() does not throw exceptions when a + # defaultdict is a member of a dataclass + + @dataclass + class C: + mp: DefaultDict[str, List] + + + dd = defaultdict(list) + dd["x"].append(12) + c = C(mp=dd) + d = asdict(c) + + assert d == {"mp": {"x": [12]}} + assert d["mp"] is not c.mp # make sure defaultdict is copied + def test_helper_astuple(self): # Basic tests for astuple(), it should return a new tuple. @dataclass diff --git a/Misc/NEWS.d/next/Library/2022-03-22-18-28-55.bpo-35540.nyijX9.rst b/Misc/NEWS.d/next/Library/2022-03-22-18-28-55.bpo-35540.nyijX9.rst new file mode 100644 index 000000000000..b7aeee6c8c8f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-03-22-18-28-55.bpo-35540.nyijX9.rst @@ -0,0 +1 @@ +Fix :func:`dataclasses.asdict` crash when :class:`collections.defaultdict` is present in the attributes. From webhook-mailer at python.org Thu Oct 6 20:30:36 2022 From: webhook-mailer at python.org (gvanrossum) Date: Fri, 07 Oct 2022 00:30:36 -0000 Subject: [Python-checkins] GH-90985: Revert "Deprecate passing a message into cancel()" (#97999) Message-ID: https://github.com/python/cpython/commit/09de8d7aafece264720afbca3052a63eee413b73 commit: 09de8d7aafece264720afbca3052a63eee413b73 branch: main author: Guido van Rossum committer: gvanrossum date: 2022-10-06T17:30:27-07:00 summary: GH-90985: Revert "Deprecate passing a message into cancel()" (#97999) Reason: we were too hasty in deprecating this. We shouldn't deprecate it before we have a replacement. files: A Misc/NEWS.d/next/Library/2022-10-06-23-42-00.gh-issue-90985.s280JY.rst M Doc/library/asyncio-future.rst M Doc/library/asyncio-task.rst M Lib/asyncio/futures.py M Lib/asyncio/tasks.py M Lib/test/test_asyncio/test_futures.py M Lib/test/test_asyncio/test_tasks.py M Modules/_asynciomodule.c diff --git a/Doc/library/asyncio-future.rst b/Doc/library/asyncio-future.rst index 8e60877f0e4c..70cec9b2f902 100644 --- a/Doc/library/asyncio-future.rst +++ b/Doc/library/asyncio-future.rst @@ -197,11 +197,6 @@ Future Object .. versionchanged:: 3.9 Added the *msg* parameter. - .. deprecated-removed:: 3.11 3.14 - *msg* parameter is ambiguous when multiple :meth:`cancel` - are called with different cancellation messages. - The argument will be removed. - .. method:: exception() Return the exception that was set on this Future. @@ -282,8 +277,3 @@ the Future has a result:: - :meth:`asyncio.Future.cancel` accepts an optional ``msg`` argument, but :func:`concurrent.futures.cancel` does not. - - .. deprecated-removed:: 3.11 3.14 - *msg* parameter is ambiguous when multiple :meth:`cancel` - are called with different cancellation messages. - The argument will be removed. diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index d922f614954f..9c17dc639736 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -1144,10 +1144,8 @@ Task Object .. versionchanged:: 3.9 Added the *msg* parameter. - .. deprecated-removed:: 3.11 3.14 - *msg* parameter is ambiguous when multiple :meth:`cancel` - are called with different cancellation messages. - The argument will be removed. + .. versionchanged:: 3.11 + The ``msg`` parameter is propagated from cancelled task to its awaiter. .. _asyncio_example_task_cancel: diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py index 39776e3c2cce..3a6b44a09108 100644 --- a/Lib/asyncio/futures.py +++ b/Lib/asyncio/futures.py @@ -8,7 +8,6 @@ import contextvars import logging import sys -import warnings from types import GenericAlias from . import base_futures @@ -151,11 +150,6 @@ def cancel(self, msg=None): change the future's state to cancelled, schedule the callbacks and return True. """ - if msg is not None: - warnings.warn("Passing 'msg' argument to Future.cancel() " - "is deprecated since Python 3.11, and " - "scheduled for removal in Python 3.14.", - DeprecationWarning, stacklevel=2) self.__log_traceback = False if self._state != _PENDING: return False diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py index 8d6dfcd81b73..571013745aa0 100644 --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -210,11 +210,6 @@ def cancel(self, msg=None): This also increases the task's count of cancellation requests. """ - if msg is not None: - warnings.warn("Passing 'msg' argument to Task.cancel() " - "is deprecated since Python 3.11, and " - "scheduled for removal in Python 3.14.", - DeprecationWarning, stacklevel=2) self._log_traceback = False if self.done(): return False diff --git a/Lib/test/test_asyncio/test_futures.py b/Lib/test/test_asyncio/test_futures.py index 3dc6b658cfae..83ea01c24525 100644 --- a/Lib/test/test_asyncio/test_futures.py +++ b/Lib/test/test_asyncio/test_futures.py @@ -229,22 +229,14 @@ def test_future_cancel_message_getter(self): self.assertTrue(hasattr(f, '_cancel_message')) self.assertEqual(f._cancel_message, None) - with self.assertWarnsRegex( - DeprecationWarning, - "Passing 'msg' argument" - ): - f.cancel('my message') + f.cancel('my message') with self.assertRaises(asyncio.CancelledError): self.loop.run_until_complete(f) self.assertEqual(f._cancel_message, 'my message') def test_future_cancel_message_setter(self): f = self._new_future(loop=self.loop) - with self.assertWarnsRegex( - DeprecationWarning, - "Passing 'msg' argument" - ): - f.cancel('my message') + f.cancel('my message') f._cancel_message = 'my new message' self.assertEqual(f._cancel_message, 'my new message') diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py index 2491285206bc..0e38e6a92e52 100644 --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -109,11 +109,7 @@ async def coro(): self.assertTrue(hasattr(t, '_cancel_message')) self.assertEqual(t._cancel_message, None) - with self.assertWarnsRegex( - DeprecationWarning, - "Passing 'msg' argument" - ): - t.cancel('my message') + t.cancel('my message') self.assertEqual(t._cancel_message, 'my message') with self.assertRaises(asyncio.CancelledError) as cm: @@ -125,11 +121,7 @@ def test_task_cancel_message_setter(self): async def coro(): pass t = self.new_task(self.loop, coro()) - with self.assertWarnsRegex( - DeprecationWarning, - "Passing 'msg' argument" - ): - t.cancel('my message') + t.cancel('my message') t._cancel_message = 'my new message' self.assertEqual(t._cancel_message, 'my new message') @@ -706,14 +698,7 @@ async def sleep(): async def coro(): task = self.new_task(loop, sleep()) await asyncio.sleep(0) - if cancel_args not in ((), (None,)): - with self.assertWarnsRegex( - DeprecationWarning, - "Passing 'msg' argument" - ): - task.cancel(*cancel_args) - else: - task.cancel(*cancel_args) + task.cancel(*cancel_args) done, pending = await asyncio.wait([task]) task.result() @@ -747,14 +732,7 @@ async def sleep(): async def coro(): task = self.new_task(loop, sleep()) await asyncio.sleep(0) - if cancel_args not in ((), (None,)): - with self.assertWarnsRegex( - DeprecationWarning, - "Passing 'msg' argument" - ): - task.cancel(*cancel_args) - else: - task.cancel(*cancel_args) + task.cancel(*cancel_args) done, pending = await asyncio.wait([task]) task.exception() @@ -777,17 +755,10 @@ async def sleep(): fut.set_result(None) await asyncio.sleep(10) - def cancel(task, msg): - with self.assertWarnsRegex( - DeprecationWarning, - "Passing 'msg' argument" - ): - task.cancel(msg) - async def coro(): inner_task = self.new_task(loop, sleep()) await fut - loop.call_soon(cancel, inner_task, 'msg') + loop.call_soon(inner_task.cancel, 'msg') try: await inner_task except asyncio.CancelledError as ex: @@ -813,11 +784,7 @@ async def sleep(): async def coro(): task = self.new_task(loop, sleep()) # We deliberately leave out the sleep here. - with self.assertWarnsRegex( - DeprecationWarning, - "Passing 'msg' argument" - ): - task.cancel('my message') + task.cancel('my message') done, pending = await asyncio.wait([task]) task.exception() @@ -2179,14 +2146,7 @@ async def test(): async def main(): qwe = self.new_task(loop, test()) await asyncio.sleep(0.2) - if cancel_args not in ((), (None,)): - with self.assertWarnsRegex( - DeprecationWarning, - "Passing 'msg' argument" - ): - qwe.cancel(*cancel_args) - else: - qwe.cancel(*cancel_args) + qwe.cancel(*cancel_args) await qwe try: diff --git a/Misc/NEWS.d/next/Library/2022-10-06-23-42-00.gh-issue-90985.s280JY.rst b/Misc/NEWS.d/next/Library/2022-10-06-23-42-00.gh-issue-90985.s280JY.rst new file mode 100644 index 000000000000..964aa3986331 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-06-23-42-00.gh-issue-90985.s280JY.rst @@ -0,0 +1 @@ +Earlier in 3.11 we deprecated ``asyncio.Task.cancel("message")``. We realized we were too harsh, and have undeprecated it. diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index efa0d2d6906e..ab6219c322f9 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -1116,16 +1116,6 @@ static PyObject * _asyncio_Future_cancel_impl(FutureObj *self, PyObject *msg) /*[clinic end generated code: output=3edebbc668e5aba3 input=925eb545251f2c5a]*/ { - if (msg != Py_None) { - if (PyErr_WarnEx(PyExc_DeprecationWarning, - "Passing 'msg' argument to Future.cancel() " - "is deprecated since Python 3.11, and " - "scheduled for removal in Python 3.14.", - 2)) - { - return NULL; - } - } ENSURE_FUTURE_ALIVE(self) return future_cancel(self, msg); } @@ -2214,16 +2204,6 @@ static PyObject * _asyncio_Task_cancel_impl(TaskObj *self, PyObject *msg) /*[clinic end generated code: output=c66b60d41c74f9f1 input=7bb51bf25974c783]*/ { - if (msg != Py_None) { - if (PyErr_WarnEx(PyExc_DeprecationWarning, - "Passing 'msg' argument to Task.cancel() " - "is deprecated since Python 3.11, and " - "scheduled for removal in Python 3.14.", - 2)) - { - return NULL; - } - } self->task_log_tb = 0; if (self->task_state != STATE_PENDING) { From webhook-mailer at python.org Thu Oct 6 20:36:45 2022 From: webhook-mailer at python.org (brandtbucher) Date: Fri, 07 Oct 2022 00:36:45 -0000 Subject: [Python-checkins] [3.11] GH-97002: Prevent _PyInterpreterFrames from backing more than one PyFrameObject (GH-98002) Message-ID: https://github.com/python/cpython/commit/89e9474327c372d84f465a6949d58a65f1e38719 commit: 89e9474327c372d84f465a6949d58a65f1e38719 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: brandtbucher date: 2022-10-06T17:36:39-07:00 summary: [3.11] GH-97002: Prevent _PyInterpreterFrames from backing more than one PyFrameObject (GH-98002) (cherry picked from commit 21a2d9ff550977f2668e2cf1cc15793bf27fa109) files: A Misc/NEWS.d/next/Core and Builtins/2022-10-06-02-11-34.gh-issue-97002.Zvsk71.rst M Lib/test/test_frame.py M Python/frame.c diff --git a/Lib/test/test_frame.py b/Lib/test/test_frame.py index 5dda2fbfac37..4b86a60d2f4c 100644 --- a/Lib/test/test_frame.py +++ b/Lib/test/test_frame.py @@ -1,3 +1,4 @@ +import gc import re import sys import textwrap @@ -261,5 +262,69 @@ def gen(): """) assert_python_ok("-c", code) + @support.cpython_only + def test_sneaky_frame_object(self): + + def trace(frame, event, arg): + """ + Don't actually do anything, just force a frame object to be created. + """ + + def callback(phase, info): + """ + Yo dawg, I heard you like frames, so I'm allocating a frame while + you're allocating a frame, so you can have a frame while you have a + frame! + """ + nonlocal sneaky_frame_object + sneaky_frame_object = sys._getframe().f_back + # We're done here: + gc.callbacks.remove(callback) + + def f(): + while True: + yield + + old_threshold = gc.get_threshold() + old_callbacks = gc.callbacks[:] + old_enabled = gc.isenabled() + old_trace = sys.gettrace() + try: + # Stop the GC for a second while we set things up: + gc.disable() + # Create a paused generator: + g = f() + next(g) + # Move all objects to the oldest generation, and tell the GC to run + # on the *very next* allocation: + gc.collect() + gc.set_threshold(1, 0, 0) + # Okay, so here's the nightmare scenario: + # - We're tracing the resumption of a generator, which creates a new + # frame object. + # - The allocation of this frame object triggers a collection + # *before* the frame object is actually created. + # - During the collection, we request the exact same frame object. + # This test does it with a GC callback, but in real code it would + # likely be a trace function, weakref callback, or finalizer. + # - The collection finishes, and the original frame object is + # created. We now have two frame objects fighting over ownership + # of the same interpreter frame! + sys.settrace(trace) + gc.callbacks.append(callback) + sneaky_frame_object = None + gc.enable() + next(g) + # g.gi_frame should be the the frame object from the callback (the + # one that was *requested* second, but *created* first): + self.assertIs(g.gi_frame, sneaky_frame_object) + finally: + gc.set_threshold(*old_threshold) + gc.callbacks[:] = old_callbacks + sys.settrace(old_trace) + if old_enabled: + gc.enable() + + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-06-02-11-34.gh-issue-97002.Zvsk71.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-06-02-11-34.gh-issue-97002.Zvsk71.rst new file mode 100644 index 000000000000..1f577e02e1fd --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-06-02-11-34.gh-issue-97002.Zvsk71.rst @@ -0,0 +1,3 @@ +Fix an issue where several frame objects could be backed by the same +interpreter frame, possibly leading to corrupted memory and hard crashes of +the interpreter. diff --git a/Python/frame.c b/Python/frame.c index 9f58c20d4fa2..d8f2f801f38c 100644 --- a/Python/frame.c +++ b/Python/frame.c @@ -35,14 +35,31 @@ _PyFrame_MakeAndSetFrameObject(_PyInterpreterFrame *frame) Py_XDECREF(error_type); Py_XDECREF(error_value); Py_XDECREF(error_traceback); + return NULL; } - else { - assert(frame->owner != FRAME_OWNED_BY_FRAME_OBJECT); - assert(frame->owner != FRAME_CLEARED); - f->f_frame = frame; - frame->frame_obj = f; - PyErr_Restore(error_type, error_value, error_traceback); + PyErr_Restore(error_type, error_value, error_traceback); + if (frame->frame_obj) { + // GH-97002: How did we get into this horrible situation? Most likely, + // allocating f triggered a GC collection, which ran some code that + // *also* created the same frame... while we were in the middle of + // creating it! See test_sneaky_frame_object in test_frame.py for a + // concrete example. + // + // Regardless, just throw f away and use that frame instead, since it's + // already been exposed to user code. It's actually a bit tricky to do + // this, since we aren't backed by a real _PyInterpreterFrame anymore. + // Just pretend that we have an owned, cleared frame so frame_dealloc + // doesn't make the situation worse: + f->f_frame = (_PyInterpreterFrame *)f->_f_frame_data; + f->f_frame->owner = FRAME_CLEARED; + f->f_frame->frame_obj = f; + Py_DECREF(f); + return frame->frame_obj; } + assert(frame->owner != FRAME_OWNED_BY_FRAME_OBJECT); + assert(frame->owner != FRAME_CLEARED); + f->f_frame = frame; + frame->frame_obj = f; return f; } From webhook-mailer at python.org Thu Oct 6 20:42:16 2022 From: webhook-mailer at python.org (nanjekyejoannah) Date: Fri, 07 Oct 2022 00:42:16 -0000 Subject: [Python-checkins] Remove extra spaces in custom openSSL documentation. (#93568) Message-ID: https://github.com/python/cpython/commit/4875433682ffec2694647ac43f1b21f5ad73fd25 commit: 4875433682ffec2694647ac43f1b21f5ad73fd25 branch: main author: Xiao Chen committer: nanjekyejoannah <33177550+nanjekyejoannah at users.noreply.github.com> date: 2022-10-06T17:42:08-07:00 summary: Remove extra spaces in custom openSSL documentation. (#93568) files: M Doc/using/unix.rst diff --git a/Doc/using/unix.rst b/Doc/using/unix.rst index 3f9f1364c8ae..061cfa5be88f 100644 --- a/Doc/using/unix.rst +++ b/Doc/using/unix.rst @@ -158,16 +158,16 @@ Custom OpenSSL .. code-block:: shell-session $ curl -O https://www.openssl.org/source/openssl-VERSION.tar.gz - $ tar xzf openssl-VERSION - $ pushd openssl-VERSION - $ ./config \ - --prefix=/usr/local/custom-openssl \ - --libdir=lib \ - --openssldir=/etc/ssl - $ make -j1 depend - $ make -j8 - $ make install_sw - $ popd + $ tar xzf openssl-VERSION + $ pushd openssl-VERSION + $ ./config \ + --prefix=/usr/local/custom-openssl \ + --libdir=lib \ + --openssldir=/etc/ssl + $ make -j1 depend + $ make -j8 + $ make install_sw + $ popd 3. Build Python with custom OpenSSL (see the configure `--with-openssl` and `--with-openssl-rpath` options) From webhook-mailer at python.org Thu Oct 6 20:56:29 2022 From: webhook-mailer at python.org (nanjekyejoannah) Date: Fri, 07 Oct 2022 00:56:29 -0000 Subject: [Python-checkins] [3.11] Remove extra spaces in custom openSSL documentation. (GH-93568) (#98007) Message-ID: https://github.com/python/cpython/commit/c9d0a7a6bc2f5d5521452790fb4885bb21deca15 commit: c9d0a7a6bc2f5d5521452790fb4885bb21deca15 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: nanjekyejoannah <33177550+nanjekyejoannah at users.noreply.github.com> date: 2022-10-06T17:56:24-07:00 summary: [3.11] Remove extra spaces in custom openSSL documentation. (GH-93568) (#98007) Remove extra spaces in custom openSSL documentation. (GH-93568) (cherry picked from commit 4875433682ffec2694647ac43f1b21f5ad73fd25) Co-authored-by: Xiao Chen Co-authored-by: Xiao Chen files: M Doc/using/unix.rst diff --git a/Doc/using/unix.rst b/Doc/using/unix.rst index 3f9f1364c8ae..061cfa5be88f 100644 --- a/Doc/using/unix.rst +++ b/Doc/using/unix.rst @@ -158,16 +158,16 @@ Custom OpenSSL .. code-block:: shell-session $ curl -O https://www.openssl.org/source/openssl-VERSION.tar.gz - $ tar xzf openssl-VERSION - $ pushd openssl-VERSION - $ ./config \ - --prefix=/usr/local/custom-openssl \ - --libdir=lib \ - --openssldir=/etc/ssl - $ make -j1 depend - $ make -j8 - $ make install_sw - $ popd + $ tar xzf openssl-VERSION + $ pushd openssl-VERSION + $ ./config \ + --prefix=/usr/local/custom-openssl \ + --libdir=lib \ + --openssldir=/etc/ssl + $ make -j1 depend + $ make -j8 + $ make install_sw + $ popd 3. Build Python with custom OpenSSL (see the configure `--with-openssl` and `--with-openssl-rpath` options) From webhook-mailer at python.org Thu Oct 6 20:56:56 2022 From: webhook-mailer at python.org (nanjekyejoannah) Date: Fri, 07 Oct 2022 00:56:56 -0000 Subject: [Python-checkins] [3.10] Remove extra spaces in custom openSSL documentation. (GH-93568) (#98008) Message-ID: https://github.com/python/cpython/commit/bb21bc335b15e35735084d4369b9d17f3e481a51 commit: bb21bc335b15e35735084d4369b9d17f3e481a51 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: nanjekyejoannah <33177550+nanjekyejoannah at users.noreply.github.com> date: 2022-10-06T17:56:51-07:00 summary: [3.10] Remove extra spaces in custom openSSL documentation. (GH-93568) (#98008) Remove extra spaces in custom openSSL documentation. (GH-93568) (cherry picked from commit 4875433682ffec2694647ac43f1b21f5ad73fd25) Co-authored-by: Xiao Chen Co-authored-by: Xiao Chen files: M Doc/using/unix.rst diff --git a/Doc/using/unix.rst b/Doc/using/unix.rst index 3f9f1364c8ae..061cfa5be88f 100644 --- a/Doc/using/unix.rst +++ b/Doc/using/unix.rst @@ -158,16 +158,16 @@ Custom OpenSSL .. code-block:: shell-session $ curl -O https://www.openssl.org/source/openssl-VERSION.tar.gz - $ tar xzf openssl-VERSION - $ pushd openssl-VERSION - $ ./config \ - --prefix=/usr/local/custom-openssl \ - --libdir=lib \ - --openssldir=/etc/ssl - $ make -j1 depend - $ make -j8 - $ make install_sw - $ popd + $ tar xzf openssl-VERSION + $ pushd openssl-VERSION + $ ./config \ + --prefix=/usr/local/custom-openssl \ + --libdir=lib \ + --openssldir=/etc/ssl + $ make -j1 depend + $ make -j8 + $ make install_sw + $ popd 3. Build Python with custom OpenSSL (see the configure `--with-openssl` and `--with-openssl-rpath` options) From webhook-mailer at python.org Thu Oct 6 20:57:19 2022 From: webhook-mailer at python.org (warsaw) Date: Fri, 07 Oct 2022 00:57:19 -0000 Subject: [Python-checkins] gh-97850: Remove deprecated functions from `importlib.utils` (#97898) Message-ID: https://github.com/python/cpython/commit/27025e158c70331d0a8fb42fe234a2a6770850d1 commit: 27025e158c70331d0a8fb42fe234a2a6770850d1 branch: main author: Nikita Sobolev committer: warsaw date: 2022-10-06T17:57:10-07:00 summary: gh-97850: Remove deprecated functions from `importlib.utils` (#97898) * gh-97850: Remove deprecated functions from `importlib.utils` * Rebase and remove `set_package` from diff files: A Misc/NEWS.d/next/Library/2022-10-05-11-40-02.gh-issue-97850.NzdREm.rst M Doc/library/importlib.rst M Lib/importlib/util.py M Lib/test/test_importlib/test_abc.py M Lib/test/test_importlib/test_spec.py M Lib/test/test_importlib/test_util.py diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst index a7c067c06e8e..3fc1531c0cdf 100644 --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -443,7 +443,7 @@ ABC hierarchy:: from the import. If the loader inserted a module and the load fails, it must be removed by the loader from :data:`sys.modules`; modules already in :data:`sys.modules` before the loader began execution should be left - alone (see :func:`importlib.util.module_for_loader`). + alone. The loader should set several attributes on the module (note that some of these attributes can change when a module is @@ -1326,58 +1326,6 @@ an :term:`importer`. .. versionadded:: 3.5 -.. decorator:: module_for_loader - - A :term:`decorator` for :meth:`importlib.abc.Loader.load_module` - to handle selecting the proper - module object to load with. The decorated method is expected to have a call - signature taking two positional arguments - (e.g. ``load_module(self, module)``) for which the second argument - will be the module **object** to be used by the loader. - Note that the decorator will not work on static methods because of the - assumption of two arguments. - - The decorated method will take in the **name** of the module to be loaded - as expected for a :term:`loader`. If the module is not found in - :data:`sys.modules` then a new one is constructed. Regardless of where the - module came from, :attr:`__loader__` set to **self** and :attr:`__package__` - is set based on what :meth:`importlib.abc.InspectLoader.is_package` returns - (if available). These attributes are set unconditionally to support - reloading. - - If an exception is raised by the decorated method and a module was added to - :data:`sys.modules`, then the module will be removed to prevent a partially - initialized module from being in left in :data:`sys.modules`. If the module - was already in :data:`sys.modules` then it is left alone. - - .. versionchanged:: 3.3 - :attr:`__loader__` and :attr:`__package__` are automatically set - (when possible). - - .. versionchanged:: 3.4 - Set :attr:`__name__`, :attr:`__loader__` :attr:`__package__` - unconditionally to support reloading. - - .. deprecated:: 3.4 - The import machinery now directly performs all the functionality - provided by this function. - -.. decorator:: set_loader - - A :term:`decorator` for :meth:`importlib.abc.Loader.load_module` - to set the :attr:`__loader__` - attribute on the returned module. If the attribute is already set the - decorator does nothing. It is assumed that the first positional argument to - the wrapped method (i.e. ``self``) is what :attr:`__loader__` should be set - to. - - .. versionchanged:: 3.4 - Set ``__loader__`` if set to ``None``, as if the attribute does not - exist. - - .. deprecated:: 3.4 - The import machinery takes care of this automatically. - .. function:: spec_from_loader(name, loader, *, origin=None, is_package=None) A factory function for creating a :class:`~importlib.machinery.ModuleSpec` diff --git a/Lib/importlib/util.py b/Lib/importlib/util.py index 7f15b029b240..9e29c581b1db 100644 --- a/Lib/importlib/util.py +++ b/Lib/importlib/util.py @@ -11,12 +11,9 @@ from ._bootstrap_external import source_from_cache from ._bootstrap_external import spec_from_file_location -from contextlib import contextmanager import _imp -import functools import sys import types -import warnings def source_hash(source_bytes): @@ -115,90 +112,6 @@ def find_spec(name, package=None): return spec - at contextmanager -def _module_to_load(name): - is_reload = name in sys.modules - - module = sys.modules.get(name) - if not is_reload: - # This must be done before open() is called as the 'io' module - # implicitly imports 'locale' and would otherwise trigger an - # infinite loop. - module = type(sys)(name) - # This must be done before putting the module in sys.modules - # (otherwise an optimization shortcut in import.c becomes wrong) - module.__initializing__ = True - sys.modules[name] = module - try: - yield module - except Exception: - if not is_reload: - try: - del sys.modules[name] - except KeyError: - pass - finally: - module.__initializing__ = False - - -def set_loader(fxn): - """Set __loader__ on the returned module. - - This function is deprecated. - - """ - @functools.wraps(fxn) - def set_loader_wrapper(self, *args, **kwargs): - warnings.warn('The import system now takes care of this automatically; ' - 'this decorator is slated for removal in Python 3.12', - DeprecationWarning, stacklevel=2) - module = fxn(self, *args, **kwargs) - if getattr(module, '__loader__', None) is None: - module.__loader__ = self - return module - return set_loader_wrapper - - -def module_for_loader(fxn): - """Decorator to handle selecting the proper module for loaders. - - The decorated function is passed the module to use instead of the module - name. The module passed in to the function is either from sys.modules if - it already exists or is a new module. If the module is new, then __name__ - is set the first argument to the method, __loader__ is set to self, and - __package__ is set accordingly (if self.is_package() is defined) will be set - before it is passed to the decorated function (if self.is_package() does - not work for the module it will be set post-load). - - If an exception is raised and the decorator created the module it is - subsequently removed from sys.modules. - - The decorator assumes that the decorated function takes the module name as - the second argument. - - """ - warnings.warn('The import system now takes care of this automatically; ' - 'this decorator is slated for removal in Python 3.12', - DeprecationWarning, stacklevel=2) - @functools.wraps(fxn) - def module_for_loader_wrapper(self, fullname, *args, **kwargs): - with _module_to_load(fullname) as module: - module.__loader__ = self - try: - is_package = self.is_package(fullname) - except (ImportError, AttributeError): - pass - else: - if is_package: - module.__package__ = fullname - else: - module.__package__ = fullname.rpartition('.')[0] - # If __package__ was not set above, __import__() will do it later. - return fxn(self, module, *args, **kwargs) - - return module_for_loader_wrapper - - class _LazyModule(types.ModuleType): """A subclass of the module type which triggers loading upon attribute access.""" diff --git a/Lib/test/test_importlib/test_abc.py b/Lib/test/test_importlib/test_abc.py index 8641b6cc6830..3c9149c4e45a 100644 --- a/Lib/test/test_importlib/test_abc.py +++ b/Lib/test/test_importlib/test_abc.py @@ -771,13 +771,7 @@ def verify_code(self, code_object): class SourceOnlyLoaderTests(SourceLoaderTestHarness): - - """Test importlib.abc.SourceLoader for source-only loading. - - Reload testing is subsumed by the tests for - importlib.util.module_for_loader. - - """ + """Test importlib.abc.SourceLoader for source-only loading.""" def test_get_source(self): # Verify the source code is returned as a string. diff --git a/Lib/test/test_importlib/test_spec.py b/Lib/test/test_importlib/test_spec.py index f1ab16c7b2a9..80aa3609c6f9 100644 --- a/Lib/test/test_importlib/test_spec.py +++ b/Lib/test/test_importlib/test_spec.py @@ -47,21 +47,6 @@ def exec_module(self, module): module.eggs = self.EGGS -class LegacyLoader(TestLoader): - - HAM = -1 - - with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) - - frozen_util = util['Frozen'] - - @frozen_util.module_for_loader - def load_module(self, module): - module.ham = self.HAM - return module - - class ModuleSpecTests: def setUp(self): @@ -302,26 +287,6 @@ def exec_module(self, module): loaded = self.bootstrap._load(self.spec) self.assertNotIn(self.spec.name, sys.modules) - def test_load_legacy(self): - with warnings.catch_warnings(): - warnings.simplefilter("ignore", ImportWarning) - self.spec.loader = LegacyLoader() - with CleanImport(self.spec.name): - loaded = self.bootstrap._load(self.spec) - - self.assertEqual(loaded.ham, -1) - - def test_load_legacy_attributes(self): - with warnings.catch_warnings(): - warnings.simplefilter("ignore", ImportWarning) - self.spec.loader = LegacyLoader() - with CleanImport(self.spec.name): - loaded = self.bootstrap._load(self.spec) - - self.assertIs(loaded.__loader__, self.spec.loader) - self.assertEqual(loaded.__package__, self.spec.parent) - self.assertIs(loaded.__spec__, self.spec) - def test_load_legacy_attributes_immutable(self): module = object() with warnings.catch_warnings(): @@ -387,19 +352,6 @@ def test_reload_init_module_attrs(self): self.assertFalse(hasattr(loaded, '__file__')) self.assertFalse(hasattr(loaded, '__cached__')) - def test_reload_legacy(self): - with warnings.catch_warnings(): - warnings.simplefilter("ignore", ImportWarning) - self.spec.loader = LegacyLoader() - with CleanImport(self.spec.name): - loaded = self.bootstrap._load(self.spec) - reloaded = self.bootstrap._exec(self.spec, loaded) - installed = sys.modules[self.spec.name] - - self.assertEqual(loaded.ham, -1) - self.assertIs(reloaded, loaded) - self.assertIs(installed, loaded) - (Frozen_ModuleSpecMethodsTests, Source_ModuleSpecMethodsTests diff --git a/Lib/test/test_importlib/test_util.py b/Lib/test/test_importlib/test_util.py index e70971e9d3bc..08a615ecf528 100644 --- a/Lib/test/test_importlib/test_util.py +++ b/Lib/test/test_importlib/test_util.py @@ -121,184 +121,6 @@ def test___cached__(self): util=importlib_util) -class ModuleForLoaderTests: - - """Tests for importlib.util.module_for_loader.""" - - @classmethod - def module_for_loader(cls, func): - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - return cls.util.module_for_loader(func) - - def test_warning(self): - # Should raise a PendingDeprecationWarning when used. - with warnings.catch_warnings(): - warnings.simplefilter('error', DeprecationWarning) - with self.assertRaises(DeprecationWarning): - func = self.util.module_for_loader(lambda x: x) - - def return_module(self, name): - fxn = self.module_for_loader(lambda self, module: module) - return fxn(self, name) - - def raise_exception(self, name): - def to_wrap(self, module): - raise ImportError - fxn = self.module_for_loader(to_wrap) - try: - fxn(self, name) - except ImportError: - pass - - def test_new_module(self): - # Test that when no module exists in sys.modules a new module is - # created. - module_name = 'a.b.c' - with util.uncache(module_name): - module = self.return_module(module_name) - self.assertIn(module_name, sys.modules) - self.assertIsInstance(module, types.ModuleType) - self.assertEqual(module.__name__, module_name) - - def test_reload(self): - # Test that a module is reused if already in sys.modules. - class FakeLoader: - def is_package(self, name): - return True - @self.module_for_loader - def load_module(self, module): - return module - name = 'a.b.c' - module = types.ModuleType('a.b.c') - module.__loader__ = 42 - module.__package__ = 42 - with util.uncache(name): - sys.modules[name] = module - loader = FakeLoader() - returned_module = loader.load_module(name) - self.assertIs(returned_module, sys.modules[name]) - self.assertEqual(module.__loader__, loader) - self.assertEqual(module.__package__, name) - - def test_new_module_failure(self): - # Test that a module is removed from sys.modules if added but an - # exception is raised. - name = 'a.b.c' - with util.uncache(name): - self.raise_exception(name) - self.assertNotIn(name, sys.modules) - - def test_reload_failure(self): - # Test that a failure on reload leaves the module in-place. - name = 'a.b.c' - module = types.ModuleType(name) - with util.uncache(name): - sys.modules[name] = module - self.raise_exception(name) - self.assertIs(module, sys.modules[name]) - - def test_decorator_attrs(self): - def fxn(self, module): pass - wrapped = self.module_for_loader(fxn) - self.assertEqual(wrapped.__name__, fxn.__name__) - self.assertEqual(wrapped.__qualname__, fxn.__qualname__) - - def test_false_module(self): - # If for some odd reason a module is considered false, still return it - # from sys.modules. - class FalseModule(types.ModuleType): - def __bool__(self): return False - - name = 'mod' - module = FalseModule(name) - with util.uncache(name): - self.assertFalse(module) - sys.modules[name] = module - given = self.return_module(name) - self.assertIs(given, module) - - def test_attributes_set(self): - # __name__, __loader__, and __package__ should be set (when - # is_package() is defined; undefined implicitly tested elsewhere). - class FakeLoader: - def __init__(self, is_package): - self._pkg = is_package - def is_package(self, name): - return self._pkg - @self.module_for_loader - def load_module(self, module): - return module - - name = 'pkg.mod' - with util.uncache(name): - loader = FakeLoader(False) - module = loader.load_module(name) - self.assertEqual(module.__name__, name) - self.assertIs(module.__loader__, loader) - self.assertEqual(module.__package__, 'pkg') - - name = 'pkg.sub' - with util.uncache(name): - loader = FakeLoader(True) - module = loader.load_module(name) - self.assertEqual(module.__name__, name) - self.assertIs(module.__loader__, loader) - self.assertEqual(module.__package__, name) - - -(Frozen_ModuleForLoaderTests, - Source_ModuleForLoaderTests - ) = util.test_both(ModuleForLoaderTests, util=importlib_util) - - -class SetLoaderTests: - - """Tests importlib.util.set_loader().""" - - @property - def DummyLoader(self): - # Set DummyLoader on the class lazily. - class DummyLoader: - @self.util.set_loader - def load_module(self, module): - return self.module - self.__class__.DummyLoader = DummyLoader - return DummyLoader - - def test_no_attribute(self): - loader = self.DummyLoader() - loader.module = types.ModuleType('blah') - try: - del loader.module.__loader__ - except AttributeError: - pass - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - self.assertEqual(loader, loader.load_module('blah').__loader__) - - def test_attribute_is_None(self): - loader = self.DummyLoader() - loader.module = types.ModuleType('blah') - loader.module.__loader__ = None - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - self.assertEqual(loader, loader.load_module('blah').__loader__) - - def test_not_reset(self): - loader = self.DummyLoader() - loader.module = types.ModuleType('blah') - loader.module.__loader__ = 42 - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - self.assertEqual(42, loader.load_module('blah').__loader__) - - -(Frozen_SetLoaderTests, - Source_SetLoaderTests - ) = util.test_both(SetLoaderTests, util=importlib_util) - - class ResolveNameTests: """Tests importlib.util.resolve_name().""" diff --git a/Misc/NEWS.d/next/Library/2022-10-05-11-40-02.gh-issue-97850.NzdREm.rst b/Misc/NEWS.d/next/Library/2022-10-05-11-40-02.gh-issue-97850.NzdREm.rst new file mode 100644 index 000000000000..5e759bc0995a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-05-11-40-02.gh-issue-97850.NzdREm.rst @@ -0,0 +1,2 @@ +Remove deprecated :func:`importlib.utils.set_loader` and +:func:`importlib.utils.module_for_loader` from :mod:`importlib.utils`. From webhook-mailer at python.org Thu Oct 6 20:59:15 2022 From: webhook-mailer at python.org (ambv) Date: Fri, 07 Oct 2022 00:59:15 -0000 Subject: [Python-checkins] [3.10] gh-97943: PyFunction_GetAnnotations should return a borrowed reference. (GH-97949) (GH-97989) Message-ID: https://github.com/python/cpython/commit/e0e303abe426d554b9e4713722b0cc20818d5bfb commit: e0e303abe426d554b9e4713722b0cc20818d5bfb branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-06T17:59:09-07:00 summary: [3.10] gh-97943: PyFunction_GetAnnotations should return a borrowed reference. (GH-97949) (GH-97989) gh-97943: PyFunction_GetAnnotations should return a borrowed reference. (GH-97949) (cherry picked from commit 6bfb0be80486c614cd60dce44c9fe7b3e6c76e3b) Co-authored-by: larryhastings files: A Misc/NEWS.d/next/Core and Builtins/2022-10-05-17-02-22.gh-issue-97943.LYAWlE.rst M Objects/funcobject.c diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-05-17-02-22.gh-issue-97943.LYAWlE.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-05-17-02-22.gh-issue-97943.LYAWlE.rst new file mode 100644 index 000000000000..9b4a421a9d47 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-05-17-02-22.gh-issue-97943.LYAWlE.rst @@ -0,0 +1,2 @@ +Bugfix: :func:`PyFunction_GetAnnotations` should return a borrowed +reference. It was returning a new reference. diff --git a/Objects/funcobject.c b/Objects/funcobject.c index 801478ade22f..eaf733392466 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -247,7 +247,6 @@ func_get_annotation_dict(PyFunctionObject *op) } Py_SETREF(op->func_annotations, ann_dict); } - Py_INCREF(op->func_annotations); assert(PyDict_Check(op->func_annotations)); return op->func_annotations; } @@ -474,7 +473,11 @@ func_get_annotations(PyFunctionObject *op, void *Py_UNUSED(ignored)) if (op->func_annotations == NULL) return NULL; } - return func_get_annotation_dict(op); + PyObject *d = func_get_annotation_dict(op); + if (d) { + Py_INCREF(d); + } + return d; } static int From webhook-mailer at python.org Thu Oct 6 21:01:38 2022 From: webhook-mailer at python.org (ambv) Date: Fri, 07 Oct 2022 01:01:38 -0000 Subject: [Python-checkins] Docs: Fix backtick errors found by sphinx-lint (#97998) Message-ID: https://github.com/python/cpython/commit/fa2d43e5184f5eaf3391844ec2400342a1b2ead4 commit: fa2d43e5184f5eaf3391844ec2400342a1b2ead4 branch: main author: Hugo van Kemenade committer: ambv date: 2022-10-06T18:01:30-07:00 summary: Docs: Fix backtick errors found by sphinx-lint (#97998) Co-authored-by: Ezio Melotti files: M Doc/c-api/init.rst M Doc/c-api/type.rst M Doc/faq/design.rst M Doc/howto/enum.rst M Doc/howto/logging-cookbook.rst M Doc/howto/logging.rst M Doc/howto/perf_profiling.rst M Doc/install/index.rst M Doc/library/asyncio-protocol.rst M Doc/library/asyncio-task.rst M Doc/library/bdb.rst M Doc/library/bz2.rst M Doc/library/concurrent.futures.rst M Doc/library/ctypes.rst M Doc/library/curses.rst M Doc/library/datetime.rst M Doc/library/decimal.rst M Doc/library/dis.rst M Doc/library/email.compat32-message.rst M Doc/library/email.headerregistry.rst M Doc/library/fractions.rst M Doc/library/hashlib.rst M Doc/library/io.rst M Doc/library/lzma.rst M Doc/library/os.rst M Doc/library/select.rst M Doc/library/socket.rst M Doc/library/statistics.rst M Doc/library/sys.rst M Doc/library/unittest.mock-examples.rst M Doc/library/xml.dom.minidom.rst M Doc/library/xmlrpc.client.rst M Doc/library/xmlrpc.server.rst M Doc/reference/expressions.rst M Doc/reference/import.rst M Doc/reference/simple_stmts.rst M Doc/requirements.txt M Doc/using/configure.rst M Doc/using/unix.rst M Doc/using/windows.rst M Doc/whatsnew/2.6.rst M Doc/whatsnew/2.7.rst M Doc/whatsnew/3.10.rst M Doc/whatsnew/3.11.rst M Doc/whatsnew/3.12.rst M Doc/whatsnew/3.2.rst M Doc/whatsnew/3.3.rst M Doc/whatsnew/3.5.rst M Doc/whatsnew/3.6.rst M Doc/whatsnew/3.7.rst M Doc/whatsnew/3.9.rst M Misc/NEWS.d/next/Core and Builtins/2022-10-01-08-55-09.gh-issue-97591.pw6kkH.rst M Misc/NEWS.d/next/Documentation/2022-09-01-17-03-04.gh-issue-96432.1EJ1-4.rst M Misc/NEWS.d/next/Library/2022-05-09-21-31-41.gh-issue-92445.tJosdm.rst M Misc/NEWS.d/next/Library/2022-07-06-14-57-33.gh-issue-94619.PRqKVX.rst diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index 513ef93a3842..9b7383373e98 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -1929,7 +1929,7 @@ is not possible due to its implementation being opaque at build time. Free the given *key* allocated by :c:func:`PyThread_tss_alloc`, after first calling :c:func:`PyThread_tss_delete` to ensure any associated thread locals have been unassigned. This is a no-op if the *key* - argument is `NULL`. + argument is ``NULL``. .. note:: A freed key becomes a dangling pointer. You should reset the key to diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst index deb5502a4dff..1dc05001adfa 100644 --- a/Doc/c-api/type.rst +++ b/Doc/c-api/type.rst @@ -40,7 +40,7 @@ Type Objects .. c:function:: unsigned long PyType_GetFlags(PyTypeObject* type) Return the :c:member:`~PyTypeObject.tp_flags` member of *type*. This function is primarily - meant for use with `Py_LIMITED_API`; the individual flag bits are + meant for use with ``Py_LIMITED_API``; the individual flag bits are guaranteed to be stable across Python releases, but access to :c:member:`~PyTypeObject.tp_flags` itself is not part of the limited API. diff --git a/Doc/faq/design.rst b/Doc/faq/design.rst index 52388fca5cdb..ccdc9bf02b1c 100644 --- a/Doc/faq/design.rst +++ b/Doc/faq/design.rst @@ -155,7 +155,7 @@ Why can't I use an assignment in an expression? Starting in Python 3.8, you can! -Assignment expressions using the walrus operator `:=` assign a variable in an +Assignment expressions using the walrus operator ``:=`` assign a variable in an expression:: while chunk := fp.read(200): diff --git a/Doc/howto/enum.rst b/Doc/howto/enum.rst index 376934a0e793..03f05657997c 100644 --- a/Doc/howto/enum.rst +++ b/Doc/howto/enum.rst @@ -1109,7 +1109,7 @@ Enum Classes The :class:`EnumType` metaclass is responsible for providing the :meth:`__contains__`, :meth:`__dir__`, :meth:`__iter__` and other methods that allow one to do things with an :class:`Enum` class that fail on a typical -class, such as `list(Color)` or `some_enum_var in Color`. :class:`EnumType` is +class, such as ``list(Color)`` or ``some_enum_var in Color``. :class:`EnumType` is responsible for ensuring that various other methods on the final :class:`Enum` class are correct (such as :meth:`__new__`, :meth:`__getnewargs__`, :meth:`__str__` and :meth:`__repr__`). diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst index ff7ba0789608..913502eba764 100644 --- a/Doc/howto/logging-cookbook.rst +++ b/Doc/howto/logging-cookbook.rst @@ -562,7 +562,7 @@ To run a logging listener in production, you may need to use a process-managemen such as `Supervisor `_. `Here `_ is a Gist which provides the bare-bones files to run the above functionality using Supervisor: you -will need to change the `/path/to/` parts in the Gist to reflect the actual paths you +will need to change the ``/path/to/`` parts in the Gist to reflect the actual paths you want to use. @@ -2774,7 +2774,7 @@ Formatting times using UTC (GMT) via configuration -------------------------------------------------- Sometimes you want to format times using UTC, which can be done using a class -such as `UTCFormatter`, shown below:: +such as ``UTCFormatter``, shown below:: import logging import time diff --git a/Doc/howto/logging.rst b/Doc/howto/logging.rst index 0caff13bd15d..145449b2dfbd 100644 --- a/Doc/howto/logging.rst +++ b/Doc/howto/logging.rst @@ -555,14 +555,14 @@ raw message. If there is no date format string, the default date format is: %Y-%m-%d %H:%M:%S -with the milliseconds tacked on at the end. The ``style`` is one of `%`, '{' -or '$'. If one of these is not specified, then '%' will be used. +with the milliseconds tacked on at the end. The ``style`` is one of ``'%'``, +``'{'``, or ``'$'``. If one of these is not specified, then ``'%'`` will be used. -If the ``style`` is '%', the message format string uses +If the ``style`` is ``'%'``, the message format string uses ``%()s`` styled string substitution; the possible keys are -documented in :ref:`logrecord-attributes`. If the style is '{', the message +documented in :ref:`logrecord-attributes`. If the style is ``'{'``, the message format string is assumed to be compatible with :meth:`str.format` (using -keyword arguments), while if the style is '$' then the message format string +keyword arguments), while if the style is ``'$'`` then the message format string should conform to what is expected by :meth:`string.Template.substitute`. .. versionchanged:: 3.2 diff --git a/Doc/howto/perf_profiling.rst b/Doc/howto/perf_profiling.rst index ed8de888b3bc..387fb3ff8935 100644 --- a/Doc/howto/perf_profiling.rst +++ b/Doc/howto/perf_profiling.rst @@ -151,7 +151,7 @@ Enabling perf profiling mode ---------------------------- There are two main ways to activate the perf profiling mode. If you want it to be -active since the start of the Python interpreter, you can use the `-Xperf` option: +active since the start of the Python interpreter, you can use the ``-Xperf`` option: $ python -Xperf my_script.py diff --git a/Doc/install/index.rst b/Doc/install/index.rst index 3fc670b19142..ab581d785ef7 100644 --- a/Doc/install/index.rst +++ b/Doc/install/index.rst @@ -765,7 +765,7 @@ And on Windows, the configuration files are: +--------------+-------------------------------------------------+-------+ On all platforms, the "personal" file can be temporarily disabled by -passing the `--no-user-cfg` option. +passing the ``--no-user-cfg`` option. Notes: diff --git a/Doc/library/asyncio-protocol.rst b/Doc/library/asyncio-protocol.rst index 8b67f4b8957e..969354ceb163 100644 --- a/Doc/library/asyncio-protocol.rst +++ b/Doc/library/asyncio-protocol.rst @@ -553,7 +553,7 @@ accept factories that return streaming protocols. a connection is open. However, :meth:`protocol.eof_received() ` - is called at most once. Once `eof_received()` is called, + is called at most once. Once ``eof_received()`` is called, ``data_received()`` is not called anymore. .. method:: Protocol.eof_received() diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index 9c17dc639736..fb6d23fda03e 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -631,7 +631,7 @@ Timeouts Change the time the timeout will trigger. - If *when* is `None`, any current deadline will be removed, and the + If *when* is ``None``, any current deadline will be removed, and the context manager will wait indefinitely. If *when* is a float, it is set as the new deadline. @@ -867,17 +867,17 @@ Running in Threads # blocking_io complete at 19:50:54 # finished main at 19:50:54 - Directly calling `blocking_io()` in any coroutine would block the event loop + Directly calling ``blocking_io()`` in any coroutine would block the event loop for its duration, resulting in an additional 1 second of run time. Instead, - by using `asyncio.to_thread()`, we can run it in a separate thread without + by using ``asyncio.to_thread()``, we can run it in a separate thread without blocking the event loop. .. note:: - Due to the :term:`GIL`, `asyncio.to_thread()` can typically only be used + Due to the :term:`GIL`, ``asyncio.to_thread()`` can typically only be used to make IO-bound functions non-blocking. However, for extension modules that release the GIL or alternative Python implementations that don't - have one, `asyncio.to_thread()` can also be used for CPU-bound functions. + have one, ``asyncio.to_thread()`` can also be used for CPU-bound functions. .. versionadded:: 3.9 diff --git a/Doc/library/bdb.rst b/Doc/library/bdb.rst index 7b74bbd652be..d201dc963b59 100644 --- a/Doc/library/bdb.rst +++ b/Doc/library/bdb.rst @@ -143,7 +143,7 @@ The :mod:`bdb` module also defines two classes: For real file names, the canonical form is an operating-system-dependent, :func:`case-normalized ` :func:`absolute path - `. A *filename* with angle brackets, such as `""` + `. A *filename* with angle brackets, such as ``""`` generated in interactive mode, is returned unchanged. .. method:: reset() diff --git a/Doc/library/bz2.rst b/Doc/library/bz2.rst index 999892e95f47..ae5a1598f84b 100644 --- a/Doc/library/bz2.rst +++ b/Doc/library/bz2.rst @@ -206,7 +206,7 @@ Incremental (de)compression will be set to ``True``. Attempting to decompress data after the end of stream is reached - raises an `EOFError`. Any data found after the end of the + raises an :exc:`EOFError`. Any data found after the end of the stream is ignored and saved in the :attr:`~.unused_data` attribute. .. versionchanged:: 3.5 @@ -303,7 +303,7 @@ Using :class:`BZ2Compressor` for incremental compression: >>> out = out + comp.flush() The example above uses a very "nonrandom" stream of data -(a stream of `b"z"` chunks). Random data tends to compress poorly, +(a stream of ``b"z"`` chunks). Random data tends to compress poorly, while ordered, repetitive data usually yields a high compression ratio. Writing and reading a bzip2-compressed file in binary mode: diff --git a/Doc/library/concurrent.futures.rst b/Doc/library/concurrent.futures.rst index 95c9e5099142..8106cc235e5a 100644 --- a/Doc/library/concurrent.futures.rst +++ b/Doc/library/concurrent.futures.rst @@ -152,7 +152,7 @@ And:: All threads enqueued to ``ThreadPoolExecutor`` will be joined before the interpreter can exit. Note that the exit handler which does this is - executed *before* any exit handlers added using `atexit`. This means + executed *before* any exit handlers added using ``atexit``. This means exceptions in the main thread must be caught and handled in order to signal threads to exit gracefully. For this reason, it is recommended that ``ThreadPoolExecutor`` not be used for long-running tasks. @@ -411,13 +411,13 @@ The :class:`Future` class encapsulates the asynchronous execution of a callable. tests. If the method returns ``False`` then the :class:`Future` was cancelled, - i.e. :meth:`Future.cancel` was called and returned `True`. Any threads + i.e. :meth:`Future.cancel` was called and returned ``True``. Any threads waiting on the :class:`Future` completing (i.e. through :func:`as_completed` or :func:`wait`) will be woken up. If the method returns ``True`` then the :class:`Future` was not cancelled and has been put in the running state, i.e. calls to - :meth:`Future.running` will return `True`. + :meth:`Future.running` will return ``True``. This method can only be called once and cannot be called after :meth:`Future.set_result` or :meth:`Future.set_exception` have been diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index 4b6b26c991fd..0351ec970be0 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -1948,7 +1948,7 @@ Utility functions .. function:: GetLastError() Windows only: Returns the last error code set by Windows in the calling thread. - This function calls the Windows `GetLastError()` function directly, + This function calls the Windows ``GetLastError()`` function directly, it does not return the ctypes-private copy of the error code. .. function:: get_errno() diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst index bb203c48f19f..bf4e69a0170a 100644 --- a/Doc/library/curses.rst +++ b/Doc/library/curses.rst @@ -275,7 +275,7 @@ The module :mod:`curses` defines the following functions: Change the definition of a color, taking the number of the color to be changed followed by three RGB values (for the amounts of red, green, and blue components). The value of *color_number* must be between ``0`` and - `COLORS - 1`. Each of *r*, *g*, *b*, must be a value between ``0`` and + ``COLORS - 1``. Each of *r*, *g*, *b*, must be a value between ``0`` and ``1000``. When :func:`init_color` is used, all occurrences of that color on the screen immediately change to the new definition. This function is a no-op on most terminals; it is active only if :func:`can_change_color` returns ``True``. diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst index c3a66a4674b1..f7e2bb3f3c6d 100644 --- a/Doc/library/datetime.rst +++ b/Doc/library/datetime.rst @@ -1769,7 +1769,7 @@ Other constructor: ISO 8601 format, with the following exceptions: 1. Time zone offsets may have fractional seconds. - 2. The leading `T`, normally required in cases where there may be ambiguity between + 2. The leading ``T``, normally required in cases where there may be ambiguity between a date and a time, is not required. 3. Fractional seconds may have any number of digits (anything beyond 6 will be truncated). @@ -2265,7 +2265,7 @@ where historical changes have been made to civil time. two digits of ``offset.hours`` and ``offset.minutes`` respectively. .. versionchanged:: 3.6 - Name generated from ``offset=timedelta(0)`` is now plain `'UTC'`, not + Name generated from ``offset=timedelta(0)`` is now plain ``'UTC'``, not ``'UTC+00:00'``. diff --git a/Doc/library/decimal.rst b/Doc/library/decimal.rst index b7e836308fa8..260108136df7 100644 --- a/Doc/library/decimal.rst +++ b/Doc/library/decimal.rst @@ -576,11 +576,11 @@ Decimal objects Alternative constructor that only accepts instances of :class:`float` or :class:`int`. - Note `Decimal.from_float(0.1)` is not the same as `Decimal('0.1')`. + Note ``Decimal.from_float(0.1)`` is not the same as ``Decimal('0.1')``. Since 0.1 is not exactly representable in binary floating point, the value is stored as the nearest representable value which is - `0x1.999999999999ap-4`. That equivalent value in decimal is - `0.1000000000000000055511151231257827021181583404541015625`. + ``0x1.999999999999ap-4``. That equivalent value in decimal is + ``0.1000000000000000055511151231257827021181583404541015625``. .. note:: From Python 3.2 onwards, a :class:`Decimal` instance can also be constructed directly from a :class:`float`. @@ -1209,7 +1209,7 @@ In addition to the three supplied contexts, new contexts can be created with the .. method:: exp(x) - Returns `e ** x`. + Returns ``e ** x``. .. method:: fma(x, y, z) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 47e4bf600721..30a336197c39 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -367,7 +367,7 @@ details of bytecode instructions as :class:`Instruction` instances: .. class:: Positions - In case the information is not available, some fields might be `None`. + In case the information is not available, some fields might be ``None``. .. data:: lineno .. data:: end_lineno diff --git a/Doc/library/email.compat32-message.rst b/Doc/library/email.compat32-message.rst index 4eaa9d588ca3..5bef155a4af3 100644 --- a/Doc/library/email.compat32-message.rst +++ b/Doc/library/email.compat32-message.rst @@ -298,7 +298,7 @@ Here are the methods of the :class:`Message` class: In a model generated from bytes, any header values that (in contravention of the RFCs) contain non-ASCII bytes will, when retrieved through this interface, be represented as :class:`~email.header.Header` objects with - a charset of `unknown-8bit`. + a charset of ``unknown-8bit``. .. method:: __len__() diff --git a/Doc/library/email.headerregistry.rst b/Doc/library/email.headerregistry.rst index 98527cea43da..00a954e0307e 100644 --- a/Doc/library/email.headerregistry.rst +++ b/Doc/library/email.headerregistry.rst @@ -153,7 +153,7 @@ headers. specified as ``-0000`` (indicating it is in UTC but contains no information about the source timezone), then :attr:`.datetime` will be a naive :class:`~datetime.datetime`. If a specific timezone offset is - found (including `+0000`), then :attr:`.datetime` will contain an aware + found (including ``+0000``), then :attr:`.datetime` will contain an aware ``datetime`` that uses :class:`datetime.timezone` to record the timezone offset. diff --git a/Doc/library/fractions.rst b/Doc/library/fractions.rst index 3751800b3b11..c46d88b2297a 100644 --- a/Doc/library/fractions.rst +++ b/Doc/library/fractions.rst @@ -99,7 +99,7 @@ another rational number, or from a string. ``typing.SupportsInt`` instance checks. .. versionchanged:: 3.12 - Space is allowed around the slash for string inputs: `Fraction('2 / 3')`. + Space is allowed around the slash for string inputs: ``Fraction('2 / 3')``. .. attribute:: numerator diff --git a/Doc/library/hashlib.rst b/Doc/library/hashlib.rst index 386541acf510..8e47312fe77b 100644 --- a/Doc/library/hashlib.rst +++ b/Doc/library/hashlib.rst @@ -426,7 +426,7 @@ Constructor functions also accept the following tree hashing parameters: BLAKE2s, 0 in sequential mode). * *last_node*: boolean indicating whether the processed node is the last - one (`False` for sequential mode). + one (``False`` for sequential mode). .. figure:: hashlib-blake2-tree.png :alt: Explanation of tree mode parameters. diff --git a/Doc/library/io.rst b/Doc/library/io.rst index 8fd6b3537019..0968509fbafe 100644 --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -1055,10 +1055,10 @@ Text I/O The initial value of the buffer can be set by providing *initial_value*. If newline translation is enabled, newlines will be encoded as if by :meth:`~TextIOBase.write`. The stream is positioned at the start of the - buffer which emulates opening an existing file in a `w+` mode, making it + buffer which emulates opening an existing file in a ``w+`` mode, making it ready for an immediate write from the beginning or for a write that - would overwrite the initial value. To emulate opening a file in an `a+` - mode ready for appending, use `f.seek(0, io.SEEK_END)` to reposition the + would overwrite the initial value. To emulate opening a file in an ``a+`` + mode ready for appending, use ``f.seek(0, io.SEEK_END)`` to reposition the stream at the end of the buffer. The *newline* argument works like that of :class:`TextIOWrapper`, diff --git a/Doc/library/lzma.rst b/Doc/library/lzma.rst index f7aaa0cb30c2..a9311f2a0356 100644 --- a/Doc/library/lzma.rst +++ b/Doc/library/lzma.rst @@ -258,7 +258,7 @@ Compressing and decompressing data in memory will be set to ``True``. Attempting to decompress data after the end of stream is reached - raises an `EOFError`. Any data found after the end of the + raises an :exc:`EOFError`. Any data found after the end of the stream is ignored and saved in the :attr:`~.unused_data` attribute. .. versionchanged:: 3.5 diff --git a/Doc/library/os.rst b/Doc/library/os.rst index cb06dc690b4d..23b014b0b659 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -3194,7 +3194,7 @@ features: system records access and modification times; see :func:`~os.stat`. The best way to preserve exact times is to use the *st_atime_ns* and *st_mtime_ns* fields from the :func:`os.stat` result object with the *ns* parameter to - `utime`. + :func:`utime`. This function can support :ref:`specifying a file descriptor `, :ref:`paths relative to directory descriptors ` and :ref:`not @@ -4094,7 +4094,7 @@ written in Python, such as a mail server's external command delivery program. library :c:data:`POSIX_SPAWN_RESETIDS` flag. If the *setsid* argument is ``True``, it will create a new session ID - for `posix_spawn`. *setsid* requires :c:data:`POSIX_SPAWN_SETSID` + for ``posix_spawn``. *setsid* requires :c:data:`POSIX_SPAWN_SETSID` or :c:data:`POSIX_SPAWN_SETSID_NP` flag. Otherwise, :exc:`NotImplementedError` is raised. diff --git a/Doc/library/select.rst b/Doc/library/select.rst index a8df81f5bd1f..2890706bab72 100644 --- a/Doc/library/select.rst +++ b/Doc/library/select.rst @@ -61,7 +61,7 @@ The module defines the following: events. *sizehint* informs epoll about the expected number of events to be - registered. It must be positive, or `-1` to use the default. It is only + registered. It must be positive, or ``-1`` to use the default. It is only used on older systems where :c:func:`epoll_create1` is not available; otherwise it has no effect (though its value is still checked). diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst index ee0c68e3a707..3f6cb4803716 100644 --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -689,7 +689,7 @@ The following functions all create :ref:`socket objects `. When :const:`SOCK_NONBLOCK` or :const:`SOCK_CLOEXEC` bit flags are applied to *type* they are cleared, and :attr:`socket.type` will not reflect them. They are still passed - to the underlying system `socket()` call. Therefore, + to the underlying system ``socket()`` call. Therefore, :: diff --git a/Doc/library/statistics.rst b/Doc/library/statistics.rst index c3f9c1f5239e..88a887960edb 100644 --- a/Doc/library/statistics.rst +++ b/Doc/library/statistics.rst @@ -839,7 +839,7 @@ of applications in statistics. The relative likelihood is computed as the probability of a sample occurring in a narrow range divided by the width of the range (hence the word "density"). Since the likelihood is relative to other points, - its value can be greater than `1.0`. + its value can be greater than ``1.0``. .. method:: NormalDist.cdf(x) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index aab3f6aa83fc..542b08b1878e 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -250,7 +250,7 @@ always available. Print low-level information to stderr about the state of CPython's memory allocator. - If Python is `built in debug mode ` (:option:`configure + If Python is :ref:`built in debug mode ` (:option:`configure --with-pydebug option <--with-pydebug>`), it also performs some expensive internal consistency checks. @@ -349,7 +349,7 @@ always available. files to (and read them from) a parallel directory tree rooted at this directory, rather than from ``__pycache__`` directories in the source code tree. Any ``__pycache__`` directories in the source code tree will be ignored - and new `.pyc` files written within the pycache prefix. Thus if you use + and new ``.pyc`` files written within the pycache prefix. Thus if you use :mod:`compileall` as a pre-build step, you must ensure you run it with the same pycache prefix (if any) that you will use at runtime. @@ -874,7 +874,7 @@ always available. .. function:: get_asyncgen_hooks() Returns an *asyncgen_hooks* object, which is similar to a - :class:`~collections.namedtuple` of the form `(firstiter, finalizer)`, + :class:`~collections.namedtuple` of the form ``(firstiter, finalizer)``, where *firstiter* and *finalizer* are expected to be either ``None`` or functions which take an :term:`asynchronous generator iterator` as an argument, and are used to schedule finalization of an asynchronous diff --git a/Doc/library/unittest.mock-examples.rst b/Doc/library/unittest.mock-examples.rst index 054efa812663..f9a207bad690 100644 --- a/Doc/library/unittest.mock-examples.rst +++ b/Doc/library/unittest.mock-examples.rst @@ -1116,7 +1116,7 @@ on first use). That aside there is a way to use ``mock`` to affect the results of an import. Importing fetches an *object* from the :data:`sys.modules` dictionary. Note that it fetches an *object*, which need not be a module. Importing a module for the -first time results in a module object being put in `sys.modules`, so usually +first time results in a module object being put in ``sys.modules``, so usually when you import something you get a module back. This need not be the case however. diff --git a/Doc/library/xml.dom.minidom.rst b/Doc/library/xml.dom.minidom.rst index 82e5d6aea231..72a7a98c2ac4 100644 --- a/Doc/library/xml.dom.minidom.rst +++ b/Doc/library/xml.dom.minidom.rst @@ -148,8 +148,8 @@ module documentation. This section lists the differences between the API and Similarly, explicitly stating the *standalone* argument causes the standalone document declarations to be added to the prologue of the XML document. - If the value is set to `True`, `standalone="yes"` is added, - otherwise it is set to `"no"`. + If the value is set to ``True``, ``standalone="yes"`` is added, + otherwise it is set to ``"no"``. Not stating the argument will omit the declaration from the document. .. versionchanged:: 3.8 diff --git a/Doc/library/xmlrpc.client.rst b/Doc/library/xmlrpc.client.rst index 8b09acd4bd30..bd2c49a6edab 100644 --- a/Doc/library/xmlrpc.client.rst +++ b/Doc/library/xmlrpc.client.rst @@ -60,7 +60,7 @@ between conformable Python objects and XML on the wire. may be passed to calls. The *headers* parameter is an optional sequence of HTTP headers to send with each request, expressed as a sequence of 2-tuples representing the header - name and value. (e.g. `[('Header-Name', 'value')]`). + name and value. (e.g. ``[('Header-Name', 'value')]``). The obsolete *use_datetime* flag is similar to *use_builtin_types* but it applies only to date/time values. diff --git a/Doc/library/xmlrpc.server.rst b/Doc/library/xmlrpc.server.rst index 9778a859da1f..016369d2b89d 100644 --- a/Doc/library/xmlrpc.server.rst +++ b/Doc/library/xmlrpc.server.rst @@ -263,7 +263,7 @@ This ExampleService demo can be invoked from the command line:: The client that interacts with the above server is included in -`Lib/xmlrpc/client.py`:: +``Lib/xmlrpc/client.py``:: server = ServerProxy("http://localhost:8000") diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst index a661e03b1734..11f49a8c33dc 100644 --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -1562,7 +1562,7 @@ built-in types. true). * Mappings (instances of :class:`dict`) compare equal if and only if they have - equal `(key, value)` pairs. Equality comparison of the keys and values + equal ``(key, value)`` pairs. Equality comparison of the keys and values enforces reflexivity. Order comparisons (``<``, ``>``, ``<=``, and ``>=``) raise :exc:`TypeError`. diff --git a/Doc/reference/import.rst b/Doc/reference/import.rst index b7a53cd0886f..3fa875f52e01 100644 --- a/Doc/reference/import.rst +++ b/Doc/reference/import.rst @@ -822,7 +822,7 @@ The path based finder iterates over every entry in the search path, and for each of these, looks for an appropriate :term:`path entry finder` (:class:`~importlib.abc.PathEntryFinder`) for the path entry. Because this can be an expensive operation (e.g. there may be -`stat()` call overheads for this search), the path based finder maintains +``stat()`` call overheads for this search), the path based finder maintains a cache mapping path entries to path entry finders. This cache is maintained in :data:`sys.path_importer_cache` (despite the name, this cache actually stores finder objects rather than being limited to :term:`importer` objects). diff --git a/Doc/reference/simple_stmts.rst b/Doc/reference/simple_stmts.rst index 8311de0457f6..5c9937fb5b6d 100644 --- a/Doc/reference/simple_stmts.rst +++ b/Doc/reference/simple_stmts.rst @@ -994,20 +994,12 @@ The :keyword:`!nonlocal` statement .. productionlist:: python-grammar nonlocal_stmt: "nonlocal" `identifier` ("," `identifier`)* -.. XXX add when implemented - : ["=" (`target_list` "=")+ starred_expression] - : | "nonlocal" identifier augop expression_list - The :keyword:`nonlocal` statement causes the listed identifiers to refer to previously bound variables in the nearest enclosing scope excluding globals. This is important because the default behavior for binding is to search the local namespace first. The statement allows encapsulated code to rebind variables outside of the local scope besides the global (module) scope. -.. XXX not implemented - The :keyword:`nonlocal` statement may prepend an assignment or augmented - assignment, but not an expression. - Names listed in a :keyword:`nonlocal` statement, unlike those listed in a :keyword:`global` statement, must refer to pre-existing bindings in an enclosing scope (the scope in which a new binding should be created cannot diff --git a/Doc/requirements.txt b/Doc/requirements.txt index 960ac54d7b91..7f82dc32113a 100644 --- a/Doc/requirements.txt +++ b/Doc/requirements.txt @@ -10,7 +10,7 @@ blurb # sphinx-lint 0.6.2 yields many default role errors due to the new regular # expression used for default role detection, so we don't use the version # until the errors are fixed. -sphinx-lint==0.6.1 +sphinx-lint==0.6.4 # The theme used by the documentation is stored separately, so we need # to install that as well. diff --git a/Doc/using/configure.rst b/Doc/using/configure.rst index ec57c880ee7a..b99d9bdaa3f0 100644 --- a/Doc/using/configure.rst +++ b/Doc/using/configure.rst @@ -755,12 +755,12 @@ Compiler flags In particular, :envvar:`CFLAGS` should not contain: - * the compiler flag `-I` (for setting the search path for include files). - The `-I` flags are processed from left to right, and any flags in - :envvar:`CFLAGS` would take precedence over user- and package-supplied `-I` + * the compiler flag ``-I`` (for setting the search path for include files). + The ``-I`` flags are processed from left to right, and any flags in + :envvar:`CFLAGS` would take precedence over user- and package-supplied ``-I`` flags. - * hardening flags such as `-Werror` because distributions cannot control + * hardening flags such as ``-Werror`` because distributions cannot control whether packages installed by users conform to such heightened standards. @@ -878,9 +878,9 @@ Linker flags In particular, :envvar:`LDFLAGS` should not contain: - * the compiler flag `-L` (for setting the search path for libraries). - The `-L` flags are processed from left to right, and any flags in - :envvar:`LDFLAGS` would take precedence over user- and package-supplied `-L` + * the compiler flag ``-L`` (for setting the search path for libraries). + The ``-L`` flags are processed from left to right, and any flags in + :envvar:`LDFLAGS` would take precedence over user- and package-supplied ``-L`` flags. .. envvar:: CONFIGURE_LDFLAGS_NODIST diff --git a/Doc/using/unix.rst b/Doc/using/unix.rst index 061cfa5be88f..24c02c99f871 100644 --- a/Doc/using/unix.rst +++ b/Doc/using/unix.rst @@ -170,7 +170,7 @@ Custom OpenSSL $ popd 3. Build Python with custom OpenSSL - (see the configure `--with-openssl` and `--with-openssl-rpath` options) + (see the configure ``--with-openssl`` and ``--with-openssl-rpath`` options) .. code-block:: shell-session diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst index 9c339521c311..b5c2c8ca7120 100644 --- a/Doc/using/windows.rst +++ b/Doc/using/windows.rst @@ -216,7 +216,7 @@ of available options is shown below. +---------------------------+--------------------------------------+--------------------------+ | Include_pip | Install bundled pip and setuptools | 1 | +---------------------------+--------------------------------------+--------------------------+ -| Include_symbols | Install debugging symbols (`*`.pdb) | 0 | +| Include_symbols | Install debugging symbols (``*.pdb``)| 0 | +---------------------------+--------------------------------------+--------------------------+ | Include_tcltk | Install Tcl/Tk support and IDLE | 1 | +---------------------------+--------------------------------------+--------------------------+ diff --git a/Doc/whatsnew/2.6.rst b/Doc/whatsnew/2.6.rst index 731ce6aac691..34f2656f765c 100644 --- a/Doc/whatsnew/2.6.rst +++ b/Doc/whatsnew/2.6.rst @@ -717,13 +717,13 @@ This will produce the output:: PEP 3101: Advanced String Formatting ===================================================== -In Python 3.0, the `%` operator is supplemented by a more powerful string +In Python 3.0, the ``%`` operator is supplemented by a more powerful string formatting method, :meth:`format`. Support for the :meth:`str.format` method has been backported to Python 2.6. -In 2.6, both 8-bit and Unicode strings have a `.format()` method that +In 2.6, both 8-bit and Unicode strings have a ``.format()`` method that treats the string as a template and takes the arguments to be formatted. -The formatting template uses curly brackets (`{`, `}`) as special characters:: +The formatting template uses curly brackets (``{``, ``}``) as special characters:: >>> # Substitute positional argument 0 into the string. >>> "User ID: {0}".format("root") diff --git a/Doc/whatsnew/2.7.rst b/Doc/whatsnew/2.7.rst index e8f701d254cd..276ab63b97f8 100644 --- a/Doc/whatsnew/2.7.rst +++ b/Doc/whatsnew/2.7.rst @@ -2485,8 +2485,8 @@ In the standard library: * The ElementTree library, :mod:`xml.etree`, no longer escapes ampersands and angle brackets when outputting an XML processing - instruction (which looks like ``) - or comment (which looks like ``). + instruction (which looks like ````) + or comment (which looks like ````). (Patch by Neil Muller; :issue:`2746`.) * The :meth:`~StringIO.StringIO.readline` method of :class:`~StringIO.StringIO` objects now does diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index 428a19453db5..8beb8b19463f 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -1184,7 +1184,7 @@ and will be incorrect in some rare cases, including some ``_``-s in New in 3.10 maintenance releases. -Apply syntax highlighting to `.pyi` files. (Contributed by Alex +Apply syntax highlighting to ``.pyi`` files. (Contributed by Alex Waygood and Terry Jan Reedy in :issue:`45447`.) Include prompts when saving Shell with inputs and outputs. diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 6103da76a34d..56a35f4e4802 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -723,7 +723,7 @@ hashlib IDLE and idlelib ---------------- -* Apply syntax highlighting to `.pyi` files. (Contributed by Alex +* Apply syntax highlighting to ``.pyi`` files. (Contributed by Alex Waygood and Terry Jan Reedy in :issue:`45447`.) * Include prompts when saving Shell with inputs and outputs. diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index d18c31fbe986..405de11e716b 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -588,7 +588,7 @@ Porting to Python 3.12 ``tp_weaklistoffset``, respectively. The use of ``tp_dictoffset`` and ``tp_weaklistoffset`` is still supported, but does not fully support multiple inheritance - (:gh: `95589`), and performance may be worse. + (:gh:`95589`), and performance may be worse. Classes declaring :const:`Py_TPFLAGS_MANAGED_DICT` should call :c:func:`_PyObject_VisitManagedDict` and :c:func:`_PyObject_ClearManagedDict` to traverse and clear their instance's dictionaries. diff --git a/Doc/whatsnew/3.2.rst b/Doc/whatsnew/3.2.rst index 65100b0be36a..6037db9f954d 100644 --- a/Doc/whatsnew/3.2.rst +++ b/Doc/whatsnew/3.2.rst @@ -1746,7 +1746,7 @@ names. instead of module names for running specific tests (:issue:`10620`). The new test discovery can find tests within packages, locating any test importable from the top-level directory. The top-level directory can be specified with - the `-t` option, a pattern for matching files with ``-p``, and a directory to + the ``-t`` option, a pattern for matching files with ``-p``, and a directory to start discovery with ``-s``: .. code-block:: shell-session @@ -1857,7 +1857,7 @@ asyncore :class:`asyncore.dispatcher` now provides a :meth:`~asyncore.dispatcher.handle_accepted()` method -returning a `(sock, addr)` pair which is called when a connection has actually +returning a ``(sock, addr)`` pair which is called when a connection has actually been established with a new remote endpoint. This is supposed to be used as a replacement for old :meth:`~asyncore.dispatcher.handle_accept()` and avoids the user to call :meth:`~asyncore.dispatcher.accept()` directly. diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst index fef1a8ac4c01..96a632577b2c 100644 --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -2389,10 +2389,10 @@ Porting Python code :attr:`sys.path_importer_cache` where it represents the use of implicit finders, but semantically it should not change anything. -* :class:`importlib.abc.Finder` no longer specifies a `find_module()` abstract +* :class:`importlib.abc.Finder` no longer specifies a ``find_module()`` abstract method that must be implemented. If you were relying on subclasses to implement that method, make sure to check for the method's existence first. - You will probably want to check for `find_loader()` first, though, in the + You will probably want to check for ``find_loader()`` first, though, in the case of working with :term:`path entry finders `. * :mod:`pkgutil` has been converted to use :mod:`importlib` internally. This diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst index 2c83c7ba3ad3..f872579ef546 100644 --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -2469,11 +2469,11 @@ Changes in the Python API ``opt-`` tag in ``.pyc`` file names. The :func:`importlib.util.cache_from_source` has gained an *optimization* parameter to help control the ``opt-`` tag. Because of this, the - *debug_override* parameter of the function is now deprecated. `.pyo` files + *debug_override* parameter of the function is now deprecated. ``.pyo`` files are also no longer supported as a file argument to the Python interpreter and thus serve no purpose when distributed on their own (i.e. sourceless code distribution). Due to the fact that the magic number for bytecode has changed - in Python 3.5, all old `.pyo` files from previous versions of Python are + in Python 3.5, all old ``.pyo`` files from previous versions of Python are invalid regardless of this PEP. * The :mod:`socket` module now exports the :data:`~socket.CAN_RAW_FD_FRAMES` diff --git a/Doc/whatsnew/3.6.rst b/Doc/whatsnew/3.6.rst index dfb56770ae70..9308d1a76fec 100644 --- a/Doc/whatsnew/3.6.rst +++ b/Doc/whatsnew/3.6.rst @@ -960,8 +960,8 @@ contextlib The :class:`contextlib.AbstractContextManager` class has been added to provide an abstract base class for context managers. It provides a -sensible default implementation for `__enter__()` which returns -``self`` and leaves `__exit__()` an abstract method. A matching +sensible default implementation for ``__enter__()`` which returns +``self`` and leaves ``__exit__()`` an abstract method. A matching class has been added to the :mod:`typing` module as :class:`typing.ContextManager`. (Contributed by Brett Cannon in :issue:`25609`.) @@ -1388,7 +1388,7 @@ are treated as punctuation. site ---- -When specifying paths to add to :attr:`sys.path` in a `.pth` file, +When specifying paths to add to :attr:`sys.path` in a ``.pth`` file, you may now specify file paths on top of directories (e.g. zip files). (Contributed by Wolfgang Langner in :issue:`26587`). diff --git a/Doc/whatsnew/3.7.rst b/Doc/whatsnew/3.7.rst index f06cf29c713f..df3b636cb9ec 100644 --- a/Doc/whatsnew/3.7.rst +++ b/Doc/whatsnew/3.7.rst @@ -2497,7 +2497,7 @@ number of other issues). Some known details affected: * :c:func:`PySys_AddWarnOptionUnicode` is not currently usable by embedding applications due to the requirement to create a Unicode object prior to - calling `Py_Initialize`. Use :c:func:`PySys_AddWarnOption` instead. + calling ``Py_Initialize``. Use :c:func:`PySys_AddWarnOption` instead. * warnings filters added by an embedding application with :c:func:`PySys_AddWarnOption` should now more consistently take precedence diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index ff01a6577299..624e71f9254c 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -500,7 +500,7 @@ Reedy in :issue:`40468`.) Move the indent space setting from the Font tab to the new Windows tab. (Contributed by Mark Roseman and Terry Jan Reedy in :issue:`33962`.) -Apply syntax highlighting to `.pyi` files. (Contributed by Alex +Apply syntax highlighting to ``.pyi`` files. (Contributed by Alex Waygood and Terry Jan Reedy in :issue:`45447`.) imaplib diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-01-08-55-09.gh-issue-97591.pw6kkH.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-01-08-55-09.gh-issue-97591.pw6kkH.rst index d3a5867db7fc..6f07529f15bb 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2022-10-01-08-55-09.gh-issue-97591.pw6kkH.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-01-08-55-09.gh-issue-97591.pw6kkH.rst @@ -1,2 +1,2 @@ -Fixed a missing incref/decref pair in `Exception.__setstate__()`. +Fixed a missing incref/decref pair in ``Exception.__setstate__()``. Patch by Ofey Chan. diff --git a/Misc/NEWS.d/next/Documentation/2022-09-01-17-03-04.gh-issue-96432.1EJ1-4.rst b/Misc/NEWS.d/next/Documentation/2022-09-01-17-03-04.gh-issue-96432.1EJ1-4.rst index a5858f432932..c4d296e626b1 100644 --- a/Misc/NEWS.d/next/Documentation/2022-09-01-17-03-04.gh-issue-96432.1EJ1-4.rst +++ b/Misc/NEWS.d/next/Documentation/2022-09-01-17-03-04.gh-issue-96432.1EJ1-4.rst @@ -1,2 +1,2 @@ Fraction literals now support whitespace around the forward slash, -`Fraction('2 / 3')`. +``Fraction('2 / 3')``. diff --git a/Misc/NEWS.d/next/Library/2022-05-09-21-31-41.gh-issue-92445.tJosdm.rst b/Misc/NEWS.d/next/Library/2022-05-09-21-31-41.gh-issue-92445.tJosdm.rst index ba69a011601f..16bad6d34b1c 100644 --- a/Misc/NEWS.d/next/Library/2022-05-09-21-31-41.gh-issue-92445.tJosdm.rst +++ b/Misc/NEWS.d/next/Library/2022-05-09-21-31-41.gh-issue-92445.tJosdm.rst @@ -1,3 +1,3 @@ -Fix a bug in :mod:`argparse` where `nargs="*"` would raise an error instead of returning +Fix a bug in :mod:`argparse` where ``nargs="*"`` would raise an error instead of returning an empty list when 0 arguments were supplied if choice was also defined in ``parser.add_argument``. diff --git a/Misc/NEWS.d/next/Library/2022-07-06-14-57-33.gh-issue-94619.PRqKVX.rst b/Misc/NEWS.d/next/Library/2022-07-06-14-57-33.gh-issue-94619.PRqKVX.rst index a79050344246..987ea6b045af 100644 --- a/Misc/NEWS.d/next/Library/2022-07-06-14-57-33.gh-issue-94619.PRqKVX.rst +++ b/Misc/NEWS.d/next/Library/2022-07-06-14-57-33.gh-issue-94619.PRqKVX.rst @@ -1 +1 @@ -Remove the long-deprecated `module_repr()` from `importlib`. +Remove the long-deprecated ``module_repr()`` from :mod:`importlib`. From webhook-mailer at python.org Thu Oct 6 21:28:00 2022 From: webhook-mailer at python.org (gpshead) Date: Fri, 07 Oct 2022 01:28:00 -0000 Subject: [Python-checkins] gh-82874: Convert remaining importlib format uses to f-str. (#98005) Message-ID: https://github.com/python/cpython/commit/27369ef56ffed8ab68abc201a52b259a065ed8d7 commit: 27369ef56ffed8ab68abc201a52b259a065ed8d7 branch: main author: Gregory P. Smith committer: gpshead date: 2022-10-06T18:27:51-07:00 summary: gh-82874: Convert remaining importlib format uses to f-str. (#98005) f-yes files: M Lib/importlib/__init__.py M Lib/importlib/_bootstrap_external.py M Lib/importlib/resources/_adapters.py M Lib/importlib/util.py M Misc/NEWS.d/next/Library/2019-11-04-22-21-27.bpo-38693.w_OAov.rst diff --git a/Lib/importlib/__init__.py b/Lib/importlib/__init__.py index ce61883288aa..21d9dee652b3 100644 --- a/Lib/importlib/__init__.py +++ b/Lib/importlib/__init__.py @@ -84,13 +84,13 @@ def find_loader(name, path=None): try: loader = sys.modules[name].__loader__ if loader is None: - raise ValueError('{}.__loader__ is None'.format(name)) + raise ValueError(f'{name}.__loader__ is None') else: return loader except KeyError: pass except AttributeError: - raise ValueError('{}.__loader__ is not set'.format(name)) from None + raise ValueError(f'{name}.__loader__ is not set') from None spec = _bootstrap._find_spec(name, path) # We won't worry about malformed specs (missing attributes). @@ -98,8 +98,7 @@ def find_loader(name, path=None): return None if spec.loader is None: if spec.submodule_search_locations is None: - raise ImportError('spec for {} missing loader'.format(name), - name=name) + raise ImportError(f'spec for {name} missing loader', name=name) raise ImportError('namespace packages do not have loaders', name=name) return spec.loader @@ -116,9 +115,8 @@ def import_module(name, package=None): level = 0 if name.startswith('.'): if not package: - msg = ("the 'package' argument is required to perform a relative " - "import for {!r}") - raise TypeError(msg.format(name)) + raise TypeError("the 'package' argument is required to perform a " + f"relative import for {name!r}") for character in name: if character != '.': break @@ -144,8 +142,7 @@ def reload(module): raise TypeError("reload() argument must be a module") if sys.modules.get(name) is not module: - msg = "module {} not in sys.modules" - raise ImportError(msg.format(name), name=name) + raise ImportError(f"module {name} not in sys.modules", name=name) if name in _RELOADING: return _RELOADING[name] _RELOADING[name] = module @@ -155,8 +152,7 @@ def reload(module): try: parent = sys.modules[parent_name] except KeyError: - msg = "parent {!r} not in sys.modules" - raise ImportError(msg.format(parent_name), + raise ImportError(f"parent {parent_name!r} not in sys.modules", name=parent_name) from None else: pkgpath = parent.__path__ diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index efda49382540..39d63ae9d6e9 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -197,7 +197,7 @@ def _write_atomic(path, data, mode=0o666): Be prepared to handle a FileExistsError if concurrent writing of the temporary file is attempted.""" # id() is used to generate a pseudo-random filename. - path_tmp = '{}.{}'.format(path, id(path)) + path_tmp = f'{path}.{id(path)}' fd = _os.open(path_tmp, _os.O_EXCL | _os.O_CREAT | _os.O_WRONLY, mode & 0o666) try: @@ -492,8 +492,8 @@ def cache_from_source(path, debug_override=None, *, optimization=None): optimization = str(optimization) if optimization != '': if not optimization.isalnum(): - raise ValueError('{!r} is not alphanumeric'.format(optimization)) - almost_filename = '{}.{}{}'.format(almost_filename, _OPT, optimization) + raise ValueError(f'{optimization!r} is not alphanumeric') + almost_filename = f'{almost_filename}.{_OPT}{optimization}' filename = almost_filename + BYTECODE_SUFFIXES[0] if sys.pycache_prefix is not None: # We need an absolute path to the py file to avoid the possibility of @@ -651,8 +651,8 @@ def _find_module_shim(self, fullname): # return None. loader, portions = self.find_loader(fullname) if loader is None and len(portions): - msg = 'Not importing directory {}: missing __init__' - _warnings.warn(msg.format(portions[0]), ImportWarning) + msg = f'Not importing directory {portions[0]}: missing __init__' + _warnings.warn(msg, ImportWarning) return loader @@ -750,7 +750,7 @@ def _compile_bytecode(data, name=None, bytecode_path=None, source_path=None): _imp._fix_co_filename(code, source_path) return code else: - raise ImportError('Non-code object in {!r}'.format(bytecode_path), + raise ImportError(f'Non-code object in {bytecode_path!r}', name=name, path=bytecode_path) @@ -951,8 +951,8 @@ def exec_module(self, module): """Execute the module.""" code = self.get_code(module.__name__) if code is None: - raise ImportError('cannot load module {!r} when get_code() ' - 'returns None'.format(module.__name__)) + raise ImportError(f'cannot load module {module.__name__!r} when ' + 'get_code() returns None') _bootstrap._call_with_frames_removed(exec, code, module.__dict__) def load_module(self, fullname): @@ -1337,7 +1337,7 @@ def __len__(self): return len(self._recalculate()) def __repr__(self): - return '_NamespacePath({!r})'.format(self._path) + return f'_NamespacePath({self._path!r})' def __contains__(self, item): return item in self._recalculate() @@ -1678,7 +1678,7 @@ def _fill_cache(self): for item in contents: name, dot, suffix = item.partition('.') if dot: - new_name = '{}.{}'.format(name, suffix.lower()) + new_name = f'{name}.{suffix.lower()}' else: new_name = name lower_suffix_contents.add(new_name) @@ -1705,7 +1705,7 @@ def path_hook_for_FileFinder(path): return path_hook_for_FileFinder def __repr__(self): - return 'FileFinder({!r})'.format(self.path) + return f'FileFinder({self.path!r})' # Import setup ############################################################### diff --git a/Lib/importlib/resources/_adapters.py b/Lib/importlib/resources/_adapters.py index ea363d86a564..f22f6bc509a3 100644 --- a/Lib/importlib/resources/_adapters.py +++ b/Lib/importlib/resources/_adapters.py @@ -35,7 +35,7 @@ def _io_wrapper(file, mode='r', *args, **kwargs): elif mode == 'rb': return file raise ValueError( - "Invalid mode value '{}', only 'r' and 'rb' are supported".format(mode) + f"Invalid mode value '{mode}', only 'r' and 'rb' are supported" ) diff --git a/Lib/importlib/util.py b/Lib/importlib/util.py index 9e29c581b1db..5294578cc26c 100644 --- a/Lib/importlib/util.py +++ b/Lib/importlib/util.py @@ -60,10 +60,10 @@ def _find_spec_from_path(name, path=None): try: spec = module.__spec__ except AttributeError: - raise ValueError('{}.__spec__ is not set'.format(name)) from None + raise ValueError(f'{name}.__spec__ is not set') from None else: if spec is None: - raise ValueError('{}.__spec__ is None'.format(name)) + raise ValueError(f'{name}.__spec__ is None') return spec @@ -105,10 +105,10 @@ def find_spec(name, package=None): try: spec = module.__spec__ except AttributeError: - raise ValueError('{}.__spec__ is not set'.format(name)) from None + raise ValueError(f'{name}.__spec__ is not set') from None else: if spec is None: - raise ValueError('{}.__spec__ is None'.format(name)) + raise ValueError(f'{name}.__spec__ is None') return spec diff --git a/Misc/NEWS.d/next/Library/2019-11-04-22-21-27.bpo-38693.w_OAov.rst b/Misc/NEWS.d/next/Library/2019-11-04-22-21-27.bpo-38693.w_OAov.rst index 6d0ad36809ee..a81e9220a8e6 100644 --- a/Misc/NEWS.d/next/Library/2019-11-04-22-21-27.bpo-38693.w_OAov.rst +++ b/Misc/NEWS.d/next/Library/2019-11-04-22-21-27.bpo-38693.w_OAov.rst @@ -1 +1 @@ -importlib now uses f-strings internally instead of str.format(). +:mod:`importlib` now uses f-strings internally instead of ``str.format``. From webhook-mailer at python.org Thu Oct 6 21:50:30 2022 From: webhook-mailer at python.org (miss-islington) Date: Fri, 07 Oct 2022 01:50:30 -0000 Subject: [Python-checkins] GH-90985: Revert "Deprecate passing a message into cancel()" (GH-97999) Message-ID: https://github.com/python/cpython/commit/d163d5976dbb07ed7bc157260ab29452f940b567 commit: d163d5976dbb07ed7bc157260ab29452f940b567 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-06T18:50:25-07:00 summary: GH-90985: Revert "Deprecate passing a message into cancel()" (GH-97999) Reason: we were too hasty in deprecating this. We shouldn't deprecate it before we have a replacement. (cherry picked from commit 09de8d7aafece264720afbca3052a63eee413b73) Co-authored-by: Guido van Rossum files: A Misc/NEWS.d/next/Library/2022-10-06-23-42-00.gh-issue-90985.s280JY.rst M Doc/library/asyncio-future.rst M Doc/library/asyncio-task.rst M Lib/asyncio/futures.py M Lib/asyncio/tasks.py M Lib/test/test_asyncio/test_futures.py M Lib/test/test_asyncio/test_tasks.py M Modules/_asynciomodule.c diff --git a/Doc/library/asyncio-future.rst b/Doc/library/asyncio-future.rst index 8e60877f0e4c..70cec9b2f902 100644 --- a/Doc/library/asyncio-future.rst +++ b/Doc/library/asyncio-future.rst @@ -197,11 +197,6 @@ Future Object .. versionchanged:: 3.9 Added the *msg* parameter. - .. deprecated-removed:: 3.11 3.14 - *msg* parameter is ambiguous when multiple :meth:`cancel` - are called with different cancellation messages. - The argument will be removed. - .. method:: exception() Return the exception that was set on this Future. @@ -282,8 +277,3 @@ the Future has a result:: - :meth:`asyncio.Future.cancel` accepts an optional ``msg`` argument, but :func:`concurrent.futures.cancel` does not. - - .. deprecated-removed:: 3.11 3.14 - *msg* parameter is ambiguous when multiple :meth:`cancel` - are called with different cancellation messages. - The argument will be removed. diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index ade969220ea7..c6b8716073fe 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -1137,10 +1137,8 @@ Task Object .. versionchanged:: 3.9 Added the *msg* parameter. - .. deprecated-removed:: 3.11 3.14 - *msg* parameter is ambiguous when multiple :meth:`cancel` - are called with different cancellation messages. - The argument will be removed. + .. versionchanged:: 3.11 + The ``msg`` parameter is propagated from cancelled task to its awaiter. .. _asyncio_example_task_cancel: diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py index 39776e3c2cce..3a6b44a09108 100644 --- a/Lib/asyncio/futures.py +++ b/Lib/asyncio/futures.py @@ -8,7 +8,6 @@ import contextvars import logging import sys -import warnings from types import GenericAlias from . import base_futures @@ -151,11 +150,6 @@ def cancel(self, msg=None): change the future's state to cancelled, schedule the callbacks and return True. """ - if msg is not None: - warnings.warn("Passing 'msg' argument to Future.cancel() " - "is deprecated since Python 3.11, and " - "scheduled for removal in Python 3.14.", - DeprecationWarning, stacklevel=2) self.__log_traceback = False if self._state != _PENDING: return False diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py index e48da0f20088..3e07ce5294c8 100644 --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -207,11 +207,6 @@ def cancel(self, msg=None): This also increases the task's count of cancellation requests. """ - if msg is not None: - warnings.warn("Passing 'msg' argument to Task.cancel() " - "is deprecated since Python 3.11, and " - "scheduled for removal in Python 3.14.", - DeprecationWarning, stacklevel=2) self._log_traceback = False if self.done(): return False diff --git a/Lib/test/test_asyncio/test_futures.py b/Lib/test/test_asyncio/test_futures.py index c4c934f547b4..f8fe2e76b622 100644 --- a/Lib/test/test_asyncio/test_futures.py +++ b/Lib/test/test_asyncio/test_futures.py @@ -228,22 +228,14 @@ def test_future_cancel_message_getter(self): self.assertTrue(hasattr(f, '_cancel_message')) self.assertEqual(f._cancel_message, None) - with self.assertWarnsRegex( - DeprecationWarning, - "Passing 'msg' argument" - ): - f.cancel('my message') + f.cancel('my message') with self.assertRaises(asyncio.CancelledError): self.loop.run_until_complete(f) self.assertEqual(f._cancel_message, 'my message') def test_future_cancel_message_setter(self): f = self._new_future(loop=self.loop) - with self.assertWarnsRegex( - DeprecationWarning, - "Passing 'msg' argument" - ): - f.cancel('my message') + f.cancel('my message') f._cancel_message = 'my new message' self.assertEqual(f._cancel_message, 'my new message') diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py index 1cc20609bebc..7585768073e6 100644 --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -113,11 +113,7 @@ async def coro(): self.assertTrue(hasattr(t, '_cancel_message')) self.assertEqual(t._cancel_message, None) - with self.assertWarnsRegex( - DeprecationWarning, - "Passing 'msg' argument" - ): - t.cancel('my message') + t.cancel('my message') self.assertEqual(t._cancel_message, 'my message') with self.assertRaises(asyncio.CancelledError) as cm: @@ -129,11 +125,7 @@ def test_task_cancel_message_setter(self): async def coro(): pass t = self.new_task(self.loop, coro()) - with self.assertWarnsRegex( - DeprecationWarning, - "Passing 'msg' argument" - ): - t.cancel('my message') + t.cancel('my message') t._cancel_message = 'my new message' self.assertEqual(t._cancel_message, 'my new message') @@ -710,14 +702,7 @@ async def sleep(): async def coro(): task = self.new_task(loop, sleep()) await asyncio.sleep(0) - if cancel_args not in ((), (None,)): - with self.assertWarnsRegex( - DeprecationWarning, - "Passing 'msg' argument" - ): - task.cancel(*cancel_args) - else: - task.cancel(*cancel_args) + task.cancel(*cancel_args) done, pending = await asyncio.wait([task]) task.result() @@ -751,14 +736,7 @@ async def sleep(): async def coro(): task = self.new_task(loop, sleep()) await asyncio.sleep(0) - if cancel_args not in ((), (None,)): - with self.assertWarnsRegex( - DeprecationWarning, - "Passing 'msg' argument" - ): - task.cancel(*cancel_args) - else: - task.cancel(*cancel_args) + task.cancel(*cancel_args) done, pending = await asyncio.wait([task]) task.exception() @@ -781,17 +759,10 @@ async def sleep(): fut.set_result(None) await asyncio.sleep(10) - def cancel(task, msg): - with self.assertWarnsRegex( - DeprecationWarning, - "Passing 'msg' argument" - ): - task.cancel(msg) - async def coro(): inner_task = self.new_task(loop, sleep()) await fut - loop.call_soon(cancel, inner_task, 'msg') + loop.call_soon(inner_task.cancel, 'msg') try: await inner_task except asyncio.CancelledError as ex: @@ -817,11 +788,7 @@ async def sleep(): async def coro(): task = self.new_task(loop, sleep()) # We deliberately leave out the sleep here. - with self.assertWarnsRegex( - DeprecationWarning, - "Passing 'msg' argument" - ): - task.cancel('my message') + task.cancel('my message') done, pending = await asyncio.wait([task]) task.exception() @@ -2183,14 +2150,7 @@ async def test(): async def main(): qwe = self.new_task(loop, test()) await asyncio.sleep(0.2) - if cancel_args not in ((), (None,)): - with self.assertWarnsRegex( - DeprecationWarning, - "Passing 'msg' argument" - ): - qwe.cancel(*cancel_args) - else: - qwe.cancel(*cancel_args) + qwe.cancel(*cancel_args) await qwe try: diff --git a/Misc/NEWS.d/next/Library/2022-10-06-23-42-00.gh-issue-90985.s280JY.rst b/Misc/NEWS.d/next/Library/2022-10-06-23-42-00.gh-issue-90985.s280JY.rst new file mode 100644 index 000000000000..964aa3986331 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-06-23-42-00.gh-issue-90985.s280JY.rst @@ -0,0 +1 @@ +Earlier in 3.11 we deprecated ``asyncio.Task.cancel("message")``. We realized we were too harsh, and have undeprecated it. diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index 49f1ce33dc72..d503018ea6c3 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -1116,16 +1116,6 @@ static PyObject * _asyncio_Future_cancel_impl(FutureObj *self, PyObject *msg) /*[clinic end generated code: output=3edebbc668e5aba3 input=925eb545251f2c5a]*/ { - if (msg != Py_None) { - if (PyErr_WarnEx(PyExc_DeprecationWarning, - "Passing 'msg' argument to Future.cancel() " - "is deprecated since Python 3.11, and " - "scheduled for removal in Python 3.14.", - 2)) - { - return NULL; - } - } ENSURE_FUTURE_ALIVE(self) return future_cancel(self, msg); } @@ -2206,16 +2196,6 @@ static PyObject * _asyncio_Task_cancel_impl(TaskObj *self, PyObject *msg) /*[clinic end generated code: output=c66b60d41c74f9f1 input=7bb51bf25974c783]*/ { - if (msg != Py_None) { - if (PyErr_WarnEx(PyExc_DeprecationWarning, - "Passing 'msg' argument to Task.cancel() " - "is deprecated since Python 3.11, and " - "scheduled for removal in Python 3.14.", - 2)) - { - return NULL; - } - } self->task_log_tb = 0; if (self->task_state != STATE_PENDING) { From webhook-mailer at python.org Thu Oct 6 22:33:17 2022 From: webhook-mailer at python.org (miss-islington) Date: Fri, 07 Oct 2022 02:33:17 -0000 Subject: [Python-checkins] gh-86298: Ensure that __loader__ and __spec__.loader agree in warnings.warn_explicit() (GH-97803) Message-ID: https://github.com/python/cpython/commit/13d44891426e0faf165f974f2e46907ab5b645a9 commit: 13d44891426e0faf165f974f2e46907ab5b645a9 branch: main author: Barry Warsaw committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-06T19:32:53-07:00 summary: gh-86298: Ensure that __loader__ and __spec__.loader agree in warnings.warn_explicit() (GH-97803) In `_warnings.c`, in the C equivalent of `warnings.warn_explicit()`, if the module globals are given (and not None), the warning will attempt to get the source line for the issued warning. To do this, it needs the module's loader. Previously, it would only look up `__loader__` in the module globals. In https://github.com/python/cpython/issues/86298 we want to defer to the `__spec__.loader` if available. The first step on this journey is to check that `loader == __spec__.loader` and issue another warning if it is not. This commit does that. Since this is a PoC, only manual testing for now. ```python # /tmp/foo.py import warnings import bar warnings.warn_explicit( 'warning!', RuntimeWarning, 'bar.py', 2, module='bar knee', module_globals=bar.__dict__, ) ``` ```python # /tmp/bar.py import sys import os import pathlib # __loader__ = pathlib.Path() ``` Then running this: `./python.exe -Wdefault /tmp/foo.py` Produces: ``` bar.py:2: RuntimeWarning: warning! import os ``` Uncomment the `__loader__ = ` line in `bar.py` and try it again: ``` sys:1: ImportWarning: Module bar; __loader__ != __spec__.loader (<_frozen_importlib_external.SourceFileLoader object at 0x109f7dfa0> != PosixPath('.')) bar.py:2: RuntimeWarning: warning! import os ``` Automerge-Triggered-By: GH:warsaw files: A Misc/NEWS.d/next/Core and Builtins/2022-10-04-14-04-40.gh-issue-86298.QVM7G1.rst M Doc/reference/import.rst M Lib/importlib/_bootstrap_external.py M Lib/test/test_importlib/import_/test_helpers.py M Python/_warnings.c diff --git a/Doc/reference/import.rst b/Doc/reference/import.rst index 3fa875f52e01..b22b5251f1de 100644 --- a/Doc/reference/import.rst +++ b/Doc/reference/import.rst @@ -558,6 +558,11 @@ listed below. It is **strongly** recommended that you rely on :attr:`__spec__` instead instead of this attribute. + .. versionchanged:: 3.12 + The value of ``__loader__`` is expected to be the same as + ``__spec__.loader``. The use of ``__loader__`` is deprecated and slated + for removal in Python 3.14. + .. attribute:: __package__ The module's ``__package__`` attribute may be set. Its value must @@ -568,6 +573,9 @@ listed below. submodules, to the parent package's name. See :pep:`366` for further details. + This attribute is used instead of ``__name__`` to calculate explicit + relative imports for main modules, as defined in :pep:`366`. + It is **strongly** recommended that you rely on :attr:`__spec__` instead instead of this attribute. diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 39d63ae9d6e9..fc50e70539ca 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -862,6 +862,54 @@ def spec_from_file_location(name, location=None, *, loader=None, return spec +def _bless_my_loader(module_globals): + """Helper function for _warnings.c + + See GH#97850 for details. + """ + # 2022-10-06(warsaw): For now, this helper is only used in _warnings.c and + # that use case only has the module globals. This function could be + # extended to accept either that or a module object. However, in the + # latter case, it would be better to raise certain exceptions when looking + # at a module, which should have either a __loader__ or __spec__.loader. + # For backward compatibility, it is possible that we'll get an empty + # dictionary for the module globals, and that cannot raise an exception. + if not isinstance(module_globals, dict): + return None + + missing = object() + loader = module_globals.get('__loader__', None) + spec = module_globals.get('__spec__', missing) + + if loader is None: + if spec is missing: + # If working with a module: + # raise AttributeError('Module globals is missing a __spec__') + return None + elif spec is None: + raise ValueError('Module globals is missing a __spec__.loader') + + spec_loader = getattr(spec, 'loader', missing) + + if spec_loader in (missing, None): + if loader is None: + exc = AttributeError if spec_loader is missing else ValueError + raise exc('Module globals is missing a __spec__.loader') + _warnings.warn( + 'Module globals is missing a __spec__.loader', + DeprecationWarning) + spec_loader = loader + + assert spec_loader is not None + if loader is not None and loader != spec_loader: + _warnings.warn( + 'Module globals; __loader__ != __spec__.loader', + DeprecationWarning) + return loader + + return spec_loader + + # Loaders ##################################################################### class WindowsRegistryFinder: diff --git a/Lib/test/test_importlib/import_/test_helpers.py b/Lib/test/test_importlib/import_/test_helpers.py index 90df56f09fe5..550f88d1d7a6 100644 --- a/Lib/test/test_importlib/import_/test_helpers.py +++ b/Lib/test/test_importlib/import_/test_helpers.py @@ -2,7 +2,9 @@ from importlib import _bootstrap_external, machinery import os.path +from types import ModuleType, SimpleNamespace import unittest +import warnings from .. import util @@ -67,5 +69,116 @@ def test_no_loader_no_spec_but_source(self): FrozenFixUpModuleTests, SourceFixUpModuleTests = util.test_both(FixUpModuleTests) + +class TestBlessMyLoader(unittest.TestCase): + # GH#86298 is part of the migration away from module attributes and toward + # __spec__ attributes. There are several cases to test here. This will + # have to change in Python 3.14 when we actually remove/ignore __loader__ + # in favor of requiring __spec__.loader. + + def test_gh86298_no_loader_and_no_spec(self): + bar = ModuleType('bar') + del bar.__loader__ + del bar.__spec__ + # 2022-10-06(warsaw): For backward compatibility with the + # implementation in _warnings.c, this can't raise an + # AttributeError. See _bless_my_loader() in _bootstrap_external.py + # If working with a module: + ## self.assertRaises( + ## AttributeError, _bootstrap_external._bless_my_loader, + ## bar.__dict__) + self.assertIsNone(_bootstrap_external._bless_my_loader(bar.__dict__)) + + def test_gh86298_loader_is_none_and_no_spec(self): + bar = ModuleType('bar') + bar.__loader__ = None + del bar.__spec__ + # 2022-10-06(warsaw): For backward compatibility with the + # implementation in _warnings.c, this can't raise an + # AttributeError. See _bless_my_loader() in _bootstrap_external.py + # If working with a module: + ## self.assertRaises( + ## AttributeError, _bootstrap_external._bless_my_loader, + ## bar.__dict__) + self.assertIsNone(_bootstrap_external._bless_my_loader(bar.__dict__)) + + def test_gh86298_no_loader_and_spec_is_none(self): + bar = ModuleType('bar') + del bar.__loader__ + bar.__spec__ = None + self.assertRaises( + ValueError, + _bootstrap_external._bless_my_loader, bar.__dict__) + + def test_gh86298_loader_is_none_and_spec_is_none(self): + bar = ModuleType('bar') + bar.__loader__ = None + bar.__spec__ = None + self.assertRaises( + ValueError, + _bootstrap_external._bless_my_loader, bar.__dict__) + + def test_gh86298_loader_is_none_and_spec_loader_is_none(self): + bar = ModuleType('bar') + bar.__loader__ = None + bar.__spec__ = SimpleNamespace(loader=None) + self.assertRaises( + ValueError, + _bootstrap_external._bless_my_loader, bar.__dict__) + + def test_gh86298_no_spec(self): + bar = ModuleType('bar') + bar.__loader__ = object() + del bar.__spec__ + with warnings.catch_warnings(): + self.assertWarns( + DeprecationWarning, + _bootstrap_external._bless_my_loader, bar.__dict__) + + def test_gh86298_spec_is_none(self): + bar = ModuleType('bar') + bar.__loader__ = object() + bar.__spec__ = None + with warnings.catch_warnings(): + self.assertWarns( + DeprecationWarning, + _bootstrap_external._bless_my_loader, bar.__dict__) + + def test_gh86298_no_spec_loader(self): + bar = ModuleType('bar') + bar.__loader__ = object() + bar.__spec__ = SimpleNamespace() + with warnings.catch_warnings(): + self.assertWarns( + DeprecationWarning, + _bootstrap_external._bless_my_loader, bar.__dict__) + + def test_gh86298_loader_and_spec_loader_disagree(self): + bar = ModuleType('bar') + bar.__loader__ = object() + bar.__spec__ = SimpleNamespace(loader=object()) + with warnings.catch_warnings(): + self.assertWarns( + DeprecationWarning, + _bootstrap_external._bless_my_loader, bar.__dict__) + + def test_gh86298_no_loader_and_no_spec_loader(self): + bar = ModuleType('bar') + del bar.__loader__ + bar.__spec__ = SimpleNamespace() + self.assertRaises( + AttributeError, + _bootstrap_external._bless_my_loader, bar.__dict__) + + def test_gh86298_no_loader_with_spec_loader_okay(self): + bar = ModuleType('bar') + del bar.__loader__ + loader = object() + bar.__spec__ = SimpleNamespace(loader=loader) + self.assertEqual( + _bootstrap_external._bless_my_loader(bar.__dict__), + loader) + + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-04-14-04-40.gh-issue-86298.QVM7G1.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-04-14-04-40.gh-issue-86298.QVM7G1.rst new file mode 100644 index 000000000000..6e349d56c99f --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-04-14-04-40.gh-issue-86298.QVM7G1.rst @@ -0,0 +1,3 @@ +In cases where ``warnings.warn_explicit()`` consults the module's loader, an +``DeprecationWarning`` is issued when ``m.__loader__`` differs from +``m.__spec__.loader``. diff --git a/Python/_warnings.c b/Python/_warnings.c index 1b9e107ea30b..0d4c50f769b0 100644 --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -977,6 +977,7 @@ warnings_warn_impl(PyObject *module, PyObject *message, PyObject *category, static PyObject * get_source_line(PyInterpreterState *interp, PyObject *module_globals, int lineno) { + PyObject *external; PyObject *loader; PyObject *module_name; PyObject *get_source; @@ -984,12 +985,18 @@ get_source_line(PyInterpreterState *interp, PyObject *module_globals, int lineno PyObject *source_list; PyObject *source_line; - /* Check/get the requisite pieces needed for the loader. */ - loader = _PyDict_GetItemWithError(module_globals, &_Py_ID(__loader__)); + /* stolen from import.c */ + external = PyObject_GetAttrString(interp->importlib, "_bootstrap_external"); + if (external == NULL) { + return NULL; + } + + loader = PyObject_CallMethod(external, "_bless_my_loader", "O", module_globals, NULL); + Py_DECREF(external); if (loader == NULL) { return NULL; } - Py_INCREF(loader); + module_name = _PyDict_GetItemWithError(module_globals, &_Py_ID(__name__)); if (!module_name) { Py_DECREF(loader); From webhook-mailer at python.org Fri Oct 7 00:51:02 2022 From: webhook-mailer at python.org (miss-islington) Date: Fri, 07 Oct 2022 04:51:02 -0000 Subject: [Python-checkins] fixes gh-96078: os.sched_yield release the GIL while calling sched_yield(2). (gh-97965) Message-ID: https://github.com/python/cpython/commit/e39b511c2bfa98935e6ff81046d64d342fcff298 commit: e39b511c2bfa98935e6ff81046d64d342fcff298 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-06T21:50:56-07:00 summary: fixes gh-96078: os.sched_yield release the GIL while calling sched_yield(2). (gh-97965) (cherry picked from commit b9d2e8171696514e9226164005f7bf24bf69e66d) Co-authored-by: Dong-hee Na files: A Misc/NEWS.d/next/Core and Builtins/2022-10-06-15-45-57.gh-issue-96078.fS-6mU.rst M Modules/posixmodule.c diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-06-15-45-57.gh-issue-96078.fS-6mU.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-06-15-45-57.gh-issue-96078.fS-6mU.rst new file mode 100644 index 000000000000..d1f949c6e13a --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-06-15-45-57.gh-issue-96078.fS-6mU.rst @@ -0,0 +1,2 @@ +:func:`os.sched_yield` now release the GIL while calling sched_yield(2). +Patch by Dong-hee Na. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 309982af824c..4bebbbd06c19 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -7096,8 +7096,13 @@ static PyObject * os_sched_yield_impl(PyObject *module) /*[clinic end generated code: output=902323500f222cac input=e54d6f98189391d4]*/ { - if (sched_yield()) + int result; + Py_BEGIN_ALLOW_THREADS + result = sched_yield(); + Py_END_ALLOW_THREADS + if (result < 0) { return posix_error(); + } Py_RETURN_NONE; } From webhook-mailer at python.org Fri Oct 7 00:51:03 2022 From: webhook-mailer at python.org (miss-islington) Date: Fri, 07 Oct 2022 04:51:03 -0000 Subject: [Python-checkins] fixes gh-96078: os.sched_yield release the GIL while calling sched_yield(2). (gh-97965) Message-ID: https://github.com/python/cpython/commit/11945f2cf6ae4aeb8202f481e8881ec0fbfabe89 commit: 11945f2cf6ae4aeb8202f481e8881ec0fbfabe89 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-06T21:50:44-07:00 summary: fixes gh-96078: os.sched_yield release the GIL while calling sched_yield(2). (gh-97965) (cherry picked from commit b9d2e8171696514e9226164005f7bf24bf69e66d) Co-authored-by: Dong-hee Na files: A Misc/NEWS.d/next/Core and Builtins/2022-10-06-15-45-57.gh-issue-96078.fS-6mU.rst M Modules/posixmodule.c diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-06-15-45-57.gh-issue-96078.fS-6mU.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-06-15-45-57.gh-issue-96078.fS-6mU.rst new file mode 100644 index 000000000000..d1f949c6e13a --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-06-15-45-57.gh-issue-96078.fS-6mU.rst @@ -0,0 +1,2 @@ +:func:`os.sched_yield` now release the GIL while calling sched_yield(2). +Patch by Dong-hee Na. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 0b8b41cb2ded..f602ae5c5892 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -7028,8 +7028,13 @@ static PyObject * os_sched_yield_impl(PyObject *module) /*[clinic end generated code: output=902323500f222cac input=e54d6f98189391d4]*/ { - if (sched_yield()) + int result; + Py_BEGIN_ALLOW_THREADS + result = sched_yield(); + Py_END_ALLOW_THREADS + if (result < 0) { return posix_error(); + } Py_RETURN_NONE; } From webhook-mailer at python.org Fri Oct 7 03:11:12 2022 From: webhook-mailer at python.org (JulienPalard) Date: Fri, 07 Oct 2022 07:11:12 -0000 Subject: [Python-checkins] Doc: sphinx-lint finds two other default roles. (GH-98019) Message-ID: https://github.com/python/cpython/commit/66cc46b2e4c841bb95cc8b8214f86e85f22fb19e commit: 66cc46b2e4c841bb95cc8b8214f86e85f22fb19e branch: main author: Julien Palard committer: JulienPalard date: 2022-10-07T09:10:51+02:00 summary: Doc: sphinx-lint finds two other default roles. (GH-98019) files: M Doc/library/functools.rst M Doc/requirements.txt diff --git a/Doc/library/functools.rst b/Doc/library/functools.rst index 943a05c39d68..2f0a9bd8be88 100644 --- a/Doc/library/functools.rst +++ b/Doc/library/functools.rst @@ -150,7 +150,7 @@ The :mod:`functools` module defines the following functions: arguments to the function must be hashable. Distinct argument patterns may be considered to be distinct calls with - separate cache entries. For example, `f(a=1, b=2)` and `f(b=2, a=1)` + separate cache entries. For example, ``f(a=1, b=2)`` and ``f(b=2, a=1)`` differ in their keyword argument order and may have two separate cache entries. @@ -197,7 +197,7 @@ The :mod:`functools` module defines the following functions: The cache keeps references to the arguments and return values until they age out of the cache or until the cache is cleared. - If a method is cached, the `self` instance argument is included in the + If a method is cached, the ``self`` instance argument is included in the cache. See :ref:`faq-cache-method-calls` An `LRU (least recently used) cache diff --git a/Doc/requirements.txt b/Doc/requirements.txt index 7f82dc32113a..32c53e95917e 100644 --- a/Doc/requirements.txt +++ b/Doc/requirements.txt @@ -10,7 +10,7 @@ blurb # sphinx-lint 0.6.2 yields many default role errors due to the new regular # expression used for default role detection, so we don't use the version # until the errors are fixed. -sphinx-lint==0.6.4 +sphinx-lint==0.6.5 # The theme used by the documentation is stored separately, so we need # to install that as well. From webhook-mailer at python.org Fri Oct 7 04:37:31 2022 From: webhook-mailer at python.org (rhettinger) Date: Fri, 07 Oct 2022 08:37:31 -0000 Subject: [Python-checkins] Misc updates to the itertools recipes and tests (GH-98018) Message-ID: https://github.com/python/cpython/commit/e500cc04517bd65668f2e203c1e37b0cc5b1cf1b commit: e500cc04517bd65668f2e203c1e37b0cc5b1cf1b branch: main author: Raymond Hettinger committer: rhettinger date: 2022-10-07T03:37:21-05:00 summary: Misc updates to the itertools recipes and tests (GH-98018) files: M Doc/library/itertools.rst diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index b83163560f4d..6571114ef311 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -775,10 +775,7 @@ which incur interpreter overhead. return sum(map(pred, iterable)) def pad_none(iterable): - """Returns the sequence elements and then returns None indefinitely. - - Useful for emulating the behavior of the built-in map() function. - """ + "Returns the sequence elements and then returns None indefinitely." return chain(iterable, repeat(None)) def ncycles(iterable, n): @@ -850,6 +847,13 @@ which incur interpreter overhead. else: raise ValueError('Expected fill, strict, or ignore') + def batched(iterable, n): + "Batch data into lists of length n. The last batch may be shorter." + # batched('ABCDEFG', 3) --> ABC DEF G + it = iter(iterable) + while (batch := list(islice(it, n))): + yield batch + def triplewise(iterable): "Return overlapping triplets from an iterable" # triplewise('ABCDEFG') --> ABC BCD CDE DEF EFG @@ -1168,8 +1172,8 @@ which incur interpreter overhead. >>> list(sieve(30)) [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] - >>> small_primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59] - >>> all(list(sieve(n)) == [p for p in small_primes if p < n] for n in range(60)) + >>> small_primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97] + >>> all(list(sieve(n)) == [p for p in small_primes if p < n] for n in range(101)) True >>> len(list(sieve(100))) 25 @@ -1212,6 +1216,36 @@ which incur interpreter overhead. >>> list(grouper('abcdefg', n=3, incomplete='ignore')) [('a', 'b', 'c'), ('d', 'e', 'f')] + >>> list(batched('ABCDEFG', 3)) + [['A', 'B', 'C'], ['D', 'E', 'F'], ['G']] + >>> list(batched('ABCDEF', 3)) + [['A', 'B', 'C'], ['D', 'E', 'F']] + >>> list(batched('ABCDE', 3)) + [['A', 'B', 'C'], ['D', 'E']] + >>> list(batched('ABCD', 3)) + [['A', 'B', 'C'], ['D']] + >>> list(batched('ABC', 3)) + [['A', 'B', 'C']] + >>> list(batched('AB', 3)) + [['A', 'B']] + >>> list(batched('A', 3)) + [['A']] + >>> list(batched('', 3)) + [] + >>> list(batched('ABCDEFG', 2)) + [['A', 'B'], ['C', 'D'], ['E', 'F'], ['G']] + >>> list(batched('ABCDEFG', 1)) + [['A'], ['B'], ['C'], ['D'], ['E'], ['F'], ['G']] + >>> list(batched('ABCDEFG', 0)) + [] + >>> list(batched('ABCDEFG', -1)) + Traceback (most recent call last): + ... + ValueError: Stop argument for islice() must be None or an integer: 0 <= x <= sys.maxsize. + >>> s = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + >>> all(list(flatten(batched(s[:n], 5))) == list(s[:n]) for n in range(len(s))) + True + >>> list(triplewise('ABCDEFG')) [('A', 'B', 'C'), ('B', 'C', 'D'), ('C', 'D', 'E'), ('D', 'E', 'F'), ('E', 'F', 'G')] From webhook-mailer at python.org Fri Oct 7 04:46:36 2022 From: webhook-mailer at python.org (miss-islington) Date: Fri, 07 Oct 2022 08:46:36 -0000 Subject: [Python-checkins] Misc updates to the itertools recipes and tests (GH-98018) Message-ID: https://github.com/python/cpython/commit/d7547fc6fbf3397095c1ea5a7ac1b51d22f3f10a commit: d7547fc6fbf3397095c1ea5a7ac1b51d22f3f10a branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-07T01:46:31-07:00 summary: Misc updates to the itertools recipes and tests (GH-98018) (cherry picked from commit e500cc04517bd65668f2e203c1e37b0cc5b1cf1b) Co-authored-by: Raymond Hettinger files: M Doc/library/itertools.rst diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 13fb80a29154..844972e5cd4f 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -775,10 +775,7 @@ which incur interpreter overhead. return sum(map(pred, iterable)) def pad_none(iterable): - """Returns the sequence elements and then returns None indefinitely. - - Useful for emulating the behavior of the built-in map() function. - """ + "Returns the sequence elements and then returns None indefinitely." return chain(iterable, repeat(None)) def ncycles(iterable, n): @@ -850,6 +847,13 @@ which incur interpreter overhead. else: raise ValueError('Expected fill, strict, or ignore') + def batched(iterable, n): + "Batch data into lists of length n. The last batch may be shorter." + # batched('ABCDEFG', 3) --> ABC DEF G + it = iter(iterable) + while (batch := list(islice(it, n))): + yield batch + def triplewise(iterable): "Return overlapping triplets from an iterable" # triplewise('ABCDEFG') --> ABC BCD CDE DEF EFG @@ -1168,8 +1172,8 @@ which incur interpreter overhead. >>> list(sieve(30)) [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] - >>> small_primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59] - >>> all(list(sieve(n)) == [p for p in small_primes if p < n] for n in range(60)) + >>> small_primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97] + >>> all(list(sieve(n)) == [p for p in small_primes if p < n] for n in range(101)) True >>> len(list(sieve(100))) 25 @@ -1212,6 +1216,36 @@ which incur interpreter overhead. >>> list(grouper('abcdefg', n=3, incomplete='ignore')) [('a', 'b', 'c'), ('d', 'e', 'f')] + >>> list(batched('ABCDEFG', 3)) + [['A', 'B', 'C'], ['D', 'E', 'F'], ['G']] + >>> list(batched('ABCDEF', 3)) + [['A', 'B', 'C'], ['D', 'E', 'F']] + >>> list(batched('ABCDE', 3)) + [['A', 'B', 'C'], ['D', 'E']] + >>> list(batched('ABCD', 3)) + [['A', 'B', 'C'], ['D']] + >>> list(batched('ABC', 3)) + [['A', 'B', 'C']] + >>> list(batched('AB', 3)) + [['A', 'B']] + >>> list(batched('A', 3)) + [['A']] + >>> list(batched('', 3)) + [] + >>> list(batched('ABCDEFG', 2)) + [['A', 'B'], ['C', 'D'], ['E', 'F'], ['G']] + >>> list(batched('ABCDEFG', 1)) + [['A'], ['B'], ['C'], ['D'], ['E'], ['F'], ['G']] + >>> list(batched('ABCDEFG', 0)) + [] + >>> list(batched('ABCDEFG', -1)) + Traceback (most recent call last): + ... + ValueError: Stop argument for islice() must be None or an integer: 0 <= x <= sys.maxsize. + >>> s = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + >>> all(list(flatten(batched(s[:n], 5))) == list(s[:n]) for n in range(len(s))) + True + >>> list(triplewise('ABCDEFG')) [('A', 'B', 'C'), ('B', 'C', 'D'), ('C', 'D', 'E'), ('D', 'E', 'F'), ('E', 'F', 'G')] From webhook-mailer at python.org Fri Oct 7 09:54:31 2022 From: webhook-mailer at python.org (iritkatriel) Date: Fri, 07 Oct 2022 13:54:31 -0000 Subject: [Python-checkins] gh-71316: Update dis documentation to include changes to jump arguments (GH-95798) Message-ID: https://github.com/python/cpython/commit/6592a62ec2939323b895c85780da7fd73a640da3 commit: 6592a62ec2939323b895c85780da7fd73a640da3 branch: main author: Christopher Chianelli committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2022-10-07T14:54:21+01:00 summary: gh-71316: Update dis documentation to include changes to jump arguments (GH-95798) files: M Doc/library/dis.rst diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 30a336197c39..33df7be43634 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -30,6 +30,10 @@ interpreter. Use 2 bytes for each instruction. Previously the number of bytes varied by instruction. + .. versionchanged:: 3.10 + The argument of jump, exception handling and loop instructions is now + the instruction offset rather than the byte offset. + .. versionchanged:: 3.11 Some instructions are accompanied by one or more inline cache entries, which take the form of :opcode:`CACHE` instructions. These instructions From webhook-mailer at python.org Fri Oct 7 10:11:04 2022 From: webhook-mailer at python.org (miss-islington) Date: Fri, 07 Oct 2022 14:11:04 -0000 Subject: [Python-checkins] gh-71316: Update dis documentation to include changes to jump arguments (GH-95798) Message-ID: https://github.com/python/cpython/commit/245ea1f5007735c2d6e28a84f23e294880e0dec4 commit: 245ea1f5007735c2d6e28a84f23e294880e0dec4 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-07T07:10:46-07:00 summary: gh-71316: Update dis documentation to include changes to jump arguments (GH-95798) (cherry picked from commit 6592a62ec2939323b895c85780da7fd73a640da3) Co-authored-by: Christopher Chianelli files: M Doc/library/dis.rst diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index f7989ea43dac..d2925929c6c9 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -30,6 +30,10 @@ interpreter. Use 2 bytes for each instruction. Previously the number of bytes varied by instruction. + .. versionchanged:: 3.10 + The argument of jump, exception handling and loop instructions is now + the instruction offset rather than the byte offset. + .. versionchanged:: 3.11 Some instructions are accompanied by one or more inline cache entries, which take the form of :opcode:`CACHE` instructions. These instructions From webhook-mailer at python.org Fri Oct 7 10:14:37 2022 From: webhook-mailer at python.org (gvanrossum) Date: Fri, 07 Oct 2022 14:14:37 -0000 Subject: [Python-checkins] gh-97983: Revert "Lay the foundation for further work in asyncio.test_streams: port server cases to IsolatedAsyncioTestCase" (#98015) Message-ID: https://github.com/python/cpython/commit/f99bb20cde258bfd8404448951f5454dc6279e98 commit: f99bb20cde258bfd8404448951f5454dc6279e98 branch: main author: Oleg Iarygin committer: gvanrossum date: 2022-10-07T07:14:28-07:00 summary: gh-97983: Revert "Lay the foundation for further work in asyncio.test_streams: port server cases to IsolatedAsyncioTestCase" (#98015) This PR reverts gh-93369 and gh-97896 because they've made asyncio tests unstable. After these PRs were merged, random GitHub action jobs of random commits started to fail unrelated tests and test framework methods. The reverting is necessary because such shrapnel failures are a symptom of some underlying bug that must be found and fixed first. I had a hope that it's a server overload because we already have extremely rare disc access errors. However, one and a half day passed, and the failures continue to emerge both in PRs and commits. Affected issue: gh-93357. First reported in https://github.com/python/cpython/pull/97940#issuecomment-1270004134. * Revert "gh-93357: Port test cases to IsolatedAsyncioTestCase, part 2 (#97896)" This reverts commit 09aea94d291fed2f3e96558dcd6db04014c3e2fb. * Revert "gh-93357: Start porting asyncio server test cases to IsolatedAsyncioTestCase (#93369)" This reverts commit ce8fc186ac81bce1727bf4192205148daabf5c2e. files: M Lib/test/test_asyncio/test_streams.py diff --git a/Lib/test/test_asyncio/test_streams.py b/Lib/test/test_asyncio/test_streams.py index 61d5e984dfbf..0c49099bc499 100644 --- a/Lib/test/test_asyncio/test_streams.py +++ b/Lib/test/test_asyncio/test_streams.py @@ -566,10 +566,46 @@ def test_exception_cancel(self): test_utils.run_briefly(self.loop) self.assertIs(stream._waiter, None) - -class NewStreamTests(unittest.IsolatedAsyncioTestCase): - - async def test_start_server(self): + def test_start_server(self): + + class MyServer: + + def __init__(self, loop): + self.server = None + self.loop = loop + + async def handle_client(self, client_reader, client_writer): + data = await client_reader.readline() + client_writer.write(data) + await client_writer.drain() + client_writer.close() + await client_writer.wait_closed() + + def start(self): + sock = socket.create_server(('127.0.0.1', 0)) + self.server = self.loop.run_until_complete( + asyncio.start_server(self.handle_client, + sock=sock)) + return sock.getsockname() + + def handle_client_callback(self, client_reader, client_writer): + self.loop.create_task(self.handle_client(client_reader, + client_writer)) + + def start_callback(self): + sock = socket.create_server(('127.0.0.1', 0)) + addr = sock.getsockname() + sock.close() + self.server = self.loop.run_until_complete( + asyncio.start_server(self.handle_client_callback, + host=addr[0], port=addr[1])) + return addr + + def stop(self): + if self.server is not None: + self.server.close() + self.loop.run_until_complete(self.server.wait_closed()) + self.server = None async def client(addr): reader, writer = await asyncio.open_connection(*addr) @@ -581,43 +617,61 @@ async def client(addr): await writer.wait_closed() return msgback - async def handle_client(client_reader, client_writer): - data = await client_reader.readline() - client_writer.write(data) - await client_writer.drain() - client_writer.close() - await client_writer.wait_closed() - - with self.subTest(msg="coroutine"): - server = await asyncio.start_server( - handle_client, - host=socket_helper.HOSTv4 - ) - addr = server.sockets[0].getsockname() - msg = await client(addr) - server.close() - await server.wait_closed() - self.assertEqual(msg, b"hello world!\n") + messages = [] + self.loop.set_exception_handler(lambda loop, ctx: messages.append(ctx)) - with self.subTest(msg="callback"): - async def handle_client_callback(client_reader, client_writer): - asyncio.get_running_loop().create_task( - handle_client(client_reader, client_writer) - ) + # test the server variant with a coroutine as client handler + server = MyServer(self.loop) + addr = server.start() + msg = self.loop.run_until_complete(self.loop.create_task(client(addr))) + server.stop() + self.assertEqual(msg, b"hello world!\n") - server = await asyncio.start_server( - handle_client_callback, - host=socket_helper.HOSTv4 - ) - addr = server.sockets[0].getsockname() - reader, writer = await asyncio.open_connection(*addr) - msg = await client(addr) - server.close() - await server.wait_closed() - self.assertEqual(msg, b"hello world!\n") + # test the server variant with a callback as client handler + server = MyServer(self.loop) + addr = server.start_callback() + msg = self.loop.run_until_complete(self.loop.create_task(client(addr))) + server.stop() + self.assertEqual(msg, b"hello world!\n") + + self.assertEqual(messages, []) @socket_helper.skip_unless_bind_unix_socket - async def test_start_unix_server(self): + def test_start_unix_server(self): + + class MyServer: + + def __init__(self, loop, path): + self.server = None + self.loop = loop + self.path = path + + async def handle_client(self, client_reader, client_writer): + data = await client_reader.readline() + client_writer.write(data) + await client_writer.drain() + client_writer.close() + await client_writer.wait_closed() + + def start(self): + self.server = self.loop.run_until_complete( + asyncio.start_unix_server(self.handle_client, + path=self.path)) + + def handle_client_callback(self, client_reader, client_writer): + self.loop.create_task(self.handle_client(client_reader, + client_writer)) + + def start_callback(self): + start = asyncio.start_unix_server(self.handle_client_callback, + path=self.path) + self.server = self.loop.run_until_complete(start) + + def stop(self): + if self.server is not None: + self.server.close() + self.loop.run_until_complete(self.server.wait_closed()) + self.server = None async def client(path): reader, writer = await asyncio.open_unix_connection(path) @@ -629,42 +683,64 @@ async def client(path): await writer.wait_closed() return msgback - async def handle_client(client_reader, client_writer): - data = await client_reader.readline() - client_writer.write(data) - await client_writer.drain() - client_writer.close() - await client_writer.wait_closed() - - with self.subTest(msg="coroutine"): - with test_utils.unix_socket_path() as path: - server = await asyncio.start_unix_server( - handle_client, - path=path - ) - msg = await client(path) - server.close() - await server.wait_closed() - self.assertEqual(msg, b"hello world!\n") - - with self.subTest(msg="callback"): - async def handle_client_callback(client_reader, client_writer): - asyncio.get_running_loop().create_task( - handle_client(client_reader, client_writer) - ) - - with test_utils.unix_socket_path() as path: - server = await asyncio.start_unix_server( - handle_client_callback, - path=path - ) - msg = await client(path) - server.close() - await server.wait_closed() - self.assertEqual(msg, b"hello world!\n") + messages = [] + self.loop.set_exception_handler(lambda loop, ctx: messages.append(ctx)) + + # test the server variant with a coroutine as client handler + with test_utils.unix_socket_path() as path: + server = MyServer(self.loop, path) + server.start() + msg = self.loop.run_until_complete( + self.loop.create_task(client(path))) + server.stop() + self.assertEqual(msg, b"hello world!\n") + + # test the server variant with a callback as client handler + with test_utils.unix_socket_path() as path: + server = MyServer(self.loop, path) + server.start_callback() + msg = self.loop.run_until_complete( + self.loop.create_task(client(path))) + server.stop() + self.assertEqual(msg, b"hello world!\n") + + self.assertEqual(messages, []) @unittest.skipIf(ssl is None, 'No ssl module') - async def test_start_tls(self): + def test_start_tls(self): + + class MyServer: + + def __init__(self, loop): + self.server = None + self.loop = loop + + async def handle_client(self, client_reader, client_writer): + data1 = await client_reader.readline() + client_writer.write(data1) + await client_writer.drain() + assert client_writer.get_extra_info('sslcontext') is None + await client_writer.start_tls( + test_utils.simple_server_sslcontext()) + assert client_writer.get_extra_info('sslcontext') is not None + data2 = await client_reader.readline() + client_writer.write(data2) + await client_writer.drain() + client_writer.close() + await client_writer.wait_closed() + + def start(self): + sock = socket.create_server(('127.0.0.1', 0)) + self.server = self.loop.run_until_complete( + asyncio.start_server(self.handle_client, + sock=sock)) + return sock.getsockname() + + def stop(self): + if self.server is not None: + self.server.close() + self.loop.run_until_complete(self.server.wait_closed()) + self.server = None async def client(addr): reader, writer = await asyncio.open_connection(*addr) @@ -681,48 +757,17 @@ async def client(addr): await writer.wait_closed() return msgback1, msgback2 - async def handle_client(client_reader, client_writer): - data1 = await client_reader.readline() - client_writer.write(data1) - await client_writer.drain() - assert client_writer.get_extra_info('sslcontext') is None - await client_writer.start_tls( - test_utils.simple_server_sslcontext()) - assert client_writer.get_extra_info('sslcontext') is not None - - data2 = await client_reader.readline() - client_writer.write(data2) - await client_writer.drain() - client_writer.close() - await client_writer.wait_closed() - - server = await asyncio.start_server( - handle_client, - host=socket_helper.HOSTv4 - ) - addr = server.sockets[0].getsockname() - - msg1, msg2 = await client(addr) - server.close() - await server.wait_closed() - self.assertEqual(msg1, b"hello world 1!\n") - self.assertEqual(msg2, b"hello world 2!\n") - - -class StreamTests2(test_utils.TestCase): - - def setUp(self): - super().setUp() - self.loop = asyncio.new_event_loop() - self.set_event_loop(self.loop) + messages = [] + self.loop.set_exception_handler(lambda loop, ctx: messages.append(ctx)) - def tearDown(self): - # just in case if we have transport close callbacks - test_utils.run_briefly(self.loop) + server = MyServer(self.loop) + addr = server.start() + msg1, msg2 = self.loop.run_until_complete(client(addr)) + server.stop() - self.loop.close() - gc.collect() - super().tearDown() + self.assertEqual(messages, []) + self.assertEqual(msg1, b"hello world 1!\n") + self.assertEqual(msg2, b"hello world 2!\n") @unittest.skipIf(sys.platform == 'win32', "Don't have pipes") def test_read_all_from_pipe_reader(self): @@ -941,32 +986,36 @@ def test_LimitOverrunError_pickleable(self): self.assertEqual(str(e), str(e2)) self.assertEqual(e.consumed, e2.consumed) -class NewStreamTests2(unittest.IsolatedAsyncioTestCase): - async def test_wait_closed_on_close(self): + def test_wait_closed_on_close(self): with test_utils.run_test_server() as httpd: - rd, wr = await asyncio.open_connection(*httpd.address) + rd, wr = self.loop.run_until_complete( + asyncio.open_connection(*httpd.address)) wr.write(b'GET / HTTP/1.0\r\n\r\n') - data = await rd.readline() + f = rd.readline() + data = self.loop.run_until_complete(f) self.assertEqual(data, b'HTTP/1.0 200 OK\r\n') - data = await rd.read() + f = rd.read() + data = self.loop.run_until_complete(f) self.assertTrue(data.endswith(b'\r\n\r\nTest message')) self.assertFalse(wr.is_closing()) wr.close() self.assertTrue(wr.is_closing()) - await wr.wait_closed() + self.loop.run_until_complete(wr.wait_closed()) - async def test_wait_closed_on_close_with_unread_data(self): + def test_wait_closed_on_close_with_unread_data(self): with test_utils.run_test_server() as httpd: - rd, wr = await asyncio.open_connection(*httpd.address) + rd, wr = self.loop.run_until_complete( + asyncio.open_connection(*httpd.address)) wr.write(b'GET / HTTP/1.0\r\n\r\n') - data = await rd.readline() + f = rd.readline() + data = self.loop.run_until_complete(f) self.assertEqual(data, b'HTTP/1.0 200 OK\r\n') wr.close() - await wr.wait_closed() + self.loop.run_until_complete(wr.wait_closed()) - async def test_async_writer_api(self): + def test_async_writer_api(self): async def inner(httpd): rd, wr = await asyncio.open_connection(*httpd.address) @@ -978,10 +1027,15 @@ async def inner(httpd): wr.close() await wr.wait_closed() + messages = [] + self.loop.set_exception_handler(lambda loop, ctx: messages.append(ctx)) + with test_utils.run_test_server() as httpd: - await inner(httpd) + self.loop.run_until_complete(inner(httpd)) - async def test_async_writer_api_exception_after_close(self): + self.assertEqual(messages, []) + + def test_async_writer_api_exception_after_close(self): async def inner(httpd): rd, wr = await asyncio.open_connection(*httpd.address) @@ -995,19 +1049,33 @@ async def inner(httpd): wr.write(b'data') await wr.drain() + messages = [] + self.loop.set_exception_handler(lambda loop, ctx: messages.append(ctx)) + with test_utils.run_test_server() as httpd: - await inner(httpd) + self.loop.run_until_complete(inner(httpd)) - async def test_eof_feed_when_closing_writer(self): + self.assertEqual(messages, []) + + def test_eof_feed_when_closing_writer(self): # See http://bugs.python.org/issue35065 + messages = [] + self.loop.set_exception_handler(lambda loop, ctx: messages.append(ctx)) + with test_utils.run_test_server() as httpd: - rd, wr = await asyncio.open_connection(*httpd.address) + rd, wr = self.loop.run_until_complete( + asyncio.open_connection(*httpd.address)) + wr.close() - await wr.wait_closed() + f = wr.wait_closed() + self.loop.run_until_complete(f) self.assertTrue(rd.at_eof()) - data = await rd.read() + f = rd.read() + data = self.loop.run_until_complete(f) self.assertEqual(data, b'') + self.assertEqual(messages, []) + if __name__ == '__main__': unittest.main() From webhook-mailer at python.org Fri Oct 7 10:35:46 2022 From: webhook-mailer at python.org (iritkatriel) Date: Fri, 07 Oct 2022 14:35:46 -0000 Subject: [Python-checkins] [3.10] gh-71316: Update dis documentation to include changes to jump arguments (GH-95798). (GH-98029) Message-ID: https://github.com/python/cpython/commit/5e87cc2ab5edb0e70c6920bbbf3c190582a29571 commit: 5e87cc2ab5edb0e70c6920bbbf3c190582a29571 branch: 3.10 author: Christopher Chianelli committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2022-10-07T15:35:41+01:00 summary: [3.10] gh-71316: Update dis documentation to include changes to jump arguments (GH-95798). (GH-98029) (cherry picked from commit 6592a62ec2939323b895c85780da7fd73a640da3) Co-authored-by: Christopher Chianelli files: M Doc/library/dis.rst diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 1df281a7e3d2..9ed0e20cbb56 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -24,6 +24,10 @@ interpreter. Use 2 bytes for each instruction. Previously the number of bytes varied by instruction. + .. versionchanged:: 3.10 + The argument of jump, exception handling and loop instructions is now + the instruction offset rather than the byte offset. + Example: Given the function :func:`myfunc`:: From webhook-mailer at python.org Fri Oct 7 11:18:10 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Fri, 07 Oct 2022 15:18:10 -0000 Subject: [Python-checkins] Fix memory leaks in test_capi (#98017) Message-ID: https://github.com/python/cpython/commit/be4099e55d30a2991b46add59ee96c531904c144 commit: be4099e55d30a2991b46add59ee96c531904c144 branch: main author: Carl Meyer committer: JelleZijlstra date: 2022-10-07T08:17:41-07:00 summary: Fix memory leaks in test_capi (#98017) files: M Lib/test/test_capi.py M Modules/_testcapimodule.c diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py index cb90d55941ca..19367dfcc1cc 100644 --- a/Lib/test/test_capi.py +++ b/Lib/test/test_capi.py @@ -1495,6 +1495,9 @@ def unraisable_hook(unraisable): unraisable = unraisables[0] self.assertIs(unraisable.object, d) self.assertEqual(str(unraisable.exc_value), "boom!") + # avoid leaking reference cycles + del unraisable + del unraisables def test_two_watchers(self): d1 = {} diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index c57dba4a5bf3..28fb43dce4c6 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -5210,6 +5210,7 @@ dict_watch_callback(PyDict_WatchEvent event, Py_DECREF(msg); return -1; } + Py_DECREF(msg); return 0; } @@ -5224,8 +5225,10 @@ dict_watch_callback_second(PyDict_WatchEvent event, return -1; } if (PyList_Append(g_dict_watch_events, msg) < 0) { + Py_DECREF(msg); return -1; } + Py_DECREF(msg); return 0; } From webhook-mailer at python.org Fri Oct 7 12:53:57 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Fri, 07 Oct 2022 16:53:57 -0000 Subject: [Python-checkins] gh-94808: Cover `%p` in `PyUnicode_FromFormat` (#96677) Message-ID: https://github.com/python/cpython/commit/72c166add89a0cd992d66f75ce94eee5eb675a99 commit: 72c166add89a0cd992d66f75ce94eee5eb675a99 branch: main author: Nikita Sobolev committer: JelleZijlstra date: 2022-10-07T09:53:42-07:00 summary: gh-94808: Cover `%p` in `PyUnicode_FromFormat` (#96677) Co-authored-by: Jelle Zijlstra files: M Lib/test/test_unicode.py diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py index 30faaaf83bec..b9ee9d30318c 100644 --- a/Lib/test/test_unicode.py +++ b/Lib/test/test_unicode.py @@ -2807,6 +2807,25 @@ def check_format(expected, format, *args): check_format('repr=abc', b'repr=%V', 'abc', b'xyz') + # test %p + # We cannot test the exact result, + # because it returns a hex representation of a C pointer, + # which is going to be different each time. But, we can test the format. + p_format_regex = r'^0x[a-zA-Z0-9]{8,}$' + p_format1 = PyUnicode_FromFormat(b'%p', 'abc') + self.assertIsInstance(p_format1, str) + self.assertRegex(p_format1, p_format_regex) + + p_format2 = PyUnicode_FromFormat(b'%p %p', '123456', b'xyz') + self.assertIsInstance(p_format2, str) + self.assertRegex(p_format2, + r'0x[a-zA-Z0-9]{8,} 0x[a-zA-Z0-9]{8,}') + + # Extra args are ignored: + p_format3 = PyUnicode_FromFormat(b'%p', '123456', None, b'xyz') + self.assertIsInstance(p_format3, str) + self.assertRegex(p_format3, p_format_regex) + # Test string decode from parameter of %s using utf-8. # b'\xe4\xba\xba\xe6\xb0\x91' is utf-8 encoded byte sequence of # '\u4eba\u6c11' From webhook-mailer at python.org Fri Oct 7 13:08:20 2022 From: webhook-mailer at python.org (nanjekyejoannah) Date: Fri, 07 Oct 2022 17:08:20 -0000 Subject: [Python-checkins] Add note on capture_output arg to subprocess.run() docstring (#98012) Message-ID: https://github.com/python/cpython/commit/80b3e32d6242c27094dd04c4c3d0c3d3b2889a01 commit: 80b3e32d6242c27094dd04c4c3d0c3d3b2889a01 branch: main author: andrei kulakov committer: nanjekyejoannah <33177550+nanjekyejoannah at users.noreply.github.com> date: 2022-10-07T10:08:08-07:00 summary: Add note on capture_output arg to subprocess.run() docstring (#98012) add note on capture_output arg to the docstring files: M Lib/subprocess.py diff --git a/Lib/subprocess.py b/Lib/subprocess.py index 760b93b47ebb..9cadd1bf8e62 100644 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -509,7 +509,8 @@ def run(*popenargs, The returned instance will have attributes args, returncode, stdout and stderr. By default, stdout and stderr are not captured, and those attributes - will be None. Pass stdout=PIPE and/or stderr=PIPE in order to capture them. + will be None. Pass stdout=PIPE and/or stderr=PIPE in order to capture them, + or pass capture_output=True to capture both. If check is True and the exit code was non-zero, it raises a CalledProcessError. The CalledProcessError object will have the return code From webhook-mailer at python.org Fri Oct 7 13:17:16 2022 From: webhook-mailer at python.org (serhiy-storchaka) Date: Fri, 07 Oct 2022 17:17:16 -0000 Subject: [Python-checkins] Add more syslog tests (GH-97953) Message-ID: https://github.com/python/cpython/commit/cae7d1d7a713f8267daf5e4f2fff5cb1dad02c7c commit: cae7d1d7a713f8267daf5e4f2fff5cb1dad02c7c branch: main author: Serhiy Storchaka committer: serhiy-storchaka date: 2022-10-07T20:17:08+03:00 summary: Add more syslog tests (GH-97953) files: M Lib/test/audit-tests.py M Lib/test/test_audit.py M Lib/test/test_syslog.py M Modules/syslogmodule.c diff --git a/Lib/test/audit-tests.py b/Lib/test/audit-tests.py index 66c08f7f2ff8..4abf33d7cad1 100644 --- a/Lib/test/audit-tests.py +++ b/Lib/test/audit-tests.py @@ -429,6 +429,26 @@ def hook(event, args): sys.addaudithook(hook) _wmi.exec_query("SELECT * FROM Win32_OperatingSystem") +def test_syslog(): + import syslog + + def hook(event, args): + if event.startswith("syslog."): + print(event, *args) + + sys.addaudithook(hook) + syslog.openlog('python') + syslog.syslog('test') + syslog.setlogmask(syslog.LOG_DEBUG) + syslog.closelog() + # implicit open + syslog.syslog('test2') + # open with default ident + syslog.openlog(logoption=syslog.LOG_NDELAY, facility=syslog.LOG_LOCAL0) + sys.argv = None + syslog.openlog() + syslog.closelog() + if __name__ == "__main__": from test.support import suppress_msvcrt_asserts diff --git a/Lib/test/test_audit.py b/Lib/test/test_audit.py index 09b3333afe18..50f78f2a6b8a 100644 --- a/Lib/test/test_audit.py +++ b/Lib/test/test_audit.py @@ -16,6 +16,7 @@ class AuditTest(unittest.TestCase): + maxDiff = None @support.requires_subprocess() def do_test(self, *args): @@ -185,7 +186,6 @@ def test_sys_getframe(self): self.assertEqual(actual, expected) - def test_wmi_exec_query(self): import_helper.import_module("_wmi") returncode, events, stderr = self.run_python("test_wmi_exec_query") @@ -199,6 +199,29 @@ def test_wmi_exec_query(self): self.assertEqual(actual, expected) + def test_syslog(self): + syslog = import_helper.import_module("syslog") + + returncode, events, stderr = self.run_python("test_syslog") + if returncode: + self.fail(stderr) + + if support.verbose: + print('Events:', *events, sep='\n ') + + self.assertSequenceEqual( + events, + [('syslog.openlog', ' ', f'python 0 {syslog.LOG_USER}'), + ('syslog.syslog', ' ', f'{syslog.LOG_INFO} test'), + ('syslog.setlogmask', ' ', f'{syslog.LOG_DEBUG}'), + ('syslog.closelog', '', ''), + ('syslog.syslog', ' ', f'{syslog.LOG_INFO} test2'), + ('syslog.openlog', ' ', f'audit-tests.py 0 {syslog.LOG_USER}'), + ('syslog.openlog', ' ', f'audit-tests.py {syslog.LOG_NDELAY} {syslog.LOG_LOCAL0}'), + ('syslog.openlog', ' ', f'None 0 {syslog.LOG_USER}'), + ('syslog.closelog', '', '')] + ) + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_syslog.py b/Lib/test/test_syslog.py index fe09bd39f8b7..2125ec58d87e 100644 --- a/Lib/test/test_syslog.py +++ b/Lib/test/test_syslog.py @@ -1,5 +1,9 @@ -from test.support import import_helper +from test.support import import_helper, threading_helper syslog = import_helper.import_module("syslog") #skip if not supported +from test import support +import sys +import threading +import time import unittest # XXX(nnorwitz): This test sucks. I don't know of a platform independent way @@ -8,6 +12,9 @@ class Test(unittest.TestCase): + def tearDown(self): + syslog.closelog() + def test_openlog(self): syslog.openlog('python') # Issue #6697. @@ -18,22 +25,59 @@ def test_syslog(self): syslog.syslog('test message from python test_syslog') syslog.syslog(syslog.LOG_ERR, 'test error from python test_syslog') + def test_syslog_implicit_open(self): + syslog.closelog() # Make sure log is closed + syslog.syslog('test message from python test_syslog') + syslog.syslog(syslog.LOG_ERR, 'test error from python test_syslog') + def test_closelog(self): syslog.openlog('python') syslog.closelog() + syslog.closelog() # idempotent operation def test_setlogmask(self): - syslog.setlogmask(syslog.LOG_DEBUG) + mask = syslog.LOG_UPTO(syslog.LOG_WARNING) + oldmask = syslog.setlogmask(mask) + self.assertEqual(syslog.setlogmask(0), mask) + self.assertEqual(syslog.setlogmask(oldmask), mask) def test_log_mask(self): - syslog.LOG_MASK(syslog.LOG_INFO) - - def test_log_upto(self): - syslog.LOG_UPTO(syslog.LOG_INFO) + mask = syslog.LOG_UPTO(syslog.LOG_WARNING) + self.assertTrue(mask & syslog.LOG_MASK(syslog.LOG_WARNING)) + self.assertTrue(mask & syslog.LOG_MASK(syslog.LOG_ERR)) + self.assertFalse(mask & syslog.LOG_MASK(syslog.LOG_INFO)) def test_openlog_noargs(self): syslog.openlog() syslog.syslog('test message from python test_syslog') + @threading_helper.requires_working_threading() + def test_syslog_threaded(self): + start = threading.Event() + stop = False + def opener(): + start.wait(10) + i = 1 + while not stop: + syslog.openlog(f'python-test-{i}') # new string object + i += 1 + def logger(): + start.wait(10) + while not stop: + syslog.syslog('test message from python test_syslog') + + orig_si = sys.getswitchinterval() + support.setswitchinterval(1e-9) + try: + threads = [threading.Thread(target=opener)] + threads += [threading.Thread(target=logger) for k in range(10)] + with threading_helper.start_threads(threads): + start.set() + time.sleep(0.1) + stop = True + finally: + sys.setswitchinterval(orig_si) + + if __name__ == "__main__": unittest.main() diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index c409fe968f88..1593eea94a62 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -235,7 +235,7 @@ syslog_setlogmask(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "l;mask for priority", &maskpri)) return NULL; - if (PySys_Audit("syslog.setlogmask", "(O)", args ? args : Py_None) < 0) { + if (PySys_Audit("syslog.setlogmask", "l", maskpri) < 0) { return NULL; } omaskpri = setlogmask(maskpri); From webhook-mailer at python.org Fri Oct 7 13:27:22 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Fri, 07 Oct 2022 17:27:22 -0000 Subject: [Python-checkins] gh-96415: Remove `types._cell_factory` from a module namespace (#96416) Message-ID: https://github.com/python/cpython/commit/5ba4875aec2031003d7ba90fd0f06f281bdecbf9 commit: 5ba4875aec2031003d7ba90fd0f06f281bdecbf9 branch: main author: Nikita Sobolev committer: JelleZijlstra date: 2022-10-07T10:27:14-07:00 summary: gh-96415: Remove `types._cell_factory` from a module namespace (#96416) Closes #96415 files: A Misc/NEWS.d/next/Library/2022-08-30-12-32-00.gh-issue-96415.6W7ORH.rst M Lib/types.py diff --git a/Lib/types.py b/Lib/types.py index 2e73fbc45013..f8353126cb52 100644 --- a/Lib/types.py +++ b/Lib/types.py @@ -60,7 +60,7 @@ def _m(self): pass GetSetDescriptorType = type(FunctionType.__code__) MemberDescriptorType = type(FunctionType.__globals__) -del sys, _f, _g, _C, _c, _ag # Not for export +del sys, _f, _g, _C, _c, _ag, _cell_factory # Not for export # Provide a PEP 3115 compliant mechanism for class creation diff --git a/Misc/NEWS.d/next/Library/2022-08-30-12-32-00.gh-issue-96415.6W7ORH.rst b/Misc/NEWS.d/next/Library/2022-08-30-12-32-00.gh-issue-96415.6W7ORH.rst new file mode 100644 index 000000000000..0c93abf6dfcf --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-08-30-12-32-00.gh-issue-96415.6W7ORH.rst @@ -0,0 +1 @@ +Remove ``types._cell_factory`` from module namespace. From webhook-mailer at python.org Fri Oct 7 13:37:04 2022 From: webhook-mailer at python.org (ambv) Date: Fri, 07 Oct 2022 17:37:04 -0000 Subject: [Python-checkins] gh-64373: Convert `_functools` to Argument Clinic (#96640) Message-ID: https://github.com/python/cpython/commit/83cbe84dc2177fcd08b7c5822b024e9311844427 commit: 83cbe84dc2177fcd08b7c5822b024e9311844427 branch: main author: Nikita Sobolev committer: ambv date: 2022-10-07T10:36:40-07:00 summary: gh-64373: Convert `_functools` to Argument Clinic (#96640) files: A Misc/NEWS.d/next/Core and Builtins/2022-09-08-20-58-10.gh-issue-64373.AfCi36.rst A Modules/clinic/_functoolsmodule.c.h M Include/internal/pycore_global_strings.h M Include/internal/pycore_runtime_init_generated.h M Lib/test/test_functools.py M Modules/_functoolsmodule.c diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 1523eef73931..94f56fadc463 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -468,6 +468,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(modules) STRUCT_FOR_ID(mro) STRUCT_FOR_ID(msg) + STRUCT_FOR_ID(mycmp) STRUCT_FOR_ID(n) STRUCT_FOR_ID(n_arg) STRUCT_FOR_ID(n_fields) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index 32ff57b731e1..ea01fc01bbef 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -977,6 +977,7 @@ extern "C" { INIT_ID(modules), \ INIT_ID(mro), \ INIT_ID(msg), \ + INIT_ID(mycmp), \ INIT_ID(n), \ INIT_ID(n_arg), \ INIT_ID(n_fields), \ @@ -2260,6 +2261,8 @@ _PyUnicode_InitStaticStrings(void) { PyUnicode_InternInPlace(&string); string = &_Py_ID(msg); PyUnicode_InternInPlace(&string); + string = &_Py_ID(mycmp); + PyUnicode_InternInPlace(&string); string = &_Py_ID(n); PyUnicode_InternInPlace(&string); string = &_Py_ID(n_arg); @@ -6447,6 +6450,10 @@ _PyStaticObjects_CheckRefcnt(void) { _PyObject_Dump((PyObject *)&_Py_ID(msg)); Py_FatalError("immortal object has less refcnt than expected _PyObject_IMMORTAL_REFCNT"); }; + if (Py_REFCNT((PyObject *)&_Py_ID(mycmp)) < _PyObject_IMMORTAL_REFCNT) { + _PyObject_Dump((PyObject *)&_Py_ID(mycmp)); + Py_FatalError("immortal object has less refcnt than expected _PyObject_IMMORTAL_REFCNT"); + }; if (Py_REFCNT((PyObject *)&_Py_ID(n)) < _PyObject_IMMORTAL_REFCNT) { _PyObject_Dump((PyObject *)&_Py_ID(n)); Py_FatalError("immortal object has less refcnt than expected _PyObject_IMMORTAL_REFCNT"); diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py index a4b098a2a5b8..730ab1f595f2 100644 --- a/Lib/test/test_functools.py +++ b/Lib/test/test_functools.py @@ -17,6 +17,7 @@ import gc from weakref import proxy import contextlib +from inspect import Signature from test.support import import_helper from test.support import threading_helper @@ -941,6 +942,10 @@ def mycmp(x, y): self.assertRaises(TypeError, hash, k) self.assertNotIsInstance(k, collections.abc.Hashable) + def test_cmp_to_signature(self): + self.assertEqual(str(Signature.from_callable(self.cmp_to_key)), + '(mycmp)') + @unittest.skipUnless(c_functools, 'requires the C _functools module') class TestCmpToKeyC(TestCmpToKey, unittest.TestCase): @@ -1853,6 +1858,13 @@ def test_staticmethod(x): for ref in refs: self.assertIsNone(ref()) + def test_common_signatures(self): + def orig(): ... + lru = self.module.lru_cache(1)(orig) + + self.assertEqual(str(Signature.from_callable(lru.cache_info)), '()') + self.assertEqual(str(Signature.from_callable(lru.cache_clear)), '()') + @py_functools.lru_cache() def py_cached_func(x, y): diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-08-20-58-10.gh-issue-64373.AfCi36.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-08-20-58-10.gh-issue-64373.AfCi36.rst new file mode 100644 index 000000000000..e7e13cb3a00c --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-09-08-20-58-10.gh-issue-64373.AfCi36.rst @@ -0,0 +1 @@ +Convert :mod:`_functools` to argument clinic. diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c index 3abb7fd710ae..e4036e166921 100644 --- a/Modules/_functoolsmodule.c +++ b/Modules/_functoolsmodule.c @@ -7,6 +7,13 @@ #include "pycore_tuple.h" // _PyTuple_ITEMS() #include "structmember.h" // PyMemberDef +#include "clinic/_functoolsmodule.c.h" +/*[clinic input] +module _functools +class _functools._lru_cache_wrapper "PyObject *" "&lru_cache_type_spec" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=bece4053896b09c0]*/ + /* _functools module written and maintained by Hye-Shik Chang with adaptations by Raymond Hettinger @@ -58,6 +65,7 @@ get_functools_state_by_type(PyTypeObject *type) return get_functools_state(module); } +// Not converted to argument clinic, because of `*args, **kwargs` arguments. static PyObject * partial_new(PyTypeObject *type, PyObject *args, PyObject *kw) { @@ -282,6 +290,7 @@ partial_setvectorcall(partialobject *pto) } +// Not converted to argument clinic, because of `*args, **kwargs` arguments. static PyObject * partial_call(partialobject *pto, PyObject *args, PyObject *kwargs) { @@ -625,33 +634,37 @@ keyobject_richcompare(PyObject *ko, PyObject *other, int op) return answer; } +/*[clinic input] +_functools.cmp_to_key + + mycmp: object + Function that compares two objects. + +Convert a cmp= function into a key= function. +[clinic start generated code]*/ + static PyObject * -functools_cmp_to_key(PyObject *self, PyObject *args, PyObject *kwds) +_functools_cmp_to_key_impl(PyObject *module, PyObject *mycmp) +/*[clinic end generated code: output=71eaad0f4fc81f33 input=d1b76f231c0dfeb3]*/ { - PyObject *cmp; - static char *kwargs[] = {"mycmp", NULL}; keyobject *object; _functools_state *state; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:cmp_to_key", kwargs, &cmp)) - return NULL; - - state = get_functools_state(self); + state = get_functools_state(module); object = PyObject_GC_New(keyobject, state->keyobject_type); if (!object) return NULL; - Py_INCREF(cmp); - object->cmp = cmp; + Py_INCREF(mycmp); + object->cmp = mycmp; object->object = NULL; PyObject_GC_Track(object); return (PyObject *)object; } -PyDoc_STRVAR(functools_cmp_to_key_doc, -"Convert a cmp= function into a key= function."); - /* reduce (used to be a builtin) ********************************************/ +// Not converted to argument clinic, because of `args` in-place modification. +// AC will affect performance. static PyObject * functools_reduce(PyObject *self, PyObject *args) { @@ -1299,25 +1312,41 @@ lru_cache_descr_get(PyObject *self, PyObject *obj, PyObject *type) return PyMethod_New(self, obj); } +/*[clinic input] +_functools._lru_cache_wrapper.cache_info + +Report cache statistics +[clinic start generated code]*/ + static PyObject * -lru_cache_cache_info(lru_cache_object *self, PyObject *unused) +_functools__lru_cache_wrapper_cache_info_impl(PyObject *self) +/*[clinic end generated code: output=cc796a0b06dbd717 input=f05e5b6ebfe38645]*/ { - if (self->maxsize == -1) { - return PyObject_CallFunction(self->cache_info_type, "nnOn", - self->hits, self->misses, Py_None, - PyDict_GET_SIZE(self->cache)); - } - return PyObject_CallFunction(self->cache_info_type, "nnnn", - self->hits, self->misses, self->maxsize, - PyDict_GET_SIZE(self->cache)); + lru_cache_object *_self = (lru_cache_object *) self; + if (_self->maxsize == -1) { + return PyObject_CallFunction(_self->cache_info_type, "nnOn", + _self->hits, _self->misses, Py_None, + PyDict_GET_SIZE(_self->cache)); + } + return PyObject_CallFunction(_self->cache_info_type, "nnnn", + _self->hits, _self->misses, _self->maxsize, + PyDict_GET_SIZE(_self->cache)); } +/*[clinic input] +_functools._lru_cache_wrapper.cache_clear + +Clear the cache and cache statistics +[clinic start generated code]*/ + static PyObject * -lru_cache_cache_clear(lru_cache_object *self, PyObject *unused) +_functools__lru_cache_wrapper_cache_clear_impl(PyObject *self) +/*[clinic end generated code: output=58423b35efc3e381 input=6ca59dba09b12584]*/ { - lru_list_elem *list = lru_cache_unlink_list(self); - self->hits = self->misses = 0; - PyDict_Clear(self->cache); + lru_cache_object *_self = (lru_cache_object *) self; + lru_list_elem *list = lru_cache_unlink_list(_self); + _self->hits = _self->misses = 0; + PyDict_Clear(_self->cache); lru_cache_clear_list(list); Py_RETURN_NONE; } @@ -1381,8 +1410,8 @@ cache_info_type: namedtuple class with the fields:\n\ ); static PyMethodDef lru_cache_methods[] = { - {"cache_info", (PyCFunction)lru_cache_cache_info, METH_NOARGS}, - {"cache_clear", (PyCFunction)lru_cache_cache_clear, METH_NOARGS}, + _FUNCTOOLS__LRU_CACHE_WRAPPER_CACHE_INFO_METHODDEF + _FUNCTOOLS__LRU_CACHE_WRAPPER_CACHE_CLEAR_METHODDEF {"__reduce__", (PyCFunction)lru_cache_reduce, METH_NOARGS}, {"__copy__", (PyCFunction)lru_cache_copy, METH_VARARGS}, {"__deepcopy__", (PyCFunction)lru_cache_deepcopy, METH_VARARGS}, @@ -1432,8 +1461,7 @@ PyDoc_STRVAR(_functools_doc, static PyMethodDef _functools_methods[] = { {"reduce", functools_reduce, METH_VARARGS, functools_reduce_doc}, - {"cmp_to_key", _PyCFunction_CAST(functools_cmp_to_key), - METH_VARARGS | METH_KEYWORDS, functools_cmp_to_key_doc}, + _FUNCTOOLS_CMP_TO_KEY_METHODDEF {NULL, NULL} /* sentinel */ }; diff --git a/Modules/clinic/_functoolsmodule.c.h b/Modules/clinic/_functoolsmodule.c.h new file mode 100644 index 000000000000..9c79e6430413 --- /dev/null +++ b/Modules/clinic/_functoolsmodule.c.h @@ -0,0 +1,104 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +# include "pycore_gc.h" // PyGC_Head +# include "pycore_runtime.h" // _Py_ID() +#endif + + +PyDoc_STRVAR(_functools_cmp_to_key__doc__, +"cmp_to_key($module, /, mycmp)\n" +"--\n" +"\n" +"Convert a cmp= function into a key= function.\n" +"\n" +" mycmp\n" +" Function that compares two objects."); + +#define _FUNCTOOLS_CMP_TO_KEY_METHODDEF \ + {"cmp_to_key", _PyCFunction_CAST(_functools_cmp_to_key), METH_FASTCALL|METH_KEYWORDS, _functools_cmp_to_key__doc__}, + +static PyObject * +_functools_cmp_to_key_impl(PyObject *module, PyObject *mycmp); + +static PyObject * +_functools_cmp_to_key(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(mycmp), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"mycmp", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "cmp_to_key", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *mycmp; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + mycmp = args[0]; + return_value = _functools_cmp_to_key_impl(module, mycmp); + +exit: + return return_value; +} + +PyDoc_STRVAR(_functools__lru_cache_wrapper_cache_info__doc__, +"cache_info($self, /)\n" +"--\n" +"\n" +"Report cache statistics"); + +#define _FUNCTOOLS__LRU_CACHE_WRAPPER_CACHE_INFO_METHODDEF \ + {"cache_info", (PyCFunction)_functools__lru_cache_wrapper_cache_info, METH_NOARGS, _functools__lru_cache_wrapper_cache_info__doc__}, + +static PyObject * +_functools__lru_cache_wrapper_cache_info_impl(PyObject *self); + +static PyObject * +_functools__lru_cache_wrapper_cache_info(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _functools__lru_cache_wrapper_cache_info_impl(self); +} + +PyDoc_STRVAR(_functools__lru_cache_wrapper_cache_clear__doc__, +"cache_clear($self, /)\n" +"--\n" +"\n" +"Clear the cache and cache statistics"); + +#define _FUNCTOOLS__LRU_CACHE_WRAPPER_CACHE_CLEAR_METHODDEF \ + {"cache_clear", (PyCFunction)_functools__lru_cache_wrapper_cache_clear, METH_NOARGS, _functools__lru_cache_wrapper_cache_clear__doc__}, + +static PyObject * +_functools__lru_cache_wrapper_cache_clear_impl(PyObject *self); + +static PyObject * +_functools__lru_cache_wrapper_cache_clear(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _functools__lru_cache_wrapper_cache_clear_impl(self); +} +/*[clinic end generated code: output=7e7f3bcf9ed61f23 input=a9049054013a1b77]*/ From webhook-mailer at python.org Fri Oct 7 13:42:47 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Fri, 07 Oct 2022 17:42:47 -0000 Subject: [Python-checkins] Fix a mistake in isSet() deprecated message doc (#95720) Message-ID: https://github.com/python/cpython/commit/7f685683f8e23084aa8b05f0c186f5c962f1db29 commit: 7f685683f8e23084aa8b05f0c186f5c962f1db29 branch: main author: Marc Monfort committer: JelleZijlstra date: 2022-10-07T10:42:35-07:00 summary: Fix a mistake in isSet() deprecated message doc (#95720) files: From webhook-mailer at python.org Fri Oct 7 13:53:16 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Fri, 07 Oct 2022 17:53:16 -0000 Subject: [Python-checkins] Make _symtable_entry.ste_type's comment consistent wit _Py_block_ty (#92414) Message-ID: https://github.com/python/cpython/commit/24a4b341586be12569e3804b5f1356e745d1f55f commit: 24a4b341586be12569e3804b5f1356e745d1f55f branch: main author: zikcheng committer: JelleZijlstra date: 2022-10-07T10:53:07-07:00 summary: Make _symtable_entry.ste_type's comment consistent wit _Py_block_ty (#92414) _Py_block_ty defines four types of block, FunctionBlock, ClassBlock, ModuleBlock and AnnotationBlock. But _symtable_entry.ste_type only comments three of them, I think it's better both sides are consistent. files: M Include/internal/pycore_symtable.h diff --git a/Include/internal/pycore_symtable.h b/Include/internal/pycore_symtable.h index 2d64aba22ff9..8532646ce7d9 100644 --- a/Include/internal/pycore_symtable.h +++ b/Include/internal/pycore_symtable.h @@ -49,7 +49,7 @@ typedef struct _symtable_entry { PyObject *ste_varnames; /* list of function parameters */ PyObject *ste_children; /* list of child blocks */ PyObject *ste_directives;/* locations of global and nonlocal statements */ - _Py_block_ty ste_type; /* module, class or function */ + _Py_block_ty ste_type; /* module, class, function or annotation */ int ste_nested; /* true if block is nested */ unsigned ste_free : 1; /* true if block has free variables */ unsigned ste_child_free : 1; /* true if a child block has free vars, From webhook-mailer at python.org Fri Oct 7 13:54:59 2022 From: webhook-mailer at python.org (miss-islington) Date: Fri, 07 Oct 2022 17:54:59 -0000 Subject: [Python-checkins] Add note on capture_output arg to subprocess.run() docstring (GH-98012) Message-ID: https://github.com/python/cpython/commit/da986c68c913e8902695704c748fb5b14d47f1f8 commit: da986c68c913e8902695704c748fb5b14d47f1f8 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-07T10:54:54-07:00 summary: Add note on capture_output arg to subprocess.run() docstring (GH-98012) add note on capture_output arg to the docstring (cherry picked from commit 80b3e32d6242c27094dd04c4c3d0c3d3b2889a01) Co-authored-by: andrei kulakov files: M Lib/subprocess.py diff --git a/Lib/subprocess.py b/Lib/subprocess.py index e5d7f0981861..ffe9170b68b2 100644 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -464,7 +464,8 @@ def run(*popenargs, The returned instance will have attributes args, returncode, stdout and stderr. By default, stdout and stderr are not captured, and those attributes - will be None. Pass stdout=PIPE and/or stderr=PIPE in order to capture them. + will be None. Pass stdout=PIPE and/or stderr=PIPE in order to capture them, + or pass capture_output=True to capture both. If check is True and the exit code was non-zero, it raises a CalledProcessError. The CalledProcessError object will have the return code From webhook-mailer at python.org Fri Oct 7 13:55:33 2022 From: webhook-mailer at python.org (miss-islington) Date: Fri, 07 Oct 2022 17:55:33 -0000 Subject: [Python-checkins] Add note on capture_output arg to subprocess.run() docstring (GH-98012) Message-ID: https://github.com/python/cpython/commit/69029bd2ca454b1b49d1974da2e47567833c55a5 commit: 69029bd2ca454b1b49d1974da2e47567833c55a5 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-07T10:55:26-07:00 summary: Add note on capture_output arg to subprocess.run() docstring (GH-98012) add note on capture_output arg to the docstring (cherry picked from commit 80b3e32d6242c27094dd04c4c3d0c3d3b2889a01) Co-authored-by: andrei kulakov files: M Lib/subprocess.py diff --git a/Lib/subprocess.py b/Lib/subprocess.py index 760b93b47ebb..9cadd1bf8e62 100644 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -509,7 +509,8 @@ def run(*popenargs, The returned instance will have attributes args, returncode, stdout and stderr. By default, stdout and stderr are not captured, and those attributes - will be None. Pass stdout=PIPE and/or stderr=PIPE in order to capture them. + will be None. Pass stdout=PIPE and/or stderr=PIPE in order to capture them, + or pass capture_output=True to capture both. If check is True and the exit code was non-zero, it raises a CalledProcessError. The CalledProcessError object will have the return code From webhook-mailer at python.org Fri Oct 7 13:57:56 2022 From: webhook-mailer at python.org (ambv) Date: Fri, 07 Oct 2022 17:57:56 -0000 Subject: [Python-checkins] gh-97669: Move difflib examples to Doc/includes/ (#97964) Message-ID: https://github.com/python/cpython/commit/002252c4ade6a5aeb7a397776dbe3c1de0740e84 commit: 002252c4ade6a5aeb7a397776dbe3c1de0740e84 branch: main author: Victor Stinner committer: ambv date: 2022-10-07T10:57:48-07:00 summary: gh-97669: Move difflib examples to Doc/includes/ (#97964) Remove diff.py and ndiff.py scripts of Tools/scripts/: move them to Doc/includes/. * diff.py and ndiff.py files are no longer executable. Remove also their shebang ("#!/usr/bin/env python3"). * Remove the -profile command from ndiff.py to simply the code. * Remove ndiff.py copyright and history command. The Python documentation examples are distributed under the "Zero Clause BSD License". files: A Doc/includes/diff.py A Doc/includes/ndiff.py D Tools/scripts/diff.py D Tools/scripts/ndiff.py M Doc/library/difflib.rst diff --git a/Tools/scripts/diff.py b/Doc/includes/diff.py old mode 100755 new mode 100644 similarity index 98% rename from Tools/scripts/diff.py rename to Doc/includes/diff.py index 96199b85116d..001619f5f83f --- a/Tools/scripts/diff.py +++ b/Doc/includes/diff.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 """ Command line interface to difflib.py providing diffs in four formats: * ndiff: lists every line and highlights interline changes. diff --git a/Tools/scripts/ndiff.py b/Doc/includes/ndiff.py old mode 100755 new mode 100644 similarity index 80% rename from Tools/scripts/ndiff.py rename to Doc/includes/ndiff.py index c6d09b8f242f..32c251bce912 --- a/Tools/scripts/ndiff.py +++ b/Doc/includes/ndiff.py @@ -1,16 +1,3 @@ -#! /usr/bin/env python3 - -# Module ndiff version 1.7.0 -# Released to the public domain 08-Dec-2000, -# by Tim Peters (tim.one at home.com). - -# Provided as-is; use at your own risk; no warranty; no promises; enjoy! - -# ndiff.py is now simply a front-end to the difflib.ndiff() function. -# Originally, it contained the difflib.SequenceMatcher class as well. -# This completes the raiding of reusable code from this formerly -# self-contained script. - """ndiff [-q] file1 file2 or ndiff (-r1 | -r2) < ndiff_output > file1_or_file2 @@ -121,13 +108,4 @@ def restore(which): sys.stdout.writelines(restored) if __name__ == '__main__': - args = sys.argv[1:] - if "-profile" in args: - import profile, pstats - args.remove("-profile") - statf = "ndiff.pro" - profile.run("main(args)", statf) - stats = pstats.Stats(statf) - stats.strip_dirs().sort_stats('time').print_stats() - else: - main(args) + main(sys.argv[1:]) diff --git a/Doc/library/difflib.rst b/Doc/library/difflib.rst index c5a279688a44..5ee1f4a02c68 100644 --- a/Doc/library/difflib.rst +++ b/Doc/library/difflib.rst @@ -145,8 +145,6 @@ diffs. For comparing directories and files, see also, the :mod:`filecmp` module. The arguments for this method are the same as those for the :meth:`make_file` method. - :file:`Tools/scripts/diff.py` is a command-line front-end to this class and - contains a good example of its use. .. function:: context_diff(a, b, fromfile='', tofile='', fromfiledate='', tofiledate='', n=3, lineterm='\n') @@ -240,8 +238,6 @@ diffs. For comparing directories and files, see also, the :mod:`filecmp` module. function :func:`IS_CHARACTER_JUNK`, which filters out whitespace characters (a blank or tab; it's a bad idea to include newline in this!). - :file:`Tools/scripts/ndiff.py` is a command-line front-end to this function. - >>> diff = ndiff('one\ntwo\nthree\n'.splitlines(keepends=True), ... 'ore\ntree\nemu\n'.splitlines(keepends=True)) >>> print(''.join(diff), end="") @@ -759,7 +755,12 @@ A command-line interface to difflib ----------------------------------- This example shows how to use difflib to create a ``diff``-like utility. -It is also contained in the Python source distribution, as -:file:`Tools/scripts/diff.py`. -.. literalinclude:: ../../Tools/scripts/diff.py +.. literalinclude:: ../includes/diff.py + +ndiff example +------------- + +This example shows how to use :func:`difflib.ndiff`. + +.. literalinclude:: ../includes/ndiff.py From webhook-mailer at python.org Fri Oct 7 14:06:32 2022 From: webhook-mailer at python.org (ambv) Date: Fri, 07 Oct 2022 18:06:32 -0000 Subject: [Python-checkins] gh-97955: Migrate `zoneinfo` to Argument Clinic (#97958) Message-ID: https://github.com/python/cpython/commit/24a664589448d99a62386d5afa180cfb52733a7e commit: 24a664589448d99a62386d5afa180cfb52733a7e branch: main author: Nikita Sobolev committer: ambv date: 2022-10-07T11:06:23-07:00 summary: gh-97955: Migrate `zoneinfo` to Argument Clinic (#97958) files: A Misc/NEWS.d/next/Core and Builtins/2022-10-06-14-14-28.gh-issue-97955.Nq5VXD.rst A Modules/clinic/_zoneinfo.c.h M Include/internal/pycore_global_strings.h M Include/internal/pycore_runtime_init_generated.h M Lib/test/test_zoneinfo/test_zoneinfo.py M Modules/_zoneinfo.c diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 94f56fadc463..2966b60e0cd8 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -494,6 +494,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(offset_src) STRUCT_FOR_ID(on_type_read) STRUCT_FOR_ID(onceregistry) + STRUCT_FOR_ID(only_keys) STRUCT_FOR_ID(oparg) STRUCT_FOR_ID(opcode) STRUCT_FOR_ID(open) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index ea01fc01bbef..617582f96e33 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -1003,6 +1003,7 @@ extern "C" { INIT_ID(offset_src), \ INIT_ID(on_type_read), \ INIT_ID(onceregistry), \ + INIT_ID(only_keys), \ INIT_ID(oparg), \ INIT_ID(opcode), \ INIT_ID(open), \ @@ -2313,6 +2314,8 @@ _PyUnicode_InitStaticStrings(void) { PyUnicode_InternInPlace(&string); string = &_Py_ID(onceregistry); PyUnicode_InternInPlace(&string); + string = &_Py_ID(only_keys); + PyUnicode_InternInPlace(&string); string = &_Py_ID(oparg); PyUnicode_InternInPlace(&string); string = &_Py_ID(opcode); @@ -6554,6 +6557,10 @@ _PyStaticObjects_CheckRefcnt(void) { _PyObject_Dump((PyObject *)&_Py_ID(onceregistry)); Py_FatalError("immortal object has less refcnt than expected _PyObject_IMMORTAL_REFCNT"); }; + if (Py_REFCNT((PyObject *)&_Py_ID(only_keys)) < _PyObject_IMMORTAL_REFCNT) { + _PyObject_Dump((PyObject *)&_Py_ID(only_keys)); + Py_FatalError("immortal object has less refcnt than expected _PyObject_IMMORTAL_REFCNT"); + }; if (Py_REFCNT((PyObject *)&_Py_ID(oparg)) < _PyObject_IMMORTAL_REFCNT) { _PyObject_Dump((PyObject *)&_Py_ID(oparg)); Py_FatalError("immortal object has less refcnt than expected _PyObject_IMMORTAL_REFCNT"); diff --git a/Lib/test/test_zoneinfo/test_zoneinfo.py b/Lib/test/test_zoneinfo/test_zoneinfo.py index a2172f3ac21d..fd0e3bc032ec 100644 --- a/Lib/test/test_zoneinfo/test_zoneinfo.py +++ b/Lib/test/test_zoneinfo/test_zoneinfo.py @@ -404,6 +404,19 @@ def test_time_fixed_offset(self): class CZoneInfoTest(ZoneInfoTest): module = c_zoneinfo + def test_signatures(self): + """Ensure that C module has valid method signatures.""" + import inspect + + must_have_signatures = ( + self.klass.clear_cache, + self.klass.no_cache, + self.klass.from_file, + ) + for method in must_have_signatures: + with self.subTest(method=method): + inspect.Signature.from_callable(method) + def test_fold_mutate(self): """Test that fold isn't mutated when no change is necessary. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-06-14-14-28.gh-issue-97955.Nq5VXD.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-06-14-14-28.gh-issue-97955.Nq5VXD.rst new file mode 100644 index 000000000000..e21794df4f18 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-06-14-14-28.gh-issue-97955.Nq5VXD.rst @@ -0,0 +1 @@ +Migrate :mod:`zoneinfo` to Argument Clinic. diff --git a/Modules/_zoneinfo.c b/Modules/_zoneinfo.c index 207340adec15..36b25bf3c054 100644 --- a/Modules/_zoneinfo.c +++ b/Modules/_zoneinfo.c @@ -12,6 +12,13 @@ #include "datetime.h" +#include "clinic/_zoneinfo.c.h" +/*[clinic input] +module zoneinfo +class zoneinfo.ZoneInfo "PyObject *" "PyTypeObject *" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=d12c73c0eef36df8]*/ + // Imports static PyObject *io_open = NULL; static PyObject *_tzpath_find_tzfile = NULL; @@ -338,20 +345,25 @@ zoneinfo_dealloc(PyObject *obj_self) Py_TYPE(self)->tp_free((PyObject *)self); } +/*[clinic input] + at classmethod +zoneinfo.ZoneInfo.from_file + + file_obj: object + / + key: object = None + +Create a ZoneInfo file from a file object. +[clinic start generated code]*/ + static PyObject * -zoneinfo_from_file(PyTypeObject *type, PyObject *args, PyObject *kwargs) +zoneinfo_ZoneInfo_from_file_impl(PyTypeObject *type, PyObject *file_obj, + PyObject *key) +/*[clinic end generated code: output=68ed2022404ae5be input=ccfe73708133d2e4]*/ { - PyObject *file_obj = NULL; PyObject *file_repr = NULL; - PyObject *key = Py_None; PyZoneInfo_ZoneInfo *self = NULL; - static char *kwlist[] = {"", "key", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O", kwlist, &file_obj, - &key)) { - return NULL; - } - PyObject *obj_self = (PyObject *)(type->tp_alloc(type, 0)); self = (PyZoneInfo_ZoneInfo *)obj_self; if (self == NULL) { @@ -379,16 +391,20 @@ zoneinfo_from_file(PyTypeObject *type, PyObject *args, PyObject *kwargs) return NULL; } +/*[clinic input] + at classmethod +zoneinfo.ZoneInfo.no_cache + + key: object + +Get a new instance of ZoneInfo, bypassing the cache. +[clinic start generated code]*/ + static PyObject * -zoneinfo_no_cache(PyTypeObject *cls, PyObject *args, PyObject *kwargs) +zoneinfo_ZoneInfo_no_cache_impl(PyTypeObject *type, PyObject *key) +/*[clinic end generated code: output=751c6894ad66f91b input=bb24afd84a80ba46]*/ { - static char *kwlist[] = {"key", NULL}; - PyObject *key = NULL; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwlist, &key)) { - return NULL; - } - - PyObject *out = zoneinfo_new_instance(cls, key); + PyObject *out = zoneinfo_new_instance(type, key); if (out != NULL) { ((PyZoneInfo_ZoneInfo *)out)->source = SOURCE_NOCACHE; } @@ -396,18 +412,20 @@ zoneinfo_no_cache(PyTypeObject *cls, PyObject *args, PyObject *kwargs) return out; } -static PyObject * -zoneinfo_clear_cache(PyObject *cls, PyObject *args, PyObject *kwargs) -{ - PyObject *only_keys = NULL; - static char *kwlist[] = {"only_keys", NULL}; +/*[clinic input] + at classmethod +zoneinfo.ZoneInfo.clear_cache - if (!(PyArg_ParseTupleAndKeywords(args, kwargs, "|$O", kwlist, - &only_keys))) { - return NULL; - } + * + only_keys: object = None - PyTypeObject *type = (PyTypeObject *)cls; +Clear the ZoneInfo cache. +[clinic start generated code]*/ + +static PyObject * +zoneinfo_ZoneInfo_clear_cache_impl(PyTypeObject *type, PyObject *only_keys) +/*[clinic end generated code: output=eec0a3276f07bd90 input=8cff0182a95f295b]*/ +{ PyObject *weak_cache = get_weak_cache(type); if (only_keys == NULL || only_keys == Py_None) { @@ -2545,15 +2563,9 @@ zoneinfo_init_subclass(PyTypeObject *cls, PyObject *args, PyObject **kwargs) ///// // Specify the ZoneInfo type static PyMethodDef zoneinfo_methods[] = { - {"clear_cache", (PyCFunction)(void (*)(void))zoneinfo_clear_cache, - METH_VARARGS | METH_KEYWORDS | METH_CLASS, - PyDoc_STR("Clear the ZoneInfo cache.")}, - {"no_cache", (PyCFunction)(void (*)(void))zoneinfo_no_cache, - METH_VARARGS | METH_KEYWORDS | METH_CLASS, - PyDoc_STR("Get a new instance of ZoneInfo, bypassing the cache.")}, - {"from_file", (PyCFunction)(void (*)(void))zoneinfo_from_file, - METH_VARARGS | METH_KEYWORDS | METH_CLASS, - PyDoc_STR("Create a ZoneInfo file from a file object.")}, + ZONEINFO_ZONEINFO_CLEAR_CACHE_METHODDEF + ZONEINFO_ZONEINFO_NO_CACHE_METHODDEF + ZONEINFO_ZONEINFO_FROM_FILE_METHODDEF {"utcoffset", (PyCFunction)zoneinfo_utcoffset, METH_O, PyDoc_STR("Retrieve a timedelta representing the UTC offset in a zone at " "the given datetime.")}, diff --git a/Modules/clinic/_zoneinfo.c.h b/Modules/clinic/_zoneinfo.c.h new file mode 100644 index 000000000000..78fcbfa9411b --- /dev/null +++ b/Modules/clinic/_zoneinfo.c.h @@ -0,0 +1,188 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +# include "pycore_gc.h" // PyGC_Head +# include "pycore_runtime.h" // _Py_ID() +#endif + + +PyDoc_STRVAR(zoneinfo_ZoneInfo_from_file__doc__, +"from_file($type, file_obj, /, key=None)\n" +"--\n" +"\n" +"Create a ZoneInfo file from a file object."); + +#define ZONEINFO_ZONEINFO_FROM_FILE_METHODDEF \ + {"from_file", _PyCFunction_CAST(zoneinfo_ZoneInfo_from_file), METH_FASTCALL|METH_KEYWORDS|METH_CLASS, zoneinfo_ZoneInfo_from_file__doc__}, + +static PyObject * +zoneinfo_ZoneInfo_from_file_impl(PyTypeObject *type, PyObject *file_obj, + PyObject *key); + +static PyObject * +zoneinfo_ZoneInfo_from_file(PyTypeObject *type, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(key), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"", "key", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "from_file", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; + PyObject *file_obj; + PyObject *key = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 2, 0, argsbuf); + if (!args) { + goto exit; + } + file_obj = args[0]; + if (!noptargs) { + goto skip_optional_pos; + } + key = args[1]; +skip_optional_pos: + return_value = zoneinfo_ZoneInfo_from_file_impl(type, file_obj, key); + +exit: + return return_value; +} + +PyDoc_STRVAR(zoneinfo_ZoneInfo_no_cache__doc__, +"no_cache($type, /, key)\n" +"--\n" +"\n" +"Get a new instance of ZoneInfo, bypassing the cache."); + +#define ZONEINFO_ZONEINFO_NO_CACHE_METHODDEF \ + {"no_cache", _PyCFunction_CAST(zoneinfo_ZoneInfo_no_cache), METH_FASTCALL|METH_KEYWORDS|METH_CLASS, zoneinfo_ZoneInfo_no_cache__doc__}, + +static PyObject * +zoneinfo_ZoneInfo_no_cache_impl(PyTypeObject *type, PyObject *key); + +static PyObject * +zoneinfo_ZoneInfo_no_cache(PyTypeObject *type, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(key), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"key", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "no_cache", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *key; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + key = args[0]; + return_value = zoneinfo_ZoneInfo_no_cache_impl(type, key); + +exit: + return return_value; +} + +PyDoc_STRVAR(zoneinfo_ZoneInfo_clear_cache__doc__, +"clear_cache($type, /, *, only_keys=None)\n" +"--\n" +"\n" +"Clear the ZoneInfo cache."); + +#define ZONEINFO_ZONEINFO_CLEAR_CACHE_METHODDEF \ + {"clear_cache", _PyCFunction_CAST(zoneinfo_ZoneInfo_clear_cache), METH_FASTCALL|METH_KEYWORDS|METH_CLASS, zoneinfo_ZoneInfo_clear_cache__doc__}, + +static PyObject * +zoneinfo_ZoneInfo_clear_cache_impl(PyTypeObject *type, PyObject *only_keys); + +static PyObject * +zoneinfo_ZoneInfo_clear_cache(PyTypeObject *type, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(only_keys), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"only_keys", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "clear_cache", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *only_keys = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_kwonly; + } + only_keys = args[0]; +skip_optional_kwonly: + return_value = zoneinfo_ZoneInfo_clear_cache_impl(type, only_keys); + +exit: + return return_value; +} +/*[clinic end generated code: output=d2da73ef66146b83 input=a9049054013a1b77]*/ From webhook-mailer at python.org Fri Oct 7 14:12:17 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Fri, 07 Oct 2022 18:12:17 -0000 Subject: [Python-checkins] gh-64921: Clarify wording for open()'s newline arg (#96171) Message-ID: https://github.com/python/cpython/commit/4a74e6ab3885e7906cc5e0b15addc7779bc76249 commit: 4a74e6ab3885e7906cc5e0b15addc7779bc76249 branch: main author: Stanley <46876382+slateny at users.noreply.github.com> committer: JelleZijlstra date: 2022-10-07T11:12:08-07:00 summary: gh-64921: Clarify wording for open()'s newline arg (#96171) files: M Doc/library/functions.rst diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 26ee302d2eab..93c9f4ad2bc2 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -1254,8 +1254,8 @@ are always available. They are listed here in alphabetical order. .. _open-newline-parameter: - *newline* controls how :term:`universal newlines` mode works (it only - applies to text mode). It can be ``None``, ``''``, ``'\n'``, ``'\r'``, and + *newline* determines how to parse newline characters from the stream. + It can be ``None``, ``''``, ``'\n'``, ``'\r'``, and ``'\r\n'``. It works as follows: * When reading input from the stream, if *newline* is ``None``, universal From webhook-mailer at python.org Fri Oct 7 14:15:42 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Fri, 07 Oct 2022 18:15:42 -0000 Subject: [Python-checkins] gh-65496: Correct wording on csv's skipinitialspace argument (#96170) Message-ID: https://github.com/python/cpython/commit/676d8ef3806758bcd1d3fd84a746c8a9b64480d0 commit: 676d8ef3806758bcd1d3fd84a746c8a9b64480d0 branch: main author: Stanley <46876382+slateny at users.noreply.github.com> committer: JelleZijlstra date: 2022-10-07T11:15:34-07:00 summary: gh-65496: Correct wording on csv's skipinitialspace argument (#96170) files: M Doc/library/csv.rst M Lib/test/test_csv.py M Modules/_csv.c diff --git a/Doc/library/csv.rst b/Doc/library/csv.rst index 0cab95e1500a..41f11505aa10 100644 --- a/Doc/library/csv.rst +++ b/Doc/library/csv.rst @@ -420,7 +420,7 @@ Dialects support the following attributes: .. attribute:: Dialect.skipinitialspace - When :const:`True`, whitespace immediately following the *delimiter* is ignored. + When :const:`True`, spaces immediately following the *delimiter* are ignored. The default is :const:`False`. diff --git a/Lib/test/test_csv.py b/Lib/test/test_csv.py index a2b00430c7dd..d64bff13a44e 100644 --- a/Lib/test/test_csv.py +++ b/Lib/test/test_csv.py @@ -362,6 +362,11 @@ def test_read_quoting(self): self._read_test(['1,@,3,@,5'], [['1', ',3,', '5']], quotechar='@') self._read_test(['1,\0,3,\0,5'], [['1', ',3,', '5']], quotechar='\0') + def test_read_skipinitialspace(self): + self._read_test(['no space, space, spaces,\ttab'], + [['no space', 'space', 'spaces', '\ttab']], + skipinitialspace=True) + def test_read_bigfield(self): # This exercises the buffer realloc functionality and field size # limits. diff --git a/Modules/_csv.c b/Modules/_csv.c index d34d0a1296ae..25bf86f78e8f 100644 --- a/Modules/_csv.c +++ b/Modules/_csv.c @@ -704,7 +704,7 @@ parse_process_char(ReaderObj *self, _csvstate *module_state, Py_UCS4 c) self->state = ESCAPED_CHAR; } else if (c == ' ' && dialect->skipinitialspace) - /* ignore space at start of field */ + /* ignore spaces at start of field */ ; else if (c == dialect->delimiter) { /* save empty field */ @@ -1647,9 +1647,9 @@ PyDoc_STRVAR(csv_module_doc, " quoting character. It defaults to '\"'.\n" " * delimiter - specifies a one-character string to use as the\n" " field separator. It defaults to ','.\n" -" * skipinitialspace - specifies how to interpret whitespace which\n" -" immediately follows a delimiter. It defaults to False, which\n" -" means that whitespace immediately following a delimiter is part\n" +" * skipinitialspace - specifies how to interpret spaces which\n" +" immediately follow a delimiter. It defaults to False, which\n" +" means that spaces immediately following a delimiter is part\n" " of the following field.\n" " * lineterminator - specifies the character sequence which should\n" " terminate rows.\n" From webhook-mailer at python.org Fri Oct 7 14:21:07 2022 From: webhook-mailer at python.org (miss-islington) Date: Fri, 07 Oct 2022 18:21:07 -0000 Subject: [Python-checkins] gh-64921: Clarify wording for open()'s newline arg (GH-96171) Message-ID: https://github.com/python/cpython/commit/3dc8eb41bcd2eda2704037886172a35e0839b892 commit: 3dc8eb41bcd2eda2704037886172a35e0839b892 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-07T11:21:01-07:00 summary: gh-64921: Clarify wording for open()'s newline arg (GH-96171) (cherry picked from commit 4a74e6ab3885e7906cc5e0b15addc7779bc76249) Co-authored-by: Stanley <46876382+slateny at users.noreply.github.com> files: M Doc/library/functions.rst diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 26ee302d2eab..93c9f4ad2bc2 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -1254,8 +1254,8 @@ are always available. They are listed here in alphabetical order. .. _open-newline-parameter: - *newline* controls how :term:`universal newlines` mode works (it only - applies to text mode). It can be ``None``, ``''``, ``'\n'``, ``'\r'``, and + *newline* determines how to parse newline characters from the stream. + It can be ``None``, ``''``, ``'\n'``, ``'\r'``, and ``'\r\n'``. It works as follows: * When reading input from the stream, if *newline* is ``None``, universal From webhook-mailer at python.org Fri Oct 7 14:21:49 2022 From: webhook-mailer at python.org (miss-islington) Date: Fri, 07 Oct 2022 18:21:49 -0000 Subject: [Python-checkins] gh-64921: Clarify wording for open()'s newline arg (GH-96171) Message-ID: https://github.com/python/cpython/commit/5054ae23ce9e5b6e43d9da4d9a4e3ed7fd9ab8e1 commit: 5054ae23ce9e5b6e43d9da4d9a4e3ed7fd9ab8e1 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-07T11:21:44-07:00 summary: gh-64921: Clarify wording for open()'s newline arg (GH-96171) (cherry picked from commit 4a74e6ab3885e7906cc5e0b15addc7779bc76249) Co-authored-by: Stanley <46876382+slateny at users.noreply.github.com> files: M Doc/library/functions.rst diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index d84977fd860d..86b88c0c552c 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -1244,8 +1244,8 @@ are always available. They are listed here in alphabetical order. .. _open-newline-parameter: - *newline* controls how :term:`universal newlines` mode works (it only - applies to text mode). It can be ``None``, ``''``, ``'\n'``, ``'\r'``, and + *newline* determines how to parse newline characters from the stream. + It can be ``None``, ``''``, ``'\n'``, ``'\r'``, and ``'\r\n'``. It works as follows: * When reading input from the stream, if *newline* is ``None``, universal From webhook-mailer at python.org Fri Oct 7 14:23:15 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Fri, 07 Oct 2022 18:23:15 -0000 Subject: [Python-checkins] GH-96073: Fix wild replacement in inspect.formatannotation (#96074) Message-ID: https://github.com/python/cpython/commit/d5fea01d9d439b1638cd8e5db19c33909841d86f commit: d5fea01d9d439b1638cd8e5db19c33909841d86f branch: main author: Anh71me committer: JelleZijlstra date: 2022-10-07T11:23:06-07:00 summary: GH-96073: Fix wild replacement in inspect.formatannotation (#96074) Co-authored-by: Jelle Zijlstra files: A Lib/test/typinganndata/__init__.py A Lib/test/typinganndata/ann_module9.py A Misc/NEWS.d/next/Library/2022-08-29-12-35-28.gh-issue-96073.WaGstf.rst M Lib/inspect.py M Lib/test/test_inspect.py diff --git a/Lib/inspect.py b/Lib/inspect.py index 8a107a894909..585875a30c35 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -1433,7 +1433,10 @@ def getargvalues(frame): def formatannotation(annotation, base_module=None): if getattr(annotation, '__module__', None) == 'typing': - return repr(annotation).replace('typing.', '') + def repl(match): + text = match.group() + return text.removeprefix('typing.') + return re.sub(r'[\w\.]+', repl, repr(annotation)) if isinstance(annotation, types.GenericAlias): return str(annotation) if isinstance(annotation, type): diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index 710b609ce550..61fed323dcea 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -1421,6 +1421,13 @@ def wrapper(a, b): self.assertEqual(inspect.get_annotations(isa.MyClassWithLocalAnnotations, eval_str=True), {'x': int}) +class TestFormatAnnotation(unittest.TestCase): + def test_typing_replacement(self): + from test.typinganndata.ann_module9 import ann, ann1 + self.assertEqual(inspect.formatannotation(ann), 'Union[List[str], int]') + self.assertEqual(inspect.formatannotation(ann1), 'Union[List[testModule.typing.A], int]') + + class TestIsDataDescriptor(unittest.TestCase): def test_custom_descriptors(self): diff --git a/Lib/test/typinganndata/__init__.py b/Lib/test/typinganndata/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/Lib/test/typinganndata/ann_module9.py b/Lib/test/typinganndata/ann_module9.py new file mode 100644 index 000000000000..952217393e1f --- /dev/null +++ b/Lib/test/typinganndata/ann_module9.py @@ -0,0 +1,14 @@ +# Test ``inspect.formatannotation`` +# https://github.com/python/cpython/issues/96073 + +from typing import Union, List + +ann = Union[List[str], int] + +# mock typing._type_repr behaviour +class A: ... + +A.__module__ = 'testModule.typing' +A.__qualname__ = 'A' + +ann1 = Union[List[A], int] diff --git a/Misc/NEWS.d/next/Library/2022-08-29-12-35-28.gh-issue-96073.WaGstf.rst b/Misc/NEWS.d/next/Library/2022-08-29-12-35-28.gh-issue-96073.WaGstf.rst new file mode 100644 index 000000000000..0e6dd8d360cb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-08-29-12-35-28.gh-issue-96073.WaGstf.rst @@ -0,0 +1 @@ +In :mod:`inspect`, fix overeager replacement of "`typing.`" in formatting annotations. From webhook-mailer at python.org Fri Oct 7 14:49:33 2022 From: webhook-mailer at python.org (ambv) Date: Fri, 07 Oct 2022 18:49:33 -0000 Subject: [Python-checkins] [3.9] gh-94208: Add even more TLS version/protocol checks for FreeBSD (#98037) Message-ID: https://github.com/python/cpython/commit/da1fe3873a592eebe6f0d961b2e3b36d29b4838e commit: da1fe3873a592eebe6f0d961b2e3b36d29b4838e branch: 3.9 author: ?ukasz Langa committer: ambv date: 2022-10-07T11:49:28-07:00 summary: [3.9] gh-94208: Add even more TLS version/protocol checks for FreeBSD (#98037) Otherwise, buildbot builds would fail since there's no TLS 1.0/1.1 support. files: M .gitignore M Lib/test/test_ssl.py diff --git a/.gitignore b/.gitignore index 1ba44ec5d635..8d9717dd8210 100644 --- a/.gitignore +++ b/.gitignore @@ -140,5 +140,7 @@ Tools/ssl/win32 # Artifacts generated by 3.11 lying around when switching branches: /_bootstrap_python /Programs/_freeze_module +/Modules/Setup.bootstrap +/Modules/Setup.stdlib /Python/deepfreeze/ /Python/frozen_modules/ \ No newline at end of file diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index 6faa2ee0bbe6..e270f44cf3fb 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -1141,8 +1141,10 @@ def test_constructor(self): def test_protocol(self): for proto in PROTOCOLS: - ctx = ssl.SSLContext(proto) - self.assertEqual(ctx.protocol, proto) + if has_tls_protocol(proto): + with warnings_helper.check_warnings(): + ctx = ssl.SSLContext(proto) + self.assertEqual(ctx.protocol, proto) def test_ciphers(self): ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) @@ -1524,7 +1526,10 @@ def test_load_dh_params(self): def test_session_stats(self): for proto in PROTOCOLS: - ctx = ssl.SSLContext(proto) + if not has_tls_protocol(proto): + continue + with warnings_helper.check_warnings(): + ctx = ssl.SSLContext(proto) self.assertEqual(ctx.session_stats(), { 'number': 0, 'connect': 0, @@ -1715,13 +1720,14 @@ def test__create_stdlib_context(self): self.assertEqual(ctx.verify_mode, ssl.CERT_NONE) self._assert_context_options(ctx) - ctx = ssl._create_stdlib_context(ssl.PROTOCOL_TLSv1, - cert_reqs=ssl.CERT_REQUIRED, - check_hostname=True) - self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1) - self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED) - self.assertTrue(ctx.check_hostname) - self._assert_context_options(ctx) + with warnings_helper.check_warnings(): + ctx = ssl._create_stdlib_context(ssl.PROTOCOL_TLSv1, + cert_reqs=ssl.CERT_REQUIRED, + check_hostname=True) + self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1) + self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED) + self.assertTrue(ctx.check_hostname) + self._assert_context_options(ctx) ctx = ssl._create_stdlib_context(purpose=ssl.Purpose.CLIENT_AUTH) self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS) From webhook-mailer at python.org Fri Oct 7 14:50:01 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Fri, 07 Oct 2022 18:50:01 -0000 Subject: [Python-checkins] Add a warning message about PyOS_snprintf (#95993) Message-ID: https://github.com/python/cpython/commit/c7b220499662f0c7a4cae51e33372f92ca7b1ee9 commit: c7b220499662f0c7a4cae51e33372f92ca7b1ee9 branch: main author: Eric Wieser committer: JelleZijlstra date: 2022-10-07T11:49:53-07:00 summary: Add a warning message about PyOS_snprintf (#95993) files: M Doc/c-api/conversion.rst M Python/mysnprintf.c diff --git a/Doc/c-api/conversion.rst b/Doc/c-api/conversion.rst index 9b9c4ffa4d03..fdb321fe7ab3 100644 --- a/Doc/c-api/conversion.rst +++ b/Doc/c-api/conversion.rst @@ -28,7 +28,8 @@ not. The wrappers ensure that ``str[size-1]`` is always ``'\0'`` upon return. They never write more than *size* bytes (including the trailing ``'\0'``) into str. Both functions require that ``str != NULL``, ``size > 0``, ``format != NULL`` -and ``size < INT_MAX``. +and ``size < INT_MAX``. Note that this means there is no equivalent to the C99 +``n = snprintf(NULL, 0, ...)`` which would determine the necessary buffer size. The return value (*rv*) for these functions should be interpreted as follows: diff --git a/Python/mysnprintf.c b/Python/mysnprintf.c index cd69198011e3..2a505d14f82c 100644 --- a/Python/mysnprintf.c +++ b/Python/mysnprintf.c @@ -9,6 +9,7 @@ would have been written had the buffer not been too small, and to set the last byte of the buffer to \0. At least MS _vsnprintf returns a negative value instead, and fills the entire buffer with non-\0 data. + Unlike C99, our wrappers do not support passing a null buffer. The wrappers ensure that str[size-1] is always \0 upon return. From webhook-mailer at python.org Fri Oct 7 14:52:54 2022 From: webhook-mailer at python.org (ambv) Date: Fri, 07 Oct 2022 18:52:54 -0000 Subject: [Python-checkins] gh-96959: Update HTTP links which are redirected to HTTPS (#98039) Message-ID: https://github.com/python/cpython/commit/c81c64ca58822156beba79dfd3035bf2a5b7354e commit: c81c64ca58822156beba79dfd3035bf2a5b7354e branch: main author: 180909 <734461790 at qq.com> committer: ambv date: 2022-10-07T11:52:45-07:00 summary: gh-96959: Update HTTP links which are redirected to HTTPS (#98039) files: M Doc/faq/library.rst M Doc/includes/tzinfo_examples.py diff --git a/Doc/faq/library.rst b/Doc/faq/library.rst index f79cf4857122..a9cde4565750 100644 --- a/Doc/faq/library.rst +++ b/Doc/faq/library.rst @@ -609,7 +609,7 @@ use ``p.read(n)``. substituted for standard input and output. You will have to use pseudo ttys ("ptys") instead of pipes. Or you can use a Python interface to Don Libes' "expect" library. A Python extension that interfaces to expect is called - "expy" and available from http://expectpy.sourceforge.net. A pure Python + "expy" and available from https://expectpy.sourceforge.net. A pure Python solution that works like expect is `pexpect `_. diff --git a/Doc/includes/tzinfo_examples.py b/Doc/includes/tzinfo_examples.py index 9b9e32a553e7..1fa6e615e46a 100644 --- a/Doc/includes/tzinfo_examples.py +++ b/Doc/includes/tzinfo_examples.py @@ -71,7 +71,7 @@ def first_sunday_on_or_after(dt): # DST start and end times. For a complete and up-to-date set of DST rules # and timezone definitions, visit the Olson Database (or try pytz): # http://www.twinsun.com/tz/tz-link.htm -# http://sourceforge.net/projects/pytz/ (might not be up-to-date) +# https://sourceforge.net/projects/pytz/ (might not be up-to-date) # # In the US, since 2007, DST starts at 2am (standard time) on the second # Sunday in March, which is the first Sunday on or after Mar 8. From webhook-mailer at python.org Fri Oct 7 14:54:54 2022 From: webhook-mailer at python.org (ambv) Date: Fri, 07 Oct 2022 18:54:54 -0000 Subject: [Python-checkins] gh-97956: Mention `generate_global_objects.py` in `AC How-To` (#97957) Message-ID: https://github.com/python/cpython/commit/586cfb01311cac1defb883b928fbb368d6d38e55 commit: 586cfb01311cac1defb883b928fbb368d6d38e55 branch: main author: Nikita Sobolev committer: ambv date: 2022-10-07T11:54:45-07:00 summary: gh-97956: Mention `generate_global_objects.py` in `AC How-To` (#97957) files: M Doc/howto/clinic.rst diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst index d634c4b47db9..b8afc7e6d762 100644 --- a/Doc/howto/clinic.rst +++ b/Doc/howto/clinic.rst @@ -539,7 +539,15 @@ Let's dive in! }; -16. Compile, then run the relevant portions of the regression-test suite. +16. Argument Clinic may generate new instances of ``_Py_ID``. For example:: + + &_Py_ID(new_unique_py_id) + + If it does, you'll have to run ``Tools/scripts/generate_global_objects.py`` + to regenerate the list of precompiled identifiers at this point. + + +17. Compile, then run the relevant portions of the regression-test suite. This change should not introduce any new compile-time warnings or errors, and there should be no externally visible change to Python's behavior. From webhook-mailer at python.org Fri Oct 7 14:59:19 2022 From: webhook-mailer at python.org (ambv) Date: Fri, 07 Oct 2022 18:59:19 -0000 Subject: [Python-checkins] gh-97923: Always run Ubuntu SSL tests with others in CI (#97940) Message-ID: https://github.com/python/cpython/commit/3108fc1c16fdb73095dd7fcf0930004ae266f805 commit: 3108fc1c16fdb73095dd7fcf0930004ae266f805 branch: main author: Nikita Sobolev committer: ambv date: 2022-10-07T11:58:46-07:00 summary: gh-97923: Always run Ubuntu SSL tests with others in CI (#97940) files: M .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1db5c5051493..dc91c0dbcb02 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -31,7 +31,6 @@ jobs: runs-on: ubuntu-latest outputs: run_tests: ${{ steps.check.outputs.run_tests }} - run_ssl_tests: ${{ steps.check.outputs.run_ssl_tests }} steps: - uses: actions/checkout at v3 - name: Check for source changes @@ -39,7 +38,6 @@ jobs: run: | if [ -z "$GITHUB_BASE_REF" ]; then echo '::set-output name=run_tests::true' - echo '::set-output name=run_ssl_tests::true' else git fetch origin $GITHUB_BASE_REF --depth=1 # git diff "origin/$GITHUB_BASE_REF..." (3 dots) may be more @@ -56,7 +54,6 @@ jobs: # # https://github.com/python/core-workflow/issues/373 git diff --name-only origin/$GITHUB_BASE_REF.. | grep -qvE '(\.rst$|^Doc|^Misc)' && echo '::set-output name=run_tests::true' || true - git diff --name-only origin/$GITHUB_BASE_REF.. | grep -qE '(ssl|hashlib|hmac|^.github)' && echo '::set-output name=run_ssl_tests::true' || true fi check_generated_files: @@ -230,7 +227,7 @@ jobs: name: 'Ubuntu SSL tests with OpenSSL' runs-on: ubuntu-20.04 needs: check_source - if: needs.check_source.outputs.run_tests == 'true' && needs.check_source.outputs.run_ssl_tests == 'true' + if: needs.check_source.outputs.run_tests == 'true' strategy: fail-fast: false matrix: From webhook-mailer at python.org Fri Oct 7 15:01:01 2022 From: webhook-mailer at python.org (ambv) Date: Fri, 07 Oct 2022 19:01:01 -0000 Subject: [Python-checkins] gh-97646: Change `.js` and `.mjs` files mimetype to conform to RFC 9239 (#97934) Message-ID: https://github.com/python/cpython/commit/2a168355f0b700d4a64ccb5de750eb9d485e1cc3 commit: 2a168355f0b700d4a64ccb5de750eb9d485e1cc3 branch: main author: Noam Cohen committer: ambv date: 2022-10-07T12:00:53-07:00 summary: gh-97646: Change `.js` and `.mjs` files mimetype to conform to RFC 9239 (#97934) files: A Misc/NEWS.d/next/Library/2022-10-05-20-52-17.gh-issue-97646.Q4fVww.rst M Lib/mimetypes.py diff --git a/Lib/mimetypes.py b/Lib/mimetypes.py index f6c43b3b92bc..3224363a3f2b 100644 --- a/Lib/mimetypes.py +++ b/Lib/mimetypes.py @@ -427,8 +427,8 @@ def _default_mime_types(): # Make sure the entry with the preferred file extension for a particular mime type # appears before any others of the same mimetype. types_map = _types_map_default = { - '.js' : 'application/javascript', - '.mjs' : 'application/javascript', + '.js' : 'text/javascript', + '.mjs' : 'text/javascript', '.json' : 'application/json', '.webmanifest': 'application/manifest+json', '.doc' : 'application/msword', diff --git a/Misc/NEWS.d/next/Library/2022-10-05-20-52-17.gh-issue-97646.Q4fVww.rst b/Misc/NEWS.d/next/Library/2022-10-05-20-52-17.gh-issue-97646.Q4fVww.rst new file mode 100644 index 000000000000..6eed16c8e8bb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-05-20-52-17.gh-issue-97646.Q4fVww.rst @@ -0,0 +1 @@ +Replace deprecated ``application/javascript`` with ``text/javascript`` in :mod:`mimetypes`. See :rfc:`9239`. Patch by Noam Cohen. From webhook-mailer at python.org Fri Oct 7 15:02:57 2022 From: webhook-mailer at python.org (ambv) Date: Fri, 07 Oct 2022 19:02:57 -0000 Subject: [Python-checkins] [3.11] gh-96959: Update HTTP links which are redirected to HTTPS (GH-98039) (#98049) Message-ID: https://github.com/python/cpython/commit/a421c87b54facbbc223c7539172a5871e1a75edb commit: a421c87b54facbbc223c7539172a5871e1a75edb branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-07T12:02:51-07:00 summary: [3.11] gh-96959: Update HTTP links which are redirected to HTTPS (GH-98039) (#98049) (cherry picked from commit c81c64ca58822156beba79dfd3035bf2a5b7354e) Co-authored-by: 180909 <734461790 at qq.com> files: M Doc/faq/library.rst M Doc/includes/tzinfo_examples.py diff --git a/Doc/faq/library.rst b/Doc/faq/library.rst index f79cf4857122..a9cde4565750 100644 --- a/Doc/faq/library.rst +++ b/Doc/faq/library.rst @@ -609,7 +609,7 @@ use ``p.read(n)``. substituted for standard input and output. You will have to use pseudo ttys ("ptys") instead of pipes. Or you can use a Python interface to Don Libes' "expect" library. A Python extension that interfaces to expect is called - "expy" and available from http://expectpy.sourceforge.net. A pure Python + "expy" and available from https://expectpy.sourceforge.net. A pure Python solution that works like expect is `pexpect `_. diff --git a/Doc/includes/tzinfo_examples.py b/Doc/includes/tzinfo_examples.py index 9b9e32a553e7..1fa6e615e46a 100644 --- a/Doc/includes/tzinfo_examples.py +++ b/Doc/includes/tzinfo_examples.py @@ -71,7 +71,7 @@ def first_sunday_on_or_after(dt): # DST start and end times. For a complete and up-to-date set of DST rules # and timezone definitions, visit the Olson Database (or try pytz): # http://www.twinsun.com/tz/tz-link.htm -# http://sourceforge.net/projects/pytz/ (might not be up-to-date) +# https://sourceforge.net/projects/pytz/ (might not be up-to-date) # # In the US, since 2007, DST starts at 2am (standard time) on the second # Sunday in March, which is the first Sunday on or after Mar 8. From webhook-mailer at python.org Fri Oct 7 15:03:41 2022 From: webhook-mailer at python.org (ambv) Date: Fri, 07 Oct 2022 19:03:41 -0000 Subject: [Python-checkins] [3.10] gh-96959: Update HTTP links which are redirected to HTTPS (GH-98039) (#98050) Message-ID: https://github.com/python/cpython/commit/7565944994a98f0c78026487009d90661b94e4b7 commit: 7565944994a98f0c78026487009d90661b94e4b7 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-07T12:03:36-07:00 summary: [3.10] gh-96959: Update HTTP links which are redirected to HTTPS (GH-98039) (#98050) (cherry picked from commit c81c64ca58822156beba79dfd3035bf2a5b7354e) Co-authored-by: 180909 <734461790 at qq.com> files: M Doc/faq/library.rst M Doc/includes/tzinfo_examples.py diff --git a/Doc/faq/library.rst b/Doc/faq/library.rst index f79cf4857122..a9cde4565750 100644 --- a/Doc/faq/library.rst +++ b/Doc/faq/library.rst @@ -609,7 +609,7 @@ use ``p.read(n)``. substituted for standard input and output. You will have to use pseudo ttys ("ptys") instead of pipes. Or you can use a Python interface to Don Libes' "expect" library. A Python extension that interfaces to expect is called - "expy" and available from http://expectpy.sourceforge.net. A pure Python + "expy" and available from https://expectpy.sourceforge.net. A pure Python solution that works like expect is `pexpect `_. diff --git a/Doc/includes/tzinfo_examples.py b/Doc/includes/tzinfo_examples.py index 9b9e32a553e7..1fa6e615e46a 100644 --- a/Doc/includes/tzinfo_examples.py +++ b/Doc/includes/tzinfo_examples.py @@ -71,7 +71,7 @@ def first_sunday_on_or_after(dt): # DST start and end times. For a complete and up-to-date set of DST rules # and timezone definitions, visit the Olson Database (or try pytz): # http://www.twinsun.com/tz/tz-link.htm -# http://sourceforge.net/projects/pytz/ (might not be up-to-date) +# https://sourceforge.net/projects/pytz/ (might not be up-to-date) # # In the US, since 2007, DST starts at 2am (standard time) on the second # Sunday in March, which is the first Sunday on or after Mar 8. From webhook-mailer at python.org Fri Oct 7 15:04:23 2022 From: webhook-mailer at python.org (nanjekyejoannah) Date: Fri, 07 Oct 2022 19:04:23 -0000 Subject: [Python-checkins] gh-73196: Add namespace/scope clarification for inheritance section (#92840) Message-ID: https://github.com/python/cpython/commit/fde74be61bfdc79afad5dfb9496688370368c179 commit: fde74be61bfdc79afad5dfb9496688370368c179 branch: main author: Stanley <46876382+slateny at users.noreply.github.com> committer: nanjekyejoannah <33177550+nanjekyejoannah at users.noreply.github.com> date: 2022-10-07T12:04:14-07:00 summary: gh-73196: Add namespace/scope clarification for inheritance section (#92840) Add namespace/scope clarification for inheritance section files: M Doc/tutorial/classes.rst diff --git a/Doc/tutorial/classes.rst b/Doc/tutorial/classes.rst index f27abe48b2d4..9ecbf8b87efb 100644 --- a/Doc/tutorial/classes.rst +++ b/Doc/tutorial/classes.rst @@ -581,7 +581,8 @@ this:: . -The name :class:`BaseClassName` must be defined in a scope containing the +The name :class:`BaseClassName` must be defined in a +namespace accessible from the scope containing the derived class definition. In place of a base class name, other arbitrary expressions are also allowed. This can be useful, for example, when the base class is defined in another module:: From webhook-mailer at python.org Fri Oct 7 15:15:49 2022 From: webhook-mailer at python.org (ambv) Date: Fri, 07 Oct 2022 19:15:49 -0000 Subject: [Python-checkins] gh-96265: Fix some formatting in faq/design.rst (#96924) Message-ID: https://github.com/python/cpython/commit/3a7e955858b21b6fc35f826d0975a26ac39f50de commit: 3a7e955858b21b6fc35f826d0975a26ac39f50de branch: main author: Stanley <46876382+slateny at users.noreply.github.com> committer: ambv date: 2022-10-07T12:15:41-07:00 summary: gh-96265: Fix some formatting in faq/design.rst (#96924) Co-authored-by: Ezio Melotti Co-authored-by: C.A.M. Gerlach files: M Doc/faq/design.rst diff --git a/Doc/faq/design.rst b/Doc/faq/design.rst index ccdc9bf02b1c..763222aba8b6 100644 --- a/Doc/faq/design.rst +++ b/Doc/faq/design.rst @@ -62,7 +62,7 @@ and think it is a bug in Python. It's not. This has little to do with Python, and much more to do with how the underlying platform handles floating-point numbers. -The :class:`float` type in CPython uses a C ``double`` for storage. A +The :class:`float` type in CPython uses a C :c:type:`double` for storage. A :class:`float` object's value is stored in binary floating-point with a fixed precision (typically 53 bits) and Python uses C operations, which in turn rely on the hardware implementation in the processor, to perform floating-point @@ -129,7 +129,7 @@ reference or call the method from a particular class. In C++, if you want to use a method from a base class which is overridden in a derived class, you have to use the ``::`` operator -- in Python you can write ``baseclass.methodname(self, )``. This is particularly useful -for :meth:`__init__` methods, and in general in cases where a derived class +for :meth:`~object.__init__` methods, and in general in cases where a derived class method wants to extend the base class method of the same name and thus has to call the base class method somehow. @@ -232,7 +232,8 @@ Similar methods exist for bytes and bytearray objects. How fast are exceptions? ------------------------ -A try/except block is extremely efficient if no exceptions are raised. Actually +A :keyword:`try`/:keyword:`except` block is extremely efficient if no exceptions +are raised. Actually catching an exception is expensive. In versions of Python prior to 2.0 it was common to use this idiom:: @@ -352,7 +353,7 @@ will probably run out of file descriptors:: c = f.read(1) Indeed, using CPython's reference counting and destructor scheme, each new -assignment to *f* closes the previous file. With a traditional GC, however, +assignment to ``f`` closes the previous file. With a traditional GC, however, those file objects will only get collected (and closed) at varying and possibly long intervals. @@ -376,10 +377,10 @@ Python to work with it.) Traditional GC also becomes a problem when Python is embedded into other applications. While in a standalone Python it's fine to replace the standard -malloc() and free() with versions provided by the GC library, an application -embedding Python may want to have its *own* substitute for malloc() and free(), +``malloc()`` and ``free()`` with versions provided by the GC library, an application +embedding Python may want to have its *own* substitute for ``malloc()`` and ``free()``, and may not want Python's. Right now, CPython works with anything that -implements malloc() and free() properly. +implements ``malloc()`` and ``free()`` properly. Why isn't all memory freed when CPython exits? @@ -401,14 +402,15 @@ Why are there separate tuple and list data types? Lists and tuples, while similar in many respects, are generally used in fundamentally different ways. Tuples can be thought of as being similar to -Pascal records or C structs; they're small collections of related data which may +Pascal ``records`` or C ``structs``; they're small collections of related data which may be of different types which are operated on as a group. For example, a Cartesian coordinate is appropriately represented as a tuple of two or three numbers. Lists, on the other hand, are more like arrays in other languages. They tend to hold a varying number of objects all of which have the same type and which are -operated on one-by-one. For example, ``os.listdir('.')`` returns a list of +operated on one-by-one. For example, :func:`os.listdir('.') ` +returns a list of strings representing the files in the current directory. Functions which operate on this output would generally not break if you added another file or two to the directory. @@ -444,9 +446,9 @@ far) under most circumstances, and the implementation is simpler. Dictionaries work by computing a hash code for each key stored in the dictionary using the :func:`hash` built-in function. The hash code varies widely depending -on the key and a per-process seed; for example, "Python" could hash to --539294296 while "python", a string that differs by a single bit, could hash -to 1142331976. The hash code is then used to calculate a location in an +on the key and a per-process seed; for example, ``'Python'`` could hash to +``-539294296`` while ``'python'``, a string that differs by a single bit, could hash +to ``1142331976``. The hash code is then used to calculate a location in an internal array where the value will be stored. Assuming that you're storing keys that all have different hash values, this means that dictionaries take constant time -- O(1), in Big-O notation -- to retrieve a key. @@ -497,7 +499,8 @@ Some unacceptable solutions that have been proposed: There is a trick to get around this if you need to, but use it at your own risk: You can wrap a mutable structure inside a class instance which has both a -:meth:`__eq__` and a :meth:`__hash__` method. You must then make sure that the +:meth:`~object.__eq__` and a :meth:`~object.__hash__` method. +You must then make sure that the hash value for all such wrapper objects that reside in a dictionary (or other hash based structure), remain fixed while the object is in the dictionary (or other structure). :: @@ -528,7 +531,7 @@ is True``) then ``hash(o1) == hash(o2)`` (ie, ``o1.__hash__() == o2.__hash__()`` regardless of whether the object is in a dictionary or not. If you fail to meet these restrictions dictionaries and other hash based structures will misbehave. -In the case of ListWrapper, whenever the wrapper object is in a dictionary the +In the case of :class:`!ListWrapper`, whenever the wrapper object is in a dictionary the wrapped list must not change to avoid anomalies. Don't do this unless you are prepared to think hard about the requirements and the consequences of not meeting them correctly. Consider yourself warned. @@ -581,9 +584,9 @@ exhaustive test suites that exercise every line of code in a module. An appropriate testing discipline can help build large complex applications in Python as well as having interface specifications would. In fact, it can be better because an interface specification cannot test certain properties of a -program. For example, the :meth:`append` method is expected to add new elements +program. For example, the :meth:`list.append` method is expected to add new elements to the end of some internal list; an interface specification cannot test that -your :meth:`append` implementation will actually do this correctly, but it's +your :meth:`list.append` implementation will actually do this correctly, but it's trivial to check this property in a test suite. Writing test suites is very helpful, and you might want to design your code to @@ -599,14 +602,14 @@ Why is there no goto? In the 1970s people realized that unrestricted goto could lead to messy "spaghetti" code that was hard to understand and revise. In a high-level language, it is also unneeded as long as there -are ways to branch (in Python, with ``if`` statements and ``or``, -``and``, and ``if-else`` expressions) and loop (with ``while`` -and ``for`` statements, possibly containing ``continue`` and ``break``). +are ways to branch (in Python, with :keyword:`if` statements and :keyword:`or`, +:keyword:`and`, and :keyword:`if`/:keyword:`else` expressions) and loop (with :keyword:`while` +and :keyword:`for` statements, possibly containing :keyword:`continue` and :keyword:`break`). One can also use exceptions to provide a "structured goto" that works even across function calls. Many feel that exceptions can conveniently emulate all -reasonable uses of the "go" or "goto" constructs of C, Fortran, and other +reasonable uses of the ``go`` or ``goto`` constructs of C, Fortran, and other languages. For example:: class label(Exception): pass # declare a label @@ -620,7 +623,7 @@ languages. For example:: ... This doesn't allow you to jump into the middle of a loop, but that's usually -considered an abuse of goto anyway. Use sparingly. +considered an abuse of ``goto`` anyway. Use sparingly. Why can't raw strings (r-strings) end with a backslash? @@ -652,7 +655,7 @@ If you're trying to build a pathname for a DOS command, try e.g. one of :: Why doesn't Python have a "with" statement for attribute assignments? --------------------------------------------------------------------- -Python has a 'with' statement that wraps the execution of a block, calling code +Python has a :keyword:`with` statement that wraps the execution of a block, calling code on the entrance and exit from the block. Some languages have a construct that looks like this:: @@ -679,13 +682,13 @@ For instance, take the following incomplete snippet:: with a: print(x) -The snippet assumes that "a" must have a member attribute called "x". However, +The snippet assumes that ``a`` must have a member attribute called ``x``. However, there is nothing in Python that tells the interpreter this. What should happen -if "a" is, let us say, an integer? If there is a global variable named "x", -will it be used inside the with block? As you see, the dynamic nature of Python +if ``a`` is, let us say, an integer? If there is a global variable named ``x``, +will it be used inside the :keyword:`with` block? As you see, the dynamic nature of Python makes such choices much harder. -The primary benefit of "with" and similar language features (reduction of code +The primary benefit of :keyword:`with` and similar language features (reduction of code volume) can, however, easily be achieved in Python by assignment. Instead of:: function(args).mydict[index][index].a = 21 @@ -714,7 +717,8 @@ Why don't generators support the with statement? For technical reasons, a generator used directly as a context manager would not work correctly. When, as is most common, a generator is used as an iterator run to completion, no closing is needed. When it is, wrap -it as "contextlib.closing(generator)" in the 'with' statement. +it as :func:`contextlib.closing(generator) ` +in the :keyword:`with` statement. Why are colons required for the if/while/def/class statements? From webhook-mailer at python.org Fri Oct 7 15:19:44 2022 From: webhook-mailer at python.org (ambv) Date: Fri, 07 Oct 2022 19:19:44 -0000 Subject: [Python-checkins] gh-91708: Revert params note in urllib.parse.urlparse table (#96699) Message-ID: https://github.com/python/cpython/commit/eed80458e8e776d15fa862da71dcce58c47e2ca7 commit: eed80458e8e776d15fa862da71dcce58c47e2ca7 branch: main author: Stanley <46876382+slateny at users.noreply.github.com> committer: ambv date: 2022-10-07T12:19:36-07:00 summary: gh-91708: Revert params note in urllib.parse.urlparse table (#96699) Revert params note in urllib.parse.urlparse table files: M Doc/library/urllib.parse.rst diff --git a/Doc/library/urllib.parse.rst b/Doc/library/urllib.parse.rst index 1478b34bc955..96b396510794 100644 --- a/Doc/library/urllib.parse.rst +++ b/Doc/library/urllib.parse.rst @@ -113,7 +113,8 @@ or on combining URL components into a URL string. +------------------+-------+-------------------------+------------------------+ | :attr:`path` | 2 | Hierarchical path | empty string | +------------------+-------+-------------------------+------------------------+ - | :attr:`params` | 3 | No longer used | always an empty string | + | :attr:`params` | 3 | Parameters for last | empty string | + | | | path element | | +------------------+-------+-------------------------+------------------------+ | :attr:`query` | 4 | Query component | empty string | +------------------+-------+-------------------------+------------------------+ From webhook-mailer at python.org Fri Oct 7 15:21:51 2022 From: webhook-mailer at python.org (ambv) Date: Fri, 07 Oct 2022 19:21:51 -0000 Subject: [Python-checkins] gh-96346: Use double caching for re._compile() (#96347) Message-ID: https://github.com/python/cpython/commit/c11b667a1d8c13095b295d1a8c4ab6e4ccf0f895 commit: c11b667a1d8c13095b295d1a8c4ab6e4ccf0f895 branch: main author: Serhiy Storchaka committer: ambv date: 2022-10-07T12:21:42-07:00 summary: gh-96346: Use double caching for re._compile() (#96347) files: A Misc/NEWS.d/next/Library/2022-08-27-23-16-09.gh-issue-96346.jJX14I.rst M Lib/re/__init__.py diff --git a/Lib/re/__init__.py b/Lib/re/__init__.py index d58c2117ef3e..8d6a4ef3880f 100644 --- a/Lib/re/__init__.py +++ b/Lib/re/__init__.py @@ -229,6 +229,7 @@ def compile(pattern, flags=0): def purge(): "Clear the regular expression caches" _cache.clear() + _cache2.clear() _compile_repl.cache_clear() def template(pattern, flags=0): @@ -266,40 +267,64 @@ def escape(pattern): # -------------------------------------------------------------------- # internals -_cache = {} # ordered! - +# Use the fact that dict keeps the insertion order. +# _cache2 uses the simple FIFO policy which has better latency. +# _cache uses the LRU policy which has better hit rate. +_cache = {} # LRU +_cache2 = {} # FIFO _MAXCACHE = 512 +_MAXCACHE2 = 256 +assert _MAXCACHE2 < _MAXCACHE + def _compile(pattern, flags): # internal: compile pattern if isinstance(flags, RegexFlag): flags = flags.value try: - return _cache[type(pattern), pattern, flags] + return _cache2[type(pattern), pattern, flags] except KeyError: pass - if isinstance(pattern, Pattern): - if flags: - raise ValueError( - "cannot process flags argument with a compiled pattern") - return pattern - if not _compiler.isstring(pattern): - raise TypeError("first argument must be string or compiled pattern") - if flags & T: - import warnings - warnings.warn("The re.TEMPLATE/re.T flag is deprecated " - "as it is an undocumented flag " - "without an obvious purpose. " - "Don't use it.", - DeprecationWarning) - p = _compiler.compile(pattern, flags) - if not (flags & DEBUG): + + key = (type(pattern), pattern, flags) + # Item in _cache should be moved to the end if found. + p = _cache.pop(key, None) + if p is None: + if isinstance(pattern, Pattern): + if flags: + raise ValueError( + "cannot process flags argument with a compiled pattern") + return pattern + if not _compiler.isstring(pattern): + raise TypeError("first argument must be string or compiled pattern") + if flags & T: + import warnings + warnings.warn("The re.TEMPLATE/re.T flag is deprecated " + "as it is an undocumented flag " + "without an obvious purpose. " + "Don't use it.", + DeprecationWarning) + p = _compiler.compile(pattern, flags) + if flags & DEBUG: + return p if len(_cache) >= _MAXCACHE: - # Drop the oldest item + # Drop the least recently used item. + # next(iter(_cache)) is known to have linear amortized time, + # but it is used here to avoid a dependency from using OrderedDict. + # For the small _MAXCACHE value it doesn't make much of a difference. try: del _cache[next(iter(_cache))] except (StopIteration, RuntimeError, KeyError): pass - _cache[type(pattern), pattern, flags] = p + # Append to the end. + _cache[key] = p + + if len(_cache2) >= _MAXCACHE2: + # Drop the oldest item. + try: + del _cache2[next(iter(_cache2))] + except (StopIteration, RuntimeError, KeyError): + pass + _cache2[key] = p return p @functools.lru_cache(_MAXCACHE) diff --git a/Misc/NEWS.d/next/Library/2022-08-27-23-16-09.gh-issue-96346.jJX14I.rst b/Misc/NEWS.d/next/Library/2022-08-27-23-16-09.gh-issue-96346.jJX14I.rst new file mode 100644 index 000000000000..9883348b9c3e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-08-27-23-16-09.gh-issue-96346.jJX14I.rst @@ -0,0 +1 @@ +Use double caching for compiled RE patterns. From webhook-mailer at python.org Fri Oct 7 15:30:45 2022 From: webhook-mailer at python.org (miss-islington) Date: Fri, 07 Oct 2022 19:30:45 -0000 Subject: [Python-checkins] gh-65496: Correct wording on csv's skipinitialspace argument (GH-96170) Message-ID: https://github.com/python/cpython/commit/e73cb54a063ddfc1530031e95c23209ed2883a82 commit: e73cb54a063ddfc1530031e95c23209ed2883a82 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-07T12:30:39-07:00 summary: gh-65496: Correct wording on csv's skipinitialspace argument (GH-96170) (cherry picked from commit 676d8ef3806758bcd1d3fd84a746c8a9b64480d0) Co-authored-by: Stanley <46876382+slateny at users.noreply.github.com> files: M Doc/library/csv.rst M Lib/test/test_csv.py M Modules/_csv.c diff --git a/Doc/library/csv.rst b/Doc/library/csv.rst index 899ce0225ce7..3a41ae284f32 100644 --- a/Doc/library/csv.rst +++ b/Doc/library/csv.rst @@ -412,7 +412,7 @@ Dialects support the following attributes: .. attribute:: Dialect.skipinitialspace - When :const:`True`, whitespace immediately following the *delimiter* is ignored. + When :const:`True`, spaces immediately following the *delimiter* are ignored. The default is :const:`False`. diff --git a/Lib/test/test_csv.py b/Lib/test/test_csv.py index d94a6f24597b..623a6b60b0fa 100644 --- a/Lib/test/test_csv.py +++ b/Lib/test/test_csv.py @@ -335,6 +335,11 @@ def test_read_quoting(self): ['abc,3'], [[]], quoting=csv.QUOTE_NONNUMERIC) + def test_read_skipinitialspace(self): + self._read_test(['no space, space, spaces,\ttab'], + [['no space', 'space', 'spaces', '\ttab']], + skipinitialspace=True) + def test_read_bigfield(self): # This exercises the buffer realloc functionality and field size # limits. diff --git a/Modules/_csv.c b/Modules/_csv.c index 72f0791a4398..c991968f83cd 100644 --- a/Modules/_csv.c +++ b/Modules/_csv.c @@ -698,7 +698,7 @@ parse_process_char(ReaderObj *self, _csvstate *module_state, Py_UCS4 c) self->state = ESCAPED_CHAR; } else if (c == ' ' && dialect->skipinitialspace) - /* ignore space at start of field */ + /* ignore spaces at start of field */ ; else if (c == dialect->delimiter) { /* save empty field */ @@ -1603,9 +1603,9 @@ PyDoc_STRVAR(csv_module_doc, " quoting character. It defaults to '\"'.\n" " * delimiter - specifies a one-character string to use as the\n" " field separator. It defaults to ','.\n" -" * skipinitialspace - specifies how to interpret whitespace which\n" -" immediately follows a delimiter. It defaults to False, which\n" -" means that whitespace immediately following a delimiter is part\n" +" * skipinitialspace - specifies how to interpret spaces which\n" +" immediately follow a delimiter. It defaults to False, which\n" +" means that spaces immediately following a delimiter is part\n" " of the following field.\n" " * lineterminator - specifies the character sequence which should\n" " terminate rows.\n" From webhook-mailer at python.org Fri Oct 7 15:56:34 2022 From: webhook-mailer at python.org (miss-islington) Date: Fri, 07 Oct 2022 19:56:34 -0000 Subject: [Python-checkins] GH-96073: Fix wild replacement in inspect.formatannotation (GH-96074) Message-ID: https://github.com/python/cpython/commit/107ba927cf60d26c1f6302a8c953de5ed136dd35 commit: 107ba927cf60d26c1f6302a8c953de5ed136dd35 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-07T12:56:16-07:00 summary: GH-96073: Fix wild replacement in inspect.formatannotation (GH-96074) Co-authored-by: Jelle Zijlstra (cherry picked from commit d5fea01d9d439b1638cd8e5db19c33909841d86f) Co-authored-by: Anh71me files: A Lib/test/typinganndata/__init__.py A Lib/test/typinganndata/ann_module9.py A Misc/NEWS.d/next/Library/2022-08-29-12-35-28.gh-issue-96073.WaGstf.rst M Lib/inspect.py M Lib/test/test_inspect.py diff --git a/Lib/inspect.py b/Lib/inspect.py index cbc0632484b8..5f7574c194ff 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -1448,7 +1448,10 @@ def getargvalues(frame): def formatannotation(annotation, base_module=None): if getattr(annotation, '__module__', None) == 'typing': - return repr(annotation).replace('typing.', '') + def repl(match): + text = match.group() + return text.removeprefix('typing.') + return re.sub(r'[\w\.]+', repl, repr(annotation)) if isinstance(annotation, types.GenericAlias): return str(annotation) if isinstance(annotation, type): diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index be9f29e04ae1..c030be77e80f 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -1421,6 +1421,13 @@ def wrapper(a, b): self.assertEqual(inspect.get_annotations(isa.MyClassWithLocalAnnotations, eval_str=True), {'x': int}) +class TestFormatAnnotation(unittest.TestCase): + def test_typing_replacement(self): + from test.typinganndata.ann_module9 import ann, ann1 + self.assertEqual(inspect.formatannotation(ann), 'Union[List[str], int]') + self.assertEqual(inspect.formatannotation(ann1), 'Union[List[testModule.typing.A], int]') + + class TestIsDataDescriptor(unittest.TestCase): def test_custom_descriptors(self): diff --git a/Lib/test/typinganndata/__init__.py b/Lib/test/typinganndata/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/Lib/test/typinganndata/ann_module9.py b/Lib/test/typinganndata/ann_module9.py new file mode 100644 index 000000000000..952217393e1f --- /dev/null +++ b/Lib/test/typinganndata/ann_module9.py @@ -0,0 +1,14 @@ +# Test ``inspect.formatannotation`` +# https://github.com/python/cpython/issues/96073 + +from typing import Union, List + +ann = Union[List[str], int] + +# mock typing._type_repr behaviour +class A: ... + +A.__module__ = 'testModule.typing' +A.__qualname__ = 'A' + +ann1 = Union[List[A], int] diff --git a/Misc/NEWS.d/next/Library/2022-08-29-12-35-28.gh-issue-96073.WaGstf.rst b/Misc/NEWS.d/next/Library/2022-08-29-12-35-28.gh-issue-96073.WaGstf.rst new file mode 100644 index 000000000000..0e6dd8d360cb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-08-29-12-35-28.gh-issue-96073.WaGstf.rst @@ -0,0 +1 @@ +In :mod:`inspect`, fix overeager replacement of "`typing.`" in formatting annotations. From webhook-mailer at python.org Fri Oct 7 15:56:35 2022 From: webhook-mailer at python.org (miss-islington) Date: Fri, 07 Oct 2022 19:56:35 -0000 Subject: [Python-checkins] GH-96073: Fix wild replacement in inspect.formatannotation (GH-96074) Message-ID: https://github.com/python/cpython/commit/a3a3701fec80599f19da0faf6547cfbe58fcad13 commit: a3a3701fec80599f19da0faf6547cfbe58fcad13 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-07T12:56:29-07:00 summary: GH-96073: Fix wild replacement in inspect.formatannotation (GH-96074) Co-authored-by: Jelle Zijlstra (cherry picked from commit d5fea01d9d439b1638cd8e5db19c33909841d86f) Co-authored-by: Anh71me files: A Lib/test/typinganndata/__init__.py A Lib/test/typinganndata/ann_module9.py A Misc/NEWS.d/next/Library/2022-08-29-12-35-28.gh-issue-96073.WaGstf.rst M Lib/inspect.py M Lib/test/test_inspect.py diff --git a/Lib/inspect.py b/Lib/inspect.py index 01df575e4bfe..60740c63b2ae 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -1356,7 +1356,10 @@ def getargvalues(frame): def formatannotation(annotation, base_module=None): if getattr(annotation, '__module__', None) == 'typing': - return repr(annotation).replace('typing.', '') + def repl(match): + text = match.group() + return text.removeprefix('typing.') + return re.sub(r'[\w\.]+', repl, repr(annotation)) if isinstance(annotation, types.GenericAlias): return str(annotation) if isinstance(annotation, type): diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index eaefe946e896..16fef5cab18d 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -1418,6 +1418,13 @@ def wrapper(a, b): self.assertEqual(inspect.get_annotations(isa.MyClassWithLocalAnnotations, eval_str=True), {'x': int}) +class TestFormatAnnotation(unittest.TestCase): + def test_typing_replacement(self): + from test.typinganndata.ann_module9 import ann, ann1 + self.assertEqual(inspect.formatannotation(ann), 'Union[List[str], int]') + self.assertEqual(inspect.formatannotation(ann1), 'Union[List[testModule.typing.A], int]') + + class TestIsDataDescriptor(unittest.TestCase): def test_custom_descriptors(self): diff --git a/Lib/test/typinganndata/__init__.py b/Lib/test/typinganndata/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/Lib/test/typinganndata/ann_module9.py b/Lib/test/typinganndata/ann_module9.py new file mode 100644 index 000000000000..952217393e1f --- /dev/null +++ b/Lib/test/typinganndata/ann_module9.py @@ -0,0 +1,14 @@ +# Test ``inspect.formatannotation`` +# https://github.com/python/cpython/issues/96073 + +from typing import Union, List + +ann = Union[List[str], int] + +# mock typing._type_repr behaviour +class A: ... + +A.__module__ = 'testModule.typing' +A.__qualname__ = 'A' + +ann1 = Union[List[A], int] diff --git a/Misc/NEWS.d/next/Library/2022-08-29-12-35-28.gh-issue-96073.WaGstf.rst b/Misc/NEWS.d/next/Library/2022-08-29-12-35-28.gh-issue-96073.WaGstf.rst new file mode 100644 index 000000000000..0e6dd8d360cb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-08-29-12-35-28.gh-issue-96073.WaGstf.rst @@ -0,0 +1 @@ +In :mod:`inspect`, fix overeager replacement of "`typing.`" in formatting annotations. From webhook-mailer at python.org Fri Oct 7 15:57:00 2022 From: webhook-mailer at python.org (gvanrossum) Date: Fri, 07 Oct 2022 19:57:00 -0000 Subject: [Python-checkins] GH-88968: Reject socket that is already used as a transport (#98010) Message-ID: https://github.com/python/cpython/commit/c06276402b5f23d49a39dfcaf45ed81b5c88efe7 commit: c06276402b5f23d49a39dfcaf45ed81b5c88efe7 branch: main author: Guido van Rossum committer: gvanrossum date: 2022-10-07T12:56:50-07:00 summary: GH-88968: Reject socket that is already used as a transport (#98010) files: M Lib/asyncio/selector_events.py M Lib/test/test_asyncio/test_selector_events.py diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py index c9bbe2ac0143..d2ee49dd88f8 100644 --- a/Lib/asyncio/selector_events.py +++ b/Lib/asyncio/selector_events.py @@ -58,6 +58,7 @@ def __init__(self, selector=None): def _make_socket_transport(self, sock, protocol, waiter=None, *, extra=None, server=None): + self._ensure_fd_no_transport(sock) return _SelectorSocketTransport(self, sock, protocol, waiter, extra, server) @@ -68,6 +69,7 @@ def _make_ssl_transport( ssl_handshake_timeout=constants.SSL_HANDSHAKE_TIMEOUT, ssl_shutdown_timeout=constants.SSL_SHUTDOWN_TIMEOUT, ): + self._ensure_fd_no_transport(rawsock) ssl_protocol = sslproto.SSLProtocol( self, protocol, sslcontext, waiter, server_side, server_hostname, @@ -80,6 +82,7 @@ def _make_ssl_transport( def _make_datagram_transport(self, sock, protocol, address=None, waiter=None, extra=None): + self._ensure_fd_no_transport(sock) return _SelectorDatagramTransport(self, sock, protocol, address, waiter, extra) diff --git a/Lib/test/test_asyncio/test_selector_events.py b/Lib/test/test_asyncio/test_selector_events.py index 22dcfb230835..796037bcf59c 100644 --- a/Lib/test/test_asyncio/test_selector_events.py +++ b/Lib/test/test_asyncio/test_selector_events.py @@ -61,8 +61,10 @@ def setUp(self): def test_make_socket_transport(self): m = mock.Mock() self.loop.add_reader = mock.Mock() + self.loop._ensure_fd_no_transport = mock.Mock() transport = self.loop._make_socket_transport(m, asyncio.Protocol()) self.assertIsInstance(transport, _SelectorSocketTransport) + self.assertEqual(self.loop._ensure_fd_no_transport.call_count, 1) # Calling repr() must not fail when the event loop is closed self.loop.close() @@ -78,8 +80,10 @@ def test_make_ssl_transport_without_ssl_error(self): self.loop.add_writer = mock.Mock() self.loop.remove_reader = mock.Mock() self.loop.remove_writer = mock.Mock() + self.loop._ensure_fd_no_transport = mock.Mock() with self.assertRaises(RuntimeError): self.loop._make_ssl_transport(m, m, m, m) + self.assertEqual(self.loop._ensure_fd_no_transport.call_count, 1) def test_close(self): class EventLoop(BaseSelectorEventLoop): From webhook-mailer at python.org Fri Oct 7 16:26:52 2022 From: webhook-mailer at python.org (miss-islington) Date: Fri, 07 Oct 2022 20:26:52 -0000 Subject: [Python-checkins] Add a warning message about PyOS_snprintf (GH-95993) Message-ID: https://github.com/python/cpython/commit/0a84b7aa4d89c9af7fa10dcb9943490669da4db6 commit: 0a84b7aa4d89c9af7fa10dcb9943490669da4db6 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-07T13:26:46-07:00 summary: Add a warning message about PyOS_snprintf (GH-95993) (cherry picked from commit c7b220499662f0c7a4cae51e33372f92ca7b1ee9) Co-authored-by: Eric Wieser files: M Doc/c-api/conversion.rst M Python/mysnprintf.c diff --git a/Doc/c-api/conversion.rst b/Doc/c-api/conversion.rst index 9b9c4ffa4d03..fdb321fe7ab3 100644 --- a/Doc/c-api/conversion.rst +++ b/Doc/c-api/conversion.rst @@ -28,7 +28,8 @@ not. The wrappers ensure that ``str[size-1]`` is always ``'\0'`` upon return. They never write more than *size* bytes (including the trailing ``'\0'``) into str. Both functions require that ``str != NULL``, ``size > 0``, ``format != NULL`` -and ``size < INT_MAX``. +and ``size < INT_MAX``. Note that this means there is no equivalent to the C99 +``n = snprintf(NULL, 0, ...)`` which would determine the necessary buffer size. The return value (*rv*) for these functions should be interpreted as follows: diff --git a/Python/mysnprintf.c b/Python/mysnprintf.c index cd69198011e3..2a505d14f82c 100644 --- a/Python/mysnprintf.c +++ b/Python/mysnprintf.c @@ -9,6 +9,7 @@ would have been written had the buffer not been too small, and to set the last byte of the buffer to \0. At least MS _vsnprintf returns a negative value instead, and fills the entire buffer with non-\0 data. + Unlike C99, our wrappers do not support passing a null buffer. The wrappers ensure that str[size-1] is always \0 upon return. From webhook-mailer at python.org Fri Oct 7 16:36:27 2022 From: webhook-mailer at python.org (miss-islington) Date: Fri, 07 Oct 2022 20:36:27 -0000 Subject: [Python-checkins] Add a warning message about PyOS_snprintf (GH-95993) Message-ID: https://github.com/python/cpython/commit/90f2c7992f3d3285bafa1eef6d0f8255ce8921c2 commit: 90f2c7992f3d3285bafa1eef6d0f8255ce8921c2 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-07T13:36:21-07:00 summary: Add a warning message about PyOS_snprintf (GH-95993) (cherry picked from commit c7b220499662f0c7a4cae51e33372f92ca7b1ee9) Co-authored-by: Eric Wieser files: M Doc/c-api/conversion.rst M Python/mysnprintf.c diff --git a/Doc/c-api/conversion.rst b/Doc/c-api/conversion.rst index 9b9c4ffa4d03..fdb321fe7ab3 100644 --- a/Doc/c-api/conversion.rst +++ b/Doc/c-api/conversion.rst @@ -28,7 +28,8 @@ not. The wrappers ensure that ``str[size-1]`` is always ``'\0'`` upon return. They never write more than *size* bytes (including the trailing ``'\0'``) into str. Both functions require that ``str != NULL``, ``size > 0``, ``format != NULL`` -and ``size < INT_MAX``. +and ``size < INT_MAX``. Note that this means there is no equivalent to the C99 +``n = snprintf(NULL, 0, ...)`` which would determine the necessary buffer size. The return value (*rv*) for these functions should be interpreted as follows: diff --git a/Python/mysnprintf.c b/Python/mysnprintf.c index cd69198011e3..2a505d14f82c 100644 --- a/Python/mysnprintf.c +++ b/Python/mysnprintf.c @@ -9,6 +9,7 @@ would have been written had the buffer not been too small, and to set the last byte of the buffer to \0. At least MS _vsnprintf returns a negative value instead, and fills the entire buffer with non-\0 data. + Unlike C99, our wrappers do not support passing a null buffer. The wrappers ensure that str[size-1] is always \0 upon return. From webhook-mailer at python.org Fri Oct 7 16:53:21 2022 From: webhook-mailer at python.org (ambv) Date: Fri, 07 Oct 2022 20:53:21 -0000 Subject: [Python-checkins] [3.11] gh-91708: Revert params note in urllib.parse.urlparse table (GH-96699) (#98052) Message-ID: https://github.com/python/cpython/commit/40d5e89d3bbd92f7340c67ae5c60c28a2d11bde3 commit: 40d5e89d3bbd92f7340c67ae5c60c28a2d11bde3 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-07T13:53:15-07:00 summary: [3.11] gh-91708: Revert params note in urllib.parse.urlparse table (GH-96699) (#98052) Revert params note in urllib.parse.urlparse table (cherry picked from commit eed80458e8e776d15fa862da71dcce58c47e2ca7) Co-authored-by: Stanley <46876382+slateny at users.noreply.github.com> files: M Doc/library/urllib.parse.rst diff --git a/Doc/library/urllib.parse.rst b/Doc/library/urllib.parse.rst index 1478b34bc955..96b396510794 100644 --- a/Doc/library/urllib.parse.rst +++ b/Doc/library/urllib.parse.rst @@ -113,7 +113,8 @@ or on combining URL components into a URL string. +------------------+-------+-------------------------+------------------------+ | :attr:`path` | 2 | Hierarchical path | empty string | +------------------+-------+-------------------------+------------------------+ - | :attr:`params` | 3 | No longer used | always an empty string | + | :attr:`params` | 3 | Parameters for last | empty string | + | | | path element | | +------------------+-------+-------------------------+------------------------+ | :attr:`query` | 4 | Query component | empty string | +------------------+-------+-------------------------+------------------------+ From webhook-mailer at python.org Fri Oct 7 16:53:45 2022 From: webhook-mailer at python.org (ambv) Date: Fri, 07 Oct 2022 20:53:45 -0000 Subject: [Python-checkins] [3.9] gh-91708: Revert params note in urllib.parse.urlparse table (GH-96699) (#98054) Message-ID: https://github.com/python/cpython/commit/1db2d952849d466303c79be25c50919a08f6a563 commit: 1db2d952849d466303c79be25c50919a08f6a563 branch: 3.9 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-07T13:53:39-07:00 summary: [3.9] gh-91708: Revert params note in urllib.parse.urlparse table (GH-96699) (#98054) Revert params note in urllib.parse.urlparse table (cherry picked from commit eed80458e8e776d15fa862da71dcce58c47e2ca7) Co-authored-by: Stanley <46876382+slateny at users.noreply.github.com> files: M Doc/library/urllib.parse.rst diff --git a/Doc/library/urllib.parse.rst b/Doc/library/urllib.parse.rst index b7430e9d4d67..f0f8605128f4 100644 --- a/Doc/library/urllib.parse.rst +++ b/Doc/library/urllib.parse.rst @@ -113,7 +113,8 @@ or on combining URL components into a URL string. +------------------+-------+-------------------------+------------------------+ | :attr:`path` | 2 | Hierarchical path | empty string | +------------------+-------+-------------------------+------------------------+ - | :attr:`params` | 3 | No longer used | always an empty string | + | :attr:`params` | 3 | Parameters for last | empty string | + | | | path element | | +------------------+-------+-------------------------+------------------------+ | :attr:`query` | 4 | Query component | empty string | +------------------+-------+-------------------------+------------------------+ From webhook-mailer at python.org Fri Oct 7 17:38:45 2022 From: webhook-mailer at python.org (pablogsal) Date: Fri, 07 Oct 2022 21:38:45 -0000 Subject: [Python-checkins] gh-97997: Add col_offset field to tokenizer and use that for AST nodes (#98000) Message-ID: https://github.com/python/cpython/commit/3de08ce8c15ab21a010d3bb0618ac42d15c8eff0 commit: 3de08ce8c15ab21a010d3bb0618ac42d15c8eff0 branch: main author: Lysandros Nikolaou committer: pablogsal date: 2022-10-07T14:38:35-07:00 summary: gh-97997: Add col_offset field to tokenizer and use that for AST nodes (#98000) files: A Misc/NEWS.d/next/Core and Builtins/2022-10-06-23-13-34.gh-issue-97997.JQaJKF.rst M Parser/tokenizer.c M Parser/tokenizer.h diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-06-23-13-34.gh-issue-97997.JQaJKF.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-06-23-13-34.gh-issue-97997.JQaJKF.rst new file mode 100644 index 000000000000..5cb5e2126638 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-06-23-13-34.gh-issue-97997.JQaJKF.rst @@ -0,0 +1 @@ +Add running column offset to the tokenizer state to avoid calculating AST column information with pointer arithmetic. diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index c5d3e580247c..1c356d3d47c9 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -37,6 +37,11 @@ #define TABSIZE 8 #define MAKE_TOKEN(token_type) token_setup(tok, token, token_type, p_start, p_end) +#define MAKE_TYPE_COMMENT_TOKEN(token_type, col_offset, end_col_offset) (\ + type_comment_token_setup(tok, token, token_type, col_offset, end_col_offset, p_start, p_end)) +#define ADVANCE_LINENO() \ + tok->lineno++; \ + tok->col_offset = 0; /* Forward */ static struct tok_state *tok_new(void); @@ -73,6 +78,8 @@ tok_new(void) tok->pendin = 0; tok->prompt = tok->nextprompt = NULL; tok->lineno = 0; + tok->starting_col_offset = -1; + tok->col_offset = -1; tok->level = 0; tok->altindstack[0] = 0; tok->decoding_state = STATE_INIT; @@ -871,7 +878,7 @@ tok_underflow_string(struct tok_state *tok) { tok->buf = tok->cur; } tok->line_start = tok->cur; - tok->lineno++; + ADVANCE_LINENO(); tok->inp = end; return 1; } @@ -930,7 +937,7 @@ tok_underflow_interactive(struct tok_state *tok) { else if (tok->start != NULL) { Py_ssize_t cur_multi_line_start = tok->multi_line_start - tok->buf; size_t size = strlen(newtok); - tok->lineno++; + ADVANCE_LINENO(); if (!tok_reserve_buf(tok, size + 1)) { PyMem_Free(tok->buf); tok->buf = NULL; @@ -943,7 +950,7 @@ tok_underflow_interactive(struct tok_state *tok) { tok->multi_line_start = tok->buf + cur_multi_line_start; } else { - tok->lineno++; + ADVANCE_LINENO(); PyMem_Free(tok->buf); tok->buf = newtok; tok->cur = tok->buf; @@ -998,7 +1005,7 @@ tok_underflow_file(struct tok_state *tok) { *tok->inp = '\0'; } - tok->lineno++; + ADVANCE_LINENO(); if (tok->decoding_state != STATE_NORMAL) { if (tok->lineno > 2) { tok->decoding_state = STATE_NORMAL; @@ -1056,6 +1063,7 @@ tok_nextc(struct tok_state *tok) int rc; for (;;) { if (tok->cur != tok->inp) { + tok->col_offset++; return Py_CHARMASK(*tok->cur++); /* Fast path */ } if (tok->done != E_OK) { @@ -1104,6 +1112,7 @@ tok_backup(struct tok_state *tok, int c) if ((int)(unsigned char)*tok->cur != c) { Py_FatalError("tok_backup: wrong character"); } + tok->col_offset--; } } @@ -1390,6 +1399,19 @@ tok_continuation_line(struct tok_state *tok) { return c; } +static int +type_comment_token_setup(struct tok_state *tok, struct token *token, int type, int col_offset, + int end_col_offset, const char *start, const char *end) +{ + token->level = tok->level; + token->lineno = token->end_lineno = tok->lineno; + token->col_offset = col_offset; + token->end_col_offset = end_col_offset; + token->start = start; + token->end = end; + return type; +} + static int token_setup(struct tok_state *tok, struct token *token, int type, const char *start, const char *end) { @@ -1397,14 +1419,13 @@ token_setup(struct tok_state *tok, struct token *token, int type, const char *st token->level = tok->level; token->lineno = type == STRING ? tok->first_lineno : tok->lineno; token->end_lineno = tok->lineno; - token->col_offset = -1; - token->end_col_offset = -1; + token->col_offset = token->end_col_offset = -1; token->start = start; token->end = end; + if (start != NULL && end != NULL) { - const char *line_start = type == STRING ? tok->multi_line_start : tok->line_start; - token->col_offset = (start >= line_start) ? (int)(start - line_start) : -1; - token->end_col_offset = (end >= tok->line_start) ? (int)(end - tok->line_start) : -1; + token->col_offset = tok->starting_col_offset; + token->end_col_offset = tok->col_offset; } return type; } @@ -1419,6 +1440,7 @@ tok_get(struct tok_state *tok, struct token *token) const char *p_end = NULL; nextline: tok->start = NULL; + tok->starting_col_offset = -1; blankline = 0; /* Get indentation level */ @@ -1518,6 +1540,7 @@ tok_get(struct tok_state *tok, struct token *token) } tok->start = tok->cur; + tok->starting_col_offset = tok->col_offset; /* Return pending indents/dedents */ if (tok->pendin != 0) { @@ -1565,10 +1588,12 @@ tok_get(struct tok_state *tok, struct token *token) /* Set start of current token */ tok->start = tok->cur == NULL ? NULL : tok->cur - 1; + tok->starting_col_offset = tok->col_offset - 1; /* Skip comment, unless it's a type comment */ if (c == '#') { const char *prefix, *p, *type_start; + int current_starting_col_offset; while (c != EOF && c != '\n') { c = tok_nextc(tok); @@ -1576,14 +1601,17 @@ tok_get(struct tok_state *tok, struct token *token) if (tok->type_comments) { p = tok->start; + current_starting_col_offset = tok->starting_col_offset; prefix = type_comment_prefix; while (*prefix && p < tok->cur) { if (*prefix == ' ') { while (*p == ' ' || *p == '\t') { p++; + current_starting_col_offset++; } } else if (*prefix == *p) { p++; + current_starting_col_offset++; } else { break; } @@ -1594,7 +1622,9 @@ tok_get(struct tok_state *tok, struct token *token) /* This is a type comment if we matched all of type_comment_prefix. */ if (!*prefix) { int is_type_ignore = 1; + // +6 in order to skip the word 'ignore' const char *ignore_end = p + 6; + const int ignore_end_col_offset = current_starting_col_offset + 6; tok_backup(tok, c); /* don't eat the newline or EOF */ type_start = p; @@ -1615,11 +1645,11 @@ tok_get(struct tok_state *tok, struct token *token) tok_nextc(tok); tok->atbol = 1; } - return MAKE_TOKEN(TYPE_IGNORE); + return MAKE_TYPE_COMMENT_TOKEN(TYPE_IGNORE, ignore_end_col_offset, tok->col_offset); } else { p_start = type_start; p_end = tok->cur; - return MAKE_TOKEN(TYPE_COMMENT); + return MAKE_TYPE_COMMENT_TOKEN(TYPE_COMMENT, current_starting_col_offset, tok->col_offset); } } } diff --git a/Parser/tokenizer.h b/Parser/tokenizer.h index 5b8c7f314386..2542d30e1da0 100644 --- a/Parser/tokenizer.h +++ b/Parser/tokenizer.h @@ -57,6 +57,8 @@ struct tok_state { int lineno; /* Current line number */ int first_lineno; /* First line of a single line or multi line string expression (cf. issue 16806) */ + int starting_col_offset; /* The column offset at the beginning of a token */ + int col_offset; /* Current col offset */ int level; /* () [] {} Parentheses nesting level */ /* Used to allow free continuations inside them */ char parenstack[MAXLEVEL]; From webhook-mailer at python.org Fri Oct 7 17:41:44 2022 From: webhook-mailer at python.org (miss-islington) Date: Fri, 07 Oct 2022 21:41:44 -0000 Subject: [Python-checkins] gh-92886: [clinic.py] raise exception on invalid input instead of assertion (GH-98051) Message-ID: https://github.com/python/cpython/commit/34e6f3567e3519e0e8cdb7bbc4b68b9ab40493c8 commit: 34e6f3567e3519e0e8cdb7bbc4b68b9ab40493c8 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-07T14:41:35-07:00 summary: gh-92886: [clinic.py] raise exception on invalid input instead of assertion (GH-98051) Tests should pass with -O (assertions off). Automerge-Triggered-By: GH:iritkatriel files: M Lib/test/test_clinic.py M Tools/clinic/clinic.py diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index 4aa9691a4829..8ab40c694f71 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -153,7 +153,7 @@ def test_right_only(self): def test_have_left_options_but_required_is_empty(self): def fn(): clinic.permute_optional_groups(['a'], [], []) - self.assertRaises(AssertionError, fn) + self.assertRaises(ValueError, fn) class ClinicLinearFormatTest(TestCase): diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 30a676328706..a8687e3470a1 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -495,7 +495,8 @@ def permute_optional_groups(left, required, right): result = [] if not required: - assert not left + if left: + raise ValueError("required is empty but left is not") accumulator = [] counts = set() From webhook-mailer at python.org Fri Oct 7 17:45:05 2022 From: webhook-mailer at python.org (miss-islington) Date: Fri, 07 Oct 2022 21:45:05 -0000 Subject: [Python-checkins] gh-96073: fix backticks in NEWS entry (GH-98056) Message-ID: https://github.com/python/cpython/commit/0f111f53c1815766583ca9d5c06671ad89abcb77 commit: 0f111f53c1815766583ca9d5c06671ad89abcb77 branch: main author: Jelle Zijlstra committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-07T14:44:56-07:00 summary: gh-96073: fix backticks in NEWS entry (GH-98056) Automerge-Triggered-By: GH:JelleZijlstra files: M Doc/faq/design.rst M Misc/NEWS.d/next/Library/2022-08-29-12-35-28.gh-issue-96073.WaGstf.rst diff --git a/Doc/faq/design.rst b/Doc/faq/design.rst index 763222aba8b6..11d01374dc1e 100644 --- a/Doc/faq/design.rst +++ b/Doc/faq/design.rst @@ -62,7 +62,7 @@ and think it is a bug in Python. It's not. This has little to do with Python, and much more to do with how the underlying platform handles floating-point numbers. -The :class:`float` type in CPython uses a C :c:type:`double` for storage. A +The :class:`float` type in CPython uses a C ``double`` for storage. A :class:`float` object's value is stored in binary floating-point with a fixed precision (typically 53 bits) and Python uses C operations, which in turn rely on the hardware implementation in the processor, to perform floating-point diff --git a/Misc/NEWS.d/next/Library/2022-08-29-12-35-28.gh-issue-96073.WaGstf.rst b/Misc/NEWS.d/next/Library/2022-08-29-12-35-28.gh-issue-96073.WaGstf.rst index 0e6dd8d360cb..8f20588c4c58 100644 --- a/Misc/NEWS.d/next/Library/2022-08-29-12-35-28.gh-issue-96073.WaGstf.rst +++ b/Misc/NEWS.d/next/Library/2022-08-29-12-35-28.gh-issue-96073.WaGstf.rst @@ -1 +1 @@ -In :mod:`inspect`, fix overeager replacement of "`typing.`" in formatting annotations. +In :mod:`inspect`, fix overeager replacement of "``typing.``" in formatting annotations. From webhook-mailer at python.org Fri Oct 7 18:06:26 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Fri, 07 Oct 2022 22:06:26 -0000 Subject: [Python-checkins] gh-96288: Add a sentence to `os.mkdir`'s docstring. (#96271) Message-ID: https://github.com/python/cpython/commit/1523c9e9d47e7d67e4889987ff0f38eb7b881fdd commit: 1523c9e9d47e7d67e4889987ff0f38eb7b881fdd branch: main author: Hagai Helman Tov committer: JelleZijlstra date: 2022-10-07T15:06:16-07:00 summary: gh-96288: Add a sentence to `os.mkdir`'s docstring. (#96271) files: M Modules/clinic/posixmodule.c.h M Modules/posixmodule.c diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h index 7fac07804686..31bd01d1c3c1 100644 --- a/Modules/clinic/posixmodule.c.h +++ b/Modules/clinic/posixmodule.c.h @@ -1849,7 +1849,8 @@ PyDoc_STRVAR(os_mkdir__doc__, "dir_fd may not be implemented on your platform.\n" " If it is unavailable, using it will raise a NotImplementedError.\n" "\n" -"The mode argument is ignored on Windows."); +"The mode argument is ignored on Windows. Where it is used, the current umask\n" +"value is first masked out."); #define OS_MKDIR_METHODDEF \ {"mkdir", _PyCFunction_CAST(os_mkdir), METH_FASTCALL|METH_KEYWORDS, os_mkdir__doc__}, @@ -11367,4 +11368,4 @@ os_waitstatus_to_exitcode(PyObject *module, PyObject *const *args, Py_ssize_t na #ifndef OS_WAITSTATUS_TO_EXITCODE_METHODDEF #define OS_WAITSTATUS_TO_EXITCODE_METHODDEF #endif /* !defined(OS_WAITSTATUS_TO_EXITCODE_METHODDEF) */ -/*[clinic end generated code: output=dd43d388b442c96d input=a9049054013a1b77]*/ +/*[clinic end generated code: output=471ab8f2ad3d46b0 input=a9049054013a1b77]*/ diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index a72d57771c22..1e556fc904b7 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -4539,12 +4539,13 @@ If dir_fd is not None, it should be a file descriptor open to a directory, dir_fd may not be implemented on your platform. If it is unavailable, using it will raise a NotImplementedError. -The mode argument is ignored on Windows. +The mode argument is ignored on Windows. Where it is used, the current umask +value is first masked out. [clinic start generated code]*/ static PyObject * os_mkdir_impl(PyObject *module, path_t *path, int mode, int dir_fd) -/*[clinic end generated code: output=a70446903abe821f input=e965f68377e9b1ce]*/ +/*[clinic end generated code: output=a70446903abe821f input=a61722e1576fab03]*/ { int result; #ifdef HAVE_MKDIRAT From webhook-mailer at python.org Fri Oct 7 18:21:24 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Fri, 07 Oct 2022 22:21:24 -0000 Subject: [Python-checkins] gh-61105: Add default param, note on using cookiejar subclass (#95427) Message-ID: https://github.com/python/cpython/commit/5eaf4d610147a3b9adc91a55790096d05bbe01d4 commit: 5eaf4d610147a3b9adc91a55790096d05bbe01d4 branch: main author: Stanley <46876382+slateny at users.noreply.github.com> committer: JelleZijlstra date: 2022-10-07T15:21:13-07:00 summary: gh-61105: Add default param, note on using cookiejar subclass (#95427) files: M Doc/library/http.cookiejar.rst diff --git a/Doc/library/http.cookiejar.rst b/Doc/library/http.cookiejar.rst index eb31315438f6..87ef156a0bed 100644 --- a/Doc/library/http.cookiejar.rst +++ b/Doc/library/http.cookiejar.rst @@ -61,7 +61,7 @@ The following classes are provided: responsible for storing and retrieving cookies from a file or database. -.. class:: FileCookieJar(filename, delayload=None, policy=None) +.. class:: FileCookieJar(filename=None, delayload=None, policy=None) *policy* is an object implementing the :class:`CookiePolicy` interface. For the other arguments, see the documentation for the corresponding attributes. @@ -71,6 +71,8 @@ The following classes are provided: :meth:`load` or :meth:`revert` method is called. Subclasses of this class are documented in section :ref:`file-cookie-jar-classes`. + This should not be initialized directly ? use its subclasses below instead. + .. versionchanged:: 3.8 The filename parameter supports a :term:`path-like object`. @@ -317,7 +319,7 @@ FileCookieJar subclasses and co-operation with web browsers The following :class:`CookieJar` subclasses are provided for reading and writing. -.. class:: MozillaCookieJar(filename, delayload=None, policy=None) +.. class:: MozillaCookieJar(filename=None, delayload=None, policy=None) A :class:`FileCookieJar` that can load from and save cookies to disk in the Mozilla ``cookies.txt`` file format (which is also used by curl and the Lynx @@ -338,7 +340,7 @@ writing. Mozilla. -.. class:: LWPCookieJar(filename, delayload=None, policy=None) +.. class:: LWPCookieJar(filename=None, delayload=None, policy=None) A :class:`FileCookieJar` that can load from and save cookies to disk in format compatible with the libwww-perl library's ``Set-Cookie3`` file format. This is From webhook-mailer at python.org Fri Oct 7 18:24:26 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Fri, 07 Oct 2022 22:24:26 -0000 Subject: [Python-checkins] GH-83901: Improve Signature.bind error message for missing keyword-only params (#95347) Message-ID: https://github.com/python/cpython/commit/f4f813338736aecc9285a9408cb8a07eaeb0e373 commit: f4f813338736aecc9285a9408cb8a07eaeb0e373 branch: main author: Frazer McLean committer: JelleZijlstra date: 2022-10-07T15:24:17-07:00 summary: GH-83901: Improve Signature.bind error message for missing keyword-only params (#95347) Fixes GH-83901 files: A Misc/NEWS.d/next/Library/2022-07-27-19-47-51.gh-issue-83901.OSw06c.rst M Lib/inspect.py M Lib/test/test_inspect.py diff --git a/Lib/inspect.py b/Lib/inspect.py index 585875a30c35..f6750c3b211f 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -3102,8 +3102,12 @@ def _bind(self, args, kwargs, *, partial=False): parameters_ex = (param,) break else: - msg = 'missing a required argument: {arg!r}' - msg = msg.format(arg=param.name) + if param.kind == _KEYWORD_ONLY: + argtype = ' keyword-only' + else: + argtype = '' + msg = 'missing a required{argtype} argument: {arg!r}' + msg = msg.format(arg=param.name, argtype=argtype) raise TypeError(msg) from None else: # We have a positional argument to process diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index 61fed323dcea..cfc6e411ea68 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -3898,7 +3898,8 @@ def test(foo, *, bar): self.call(test, 1, bar=2, spam='ham') with self.assertRaisesRegex(TypeError, - "missing a required argument: 'bar'"): + "missing a required keyword-only " + "argument: 'bar'"): self.call(test, 1) def test(foo, *, bar, **bin): diff --git a/Misc/NEWS.d/next/Library/2022-07-27-19-47-51.gh-issue-83901.OSw06c.rst b/Misc/NEWS.d/next/Library/2022-07-27-19-47-51.gh-issue-83901.OSw06c.rst new file mode 100644 index 000000000000..da407905a886 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-07-27-19-47-51.gh-issue-83901.OSw06c.rst @@ -0,0 +1 @@ +Improve :meth:`Signature.bind ` error message for missing keyword-only arguments. From webhook-mailer at python.org Fri Oct 7 18:38:29 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Fri, 07 Oct 2022 22:38:29 -0000 Subject: [Python-checkins] gh-90085: Remove vestigial -t and -c timeit options (#94941) Message-ID: https://github.com/python/cpython/commit/cb4615fd43e678fe44e9aeb6a486475a05b492e7 commit: cb4615fd43e678fe44e9aeb6a486475a05b492e7 branch: main author: Shantanu <12621235+hauntsaninja at users.noreply.github.com> committer: JelleZijlstra date: 2022-10-07T15:38:20-07:00 summary: gh-90085: Remove vestigial -t and -c timeit options (#94941) See bpo-28240. The functionality was removed in 3d7feb9ac2. The options had been deprecated since Python 3.3 files: A Misc/NEWS.d/next/Library/2022-07-17-22-31-32.gh-issue-90085.c4FWcS.rst M Lib/timeit.py diff --git a/Lib/timeit.py b/Lib/timeit.py index 9dfd454936e6..0cf8db67723a 100755 --- a/Lib/timeit.py +++ b/Lib/timeit.py @@ -259,10 +259,9 @@ def main(args=None, *, _wrap_timer=None): args = sys.argv[1:] import getopt try: - opts, args = getopt.getopt(args, "n:u:s:r:tcpvh", + opts, args = getopt.getopt(args, "n:u:s:r:pvh", ["number=", "setup=", "repeat=", - "time", "clock", "process", - "verbose", "unit=", "help"]) + "process", "verbose", "unit=", "help"]) except getopt.error as err: print(err) print("use -h/--help for command line help") diff --git a/Misc/NEWS.d/next/Library/2022-07-17-22-31-32.gh-issue-90085.c4FWcS.rst b/Misc/NEWS.d/next/Library/2022-07-17-22-31-32.gh-issue-90085.c4FWcS.rst new file mode 100644 index 000000000000..37952adc8f1a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-07-17-22-31-32.gh-issue-90085.c4FWcS.rst @@ -0,0 +1,3 @@ +Remove ``-c/--clock`` and ``-t/--time`` CLI options of :mod:`timeit`. +The options had been deprecated since Python 3.3 and the functionality +was removed in Python 3.7. Patch by Shantanu Jain. From webhook-mailer at python.org Fri Oct 7 18:38:41 2022 From: webhook-mailer at python.org (miss-islington) Date: Fri, 07 Oct 2022 22:38:41 -0000 Subject: [Python-checkins] gh-96073: fix backticks in NEWS entry (GH-98056) Message-ID: https://github.com/python/cpython/commit/8c81d330b98db3624317feb5f77a594d2b00d299 commit: 8c81d330b98db3624317feb5f77a594d2b00d299 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-07T15:38:35-07:00 summary: gh-96073: fix backticks in NEWS entry (GH-98056) Automerge-Triggered-By: GH:JelleZijlstra (cherry picked from commit 0f111f53c1815766583ca9d5c06671ad89abcb77) Co-authored-by: Jelle Zijlstra files: M Misc/NEWS.d/next/Library/2022-08-29-12-35-28.gh-issue-96073.WaGstf.rst diff --git a/Misc/NEWS.d/next/Library/2022-08-29-12-35-28.gh-issue-96073.WaGstf.rst b/Misc/NEWS.d/next/Library/2022-08-29-12-35-28.gh-issue-96073.WaGstf.rst index 0e6dd8d360cb..8f20588c4c58 100644 --- a/Misc/NEWS.d/next/Library/2022-08-29-12-35-28.gh-issue-96073.WaGstf.rst +++ b/Misc/NEWS.d/next/Library/2022-08-29-12-35-28.gh-issue-96073.WaGstf.rst @@ -1 +1 @@ -In :mod:`inspect`, fix overeager replacement of "`typing.`" in formatting annotations. +In :mod:`inspect`, fix overeager replacement of "``typing.``" in formatting annotations. From webhook-mailer at python.org Fri Oct 7 18:40:00 2022 From: webhook-mailer at python.org (miss-islington) Date: Fri, 07 Oct 2022 22:40:00 -0000 Subject: [Python-checkins] gh-96073: fix backticks in NEWS entry (GH-98056) Message-ID: https://github.com/python/cpython/commit/9dea4e218f61b4c97db0099d70f9f59a93e9e371 commit: 9dea4e218f61b4c97db0099d70f9f59a93e9e371 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-07T15:39:54-07:00 summary: gh-96073: fix backticks in NEWS entry (GH-98056) Automerge-Triggered-By: GH:JelleZijlstra (cherry picked from commit 0f111f53c1815766583ca9d5c06671ad89abcb77) Co-authored-by: Jelle Zijlstra files: M Misc/NEWS.d/next/Library/2022-08-29-12-35-28.gh-issue-96073.WaGstf.rst diff --git a/Misc/NEWS.d/next/Library/2022-08-29-12-35-28.gh-issue-96073.WaGstf.rst b/Misc/NEWS.d/next/Library/2022-08-29-12-35-28.gh-issue-96073.WaGstf.rst index 0e6dd8d360cb..8f20588c4c58 100644 --- a/Misc/NEWS.d/next/Library/2022-08-29-12-35-28.gh-issue-96073.WaGstf.rst +++ b/Misc/NEWS.d/next/Library/2022-08-29-12-35-28.gh-issue-96073.WaGstf.rst @@ -1 +1 @@ -In :mod:`inspect`, fix overeager replacement of "`typing.`" in formatting annotations. +In :mod:`inspect`, fix overeager replacement of "``typing.``" in formatting annotations. From webhook-mailer at python.org Fri Oct 7 18:40:02 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Fri, 07 Oct 2022 22:40:02 -0000 Subject: [Python-checkins] gh-94808: Fix regex on exotic platforms (#98036) Message-ID: https://github.com/python/cpython/commit/a54a69989eade3589459d15def53b3c4f21b7551 commit: a54a69989eade3589459d15def53b3c4f21b7551 branch: main author: Jelle Zijlstra committer: JelleZijlstra date: 2022-10-07T15:39:53-07:00 summary: gh-94808: Fix regex on exotic platforms (#98036) The test failed on a buildbot because the pointer was only 7 hex characters. To be safe, I bumped it down to 3: 4 in case we have 32-bit platforms, and 3 in case the pointer is very small. files: M Lib/test/test_unicode.py M Makefile.pre.in diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py index b9ee9d30318c..5b816574f2c3 100644 --- a/Lib/test/test_unicode.py +++ b/Lib/test/test_unicode.py @@ -2811,7 +2811,7 @@ def check_format(expected, format, *args): # We cannot test the exact result, # because it returns a hex representation of a C pointer, # which is going to be different each time. But, we can test the format. - p_format_regex = r'^0x[a-zA-Z0-9]{8,}$' + p_format_regex = r'^0x[a-zA-Z0-9]{3,}$' p_format1 = PyUnicode_FromFormat(b'%p', 'abc') self.assertIsInstance(p_format1, str) self.assertRegex(p_format1, p_format_regex) @@ -2819,7 +2819,7 @@ def check_format(expected, format, *args): p_format2 = PyUnicode_FromFormat(b'%p %p', '123456', b'xyz') self.assertIsInstance(p_format2, str) self.assertRegex(p_format2, - r'0x[a-zA-Z0-9]{8,} 0x[a-zA-Z0-9]{8,}') + r'0x[a-zA-Z0-9]{3,} 0x[a-zA-Z0-9]{3,}') # Extra args are ignored: p_format3 = PyUnicode_FromFormat(b'%p', '123456', None, b'xyz') diff --git a/Makefile.pre.in b/Makefile.pre.in index 11118354f15d..4602db69d15a 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -2038,6 +2038,7 @@ TESTSUBDIRS= distutils/tests \ test/test_zoneinfo test/test_zoneinfo/data \ test/test_unittest test/test_unittest/testmock \ test/tracedmodules \ + test/typinganndata \ test/xmltestdata test/xmltestdata/c14n-20 \ test/ziptestdata From webhook-mailer at python.org Fri Oct 7 18:41:12 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Fri, 07 Oct 2022 22:41:12 -0000 Subject: [Python-checkins] [3.10] gh-94808: Cover `%p` in `PyUnicode_FromFormat` (GH-96677) (#98032) Message-ID: https://github.com/python/cpython/commit/6f40e2fb930ff51bbc5a525f661dcc0b71b38a13 commit: 6f40e2fb930ff51bbc5a525f661dcc0b71b38a13 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: JelleZijlstra date: 2022-10-07T15:41:06-07:00 summary: [3.10] gh-94808: Cover `%p` in `PyUnicode_FromFormat` (GH-96677) (#98032) Co-authored-by: Nikita Sobolev Co-authored-by: Jelle Zijlstra (cherry picked from commit 72c166add89a0cd992d66f75ce94eee5eb675a99) files: M Lib/test/test_unicode.py diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py index dd1428710d56..f5ce095d1c12 100644 --- a/Lib/test/test_unicode.py +++ b/Lib/test/test_unicode.py @@ -2759,6 +2759,25 @@ def check_format(expected, format, *args): check_format('repr=abc', b'repr=%V', 'abc', b'xyz') + # test %p + # We cannot test the exact result, + # because it returns a hex representation of a C pointer, + # which is going to be different each time. But, we can test the format. + p_format_regex = r'^0x[a-zA-Z0-9]{3,}$' + p_format1 = PyUnicode_FromFormat(b'%p', 'abc') + self.assertIsInstance(p_format1, str) + self.assertRegex(p_format1, p_format_regex) + + p_format2 = PyUnicode_FromFormat(b'%p %p', '123456', b'xyz') + self.assertIsInstance(p_format2, str) + self.assertRegex(p_format2, + r'0x[a-zA-Z0-9]{3,} 0x[a-zA-Z0-9]{3,}') + + # Extra args are ignored: + p_format3 = PyUnicode_FromFormat(b'%p', '123456', None, b'xyz') + self.assertIsInstance(p_format3, str) + self.assertRegex(p_format3, p_format_regex) + # Test string decode from parameter of %s using utf-8. # b'\xe4\xba\xba\xe6\xb0\x91' is utf-8 encoded byte sequence of # '\u4eba\u6c11' From webhook-mailer at python.org Fri Oct 7 18:51:59 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Fri, 07 Oct 2022 22:51:59 -0000 Subject: [Python-checkins] gh-57179: Add note on symlinks for os.walk (#94799) Message-ID: https://github.com/python/cpython/commit/0f498f1a95306995ca1e287f552c5c3d856be02d commit: 0f498f1a95306995ca1e287f552c5c3d856be02d branch: main author: Stanley <46876382+slateny at users.noreply.github.com> committer: JelleZijlstra date: 2022-10-07T15:51:50-07:00 summary: gh-57179: Add note on symlinks for os.walk (#94799) files: M Doc/library/os.rst M Lib/os.py diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 23b014b0b659..8727f811def1 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -3222,7 +3222,8 @@ features: filenames)``. *dirpath* is a string, the path to the directory. *dirnames* is a list of the - names of the subdirectories in *dirpath* (excluding ``'.'`` and ``'..'``). + names of the subdirectories in *dirpath* (including symlinks to directories, + and excluding ``'.'`` and ``'..'``). *filenames* is a list of the names of the non-directory files in *dirpath*. Note that the names in the lists contain no path components. To get a full path (which begins with *top*) to a file or directory in *dirpath*, do diff --git a/Lib/os.py b/Lib/os.py index 648188e0f134..fd1e774fdcbc 100644 --- a/Lib/os.py +++ b/Lib/os.py @@ -288,7 +288,8 @@ def walk(top, topdown=True, onerror=None, followlinks=False): dirpath, dirnames, filenames dirpath is a string, the path to the directory. dirnames is a list of - the names of the subdirectories in dirpath (excluding '.' and '..'). + the names of the subdirectories in dirpath (including symlinks to directories, + and excluding '.' and '..'). filenames is a list of the names of the non-directory files in dirpath. Note that the names in the lists are just names, with no path components. To get a full path (which begins with top) to a file or directory in From webhook-mailer at python.org Fri Oct 7 19:02:49 2022 From: webhook-mailer at python.org (ambv) Date: Fri, 07 Oct 2022 23:02:49 -0000 Subject: [Python-checkins] [3.10] gh-91708: Revert params note in urllib.parse.urlparse table (GH-96699) (#98053) Message-ID: https://github.com/python/cpython/commit/02394400f3e03b2c8be7154fd38981fa9e7d1ef0 commit: 02394400f3e03b2c8be7154fd38981fa9e7d1ef0 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-07T16:02:43-07:00 summary: [3.10] gh-91708: Revert params note in urllib.parse.urlparse table (GH-96699) (#98053) Revert params note in urllib.parse.urlparse table (cherry picked from commit eed80458e8e776d15fa862da71dcce58c47e2ca7) Co-authored-by: Stanley <46876382+slateny at users.noreply.github.com> files: M Doc/library/urllib.parse.rst diff --git a/Doc/library/urllib.parse.rst b/Doc/library/urllib.parse.rst index 1478b34bc955..96b396510794 100644 --- a/Doc/library/urllib.parse.rst +++ b/Doc/library/urllib.parse.rst @@ -113,7 +113,8 @@ or on combining URL components into a URL string. +------------------+-------+-------------------------+------------------------+ | :attr:`path` | 2 | Hierarchical path | empty string | +------------------+-------+-------------------------+------------------------+ - | :attr:`params` | 3 | No longer used | always an empty string | + | :attr:`params` | 3 | Parameters for last | empty string | + | | | path element | | +------------------+-------+-------------------------+------------------------+ | :attr:`query` | 4 | Query component | empty string | +------------------+-------+-------------------------+------------------------+ From webhook-mailer at python.org Fri Oct 7 19:05:58 2022 From: webhook-mailer at python.org (miss-islington) Date: Fri, 07 Oct 2022 23:05:58 -0000 Subject: [Python-checkins] gh-61105: Add default param, note on using cookiejar subclass (GH-95427) Message-ID: https://github.com/python/cpython/commit/17c9ce112fd80300afc446d1a67efefdf97faf68 commit: 17c9ce112fd80300afc446d1a67efefdf97faf68 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-07T16:05:52-07:00 summary: gh-61105: Add default param, note on using cookiejar subclass (GH-95427) (cherry picked from commit 5eaf4d610147a3b9adc91a55790096d05bbe01d4) Co-authored-by: Stanley <46876382+slateny at users.noreply.github.com> files: M Doc/library/http.cookiejar.rst diff --git a/Doc/library/http.cookiejar.rst b/Doc/library/http.cookiejar.rst index eb31315438f6..87ef156a0bed 100644 --- a/Doc/library/http.cookiejar.rst +++ b/Doc/library/http.cookiejar.rst @@ -61,7 +61,7 @@ The following classes are provided: responsible for storing and retrieving cookies from a file or database. -.. class:: FileCookieJar(filename, delayload=None, policy=None) +.. class:: FileCookieJar(filename=None, delayload=None, policy=None) *policy* is an object implementing the :class:`CookiePolicy` interface. For the other arguments, see the documentation for the corresponding attributes. @@ -71,6 +71,8 @@ The following classes are provided: :meth:`load` or :meth:`revert` method is called. Subclasses of this class are documented in section :ref:`file-cookie-jar-classes`. + This should not be initialized directly ? use its subclasses below instead. + .. versionchanged:: 3.8 The filename parameter supports a :term:`path-like object`. @@ -317,7 +319,7 @@ FileCookieJar subclasses and co-operation with web browsers The following :class:`CookieJar` subclasses are provided for reading and writing. -.. class:: MozillaCookieJar(filename, delayload=None, policy=None) +.. class:: MozillaCookieJar(filename=None, delayload=None, policy=None) A :class:`FileCookieJar` that can load from and save cookies to disk in the Mozilla ``cookies.txt`` file format (which is also used by curl and the Lynx @@ -338,7 +340,7 @@ writing. Mozilla. -.. class:: LWPCookieJar(filename, delayload=None, policy=None) +.. class:: LWPCookieJar(filename=None, delayload=None, policy=None) A :class:`FileCookieJar` that can load from and save cookies to disk in format compatible with the libwww-perl library's ``Set-Cookie3`` file format. This is From webhook-mailer at python.org Fri Oct 7 19:12:38 2022 From: webhook-mailer at python.org (miss-islington) Date: Fri, 07 Oct 2022 23:12:38 -0000 Subject: [Python-checkins] gh-92886: make test_coroutines pass with -O (assertions off) (GH-98060) Message-ID: https://github.com/python/cpython/commit/45f21472daad3934baf364c3100063ecc51c6e04 commit: 45f21472daad3934baf364c3100063ecc51c6e04 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-07T16:12:28-07:00 summary: gh-92886: make test_coroutines pass with -O (assertions off) (GH-98060) Automerge-Triggered-By: GH:iritkatriel files: M Lib/test/test_coroutines.py diff --git a/Lib/test/test_coroutines.py b/Lib/test/test_coroutines.py index 9a2279d353ff..f91c9cc47741 100644 --- a/Lib/test/test_coroutines.py +++ b/Lib/test/test_coroutines.py @@ -1287,7 +1287,7 @@ async def __aexit__(self, *exc): async def func(): async with CM(): - assert (1, ) == 1 + self.assertEqual((1, ), 1) with self.assertRaises(AssertionError): run_async(func()) From webhook-mailer at python.org Fri Oct 7 19:30:41 2022 From: webhook-mailer at python.org (miss-islington) Date: Fri, 07 Oct 2022 23:30:41 -0000 Subject: [Python-checkins] gh-92886: make test_ast pass with -O (assertions off) (GH-98058) Message-ID: https://github.com/python/cpython/commit/27ce45d8e105d0c9f9286c3cab830590d4c7cea3 commit: 27ce45d8e105d0c9f9286c3cab830590d4c7cea3 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-07T16:30:23-07:00 summary: gh-92886: make test_ast pass with -O (assertions off) (GH-98058) -O does not strip docstrings. Automerge-Triggered-By: GH:iritkatriel files: M Lib/test/test_dis.py diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index fc2862c61baa..667b267d27a0 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -1212,7 +1212,7 @@ def get_disassembly(self, func, lasti=-1, wrapper=True, **kwargs): return output.getvalue() -if sys.flags.optimize: +if dis.code_info.__doc__ is None: code_info_consts = "0: None" else: code_info_consts = "0: 'Formatted details of methods, functions, or code.'" From webhook-mailer at python.org Fri Oct 7 19:45:58 2022 From: webhook-mailer at python.org (miss-islington) Date: Fri, 07 Oct 2022 23:45:58 -0000 Subject: [Python-checkins] gh-65496: Correct wording on csv's skipinitialspace argument (GH-96170) Message-ID: https://github.com/python/cpython/commit/c2f21af42a50b36e0ef2fce9caaf3a36e946431c commit: c2f21af42a50b36e0ef2fce9caaf3a36e946431c branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-07T16:45:53-07:00 summary: gh-65496: Correct wording on csv's skipinitialspace argument (GH-96170) (cherry picked from commit 676d8ef3806758bcd1d3fd84a746c8a9b64480d0) Co-authored-by: Stanley <46876382+slateny at users.noreply.github.com> files: M Doc/library/csv.rst M Lib/test/test_csv.py M Modules/_csv.c diff --git a/Doc/library/csv.rst b/Doc/library/csv.rst index 9dec7240d9c5..f7e85f2baa73 100644 --- a/Doc/library/csv.rst +++ b/Doc/library/csv.rst @@ -416,7 +416,7 @@ Dialects support the following attributes: .. attribute:: Dialect.skipinitialspace - When :const:`True`, whitespace immediately following the *delimiter* is ignored. + When :const:`True`, spaces immediately following the *delimiter* are ignored. The default is :const:`False`. diff --git a/Lib/test/test_csv.py b/Lib/test/test_csv.py index ff2a668c422f..834217bf6030 100644 --- a/Lib/test/test_csv.py +++ b/Lib/test/test_csv.py @@ -362,6 +362,11 @@ def test_read_quoting(self): self._read_test(['1,@,3,@,5'], [['1', ',3,', '5']], quotechar='@') self._read_test(['1,\0,3,\0,5'], [['1', ',3,', '5']], quotechar='\0') + def test_read_skipinitialspace(self): + self._read_test(['no space, space, spaces,\ttab'], + [['no space', 'space', 'spaces', '\ttab']], + skipinitialspace=True) + def test_read_bigfield(self): # This exercises the buffer realloc functionality and field size # limits. diff --git a/Modules/_csv.c b/Modules/_csv.c index cbf4c5de5196..7519da6807fe 100644 --- a/Modules/_csv.c +++ b/Modules/_csv.c @@ -704,7 +704,7 @@ parse_process_char(ReaderObj *self, _csvstate *module_state, Py_UCS4 c) self->state = ESCAPED_CHAR; } else if (c == ' ' && dialect->skipinitialspace) - /* ignore space at start of field */ + /* ignore spaces at start of field */ ; else if (c == dialect->delimiter) { /* save empty field */ @@ -1647,9 +1647,9 @@ PyDoc_STRVAR(csv_module_doc, " quoting character. It defaults to '\"'.\n" " * delimiter - specifies a one-character string to use as the\n" " field separator. It defaults to ','.\n" -" * skipinitialspace - specifies how to interpret whitespace which\n" -" immediately follows a delimiter. It defaults to False, which\n" -" means that whitespace immediately following a delimiter is part\n" +" * skipinitialspace - specifies how to interpret spaces which\n" +" immediately follow a delimiter. It defaults to False, which\n" +" means that spaces immediately following a delimiter is part\n" " of the following field.\n" " * lineterminator - specifies the character sequence which should\n" " terminate rows.\n" From webhook-mailer at python.org Fri Oct 7 20:09:59 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Sat, 08 Oct 2022 00:09:59 -0000 Subject: [Python-checkins] [3.11] gh-94808: Cover `%p` in `PyUnicode_FromFormat` (GH-96677) (#98033) Message-ID: https://github.com/python/cpython/commit/46aa5d2c2dc60da50291dfdfc00126b14cd92676 commit: 46aa5d2c2dc60da50291dfdfc00126b14cd92676 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: JelleZijlstra date: 2022-10-07T17:09:53-07:00 summary: [3.11] gh-94808: Cover `%p` in `PyUnicode_FromFormat` (GH-96677) (#98033) Co-authored-by: Nikita Sobolev Co-authored-by: Jelle Zijlstra (cherry picked from commit 72c166add89a0cd992d66f75ce94eee5eb675a99) files: M Lib/test/test_unicode.py diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py index 90bd75f550df..9b0e4b230506 100644 --- a/Lib/test/test_unicode.py +++ b/Lib/test/test_unicode.py @@ -2809,6 +2809,25 @@ def check_format(expected, format, *args): check_format('repr=abc', b'repr=%V', 'abc', b'xyz') + # test %p + # We cannot test the exact result, + # because it returns a hex representation of a C pointer, + # which is going to be different each time. But, we can test the format. + p_format_regex = r'^0x[a-zA-Z0-9]{3,}$' + p_format1 = PyUnicode_FromFormat(b'%p', 'abc') + self.assertIsInstance(p_format1, str) + self.assertRegex(p_format1, p_format_regex) + + p_format2 = PyUnicode_FromFormat(b'%p %p', '123456', b'xyz') + self.assertIsInstance(p_format2, str) + self.assertRegex(p_format2, + r'0x[a-zA-Z0-9]{3,} 0x[a-zA-Z0-9]{3,}') + + # Extra args are ignored: + p_format3 = PyUnicode_FromFormat(b'%p', '123456', None, b'xyz') + self.assertIsInstance(p_format3, str) + self.assertRegex(p_format3, p_format_regex) + # Test string decode from parameter of %s using utf-8. # b'\xe4\xba\xba\xe6\xb0\x91' is utf-8 encoded byte sequence of # '\u4eba\u6c11' From webhook-mailer at python.org Fri Oct 7 20:24:10 2022 From: webhook-mailer at python.org (gvanrossum) Date: Sat, 08 Oct 2022 00:24:10 -0000 Subject: [Python-checkins] GH-94182: Run the PidfdChildWatcher on the running loop (#94184) Message-ID: https://github.com/python/cpython/commit/3d8b22454728b6d54cc476cfb59e47ab40f3f527 commit: 3d8b22454728b6d54cc476cfb59e47ab40f3f527 branch: main author: Thomas Grainger committer: gvanrossum date: 2022-10-07T17:24:01-07:00 summary: GH-94182: Run the PidfdChildWatcher on the running loop (#94184) There is no reason for this watcher to be attached to any particular loop. This should make it safe to use regardless of the lifetime of the event loop running in the main thread (relative to other loops). Co-authored-by: Yury Selivanov Co-authored-by: Jelle Zijlstra files: A Misc/NEWS.d/next/Library/2022-06-24-08-49-47.gh-issue-94182.Wknau0.rst M Lib/asyncio/unix_events.py M Lib/test/test_asyncio/test_subprocess.py diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py index 96e6d73a7597..0f67b4d469f2 100644 --- a/Lib/asyncio/unix_events.py +++ b/Lib/asyncio/unix_events.py @@ -912,10 +912,6 @@ class PidfdChildWatcher(AbstractChildWatcher): recent (5.3+) kernels. """ - def __init__(self): - self._loop = None - self._callbacks = {} - def __enter__(self): return self @@ -923,35 +919,22 @@ def __exit__(self, exc_type, exc_value, exc_traceback): pass def is_active(self): - return self._loop is not None and self._loop.is_running() + return True def close(self): - self.attach_loop(None) + pass def attach_loop(self, loop): - if self._loop is not None and loop is None and self._callbacks: - warnings.warn( - 'A loop is being detached ' - 'from a child watcher with pending handlers', - RuntimeWarning) - for pidfd, _, _ in self._callbacks.values(): - self._loop._remove_reader(pidfd) - os.close(pidfd) - self._callbacks.clear() - self._loop = loop + pass def add_child_handler(self, pid, callback, *args): - existing = self._callbacks.get(pid) - if existing is not None: - self._callbacks[pid] = existing[0], callback, args - else: - pidfd = os.pidfd_open(pid) - self._loop._add_reader(pidfd, self._do_wait, pid) - self._callbacks[pid] = pidfd, callback, args + loop = events.get_running_loop() + pidfd = os.pidfd_open(pid) + loop._add_reader(pidfd, self._do_wait, pid, pidfd, callback, args) - def _do_wait(self, pid): - pidfd, callback, args = self._callbacks.pop(pid) - self._loop._remove_reader(pidfd) + def _do_wait(self, pid, pidfd, callback, args): + loop = events.get_running_loop() + loop._remove_reader(pidfd) try: _, status = os.waitpid(pid, 0) except ChildProcessError: @@ -969,12 +952,9 @@ def _do_wait(self, pid): callback(pid, returncode, *args) def remove_child_handler(self, pid): - try: - pidfd, _, _ = self._callbacks.pop(pid) - except KeyError: - return False - self._loop._remove_reader(pidfd) - os.close(pidfd) + # asyncio never calls remove_child_handler() !!! + # The method is no-op but is implemented because + # abstract base classes require it. return True diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py index 9bc60b9dc2ae..6ba889407b80 100644 --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -4,6 +4,7 @@ import sys import unittest import warnings +import functools from unittest import mock import asyncio @@ -30,6 +31,19 @@ 'sys.stdout.buffer.write(data)'))] + at functools.cache +def _has_pidfd_support(): + if not hasattr(os, 'pidfd_open'): + return False + + try: + os.close(os.pidfd_open(os.getpid())) + except OSError: + return False + + return True + + def tearDownModule(): asyncio.set_event_loop_policy(None) @@ -708,17 +722,8 @@ class SubprocessFastWatcherTests(SubprocessWatcherMixin, Watcher = unix_events.FastChildWatcher - def has_pidfd_support(): - if not hasattr(os, 'pidfd_open'): - return False - try: - os.close(os.pidfd_open(os.getpid())) - except OSError: - return False - return True - @unittest.skipUnless( - has_pidfd_support(), + _has_pidfd_support(), "operating system does not support pidfds", ) class SubprocessPidfdWatcherTests(SubprocessWatcherMixin, @@ -751,6 +756,35 @@ async def execute(): mock.call.__exit__(RuntimeError, mock.ANY, mock.ANY), ]) + + @unittest.skipUnless( + _has_pidfd_support(), + "operating system does not support pidfds", + ) + def test_create_subprocess_with_pidfd(self): + async def in_thread(): + proc = await asyncio.create_subprocess_exec( + *PROGRAM_CAT, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + ) + stdout, stderr = await proc.communicate(b"some data") + return proc.returncode, stdout + + async def main(): + # asyncio.Runner did not call asyncio.set_event_loop() + with self.assertRaises(RuntimeError): + asyncio.get_event_loop_policy().get_event_loop() + return await asyncio.to_thread(asyncio.run, in_thread()) + + asyncio.set_child_watcher(asyncio.PidfdChildWatcher()) + try: + with asyncio.Runner(loop_factory=asyncio.new_event_loop) as runner: + returncode, stdout = runner.run(main()) + self.assertEqual(returncode, 0) + self.assertEqual(stdout, b'some data') + finally: + asyncio.set_child_watcher(None) else: # Windows class SubprocessProactorTests(SubprocessMixin, test_utils.TestCase): diff --git a/Misc/NEWS.d/next/Library/2022-06-24-08-49-47.gh-issue-94182.Wknau0.rst b/Misc/NEWS.d/next/Library/2022-06-24-08-49-47.gh-issue-94182.Wknau0.rst new file mode 100644 index 000000000000..c7be8640ef1f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-06-24-08-49-47.gh-issue-94182.Wknau0.rst @@ -0,0 +1 @@ +run the :class:`asyncio.PidfdChildWatcher` on the running loop, this allows event loops to run subprocesses when there is no default event loop running on the main thread From webhook-mailer at python.org Fri Oct 7 20:29:17 2022 From: webhook-mailer at python.org (gvanrossum) Date: Sat, 08 Oct 2022 00:29:17 -0000 Subject: [Python-checkins] GH-98023: Change default child watcher to PidfdChildWatcher on supported systems (#98024) Message-ID: https://github.com/python/cpython/commit/8ba9378b168ad330c158a001afca03d6c028d39b commit: 8ba9378b168ad330c158a001afca03d6c028d39b branch: main author: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> committer: gvanrossum date: 2022-10-07T17:29:09-07:00 summary: GH-98023: Change default child watcher to PidfdChildWatcher on supported systems (#98024) files: A Misc/NEWS.d/next/Library/2022-10-07-09-52-37.gh-issue-98023.aliEcl.rst M Lib/asyncio/unix_events.py M Lib/test/test_asyncio/test_unix_events.py diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py index 0f67b4d469f2..7fc75cd17ef7 100644 --- a/Lib/asyncio/unix_events.py +++ b/Lib/asyncio/unix_events.py @@ -1403,6 +1403,17 @@ def _do_waitpid(self, loop, expected_pid, callback, args): self._threads.pop(expected_pid) +def can_use_pidfd(): + if not hasattr(os, 'pidfd_open'): + return False + try: + pid = os.getpid() + os.close(os.pidfd_open(pid, 0)) + except OSError: + # blocked by security policy like SECCOMP + return False + return True + class _UnixDefaultEventLoopPolicy(events.BaseDefaultEventLoopPolicy): """UNIX event loop policy with a watcher for child processes.""" @@ -1415,7 +1426,10 @@ def __init__(self): def _init_watcher(self): with events._lock: if self._watcher is None: # pragma: no branch - self._watcher = ThreadedChildWatcher() + if can_use_pidfd(): + self._watcher = PidfdChildWatcher() + else: + self._watcher = ThreadedChildWatcher() if threading.current_thread() is threading.main_thread(): self._watcher.attach_loop(self._local._loop) diff --git a/Lib/test/test_asyncio/test_unix_events.py b/Lib/test/test_asyncio/test_unix_events.py index 5bad21ecbae4..03fb5e649d8e 100644 --- a/Lib/test/test_asyncio/test_unix_events.py +++ b/Lib/test/test_asyncio/test_unix_events.py @@ -1702,7 +1702,8 @@ def create_policy(self): def test_get_default_child_watcher(self): policy = self.create_policy() self.assertIsNone(policy._watcher) - + unix_events.can_use_pidfd = mock.Mock() + unix_events.can_use_pidfd.return_value = False watcher = policy.get_child_watcher() self.assertIsInstance(watcher, asyncio.ThreadedChildWatcher) @@ -1710,6 +1711,17 @@ def test_get_default_child_watcher(self): self.assertIs(watcher, policy.get_child_watcher()) + policy = self.create_policy() + self.assertIsNone(policy._watcher) + unix_events.can_use_pidfd = mock.Mock() + unix_events.can_use_pidfd.return_value = True + watcher = policy.get_child_watcher() + self.assertIsInstance(watcher, asyncio.PidfdChildWatcher) + + self.assertIs(policy._watcher, watcher) + + self.assertIs(watcher, policy.get_child_watcher()) + def test_get_child_watcher_after_set(self): policy = self.create_policy() watcher = asyncio.FastChildWatcher() diff --git a/Misc/NEWS.d/next/Library/2022-10-07-09-52-37.gh-issue-98023.aliEcl.rst b/Misc/NEWS.d/next/Library/2022-10-07-09-52-37.gh-issue-98023.aliEcl.rst new file mode 100644 index 000000000000..1bfd68d4ac7c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-07-09-52-37.gh-issue-98023.aliEcl.rst @@ -0,0 +1 @@ +Change default child watcher to :class:`~asyncio.PidfdChildWatcher` on Linux systems which supports it. Patch by Kumar Aditya. From webhook-mailer at python.org Fri Oct 7 20:37:55 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Sat, 08 Oct 2022 00:37:55 -0000 Subject: [Python-checkins] gh-91052: Add PyDict_Unwatch for unwatching a dictionary (#98055) Message-ID: https://github.com/python/cpython/commit/e82d977eb0b53b0d69509b7080107108e5cfc6f9 commit: e82d977eb0b53b0d69509b7080107108e5cfc6f9 branch: main author: Carl Meyer committer: JelleZijlstra date: 2022-10-07T17:37:46-07:00 summary: gh-91052: Add PyDict_Unwatch for unwatching a dictionary (#98055) files: M Doc/c-api/dict.rst M Doc/whatsnew/3.12.rst M Include/cpython/dictobject.h M Lib/test/test_capi.py M Modules/_testcapimodule.c M Objects/dictobject.c diff --git a/Doc/c-api/dict.rst b/Doc/c-api/dict.rst index 7bebea0c97de..e5f28b59a701 100644 --- a/Doc/c-api/dict.rst +++ b/Doc/c-api/dict.rst @@ -246,17 +246,32 @@ Dictionary Objects of error (e.g. no more watcher IDs available), return ``-1`` and set an exception. + .. versionadded:: 3.12 + .. c:function:: int PyDict_ClearWatcher(int watcher_id) Clear watcher identified by *watcher_id* previously returned from :c:func:`PyDict_AddWatcher`. Return ``0`` on success, ``-1`` on error (e.g. if the given *watcher_id* was never registered.) + .. versionadded:: 3.12 + .. c:function:: int PyDict_Watch(int watcher_id, PyObject *dict) Mark dictionary *dict* as watched. The callback granted *watcher_id* by :c:func:`PyDict_AddWatcher` will be called when *dict* is modified or - deallocated. + deallocated. Return ``0`` on success or ``-1`` on error. + + .. versionadded:: 3.12 + +.. c:function:: int PyDict_Unwatch(int watcher_id, PyObject *dict) + + Mark dictionary *dict* as no longer watched. The callback granted + *watcher_id* by :c:func:`PyDict_AddWatcher` will no longer be called when + *dict* is modified or deallocated. The dict must previously have been + watched by this watcher. Return ``0`` on success or ``-1`` on error. + + .. versionadded:: 3.12 .. c:type:: PyDict_WatchEvent @@ -264,6 +279,8 @@ Dictionary Objects ``PyDict_EVENT_MODIFIED``, ``PyDict_EVENT_DELETED``, ``PyDict_EVENT_CLONED``, ``PyDict_EVENT_CLEARED``, or ``PyDict_EVENT_DEALLOCATED``. + .. versionadded:: 3.12 + .. c:type:: int (*PyDict_WatchCallback)(PyDict_WatchEvent event, PyObject *dict, PyObject *key, PyObject *new_value) Type of a dict watcher callback function. @@ -289,3 +306,5 @@ Dictionary Objects If the callback returns with an exception set, it must return ``-1``; this exception will be printed as an unraisable exception using :c:func:`PyErr_WriteUnraisable`. Otherwise it should return ``0``. + + .. versionadded:: 3.12 diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 405de11e716b..f873974b3e78 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -546,6 +546,11 @@ New Features which sets the vectorcall field of a given :c:type:`PyFunctionObject`. (Contributed by Andrew Frost in :gh:`92257`.) +* The C API now permits registering callbacks via :c:func:`PyDict_AddWatcher`, + :c:func:`PyDict_AddWatch` and related APIs to be called whenever a dictionary + is modified. This is intended for use by optimizing interpreters, JIT + compilers, or debuggers. + Porting to Python 3.12 ---------------------- diff --git a/Include/cpython/dictobject.h b/Include/cpython/dictobject.h index f8a74a597b0e..2dff59ef0b8a 100644 --- a/Include/cpython/dictobject.h +++ b/Include/cpython/dictobject.h @@ -106,3 +106,4 @@ PyAPI_FUNC(int) PyDict_ClearWatcher(int watcher_id); // Mark given dictionary as "watched" (callback will be called if it is modified) PyAPI_FUNC(int) PyDict_Watch(int watcher_id, PyObject* dict); +PyAPI_FUNC(int) PyDict_Unwatch(int watcher_id, PyObject* dict); diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py index 19367dfcc1cc..17425050ce00 100644 --- a/Lib/test/test_capi.py +++ b/Lib/test/test_capi.py @@ -20,6 +20,7 @@ import weakref from test import support from test.support import MISSING_C_DOCSTRINGS +from test.support import catch_unraisable_exception from test.support import import_helper from test.support import threading_helper from test.support import warnings_helper @@ -1421,6 +1422,9 @@ def assert_events(self, expected): def watch(self, wid, d): _testcapi.watch_dict(wid, d) + def unwatch(self, wid, d): + _testcapi.unwatch_dict(wid, d) + def test_set_new_item(self): d = {} with self.watcher() as wid: @@ -1477,27 +1481,24 @@ def test_dealloc(self): del d self.assert_events(["dealloc"]) + def test_unwatch(self): + d = {} + with self.watcher() as wid: + self.watch(wid, d) + d["foo"] = "bar" + self.unwatch(wid, d) + d["hmm"] = "baz" + self.assert_events(["new:foo:bar"]) + def test_error(self): d = {} - unraisables = [] - def unraisable_hook(unraisable): - unraisables.append(unraisable) with self.watcher(kind=self.ERROR) as wid: self.watch(wid, d) - orig_unraisable_hook = sys.unraisablehook - sys.unraisablehook = unraisable_hook - try: + with catch_unraisable_exception() as cm: d["foo"] = "bar" - finally: - sys.unraisablehook = orig_unraisable_hook + self.assertIs(cm.unraisable.object, d) + self.assertEqual(str(cm.unraisable.exc_value), "boom!") self.assert_events([]) - self.assertEqual(len(unraisables), 1) - unraisable = unraisables[0] - self.assertIs(unraisable.object, d) - self.assertEqual(str(unraisable.exc_value), "boom!") - # avoid leaking reference cycles - del unraisable - del unraisables def test_two_watchers(self): d1 = {} @@ -1522,11 +1523,38 @@ def test_watch_out_of_range_watcher_id(self): with self.assertRaisesRegex(ValueError, r"Invalid dict watcher ID 8"): self.watch(8, d) # DICT_MAX_WATCHERS = 8 - def test_unassigned_watcher_id(self): + def test_watch_unassigned_watcher_id(self): d = {} with self.assertRaisesRegex(ValueError, r"No dict watcher set for ID 1"): self.watch(1, d) + def test_unwatch_non_dict(self): + with self.watcher() as wid: + with self.assertRaisesRegex(ValueError, r"Cannot watch non-dictionary"): + self.unwatch(wid, 1) + + def test_unwatch_out_of_range_watcher_id(self): + d = {} + with self.assertRaisesRegex(ValueError, r"Invalid dict watcher ID -1"): + self.unwatch(-1, d) + with self.assertRaisesRegex(ValueError, r"Invalid dict watcher ID 8"): + self.unwatch(8, d) # DICT_MAX_WATCHERS = 8 + + def test_unwatch_unassigned_watcher_id(self): + d = {} + with self.assertRaisesRegex(ValueError, r"No dict watcher set for ID 1"): + self.unwatch(1, d) + + def test_clear_out_of_range_watcher_id(self): + with self.assertRaisesRegex(ValueError, r"Invalid dict watcher ID -1"): + self.clear_watcher(-1) + with self.assertRaisesRegex(ValueError, r"Invalid dict watcher ID 8"): + self.clear_watcher(8) # DICT_MAX_WATCHERS = 8 + + def test_clear_unassigned_watcher_id(self): + with self.assertRaisesRegex(ValueError, r"No dict watcher set for ID 1"): + self.clear_watcher(1) + if __name__ == "__main__": unittest.main() diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 28fb43dce4c6..173d7c2cb805 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -5296,6 +5296,20 @@ watch_dict(PyObject *self, PyObject *args) Py_RETURN_NONE; } +static PyObject * +unwatch_dict(PyObject *self, PyObject *args) +{ + PyObject *dict; + int watcher_id; + if (!PyArg_ParseTuple(args, "iO", &watcher_id, &dict)) { + return NULL; + } + if (PyDict_Unwatch(watcher_id, dict)) { + return NULL; + } + Py_RETURN_NONE; +} + static PyObject * get_dict_watcher_events(PyObject *self, PyObject *Py_UNUSED(args)) { @@ -5904,6 +5918,7 @@ static PyMethodDef TestMethods[] = { {"add_dict_watcher", add_dict_watcher, METH_O, NULL}, {"clear_dict_watcher", clear_dict_watcher, METH_O, NULL}, {"watch_dict", watch_dict, METH_VARARGS, NULL}, + {"unwatch_dict", unwatch_dict, METH_VARARGS, NULL}, {"get_dict_watcher_events", get_dict_watcher_events, METH_NOARGS, NULL}, {NULL, NULL} /* sentinel */ }; diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 6542b1803ffa..97007479b1be 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -5720,6 +5720,20 @@ uint32_t _PyDictKeys_GetVersionForCurrentState(PyDictKeysObject *dictkeys) return v; } +static inline int +validate_watcher_id(PyInterpreterState *interp, int watcher_id) +{ + if (watcher_id < 0 || watcher_id >= DICT_MAX_WATCHERS) { + PyErr_Format(PyExc_ValueError, "Invalid dict watcher ID %d", watcher_id); + return -1; + } + if (!interp->dict_watchers[watcher_id]) { + PyErr_Format(PyExc_ValueError, "No dict watcher set for ID %d", watcher_id); + return -1; + } + return 0; +} + int PyDict_Watch(int watcher_id, PyObject* dict) { @@ -5727,16 +5741,26 @@ PyDict_Watch(int watcher_id, PyObject* dict) PyErr_SetString(PyExc_ValueError, "Cannot watch non-dictionary"); return -1; } - if (watcher_id < 0 || watcher_id >= DICT_MAX_WATCHERS) { - PyErr_Format(PyExc_ValueError, "Invalid dict watcher ID %d", watcher_id); + PyInterpreterState *interp = _PyInterpreterState_GET(); + if (validate_watcher_id(interp, watcher_id)) { + return -1; + } + ((PyDictObject*)dict)->ma_version_tag |= (1LL << watcher_id); + return 0; +} + +int +PyDict_Unwatch(int watcher_id, PyObject* dict) +{ + if (!PyDict_Check(dict)) { + PyErr_SetString(PyExc_ValueError, "Cannot watch non-dictionary"); return -1; } PyInterpreterState *interp = _PyInterpreterState_GET(); - if (!interp->dict_watchers[watcher_id]) { - PyErr_Format(PyExc_ValueError, "No dict watcher set for ID %d", watcher_id); + if (validate_watcher_id(interp, watcher_id)) { return -1; } - ((PyDictObject*)dict)->ma_version_tag |= (1LL << watcher_id); + ((PyDictObject*)dict)->ma_version_tag &= ~(1LL << watcher_id); return 0; } @@ -5759,13 +5783,8 @@ PyDict_AddWatcher(PyDict_WatchCallback callback) int PyDict_ClearWatcher(int watcher_id) { - if (watcher_id < 0 || watcher_id >= DICT_MAX_WATCHERS) { - PyErr_Format(PyExc_ValueError, "Invalid dict watcher ID %d", watcher_id); - return -1; - } PyInterpreterState *interp = _PyInterpreterState_GET(); - if (!interp->dict_watchers[watcher_id]) { - PyErr_Format(PyExc_ValueError, "No dict watcher set for ID %d", watcher_id); + if (validate_watcher_id(interp, watcher_id)) { return -1; } interp->dict_watchers[watcher_id] = NULL; From webhook-mailer at python.org Fri Oct 7 22:00:41 2022 From: webhook-mailer at python.org (miss-islington) Date: Sat, 08 Oct 2022 02:00:41 -0000 Subject: [Python-checkins] gh-61105: Add default param, note on using cookiejar subclass (GH-95427) Message-ID: https://github.com/python/cpython/commit/1a31799d168d6f75ed0db89b5ea7cefda74be37b commit: 1a31799d168d6f75ed0db89b5ea7cefda74be37b branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-07T19:00:35-07:00 summary: gh-61105: Add default param, note on using cookiejar subclass (GH-95427) (cherry picked from commit 5eaf4d610147a3b9adc91a55790096d05bbe01d4) Co-authored-by: Stanley <46876382+slateny at users.noreply.github.com> files: M Doc/library/http.cookiejar.rst diff --git a/Doc/library/http.cookiejar.rst b/Doc/library/http.cookiejar.rst index 1ce24c676182..3bdf9b5ead74 100644 --- a/Doc/library/http.cookiejar.rst +++ b/Doc/library/http.cookiejar.rst @@ -61,7 +61,7 @@ The following classes are provided: responsible for storing and retrieving cookies from a file or database. -.. class:: FileCookieJar(filename, delayload=None, policy=None) +.. class:: FileCookieJar(filename=None, delayload=None, policy=None) *policy* is an object implementing the :class:`CookiePolicy` interface. For the other arguments, see the documentation for the corresponding attributes. @@ -71,6 +71,8 @@ The following classes are provided: :meth:`load` or :meth:`revert` method is called. Subclasses of this class are documented in section :ref:`file-cookie-jar-classes`. + This should not be initialized directly ? use its subclasses below instead. + .. versionchanged:: 3.8 The filename parameter supports a :term:`path-like object`. @@ -317,7 +319,7 @@ FileCookieJar subclasses and co-operation with web browsers The following :class:`CookieJar` subclasses are provided for reading and writing. -.. class:: MozillaCookieJar(filename, delayload=None, policy=None) +.. class:: MozillaCookieJar(filename=None, delayload=None, policy=None) A :class:`FileCookieJar` that can load from and save cookies to disk in the Mozilla ``cookies.txt`` file format (which is also used by curl and the Lynx @@ -338,7 +340,7 @@ writing. Mozilla. -.. class:: LWPCookieJar(filename, delayload=None, policy=None) +.. class:: LWPCookieJar(filename=None, delayload=None, policy=None) A :class:`FileCookieJar` that can load from and save cookies to disk in format compatible with the libwww-perl library's ``Set-Cookie3`` file format. This is From webhook-mailer at python.org Fri Oct 7 23:00:10 2022 From: webhook-mailer at python.org (miss-islington) Date: Sat, 08 Oct 2022 03:00:10 -0000 Subject: [Python-checkins] gh-57179: Add note on symlinks for os.walk (GH-94799) Message-ID: https://github.com/python/cpython/commit/8d6591b593e05e9d00f74f444b3c040905450548 commit: 8d6591b593e05e9d00f74f444b3c040905450548 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-07T20:00:04-07:00 summary: gh-57179: Add note on symlinks for os.walk (GH-94799) (cherry picked from commit 0f498f1a95306995ca1e287f552c5c3d856be02d) Co-authored-by: Stanley <46876382+slateny at users.noreply.github.com> files: M Doc/library/os.rst M Lib/os.py diff --git a/Doc/library/os.rst b/Doc/library/os.rst index fbfeeb2d7e1f..833779166910 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -3208,7 +3208,8 @@ features: filenames)``. *dirpath* is a string, the path to the directory. *dirnames* is a list of the - names of the subdirectories in *dirpath* (excluding ``'.'`` and ``'..'``). + names of the subdirectories in *dirpath* (including symlinks to directories, + and excluding ``'.'`` and ``'..'``). *filenames* is a list of the names of the non-directory files in *dirpath*. Note that the names in the lists contain no path components. To get a full path (which begins with *top*) to a file or directory in *dirpath*, do diff --git a/Lib/os.py b/Lib/os.py index 648188e0f134..fd1e774fdcbc 100644 --- a/Lib/os.py +++ b/Lib/os.py @@ -288,7 +288,8 @@ def walk(top, topdown=True, onerror=None, followlinks=False): dirpath, dirnames, filenames dirpath is a string, the path to the directory. dirnames is a list of - the names of the subdirectories in dirpath (excluding '.' and '..'). + the names of the subdirectories in dirpath (including symlinks to directories, + and excluding '.' and '..'). filenames is a list of the names of the non-directory files in dirpath. Note that the names in the lists are just names, with no path components. To get a full path (which begins with top) to a file or directory in From webhook-mailer at python.org Fri Oct 7 23:15:15 2022 From: webhook-mailer at python.org (miss-islington) Date: Sat, 08 Oct 2022 03:15:15 -0000 Subject: [Python-checkins] gh-57179: Add note on symlinks for os.walk (GH-94799) Message-ID: https://github.com/python/cpython/commit/1818235f402843db0fbeb21a7954b6ef209c916c commit: 1818235f402843db0fbeb21a7954b6ef209c916c branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-07T20:15:08-07:00 summary: gh-57179: Add note on symlinks for os.walk (GH-94799) (cherry picked from commit 0f498f1a95306995ca1e287f552c5c3d856be02d) Co-authored-by: Stanley <46876382+slateny at users.noreply.github.com> files: M Doc/library/os.rst M Lib/os.py diff --git a/Doc/library/os.rst b/Doc/library/os.rst index c8bb5a902d81..58f01e97459c 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -3135,7 +3135,8 @@ features: filenames)``. *dirpath* is a string, the path to the directory. *dirnames* is a list of the - names of the subdirectories in *dirpath* (excluding ``'.'`` and ``'..'``). + names of the subdirectories in *dirpath* (including symlinks to directories, + and excluding ``'.'`` and ``'..'``). *filenames* is a list of the names of the non-directory files in *dirpath*. Note that the names in the lists contain no path components. To get a full path (which begins with *top*) to a file or directory in *dirpath*, do diff --git a/Lib/os.py b/Lib/os.py index d26cfc99939f..4f2ffceaaf38 100644 --- a/Lib/os.py +++ b/Lib/os.py @@ -288,7 +288,8 @@ def walk(top, topdown=True, onerror=None, followlinks=False): dirpath, dirnames, filenames dirpath is a string, the path to the directory. dirnames is a list of - the names of the subdirectories in dirpath (excluding '.' and '..'). + the names of the subdirectories in dirpath (including symlinks to directories, + and excluding '.' and '..'). filenames is a list of the names of the non-directory files in dirpath. Note that the names in the lists are just names, with no path components. To get a full path (which begins with top) to a file or directory in From webhook-mailer at python.org Fri Oct 7 23:59:15 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Sat, 08 Oct 2022 03:59:15 -0000 Subject: [Python-checkins] [3.10] gh-96073: Fix installed tests by adding to Makefile.pre.in (#98072) Message-ID: https://github.com/python/cpython/commit/f50e3a7feab457f2fa0fc4b26d404470d186087a commit: f50e3a7feab457f2fa0fc4b26d404470d186087a branch: 3.10 author: Jelle Zijlstra committer: JelleZijlstra date: 2022-10-07T20:59:10-07:00 summary: [3.10] gh-96073: Fix installed tests by adding to Makefile.pre.in (#98072) This was broken in #98045 but already fixed on main. files: M Makefile.pre.in diff --git a/Makefile.pre.in b/Makefile.pre.in index 95f0d870a38a..8ee44bfc0adb 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1521,6 +1521,7 @@ TESTSUBDIRS= ctypes/test \ test/test_warnings test/test_warnings/data \ test/test_zoneinfo test/test_zoneinfo/data \ test/tracedmodules \ + test/typinganndata \ test/xmltestdata test/xmltestdata/c14n-20 \ test/ziptestdata \ tkinter/test tkinter/test/test_tkinter \ From webhook-mailer at python.org Fri Oct 7 23:59:24 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Sat, 08 Oct 2022 03:59:24 -0000 Subject: [Python-checkins] [3.11] gh-96073: Fix installed tests by adding to Makefile.pre.in (#98071) Message-ID: https://github.com/python/cpython/commit/52dab90500abe30eedfb908ee3881a68b8bd2c17 commit: 52dab90500abe30eedfb908ee3881a68b8bd2c17 branch: 3.11 author: Jelle Zijlstra committer: JelleZijlstra date: 2022-10-07T20:59:18-07:00 summary: [3.11] gh-96073: Fix installed tests by adding to Makefile.pre.in (#98071) [3.11] Fix installed tests by adding to Makefile.pre.in This was broken in #98045 but already fixed on main. files: M Makefile.pre.in diff --git a/Makefile.pre.in b/Makefile.pre.in index d23976ff80fb..e837a64a3c7c 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -2004,6 +2004,7 @@ TESTSUBDIRS= ctypes/test \ test/test_warnings test/test_warnings/data \ test/test_zoneinfo test/test_zoneinfo/data \ test/tracedmodules \ + test/typinganndata \ test/xmltestdata test/xmltestdata/c14n-20 \ test/ziptestdata \ tkinter/test tkinter/test/test_tkinter \ From webhook-mailer at python.org Fri Oct 7 23:59:54 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Sat, 08 Oct 2022 03:59:54 -0000 Subject: [Python-checkins] [3.10] gh-96288: Add a sentence to `os.mkdir`'s docstring. (GH-96271). (#98066) Message-ID: https://github.com/python/cpython/commit/2090eeb46d4180174ff9f5552042095084563344 commit: 2090eeb46d4180174ff9f5552042095084563344 branch: 3.10 author: Jelle Zijlstra committer: JelleZijlstra date: 2022-10-07T20:59:48-07:00 summary: [3.10] gh-96288: Add a sentence to `os.mkdir`'s docstring. (GH-96271). (#98066) (cherry picked from commit 1523c9e9d47e7d67e4889987ff0f38eb7b881fdd) Co-authored-by: Hagai Helman Tov files: M Modules/clinic/posixmodule.c.h M Modules/posixmodule.c diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h index 1c3e9bc6d613..da190b870771 100644 --- a/Modules/clinic/posixmodule.c.h +++ b/Modules/clinic/posixmodule.c.h @@ -1328,7 +1328,8 @@ PyDoc_STRVAR(os_mkdir__doc__, "dir_fd may not be implemented on your platform.\n" " If it is unavailable, using it will raise a NotImplementedError.\n" "\n" -"The mode argument is ignored on Windows."); +"The mode argument is ignored on Windows. Where it is used, the current umask\n" +"value is first masked out."); #define OS_MKDIR_METHODDEF \ {"mkdir", (PyCFunction)(void(*)(void))os_mkdir, METH_FASTCALL|METH_KEYWORDS, os_mkdir__doc__}, @@ -9291,4 +9292,4 @@ os_waitstatus_to_exitcode(PyObject *module, PyObject *const *args, Py_ssize_t na #ifndef OS_WAITSTATUS_TO_EXITCODE_METHODDEF #define OS_WAITSTATUS_TO_EXITCODE_METHODDEF #endif /* !defined(OS_WAITSTATUS_TO_EXITCODE_METHODDEF) */ -/*[clinic end generated code: output=ddc35c3177c3b3ed input=a9049054013a1b77]*/ +/*[clinic end generated code: output=f8cdbd04ea0e3502 input=a9049054013a1b77]*/ diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index f602ae5c5892..f92e2ae6290a 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -4494,12 +4494,13 @@ If dir_fd is not None, it should be a file descriptor open to a directory, dir_fd may not be implemented on your platform. If it is unavailable, using it will raise a NotImplementedError. -The mode argument is ignored on Windows. +The mode argument is ignored on Windows. Where it is used, the current umask +value is first masked out. [clinic start generated code]*/ static PyObject * os_mkdir_impl(PyObject *module, path_t *path, int mode, int dir_fd) -/*[clinic end generated code: output=a70446903abe821f input=e965f68377e9b1ce]*/ +/*[clinic end generated code: output=a70446903abe821f input=a61722e1576fab03]*/ { int result; #ifdef HAVE_MKDIRAT From webhook-mailer at python.org Sat Oct 8 00:00:06 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Sat, 08 Oct 2022 04:00:06 -0000 Subject: [Python-checkins] [3.11] gh-96288: Add a sentence to `os.mkdir`'s docstring. (GH-96271). (#98065) Message-ID: https://github.com/python/cpython/commit/15732114b8a110668baf982e00ffb26081a8bac9 commit: 15732114b8a110668baf982e00ffb26081a8bac9 branch: 3.11 author: Jelle Zijlstra committer: JelleZijlstra date: 2022-10-07T21:00:00-07:00 summary: [3.11] gh-96288: Add a sentence to `os.mkdir`'s docstring. (GH-96271). (#98065) (cherry picked from commit 1523c9e9d47e7d67e4889987ff0f38eb7b881fdd) Co-authored-by: Hagai Helman Tov files: M Modules/clinic/posixmodule.c.h M Modules/posixmodule.c diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h index e636f8b94ff7..b66cd857e449 100644 --- a/Modules/clinic/posixmodule.c.h +++ b/Modules/clinic/posixmodule.c.h @@ -1360,7 +1360,8 @@ PyDoc_STRVAR(os_mkdir__doc__, "dir_fd may not be implemented on your platform.\n" " If it is unavailable, using it will raise a NotImplementedError.\n" "\n" -"The mode argument is ignored on Windows."); +"The mode argument is ignored on Windows. Where it is used, the current umask\n" +"value is first masked out."); #define OS_MKDIR_METHODDEF \ {"mkdir", _PyCFunction_CAST(os_mkdir), METH_FASTCALL|METH_KEYWORDS, os_mkdir__doc__}, @@ -9378,4 +9379,4 @@ os_waitstatus_to_exitcode(PyObject *module, PyObject *const *args, Py_ssize_t na #ifndef OS_WAITSTATUS_TO_EXITCODE_METHODDEF #define OS_WAITSTATUS_TO_EXITCODE_METHODDEF #endif /* !defined(OS_WAITSTATUS_TO_EXITCODE_METHODDEF) */ -/*[clinic end generated code: output=836be9d51f01140e input=a9049054013a1b77]*/ +/*[clinic end generated code: output=8dd784bf1e41b881 input=a9049054013a1b77]*/ diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 4bebbbd06c19..a45179f6a1fa 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -4560,12 +4560,13 @@ If dir_fd is not None, it should be a file descriptor open to a directory, dir_fd may not be implemented on your platform. If it is unavailable, using it will raise a NotImplementedError. -The mode argument is ignored on Windows. +The mode argument is ignored on Windows. Where it is used, the current umask +value is first masked out. [clinic start generated code]*/ static PyObject * os_mkdir_impl(PyObject *module, path_t *path, int mode, int dir_fd) -/*[clinic end generated code: output=a70446903abe821f input=e965f68377e9b1ce]*/ +/*[clinic end generated code: output=a70446903abe821f input=a61722e1576fab03]*/ { int result; #ifdef HAVE_MKDIRAT From webhook-mailer at python.org Sat Oct 8 00:07:14 2022 From: webhook-mailer at python.org (miss-islington) Date: Sat, 08 Oct 2022 04:07:14 -0000 Subject: [Python-checkins] gh-92886: make test_coroutines pass with -O (assertions off) (GH-98060) Message-ID: https://github.com/python/cpython/commit/8d40fbe48bf58295c8053fce2119be989c1e8948 commit: 8d40fbe48bf58295c8053fce2119be989c1e8948 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-07T21:07:09-07:00 summary: gh-92886: make test_coroutines pass with -O (assertions off) (GH-98060) Automerge-Triggered-By: GH:iritkatriel (cherry picked from commit 45f21472daad3934baf364c3100063ecc51c6e04) Co-authored-by: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> files: M Lib/test/test_coroutines.py diff --git a/Lib/test/test_coroutines.py b/Lib/test/test_coroutines.py index a414a6f505c9..acff24537cf8 100644 --- a/Lib/test/test_coroutines.py +++ b/Lib/test/test_coroutines.py @@ -1262,7 +1262,7 @@ async def __aexit__(self, *exc): async def func(): async with CM(): - assert (1, ) == 1 + self.assertEqual((1, ), 1) with self.assertRaises(AssertionError): run_async(func()) From webhook-mailer at python.org Sat Oct 8 00:24:07 2022 From: webhook-mailer at python.org (miss-islington) Date: Sat, 08 Oct 2022 04:24:07 -0000 Subject: [Python-checkins] gh-92886: make test_coroutines pass with -O (assertions off) (GH-98060) Message-ID: https://github.com/python/cpython/commit/72a23d8f0641fc30b3182000a91a546f8b24ea31 commit: 72a23d8f0641fc30b3182000a91a546f8b24ea31 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-07T21:24:02-07:00 summary: gh-92886: make test_coroutines pass with -O (assertions off) (GH-98060) Automerge-Triggered-By: GH:iritkatriel (cherry picked from commit 45f21472daad3934baf364c3100063ecc51c6e04) Co-authored-by: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> files: M Lib/test/test_coroutines.py diff --git a/Lib/test/test_coroutines.py b/Lib/test/test_coroutines.py index 8fff2d47c10f..a15736e9f945 100644 --- a/Lib/test/test_coroutines.py +++ b/Lib/test/test_coroutines.py @@ -1280,7 +1280,7 @@ async def __aexit__(self, *exc): async def func(): async with CM(): - assert (1, ) == 1 + self.assertEqual((1, ), 1) with self.assertRaises(AssertionError): run_async(func()) From webhook-mailer at python.org Sat Oct 8 00:46:33 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Sat, 08 Oct 2022 04:46:33 -0000 Subject: [Python-checkins] gh-97822: Fix http.server documentation reference to test() function (#98027) Message-ID: https://github.com/python/cpython/commit/6b485629d2e3e232460db7da3f8b18b67d4f4da8 commit: 6b485629d2e3e232460db7da3f8b18b67d4f4da8 branch: main author: JasonYZ committer: JelleZijlstra date: 2022-10-07T21:46:23-07:00 summary: gh-97822: Fix http.server documentation reference to test() function (#98027) Co-authored-by: Jelle Zijlstra files: M Doc/library/http.server.rst diff --git a/Doc/library/http.server.rst b/Doc/library/http.server.rst index 48f952daae12..81b6bf5373b4 100644 --- a/Doc/library/http.server.rst +++ b/Doc/library/http.server.rst @@ -392,8 +392,8 @@ provides three different variants: contents of the file are output. If the file's MIME type starts with ``text/`` the file is opened in text mode; otherwise binary mode is used. - For example usage, see the implementation of the :func:`test` function - invocation in the :mod:`http.server` module. + For example usage, see the implementation of the ``test`` function + in :source:`Lib/http/server.py`. .. versionchanged:: 3.7 Support of the ``'If-Modified-Since'`` header. From webhook-mailer at python.org Sat Oct 8 01:02:43 2022 From: webhook-mailer at python.org (miss-islington) Date: Sat, 08 Oct 2022 05:02:43 -0000 Subject: [Python-checkins] gh-92886: make test_ast pass with -O (assertions off) (GH-98058) Message-ID: https://github.com/python/cpython/commit/e4937926122a3b12b0b747a727424271e6c30bd5 commit: e4937926122a3b12b0b747a727424271e6c30bd5 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-07T22:02:38-07:00 summary: gh-92886: make test_ast pass with -O (assertions off) (GH-98058) -O does not strip docstrings. Automerge-Triggered-By: GH:iritkatriel (cherry picked from commit 27ce45d8e105d0c9f9286c3cab830590d4c7cea3) Co-authored-by: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> files: M Lib/test/test_dis.py diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 6d16021a6120..6a0a2d927967 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -1076,7 +1076,7 @@ def get_disassembly(self, func, lasti=-1, wrapper=True, **kwargs): return output.getvalue() -if sys.flags.optimize: +if dis.code_info.__doc__ is None: code_info_consts = "0: None" else: code_info_consts = "0: 'Formatted details of methods, functions, or code.'" From webhook-mailer at python.org Sat Oct 8 01:02:50 2022 From: webhook-mailer at python.org (miss-islington) Date: Sat, 08 Oct 2022 05:02:50 -0000 Subject: [Python-checkins] gh-92886: make test_ast pass with -O (assertions off) (GH-98058) Message-ID: https://github.com/python/cpython/commit/225bee75e3be92fa7b07ed66fde263f87bd81ac7 commit: 225bee75e3be92fa7b07ed66fde263f87bd81ac7 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-07T22:02:45-07:00 summary: gh-92886: make test_ast pass with -O (assertions off) (GH-98058) -O does not strip docstrings. Automerge-Triggered-By: GH:iritkatriel (cherry picked from commit 27ce45d8e105d0c9f9286c3cab830590d4c7cea3) Co-authored-by: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> files: M Lib/test/test_dis.py diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 23a171853636..69f7db7b923b 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -707,7 +707,7 @@ def get_disassembly(self, func, lasti=-1, wrapper=True, **kwargs): return output.getvalue() -if sys.flags.optimize: +if dis.code_info.__doc__ is None: code_info_consts = "0: None" else: code_info_consts = "0: 'Formatted details of methods, functions, or code.'" From webhook-mailer at python.org Sat Oct 8 01:07:11 2022 From: webhook-mailer at python.org (miss-islington) Date: Sat, 08 Oct 2022 05:07:11 -0000 Subject: [Python-checkins] gh-97822: Fix http.server documentation reference to test() function (GH-98027) Message-ID: https://github.com/python/cpython/commit/b5196faff3588ef374b7ee68d803d1727237727d commit: b5196faff3588ef374b7ee68d803d1727237727d branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-07T22:07:06-07:00 summary: gh-97822: Fix http.server documentation reference to test() function (GH-98027) Co-authored-by: Jelle Zijlstra (cherry picked from commit 6b485629d2e3e232460db7da3f8b18b67d4f4da8) Co-authored-by: JasonYZ files: M Doc/library/http.server.rst diff --git a/Doc/library/http.server.rst b/Doc/library/http.server.rst index 48f952daae12..81b6bf5373b4 100644 --- a/Doc/library/http.server.rst +++ b/Doc/library/http.server.rst @@ -392,8 +392,8 @@ provides three different variants: contents of the file are output. If the file's MIME type starts with ``text/`` the file is opened in text mode; otherwise binary mode is used. - For example usage, see the implementation of the :func:`test` function - invocation in the :mod:`http.server` module. + For example usage, see the implementation of the ``test`` function + in :source:`Lib/http/server.py`. .. versionchanged:: 3.7 Support of the ``'If-Modified-Since'`` header. From webhook-mailer at python.org Sat Oct 8 01:55:43 2022 From: webhook-mailer at python.org (ambv) Date: Sat, 08 Oct 2022 05:55:43 -0000 Subject: [Python-checkins] [doc] Fix broken links to C extensions accelerating stdlib modules (#96914) Message-ID: https://github.com/python/cpython/commit/840fd19590935b91f9125bbf1cb93282d6073359 commit: 840fd19590935b91f9125bbf1cb93282d6073359 branch: main author: partev committer: ambv date: 2022-10-07T22:55:35-07:00 summary: [doc] Fix broken links to C extensions accelerating stdlib modules (#96914) Co-authored-by: ?ukasz Langa Co-authored-by: C.A.M. Gerlach files: M Doc/license.rst diff --git a/Doc/license.rst b/Doc/license.rst index 00691b30ba6d..54643744dcf9 100644 --- a/Doc/license.rst +++ b/Doc/license.rst @@ -302,7 +302,8 @@ for third-party software incorporated in the Python distribution. Mersenne Twister ---------------- -The :mod:`_random` module includes code based on a download from +The :mod:`!_random` C extension underlying the :mod:`random` module +includes code based on a download from http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/emt19937ar.html. The following are the verbatim comments from the original code:: @@ -819,7 +820,8 @@ sources unless the build is configured ``--with-system-expat``:: libffi ------ -The :mod:`_ctypes` extension is built using an included copy of the libffi +The :mod:`!_ctypes` C extension underlying the :mod:`ctypes` module +is built using an included copy of the libffi sources unless the build is configured ``--with-system-libffi``:: Copyright (c) 1996-2008 Red Hat, Inc and others. @@ -920,7 +922,8 @@ on the cfuhash project:: libmpdec -------- -The :mod:`_decimal` module is built using an included copy of the libmpdec +The :mod:`!_decimal` C extension underlying the :mod:`decimal` module +is built using an included copy of the libmpdec library unless the build is configured ``--with-system-libmpdec``:: Copyright (c) 2008-2020 Stefan Krah. All rights reserved. From webhook-mailer at python.org Sat Oct 8 02:54:24 2022 From: webhook-mailer at python.org (ezio-melotti) Date: Sat, 08 Oct 2022 06:54:24 -0000 Subject: [Python-checkins] gh-97913 Docs: Add walrus operator to the index (#97921) Message-ID: https://github.com/python/cpython/commit/296313002fde56f52d6c81f17d7ba5c2eb57d098 commit: 296313002fde56f52d6c81f17d7ba5c2eb57d098 branch: main author: Hugo van Kemenade committer: ezio-melotti date: 2022-10-08T08:54:16+02:00 summary: gh-97913 Docs: Add walrus operator to the index (#97921) * Add walrus operator to the index * Add named expression to the index Co-authored-by: Mariatta Wijaya * Fix indentation and add missing newline Co-authored-by: Ezio Melotti Co-authored-by: Mariatta Wijaya Co-authored-by: Ezio Melotti files: M Doc/reference/expressions.rst diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst index 11f49a8c33dc..28c17566009f 100644 --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -1741,6 +1741,12 @@ returns a boolean value regardless of the type of its argument (for example, ``not 'foo'`` produces ``False`` rather than ``''``.) +.. index:: + single: := (colon equals) + single: assignment expression + single: walrus operator + single: named expression + Assignment expressions ====================== From webhook-mailer at python.org Sat Oct 8 02:57:36 2022 From: webhook-mailer at python.org (miss-islington) Date: Sat, 08 Oct 2022 06:57:36 -0000 Subject: [Python-checkins] gh-97822: Fix http.server documentation reference to test() function (GH-98027) Message-ID: https://github.com/python/cpython/commit/786fde5d70ca18cc93fe2b4197f05bcae2bdc908 commit: 786fde5d70ca18cc93fe2b4197f05bcae2bdc908 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-07T23:57:31-07:00 summary: gh-97822: Fix http.server documentation reference to test() function (GH-98027) Co-authored-by: Jelle Zijlstra (cherry picked from commit 6b485629d2e3e232460db7da3f8b18b67d4f4da8) Co-authored-by: JasonYZ files: M Doc/library/http.server.rst diff --git a/Doc/library/http.server.rst b/Doc/library/http.server.rst index 8584f99d1567..89a25b8cc797 100644 --- a/Doc/library/http.server.rst +++ b/Doc/library/http.server.rst @@ -388,8 +388,8 @@ provides three different variants: contents of the file are output. If the file's MIME type starts with ``text/`` the file is opened in text mode; otherwise binary mode is used. - For example usage, see the implementation of the :func:`test` function - invocation in the :mod:`http.server` module. + For example usage, see the implementation of the ``test`` function + in :source:`Lib/http/server.py`. .. versionchanged:: 3.7 Support of the ``'If-Modified-Since'`` header. From webhook-mailer at python.org Sat Oct 8 03:01:32 2022 From: webhook-mailer at python.org (miss-islington) Date: Sat, 08 Oct 2022 07:01:32 -0000 Subject: [Python-checkins] gh-97913 Docs: Add walrus operator to the index (GH-97921) Message-ID: https://github.com/python/cpython/commit/9828ccb63bb53311381d8ee08ef447d0048e4189 commit: 9828ccb63bb53311381d8ee08ef447d0048e4189 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-08T00:01:27-07:00 summary: gh-97913 Docs: Add walrus operator to the index (GH-97921) * Add walrus operator to the index * Add named expression to the index Co-authored-by: Mariatta Wijaya * Fix indentation and add missing newline Co-authored-by: Ezio Melotti Co-authored-by: Mariatta Wijaya Co-authored-by: Ezio Melotti (cherry picked from commit 296313002fde56f52d6c81f17d7ba5c2eb57d098) Co-authored-by: Hugo van Kemenade files: M Doc/reference/expressions.rst diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst index fd43e6c161f7..6b5e0e1628f1 100644 --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -1730,6 +1730,12 @@ returns a boolean value regardless of the type of its argument (for example, ``not 'foo'`` produces ``False`` rather than ``''``.) +.. index:: + single: := (colon equals) + single: assignment expression + single: walrus operator + single: named expression + Assignment expressions ====================== From webhook-mailer at python.org Sat Oct 8 03:03:38 2022 From: webhook-mailer at python.org (miss-islington) Date: Sat, 08 Oct 2022 07:03:38 -0000 Subject: [Python-checkins] gh-97913 Docs: Add walrus operator to the index (GH-97921) Message-ID: https://github.com/python/cpython/commit/a2ce21f763c03dc36a28ee3e4d8808eb3928075f commit: a2ce21f763c03dc36a28ee3e4d8808eb3928075f branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-08T00:03:33-07:00 summary: gh-97913 Docs: Add walrus operator to the index (GH-97921) * Add walrus operator to the index * Add named expression to the index Co-authored-by: Mariatta Wijaya * Fix indentation and add missing newline Co-authored-by: Ezio Melotti Co-authored-by: Mariatta Wijaya Co-authored-by: Ezio Melotti (cherry picked from commit 296313002fde56f52d6c81f17d7ba5c2eb57d098) Co-authored-by: Hugo van Kemenade files: M Doc/reference/expressions.rst diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst index 1e76b25f4880..31cdc5c1e16b 100644 --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -1723,6 +1723,12 @@ returns a boolean value regardless of the type of its argument (for example, ``not 'foo'`` produces ``False`` rather than ``''``.) +.. index:: + single: := (colon equals) + single: assignment expression + single: walrus operator + single: named expression + Assignment expressions ====================== From webhook-mailer at python.org Sat Oct 8 03:11:50 2022 From: webhook-mailer at python.org (ezio-melotti) Date: Sat, 08 Oct 2022 07:11:50 -0000 Subject: [Python-checkins] Add `@ezio-melotti` as codeowner for `.github/`. (#98079) Message-ID: https://github.com/python/cpython/commit/531ffaa7cdc58c5df2abe505803394dbd5293602 commit: 531ffaa7cdc58c5df2abe505803394dbd5293602 branch: main author: Ezio Melotti committer: ezio-melotti date: 2022-10-08T09:11:38+02:00 summary: Add `@ezio-melotti` as codeowner for `.github/`. (#98079) files: M .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 2568560c074f..585589d6ce3b 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -4,6 +4,9 @@ # It uses the same pattern rule for gitignore file # https://git-scm.com/docs/gitignore#_pattern_format +# GitHub +.github/** @ezio-melotti + # asyncio **/*asyncio* @1st1 @asvetlov @gvanrossum From webhook-mailer at python.org Sat Oct 8 04:01:49 2022 From: webhook-mailer at python.org (miss-islington) Date: Sat, 08 Oct 2022 08:01:49 -0000 Subject: [Python-checkins] Add `@ezio-melotti` as codeowner for `.github/`. (GH-98079) Message-ID: https://github.com/python/cpython/commit/bdc108772495e67c3add0d742169e0df4effadb2 commit: bdc108772495e67c3add0d742169e0df4effadb2 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-08T01:01:42-07:00 summary: Add `@ezio-melotti` as codeowner for `.github/`. (GH-98079) (cherry picked from commit 531ffaa7cdc58c5df2abe505803394dbd5293602) Co-authored-by: Ezio Melotti files: M .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 0aea3983fa60..227fd2bc7702 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -4,6 +4,9 @@ # It uses the same pattern rule for gitignore file # https://git-scm.com/docs/gitignore#_pattern_format +# GitHub +.github/** @ezio-melotti + # asyncio **/*asyncio* @1st1 @asvetlov From webhook-mailer at python.org Sat Oct 8 04:12:06 2022 From: webhook-mailer at python.org (miss-islington) Date: Sat, 08 Oct 2022 08:12:06 -0000 Subject: [Python-checkins] Add `@ezio-melotti` as codeowner for `.github/`. (GH-98079) Message-ID: https://github.com/python/cpython/commit/15a11a69e0001eb13998e96a6698dc61937c1d2f commit: 15a11a69e0001eb13998e96a6698dc61937c1d2f branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-08T01:12:01-07:00 summary: Add `@ezio-melotti` as codeowner for `.github/`. (GH-98079) (cherry picked from commit 531ffaa7cdc58c5df2abe505803394dbd5293602) Co-authored-by: Ezio Melotti files: M .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 173b957b108c..3c4e8697f807 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -4,6 +4,9 @@ # It uses the same pattern rule for gitignore file # https://git-scm.com/docs/gitignore#_pattern_format +# GitHub +.github/** @ezio-melotti + # asyncio **/*asyncio* @1st1 @asvetlov From webhook-mailer at python.org Sat Oct 8 04:13:43 2022 From: webhook-mailer at python.org (ezio-melotti) Date: Sat, 08 Oct 2022 08:13:43 -0000 Subject: [Python-checkins] GitHub Workflows security hardening (#96492) Message-ID: https://github.com/python/cpython/commit/c66dbddfbaa374a6954897809574ee9fb463e393 commit: c66dbddfbaa374a6954897809574ee9fb463e393 branch: main author: Alex committer: ezio-melotti date: 2022-10-08T10:13:34+02:00 summary: GitHub Workflows security hardening (#96492) * Update project-updater.yml Signed-off-by: sashashura <93376818+sashashura at users.noreply.github.com> * Update project-updater.yml repository-projects: write is not needed because a separate secrets.ADD_TO_PROJECT_PAT is used Signed-off-by: sashashura <93376818+sashashura at users.noreply.github.com> files: M .github/workflows/project-updater.yml diff --git a/.github/workflows/project-updater.yml b/.github/workflows/project-updater.yml index 77e55ed019b2..99c7a05ae8ca 100644 --- a/.github/workflows/project-updater.yml +++ b/.github/workflows/project-updater.yml @@ -6,6 +6,9 @@ on: - opened - labeled +permissions: + contents: read + jobs: add-to-project: name: Add issues to projects From webhook-mailer at python.org Sat Oct 8 10:57:18 2022 From: webhook-mailer at python.org (pablogsal) Date: Sat, 08 Oct 2022 14:57:18 -0000 Subject: [Python-checkins] gh-97922: Run the GC only on eval breaker (#97920) Message-ID: https://github.com/python/cpython/commit/83eb827247dd28b13fd816936c74c162e9f52a2d commit: 83eb827247dd28b13fd816936c74c162e9f52a2d branch: main author: Pablo Galindo Salgado committer: pablogsal date: 2022-10-08T07:57:09-07:00 summary: gh-97922: Run the GC only on eval breaker (#97920) files: A Misc/NEWS.d/next/Core and Builtins/2022-10-05-11-37-15.gh-issue-97922.Zu9Bge.rst M Doc/whatsnew/3.12.rst M Include/internal/pycore_gc.h M Include/internal/pycore_interp.h M Lib/test/test_frame.py M Modules/gcmodule.c M Modules/signalmodule.c M Python/ceval_gil.c diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index f873974b3e78..341e85103a3c 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -93,6 +93,13 @@ Other Language Changes when parsing source code containing null bytes. (Contributed by Pablo Galindo in :gh:`96670`.) +* The Garbage Collector now runs only on the eval breaker mechanism of the + Python bytecode evaluation loop instead on object allocations. The GC can + also run when :c:func:`PyErr_CheckSignals` is called so C extensions that + need to run for a long time without executing any Python code also have a + chance to execute the GC periodically. (Contributed by Pablo Galindo in + :gh:`97922`.) + New Modules =========== diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h index bfab0adfffc9..b3abe2030a03 100644 --- a/Include/internal/pycore_gc.h +++ b/Include/internal/pycore_gc.h @@ -202,6 +202,8 @@ extern void _PyList_ClearFreeList(PyInterpreterState *interp); extern void _PyDict_ClearFreeList(PyInterpreterState *interp); extern void _PyAsyncGen_ClearFreeLists(PyInterpreterState *interp); extern void _PyContext_ClearFreeList(PyInterpreterState *interp); +extern void _Py_ScheduleGC(PyInterpreterState *interp); +extern void _Py_RunGC(PyThreadState *tstate); #ifdef __cplusplus } diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index 8cecd5ab3e54..c11e897305d4 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -49,6 +49,8 @@ struct _ceval_state { _Py_atomic_int eval_breaker; /* Request for dropping the GIL */ _Py_atomic_int gil_drop_request; + /* The GC is ready to be executed */ + _Py_atomic_int gc_scheduled; struct _pending_calls pending; }; diff --git a/Lib/test/test_frame.py b/Lib/test/test_frame.py index 4b86a60d2f4c..4b5bb7f94ac4 100644 --- a/Lib/test/test_frame.py +++ b/Lib/test/test_frame.py @@ -277,7 +277,7 @@ def callback(phase, info): frame! """ nonlocal sneaky_frame_object - sneaky_frame_object = sys._getframe().f_back + sneaky_frame_object = sys._getframe().f_back.f_back # We're done here: gc.callbacks.remove(callback) diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-05-11-37-15.gh-issue-97922.Zu9Bge.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-05-11-37-15.gh-issue-97922.Zu9Bge.rst new file mode 100644 index 000000000000..bf78709362f4 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-05-11-37-15.gh-issue-97922.Zu9Bge.rst @@ -0,0 +1,5 @@ +The Garbage Collector now runs only on the eval breaker mechanism of the +Python bytecode evaluation loop instead on object allocations. The GC can +also run when :c:func:`PyErr_CheckSignals` is called so C extensions that +need to run for a long time without executing any Python code also have a +chance to execute the GC periodically. diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 97cb6e6e1efb..75832e9dd3da 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -2252,6 +2252,20 @@ PyObject_IS_GC(PyObject *obj) return _PyObject_IS_GC(obj); } +void +_Py_ScheduleGC(PyInterpreterState *interp) +{ + GCState *gcstate = &interp->gc; + if (gcstate->collecting == 1) { + return; + } + struct _ceval_state *ceval = &interp->ceval; + if (!_Py_atomic_load_relaxed(&ceval->gc_scheduled)) { + _Py_atomic_store_relaxed(&ceval->gc_scheduled, 1); + _Py_atomic_store_relaxed(&ceval->eval_breaker, 1); + } +} + void _PyObject_GC_Link(PyObject *op) { @@ -2269,12 +2283,19 @@ _PyObject_GC_Link(PyObject *op) !gcstate->collecting && !_PyErr_Occurred(tstate)) { - gcstate->collecting = 1; - gc_collect_generations(tstate); - gcstate->collecting = 0; + _Py_ScheduleGC(tstate->interp); } } +void +_Py_RunGC(PyThreadState *tstate) +{ + GCState *gcstate = &tstate->interp->gc; + gcstate->collecting = 1; + gc_collect_generations(tstate); + gcstate->collecting = 0; +} + static PyObject * gc_alloc(size_t basicsize, size_t presize) { diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c index 0f30b4da0363..b85d6d19e8cd 100644 --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -1798,6 +1798,19 @@ int PyErr_CheckSignals(void) { PyThreadState *tstate = _PyThreadState_GET(); + + /* Opportunistically check if the GC is scheduled to run and run it + if we have a request. This is done here because native code needs + to call this API if is going to run for some time without executing + Python code to ensure signals are handled. Checking for the GC here + allows long running native code to clean cycles created using the C-API + even if it doesn't run the evaluation loop */ + struct _ceval_state *interp_ceval_state = &tstate->interp->ceval; + if (_Py_atomic_load_relaxed(&interp_ceval_state->gc_scheduled)) { + _Py_atomic_store_relaxed(&interp_ceval_state->gc_scheduled, 0); + _Py_RunGC(tstate); + } + if (!_Py_ThreadCanHandleSignals(tstate->interp)) { return 0; } diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c index fd737b5738e8..9b9d7dc1d1af 100644 --- a/Python/ceval_gil.c +++ b/Python/ceval_gil.c @@ -5,6 +5,7 @@ #include "pycore_pyerrors.h" // _PyErr_Fetch() #include "pycore_pylifecycle.h" // _PyErr_Print() #include "pycore_initconfig.h" // _PyStatus_OK() +#include "pycore_interp.h" // _Py_RunGC() #include "pycore_pymem.h" // _PyMem_IsPtrFreed() /* @@ -69,7 +70,8 @@ COMPUTE_EVAL_BREAKER(PyInterpreterState *interp, && _Py_ThreadCanHandleSignals(interp)) | (_Py_atomic_load_relaxed_int32(&ceval2->pending.calls_to_do) && _Py_ThreadCanHandlePendingCalls()) - | ceval2->pending.async_exc); + | ceval2->pending.async_exc + | _Py_atomic_load_relaxed_int32(&ceval2->gc_scheduled)); } @@ -938,6 +940,7 @@ _Py_HandlePending(PyThreadState *tstate) { _PyRuntimeState * const runtime = &_PyRuntime; struct _ceval_runtime_state *ceval = &runtime->ceval; + struct _ceval_state *interp_ceval_state = &tstate->interp->ceval; /* Pending signals */ if (_Py_atomic_load_relaxed_int32(&ceval->signals_pending)) { @@ -947,20 +950,26 @@ _Py_HandlePending(PyThreadState *tstate) } /* Pending calls */ - struct _ceval_state *ceval2 = &tstate->interp->ceval; - if (_Py_atomic_load_relaxed_int32(&ceval2->pending.calls_to_do)) { + if (_Py_atomic_load_relaxed_int32(&interp_ceval_state->pending.calls_to_do)) { if (make_pending_calls(tstate->interp) != 0) { return -1; } } + /* GC scheduled to run */ + if (_Py_atomic_load_relaxed_int32(&interp_ceval_state->gc_scheduled)) { + _Py_atomic_store_relaxed(&interp_ceval_state->gc_scheduled, 0); + COMPUTE_EVAL_BREAKER(tstate->interp, ceval, interp_ceval_state); + _Py_RunGC(tstate); + } + /* GIL drop request */ - if (_Py_atomic_load_relaxed_int32(&ceval2->gil_drop_request)) { + if (_Py_atomic_load_relaxed_int32(&interp_ceval_state->gil_drop_request)) { /* Give another thread a chance */ if (_PyThreadState_Swap(&runtime->gilstate, NULL) != tstate) { Py_FatalError("tstate mix-up"); } - drop_gil(ceval, ceval2, tstate); + drop_gil(ceval, interp_ceval_state, tstate); /* Other threads may run now */ @@ -981,16 +990,17 @@ _Py_HandlePending(PyThreadState *tstate) return -1; } -#ifdef MS_WINDOWS - // bpo-42296: On Windows, _PyEval_SignalReceived() can be called in a - // different thread than the Python thread, in which case + + // It is possible that some of the conditions that trigger the eval breaker + // are called in a different thread than the Python thread. An example of + // this is bpo-42296: On Windows, _PyEval_SignalReceived() can be called in + // a different thread than the Python thread, in which case // _Py_ThreadCanHandleSignals() is wrong. Recompute eval_breaker in the // current Python thread with the correct _Py_ThreadCanHandleSignals() // value. It prevents to interrupt the eval loop at every instruction if // the current Python thread cannot handle signals (if // _Py_ThreadCanHandleSignals() is false). - COMPUTE_EVAL_BREAKER(tstate->interp, ceval, ceval2); -#endif + COMPUTE_EVAL_BREAKER(tstate->interp, ceval, interp_ceval_state); return 0; } From webhook-mailer at python.org Sat Oct 8 10:57:55 2022 From: webhook-mailer at python.org (nanjekyejoannah) Date: Sat, 08 Oct 2022 14:57:55 -0000 Subject: [Python-checkins] gh-68686: Retire eptag ptag scripts (#98064) Message-ID: https://github.com/python/cpython/commit/4ed00be98f5b7dbac3ab71159dda907c931de486 commit: 4ed00be98f5b7dbac3ab71159dda907c931de486 branch: main author: Joannah Nanjekye <33177550+nanjekyejoannah at users.noreply.github.com> committer: nanjekyejoannah <33177550+nanjekyejoannah at users.noreply.github.com> date: 2022-10-08T07:57:47-07:00 summary: gh-68686: Retire eptag ptag scripts (#98064) * Retire eptag ptag scripts * ?? Added by blurb_it. * fix news entry error Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> files: A Misc/NEWS.d/next/Tools-Demos/2022-10-07-22-06-11.gh-issue-68686.6KNIQ4.rst D Tools/scripts/eptags.py D Tools/scripts/ptags.py M Tools/scripts/README diff --git a/Misc/NEWS.d/next/Tools-Demos/2022-10-07-22-06-11.gh-issue-68686.6KNIQ4.rst b/Misc/NEWS.d/next/Tools-Demos/2022-10-07-22-06-11.gh-issue-68686.6KNIQ4.rst new file mode 100644 index 000000000000..a4289d675703 --- /dev/null +++ b/Misc/NEWS.d/next/Tools-Demos/2022-10-07-22-06-11.gh-issue-68686.6KNIQ4.rst @@ -0,0 +1 @@ +Remove ptags and eptags scripts. diff --git a/Tools/scripts/README b/Tools/scripts/README index b53b0f21d7c2..70ea5f4cd0fe 100644 --- a/Tools/scripts/README +++ b/Tools/scripts/README @@ -5,7 +5,6 @@ useful while building, extending or managing Python. abitype.py Converts a C file to use the PEP 384 type definition API combinerefs.py A helper for analyzing PYTHONDUMPREFS output diff.py Print file diffs in context, unified, or ndiff formats -eptags.py Create Emacs TAGS file for Python modules gprof2html.py Transform gprof(1) output into useful HTML idle3 Main program to start IDLE md5sum.py Print MD5 checksums of argument files diff --git a/Tools/scripts/eptags.py b/Tools/scripts/eptags.py deleted file mode 100755 index 7f8059ba71ad..000000000000 --- a/Tools/scripts/eptags.py +++ /dev/null @@ -1,57 +0,0 @@ -#! /usr/bin/env python3 -"""Create a TAGS file for Python programs, usable with GNU Emacs. - -usage: eptags pyfiles... - -The output TAGS file is usable with Emacs version 18, 19, 20. -Tagged are: - - functions (even inside other defs or classes) - - classes - -eptags warns about files it cannot open. -eptags will not give warnings about duplicate tags. - -BUGS: - Because of tag duplication (methods with the same name in different - classes), TAGS files are not very useful for most object-oriented - python projects. -""" -import sys,re - -expr = r'^[ \t]*(def|class)[ \t]+([a-zA-Z_][a-zA-Z0-9_]*)[ \t]*[:\(]' -matcher = re.compile(expr) - -def treat_file(filename, outfp): - """Append tags found in file named 'filename' to the open file 'outfp'""" - try: - fp = open(filename, 'r') - except OSError: - sys.stderr.write('Cannot open %s\n'%filename) - return - with fp: - charno = 0 - lineno = 0 - tags = [] - size = 0 - while 1: - line = fp.readline() - if not line: - break - lineno = lineno + 1 - m = matcher.search(line) - if m: - tag = m.group(0) + '\177%d,%d\n' % (lineno, charno) - tags.append(tag) - size = size + len(tag) - charno = charno + len(line) - outfp.write('\f\n%s,%d\n' % (filename,size)) - for tag in tags: - outfp.write(tag) - -def main(): - with open('TAGS', 'w') as outfp: - for filename in sys.argv[1:]: - treat_file(filename, outfp) - -if __name__=="__main__": - main() diff --git a/Tools/scripts/ptags.py b/Tools/scripts/ptags.py deleted file mode 100755 index eedd411702c1..000000000000 --- a/Tools/scripts/ptags.py +++ /dev/null @@ -1,54 +0,0 @@ -#! /usr/bin/env python3 - -# ptags -# -# Create a tags file for Python programs, usable with vi. -# Tagged are: -# - functions (even inside other defs or classes) -# - classes -# - filenames -# Warns about files it cannot open. -# No warnings about duplicate tags. - -import sys, re, os - -tags = [] # Modified global variable! - -def main(): - args = sys.argv[1:] - for filename in args: - treat_file(filename) - if tags: - with open('tags', 'w') as fp: - tags.sort() - for s in tags: fp.write(s) - - -expr = r'^[ \t]*(def|class)[ \t]+([a-zA-Z0-9_]+)[ \t]*[:\(]' -matcher = re.compile(expr) - -def treat_file(filename): - try: - fp = open(filename, 'r') - except: - sys.stderr.write('Cannot open %s\n' % filename) - return - with fp: - base = os.path.basename(filename) - if base[-3:] == '.py': - base = base[:-3] - s = base + '\t' + filename + '\t' + '1\n' - tags.append(s) - while 1: - line = fp.readline() - if not line: - break - m = matcher.match(line) - if m: - content = m.group(0) - name = m.group(2) - s = name + '\t' + filename + '\t/^' + content + '/\n' - tags.append(s) - -if __name__ == '__main__': - main() From webhook-mailer at python.org Sat Oct 8 14:32:28 2022 From: webhook-mailer at python.org (serhiy-storchaka) Date: Sat, 08 Oct 2022 18:32:28 -0000 Subject: [Python-checkins] gh-95011: Migrate syslog module to Argument Clinic (GH-95012) Message-ID: https://github.com/python/cpython/commit/5405537813750dbfb133c1af26360297954765f8 commit: 5405537813750dbfb133c1af26360297954765f8 branch: main author: Noam Cohen committer: serhiy-storchaka date: 2022-10-08T21:31:57+03:00 summary: gh-95011: Migrate syslog module to Argument Clinic (GH-95012) files: A Modules/clinic/syslogmodule.c.h M Include/internal/pycore_global_strings.h M Include/internal/pycore_runtime_init_generated.h M Modules/syslogmodule.c diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 2966b60e0cd8..f646979910c8 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -350,6 +350,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(exception) STRUCT_FOR_ID(exp) STRUCT_FOR_ID(extend) + STRUCT_FOR_ID(facility) STRUCT_FOR_ID(factory) STRUCT_FOR_ID(family) STRUCT_FOR_ID(fanout) @@ -392,6 +393,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(hi) STRUCT_FOR_ID(hook) STRUCT_FOR_ID(id) + STRUCT_FOR_ID(ident) STRUCT_FOR_ID(ignore) STRUCT_FOR_ID(imag) STRUCT_FOR_ID(importlib) @@ -447,6 +449,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(lo) STRUCT_FOR_ID(locale) STRUCT_FOR_ID(locals) + STRUCT_FOR_ID(logoption) STRUCT_FOR_ID(loop) STRUCT_FOR_ID(mapping) STRUCT_FOR_ID(match) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index 617582f96e33..bd1fedebd65c 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -859,6 +859,7 @@ extern "C" { INIT_ID(exception), \ INIT_ID(exp), \ INIT_ID(extend), \ + INIT_ID(facility), \ INIT_ID(factory), \ INIT_ID(family), \ INIT_ID(fanout), \ @@ -901,6 +902,7 @@ extern "C" { INIT_ID(hi), \ INIT_ID(hook), \ INIT_ID(id), \ + INIT_ID(ident), \ INIT_ID(ignore), \ INIT_ID(imag), \ INIT_ID(importlib), \ @@ -956,6 +958,7 @@ extern "C" { INIT_ID(lo), \ INIT_ID(locale), \ INIT_ID(locals), \ + INIT_ID(logoption), \ INIT_ID(loop), \ INIT_ID(mapping), \ INIT_ID(match), \ @@ -2026,6 +2029,8 @@ _PyUnicode_InitStaticStrings(void) { PyUnicode_InternInPlace(&string); string = &_Py_ID(extend); PyUnicode_InternInPlace(&string); + string = &_Py_ID(facility); + PyUnicode_InternInPlace(&string); string = &_Py_ID(factory); PyUnicode_InternInPlace(&string); string = &_Py_ID(family); @@ -2110,6 +2115,8 @@ _PyUnicode_InitStaticStrings(void) { PyUnicode_InternInPlace(&string); string = &_Py_ID(id); PyUnicode_InternInPlace(&string); + string = &_Py_ID(ident); + PyUnicode_InternInPlace(&string); string = &_Py_ID(ignore); PyUnicode_InternInPlace(&string); string = &_Py_ID(imag); @@ -2220,6 +2227,8 @@ _PyUnicode_InitStaticStrings(void) { PyUnicode_InternInPlace(&string); string = &_Py_ID(locals); PyUnicode_InternInPlace(&string); + string = &_Py_ID(logoption); + PyUnicode_InternInPlace(&string); string = &_Py_ID(loop); PyUnicode_InternInPlace(&string); string = &_Py_ID(mapping); @@ -5981,6 +5990,10 @@ _PyStaticObjects_CheckRefcnt(void) { _PyObject_Dump((PyObject *)&_Py_ID(extend)); Py_FatalError("immortal object has less refcnt than expected _PyObject_IMMORTAL_REFCNT"); }; + if (Py_REFCNT((PyObject *)&_Py_ID(facility)) < _PyObject_IMMORTAL_REFCNT) { + _PyObject_Dump((PyObject *)&_Py_ID(facility)); + Py_FatalError("immortal object has less refcnt than expected _PyObject_IMMORTAL_REFCNT"); + }; if (Py_REFCNT((PyObject *)&_Py_ID(factory)) < _PyObject_IMMORTAL_REFCNT) { _PyObject_Dump((PyObject *)&_Py_ID(factory)); Py_FatalError("immortal object has less refcnt than expected _PyObject_IMMORTAL_REFCNT"); @@ -6149,6 +6162,10 @@ _PyStaticObjects_CheckRefcnt(void) { _PyObject_Dump((PyObject *)&_Py_ID(id)); Py_FatalError("immortal object has less refcnt than expected _PyObject_IMMORTAL_REFCNT"); }; + if (Py_REFCNT((PyObject *)&_Py_ID(ident)) < _PyObject_IMMORTAL_REFCNT) { + _PyObject_Dump((PyObject *)&_Py_ID(ident)); + Py_FatalError("immortal object has less refcnt than expected _PyObject_IMMORTAL_REFCNT"); + }; if (Py_REFCNT((PyObject *)&_Py_ID(ignore)) < _PyObject_IMMORTAL_REFCNT) { _PyObject_Dump((PyObject *)&_Py_ID(ignore)); Py_FatalError("immortal object has less refcnt than expected _PyObject_IMMORTAL_REFCNT"); @@ -6369,6 +6386,10 @@ _PyStaticObjects_CheckRefcnt(void) { _PyObject_Dump((PyObject *)&_Py_ID(locals)); Py_FatalError("immortal object has less refcnt than expected _PyObject_IMMORTAL_REFCNT"); }; + if (Py_REFCNT((PyObject *)&_Py_ID(logoption)) < _PyObject_IMMORTAL_REFCNT) { + _PyObject_Dump((PyObject *)&_Py_ID(logoption)); + Py_FatalError("immortal object has less refcnt than expected _PyObject_IMMORTAL_REFCNT"); + }; if (Py_REFCNT((PyObject *)&_Py_ID(loop)) < _PyObject_IMMORTAL_REFCNT) { _PyObject_Dump((PyObject *)&_Py_ID(loop)); Py_FatalError("immortal object has less refcnt than expected _PyObject_IMMORTAL_REFCNT"); diff --git a/Modules/clinic/syslogmodule.c.h b/Modules/clinic/syslogmodule.c.h new file mode 100644 index 000000000000..0ce66ad4e1a4 --- /dev/null +++ b/Modules/clinic/syslogmodule.c.h @@ -0,0 +1,257 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +# include "pycore_gc.h" // PyGC_Head +# include "pycore_runtime.h" // _Py_ID() +#endif + + +PyDoc_STRVAR(syslog_openlog__doc__, +"openlog($module, /, ident=, logoption=0,\n" +" facility=LOG_USER)\n" +"--\n" +"\n" +"Set logging options of subsequent syslog() calls."); + +#define SYSLOG_OPENLOG_METHODDEF \ + {"openlog", _PyCFunction_CAST(syslog_openlog), METH_FASTCALL|METH_KEYWORDS, syslog_openlog__doc__}, + +static PyObject * +syslog_openlog_impl(PyObject *module, PyObject *ident, long logopt, + long facility); + +static PyObject * +syslog_openlog(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 3 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(ident), &_Py_ID(logoption), &_Py_ID(facility), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"ident", "logoption", "facility", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "openlog", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[3]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *ident = NULL; + long logopt = 0; + long facility = LOG_USER; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 3, 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (args[0]) { + if (!PyUnicode_Check(args[0])) { + _PyArg_BadArgument("openlog", "argument 'ident'", "str", args[0]); + goto exit; + } + if (PyUnicode_READY(args[0]) == -1) { + goto exit; + } + ident = args[0]; + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (args[1]) { + logopt = PyLong_AsLong(args[1]); + if (logopt == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + facility = PyLong_AsLong(args[2]); + if (facility == -1 && PyErr_Occurred()) { + goto exit; + } +skip_optional_pos: + return_value = syslog_openlog_impl(module, ident, logopt, facility); + +exit: + return return_value; +} + +PyDoc_STRVAR(syslog_syslog__doc__, +"syslog([priority=LOG_INFO,] message)\n" +"Send the string message to the system logger."); + +#define SYSLOG_SYSLOG_METHODDEF \ + {"syslog", (PyCFunction)syslog_syslog, METH_VARARGS, syslog_syslog__doc__}, + +static PyObject * +syslog_syslog_impl(PyObject *module, int group_left_1, int priority, + const char *message); + +static PyObject * +syslog_syslog(PyObject *module, PyObject *args) +{ + PyObject *return_value = NULL; + int group_left_1 = 0; + int priority = LOG_INFO; + const char *message; + + switch (PyTuple_GET_SIZE(args)) { + case 1: + if (!PyArg_ParseTuple(args, "s:syslog", &message)) { + goto exit; + } + break; + case 2: + if (!PyArg_ParseTuple(args, "is:syslog", &priority, &message)) { + goto exit; + } + group_left_1 = 1; + break; + default: + PyErr_SetString(PyExc_TypeError, "syslog.syslog requires 1 to 2 arguments"); + goto exit; + } + return_value = syslog_syslog_impl(module, group_left_1, priority, message); + +exit: + return return_value; +} + +PyDoc_STRVAR(syslog_closelog__doc__, +"closelog($module, /)\n" +"--\n" +"\n" +"Reset the syslog module values and call the system library closelog()."); + +#define SYSLOG_CLOSELOG_METHODDEF \ + {"closelog", (PyCFunction)syslog_closelog, METH_NOARGS, syslog_closelog__doc__}, + +static PyObject * +syslog_closelog_impl(PyObject *module); + +static PyObject * +syslog_closelog(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return syslog_closelog_impl(module); +} + +PyDoc_STRVAR(syslog_setlogmask__doc__, +"setlogmask($module, maskpri, /)\n" +"--\n" +"\n" +"Set the priority mask to maskpri and return the previous mask value."); + +#define SYSLOG_SETLOGMASK_METHODDEF \ + {"setlogmask", (PyCFunction)syslog_setlogmask, METH_O, syslog_setlogmask__doc__}, + +static long +syslog_setlogmask_impl(PyObject *module, long maskpri); + +static PyObject * +syslog_setlogmask(PyObject *module, PyObject *arg) +{ + PyObject *return_value = NULL; + long maskpri; + long _return_value; + + maskpri = PyLong_AsLong(arg); + if (maskpri == -1 && PyErr_Occurred()) { + goto exit; + } + _return_value = syslog_setlogmask_impl(module, maskpri); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } + return_value = PyLong_FromLong(_return_value); + +exit: + return return_value; +} + +PyDoc_STRVAR(syslog_LOG_MASK__doc__, +"LOG_MASK($module, pri, /)\n" +"--\n" +"\n" +"Calculates the mask for the individual priority pri."); + +#define SYSLOG_LOG_MASK_METHODDEF \ + {"LOG_MASK", (PyCFunction)syslog_LOG_MASK, METH_O, syslog_LOG_MASK__doc__}, + +static long +syslog_LOG_MASK_impl(PyObject *module, long pri); + +static PyObject * +syslog_LOG_MASK(PyObject *module, PyObject *arg) +{ + PyObject *return_value = NULL; + long pri; + long _return_value; + + pri = PyLong_AsLong(arg); + if (pri == -1 && PyErr_Occurred()) { + goto exit; + } + _return_value = syslog_LOG_MASK_impl(module, pri); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } + return_value = PyLong_FromLong(_return_value); + +exit: + return return_value; +} + +PyDoc_STRVAR(syslog_LOG_UPTO__doc__, +"LOG_UPTO($module, pri, /)\n" +"--\n" +"\n" +"Calculates the mask for all priorities up to and including pri."); + +#define SYSLOG_LOG_UPTO_METHODDEF \ + {"LOG_UPTO", (PyCFunction)syslog_LOG_UPTO, METH_O, syslog_LOG_UPTO__doc__}, + +static long +syslog_LOG_UPTO_impl(PyObject *module, long pri); + +static PyObject * +syslog_LOG_UPTO(PyObject *module, PyObject *arg) +{ + PyObject *return_value = NULL; + long pri; + long _return_value; + + pri = PyLong_AsLong(arg); + if (pri == -1 && PyErr_Occurred()) { + goto exit; + } + _return_value = syslog_LOG_UPTO_impl(module, pri); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } + return_value = PyLong_FromLong(_return_value); + +exit: + return return_value; +} +/*[clinic end generated code: output=3b1bdb16565b8fda input=a9049054013a1b77]*/ diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index 1593eea94a62..b6296ed0a69a 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -54,6 +54,13 @@ Revision history: #include +/*[clinic input] +module syslog +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=478f4ac94a1d4cae]*/ + +#include "clinic/syslogmodule.c.h" + /* only one instance, only one syslog, so globals should be ok */ static PyObject *S_ident_o = NULL; /* identifier, held by openlog() */ static char S_log_open = 0; @@ -113,19 +120,23 @@ syslog_get_argv(void) } +/*[clinic input] +syslog.openlog + + ident: unicode = NULL + logoption as logopt: long = 0 + facility: long(c_default="LOG_USER") = LOG_USER + +Set logging options of subsequent syslog() calls. +[clinic start generated code]*/ + static PyObject * -syslog_openlog(PyObject * self, PyObject * args, PyObject *kwds) +syslog_openlog_impl(PyObject *module, PyObject *ident, long logopt, + long facility) +/*[clinic end generated code: output=5476c12829b6eb75 input=8a987a96a586eee7]*/ { - long logopt = 0; - long facility = LOG_USER; - PyObject *ident = NULL; - static char *keywords[] = {"ident", "logoption", "facility", 0}; const char *ident_str = NULL; - if (!PyArg_ParseTupleAndKeywords(args, kwds, - "|Ull:openlog", keywords, &ident, &logopt, &facility)) - return NULL; - if (ident) { Py_INCREF(ident); } @@ -158,48 +169,37 @@ syslog_openlog(PyObject * self, PyObject * args, PyObject *kwds) } -static PyObject * -syslog_syslog(PyObject * self, PyObject * args) -{ - PyObject *message_object; - const char *message; - int priority = LOG_INFO; - if (!PyArg_ParseTuple(args, "iU;[priority,] message string", - &priority, &message_object)) { - PyErr_Clear(); - if (!PyArg_ParseTuple(args, "U;[priority,] message string", - &message_object)) - return NULL; - } +/*[clinic input] +syslog.syslog - message = PyUnicode_AsUTF8(message_object); - if (message == NULL) - return NULL; + [ + priority: int(c_default="LOG_INFO") = LOG_INFO + ] + + message: str + + / +Send the string message to the system logger. +[clinic start generated code]*/ + +static PyObject * +syslog_syslog_impl(PyObject *module, int group_left_1, int priority, + const char *message) +/*[clinic end generated code: output=c3dbc73445a0e078 input=ac83d92b12ea3d4e]*/ +{ if (PySys_Audit("syslog.syslog", "is", priority, message) < 0) { return NULL; } /* if log is not opened, open it now */ if (!S_log_open) { - PyObject *openargs; - - /* Continue even if PyTuple_New fails, because openlog(3) is optional. - * So, we can still do logging in the unlikely event things are so hosed - * that we can't do this tuple. - */ - if ((openargs = PyTuple_New(0))) { - PyObject *openlog_ret = syslog_openlog(self, openargs, NULL); - Py_DECREF(openargs); - if (openlog_ret == NULL) { - return NULL; - } - Py_DECREF(openlog_ret); - } - else { + PyObject *openlog_ret = syslog_openlog_impl(module, NULL, 0, LOG_USER); + if (openlog_ret == NULL) { return NULL; } + Py_DECREF(openlog_ret); } /* Incref ident, because it can be decrefed if syslog.openlog() is @@ -214,8 +214,16 @@ syslog_syslog(PyObject * self, PyObject * args) Py_RETURN_NONE; } + +/*[clinic input] +syslog.closelog + +Reset the syslog module values and call the system library closelog(). +[clinic start generated code]*/ + static PyObject * -syslog_closelog(PyObject *self, PyObject *unused) +syslog_closelog_impl(PyObject *module) +/*[clinic end generated code: output=97890a80a24b1b84 input=fb77a54d447acf07]*/ { if (PySys_Audit("syslog.closelog", NULL) < 0) { return NULL; @@ -228,51 +236,67 @@ syslog_closelog(PyObject *self, PyObject *unused) Py_RETURN_NONE; } -static PyObject * -syslog_setlogmask(PyObject *self, PyObject *args) -{ - long maskpri, omaskpri; +/*[clinic input] +syslog.setlogmask -> long - if (!PyArg_ParseTuple(args, "l;mask for priority", &maskpri)) - return NULL; + maskpri: long + / + +Set the priority mask to maskpri and return the previous mask value. +[clinic start generated code]*/ + +static long +syslog_setlogmask_impl(PyObject *module, long maskpri) +/*[clinic end generated code: output=d6ed163917b434bf input=adff2c2b76c7629c]*/ +{ if (PySys_Audit("syslog.setlogmask", "l", maskpri) < 0) { - return NULL; + return -1; } - omaskpri = setlogmask(maskpri); - return PyLong_FromLong(omaskpri); + + return setlogmask(maskpri); } -static PyObject * -syslog_log_mask(PyObject *self, PyObject *args) +/*[clinic input] +syslog.LOG_MASK -> long + + pri: long + / + +Calculates the mask for the individual priority pri. +[clinic start generated code]*/ + +static long +syslog_LOG_MASK_impl(PyObject *module, long pri) +/*[clinic end generated code: output=c4a5bbfcc74c7c94 input=534829cb7fb5f7d2]*/ { - long mask; - long pri; - if (!PyArg_ParseTuple(args, "l:LOG_MASK", &pri)) - return NULL; - mask = LOG_MASK(pri); - return PyLong_FromLong(mask); + return LOG_MASK(pri); } -static PyObject * -syslog_log_upto(PyObject *self, PyObject *args) +/*[clinic input] +syslog.LOG_UPTO -> long + + pri: long + / + +Calculates the mask for all priorities up to and including pri. +[clinic start generated code]*/ + +static long +syslog_LOG_UPTO_impl(PyObject *module, long pri) +/*[clinic end generated code: output=9eab083c90601d7e input=5e906d6c406b7458]*/ { - long mask; - long pri; - if (!PyArg_ParseTuple(args, "l:LOG_UPTO", &pri)) - return NULL; - mask = LOG_UPTO(pri); - return PyLong_FromLong(mask); + return LOG_UPTO(pri); } /* List of functions defined in the module */ static PyMethodDef syslog_methods[] = { - {"openlog", _PyCFunction_CAST(syslog_openlog), METH_VARARGS | METH_KEYWORDS}, - {"closelog", syslog_closelog, METH_NOARGS}, - {"syslog", syslog_syslog, METH_VARARGS}, - {"setlogmask", syslog_setlogmask, METH_VARARGS}, - {"LOG_MASK", syslog_log_mask, METH_VARARGS}, - {"LOG_UPTO", syslog_log_upto, METH_VARARGS}, + SYSLOG_OPENLOG_METHODDEF + SYSLOG_CLOSELOG_METHODDEF + SYSLOG_SYSLOG_METHODDEF + SYSLOG_SETLOGMASK_METHODDEF + SYSLOG_LOG_MASK_METHODDEF + SYSLOG_LOG_UPTO_METHODDEF {NULL, NULL, 0} }; From webhook-mailer at python.org Sat Oct 8 15:21:46 2022 From: webhook-mailer at python.org (ezio-melotti) Date: Sat, 08 Oct 2022 19:21:46 -0000 Subject: [Python-checkins] Auto-cancel old builds when new commit pushed to branch (#98009) Message-ID: https://github.com/python/cpython/commit/75751f4aa5d70f65856645a9128fd42d92d6692c commit: 75751f4aa5d70f65856645a9128fd42d92d6692c branch: main author: Hugo van Kemenade committer: ezio-melotti date: 2022-10-08T21:21:38+02:00 summary: Auto-cancel old builds when new commit pushed to branch (#98009) * Auto-cancel old builds when new commit pushed to branch * Add a fallback Co-authored-by: Ezio Melotti * Use the same group for all workflows. Co-authored-by: Ezio Melotti files: M .github/workflows/build.yml M .github/workflows/build_msi.yml M .github/workflows/doc.yml M .github/workflows/verify-ensurepip-wheels.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index dc91c0dbcb02..8f5676eec08e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -25,6 +25,10 @@ on: permissions: contents: read +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + jobs: check_source: name: 'Check for source changes' diff --git a/.github/workflows/build_msi.yml b/.github/workflows/build_msi.yml index 528679c0ac6b..5f1dcae190ef 100644 --- a/.github/workflows/build_msi.yml +++ b/.github/workflows/build_msi.yml @@ -18,6 +18,10 @@ on: permissions: contents: read +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + jobs: build: name: Windows Installer diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index d95d089ed667..10e4cf074a59 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -28,6 +28,10 @@ on: permissions: contents: read +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + jobs: build_doc: name: 'Docs' diff --git a/.github/workflows/verify-ensurepip-wheels.yml b/.github/workflows/verify-ensurepip-wheels.yml index 61e3d1adf534..9f4754f912b0 100644 --- a/.github/workflows/verify-ensurepip-wheels.yml +++ b/.github/workflows/verify-ensurepip-wheels.yml @@ -16,6 +16,10 @@ on: permissions: contents: read +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + jobs: verify: runs-on: ubuntu-latest From webhook-mailer at python.org Sat Oct 8 15:22:33 2022 From: webhook-mailer at python.org (serhiy-storchaka) Date: Sat, 08 Oct 2022 19:22:33 -0000 Subject: [Python-checkins] [3.11] Add more syslog tests (GH-97953). (GH-98096) Message-ID: https://github.com/python/cpython/commit/f6e50b82f68f48323fcee5800396760e4f7833af commit: f6e50b82f68f48323fcee5800396760e4f7833af branch: 3.11 author: Serhiy Storchaka committer: serhiy-storchaka date: 2022-10-08T22:22:26+03:00 summary: [3.11] Add more syslog tests (GH-97953). (GH-98096) (cherry picked from commit cae7d1d7a713f8267daf5e4f2fff5cb1dad02c7c) files: M Lib/test/audit-tests.py M Lib/test/test_audit.py M Lib/test/test_syslog.py M Modules/syslogmodule.c diff --git a/Lib/test/audit-tests.py b/Lib/test/audit-tests.py index 00333cc9036a..fea2f2177494 100644 --- a/Lib/test/audit-tests.py +++ b/Lib/test/audit-tests.py @@ -419,6 +419,27 @@ def hook(event, args): sys._getframe() +def test_syslog(): + import syslog + + def hook(event, args): + if event.startswith("syslog."): + print(event, *args) + + sys.addaudithook(hook) + syslog.openlog('python') + syslog.syslog('test') + syslog.setlogmask(syslog.LOG_DEBUG) + syslog.closelog() + # implicit open + syslog.syslog('test2') + # open with default ident + syslog.openlog(logoption=syslog.LOG_NDELAY, facility=syslog.LOG_LOCAL0) + sys.argv = None + syslog.openlog() + syslog.closelog() + + if __name__ == "__main__": from test.support import suppress_msvcrt_asserts diff --git a/Lib/test/test_audit.py b/Lib/test/test_audit.py index 18426f27a2e3..7cfb1d0d44f7 100644 --- a/Lib/test/test_audit.py +++ b/Lib/test/test_audit.py @@ -16,6 +16,7 @@ class AuditTest(unittest.TestCase): + maxDiff = None @support.requires_subprocess() def do_test(self, *args): @@ -185,5 +186,29 @@ def test_sys_getframe(self): self.assertEqual(actual, expected) + def test_syslog(self): + syslog = import_helper.import_module("syslog") + + returncode, events, stderr = self.run_python("test_syslog") + if returncode: + self.fail(stderr) + + if support.verbose: + print('Events:', *events, sep='\n ') + + self.assertSequenceEqual( + events, + [('syslog.openlog', ' ', f'python 0 {syslog.LOG_USER}'), + ('syslog.syslog', ' ', f'{syslog.LOG_INFO} test'), + ('syslog.setlogmask', ' ', f'{syslog.LOG_DEBUG}'), + ('syslog.closelog', '', ''), + ('syslog.syslog', ' ', f'{syslog.LOG_INFO} test2'), + ('syslog.openlog', ' ', f'audit-tests.py 0 {syslog.LOG_USER}'), + ('syslog.openlog', ' ', f'audit-tests.py {syslog.LOG_NDELAY} {syslog.LOG_LOCAL0}'), + ('syslog.openlog', ' ', f'None 0 {syslog.LOG_USER}'), + ('syslog.closelog', '', '')] + ) + + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_syslog.py b/Lib/test/test_syslog.py index fe09bd39f8b7..2125ec58d87e 100644 --- a/Lib/test/test_syslog.py +++ b/Lib/test/test_syslog.py @@ -1,5 +1,9 @@ -from test.support import import_helper +from test.support import import_helper, threading_helper syslog = import_helper.import_module("syslog") #skip if not supported +from test import support +import sys +import threading +import time import unittest # XXX(nnorwitz): This test sucks. I don't know of a platform independent way @@ -8,6 +12,9 @@ class Test(unittest.TestCase): + def tearDown(self): + syslog.closelog() + def test_openlog(self): syslog.openlog('python') # Issue #6697. @@ -18,22 +25,59 @@ def test_syslog(self): syslog.syslog('test message from python test_syslog') syslog.syslog(syslog.LOG_ERR, 'test error from python test_syslog') + def test_syslog_implicit_open(self): + syslog.closelog() # Make sure log is closed + syslog.syslog('test message from python test_syslog') + syslog.syslog(syslog.LOG_ERR, 'test error from python test_syslog') + def test_closelog(self): syslog.openlog('python') syslog.closelog() + syslog.closelog() # idempotent operation def test_setlogmask(self): - syslog.setlogmask(syslog.LOG_DEBUG) + mask = syslog.LOG_UPTO(syslog.LOG_WARNING) + oldmask = syslog.setlogmask(mask) + self.assertEqual(syslog.setlogmask(0), mask) + self.assertEqual(syslog.setlogmask(oldmask), mask) def test_log_mask(self): - syslog.LOG_MASK(syslog.LOG_INFO) - - def test_log_upto(self): - syslog.LOG_UPTO(syslog.LOG_INFO) + mask = syslog.LOG_UPTO(syslog.LOG_WARNING) + self.assertTrue(mask & syslog.LOG_MASK(syslog.LOG_WARNING)) + self.assertTrue(mask & syslog.LOG_MASK(syslog.LOG_ERR)) + self.assertFalse(mask & syslog.LOG_MASK(syslog.LOG_INFO)) def test_openlog_noargs(self): syslog.openlog() syslog.syslog('test message from python test_syslog') + @threading_helper.requires_working_threading() + def test_syslog_threaded(self): + start = threading.Event() + stop = False + def opener(): + start.wait(10) + i = 1 + while not stop: + syslog.openlog(f'python-test-{i}') # new string object + i += 1 + def logger(): + start.wait(10) + while not stop: + syslog.syslog('test message from python test_syslog') + + orig_si = sys.getswitchinterval() + support.setswitchinterval(1e-9) + try: + threads = [threading.Thread(target=opener)] + threads += [threading.Thread(target=logger) for k in range(10)] + with threading_helper.start_threads(threads): + start.set() + time.sleep(0.1) + stop = True + finally: + sys.setswitchinterval(orig_si) + + if __name__ == "__main__": unittest.main() diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index c409fe968f88..1593eea94a62 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -235,7 +235,7 @@ syslog_setlogmask(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "l;mask for priority", &maskpri)) return NULL; - if (PySys_Audit("syslog.setlogmask", "(O)", args ? args : Py_None) < 0) { + if (PySys_Audit("syslog.setlogmask", "l", maskpri) < 0) { return NULL; } omaskpri = setlogmask(maskpri); From webhook-mailer at python.org Sat Oct 8 16:52:28 2022 From: webhook-mailer at python.org (gvanrossum) Date: Sat, 08 Oct 2022 20:52:28 -0000 Subject: [Python-checkins] GH-94597: deprecate `SafeChildWatcher`, `FastChildWatcher` and `MultiLoopChildWatcher` child watchers (#98089) Message-ID: https://github.com/python/cpython/commit/d8765284f33ec221b5fe07b439ca2dc2d648251d commit: d8765284f33ec221b5fe07b439ca2dc2d648251d branch: main author: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> committer: gvanrossum date: 2022-10-08T13:52:19-07:00 summary: GH-94597: deprecate `SafeChildWatcher`, `FastChildWatcher` and `MultiLoopChildWatcher` child watchers (#98089) files: A Misc/NEWS.d/next/Library/2022-10-08-06-59-46.gh-issue-94597.TsS0oT.rst M Doc/whatsnew/3.12.rst M Lib/asyncio/unix_events.py M Lib/test/test_asyncio/test_events.py M Lib/test/test_asyncio/test_streams.py M Lib/test/test_asyncio/test_subprocess.py M Lib/test/test_asyncio/test_unix_events.py diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 341e85103a3c..903533261006 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -109,6 +109,24 @@ New Modules Improved Modules ================ +asyncio +------- + +* On Linux, :mod:`asyncio` uses :class:`~asyncio.PidfdChildWatcher` by default + if :func:`os.pidfd_open` is available and functional instead of + :class:`~asyncio.ThreadedChildWatcher`. + (Contributed by Kumar Aditya in :gh:`98024`.) + +* The child watcher classes :class:`~asyncio.MultiLoopChildWatcher`, + :class:`~asyncio.FastChildWatcher` and + :class:`~asyncio.SafeChildWatcher` are deprecated and + will be removed in Python 3.14. It is recommended to not manually + configure a child watcher as the event loop now uses the best available + child watcher for each platform (:class:`~asyncio.PidfdChildWatcher` + if supported and :class:`~asyncio.ThreadedChildWatcher` otherwise). + (Contributed by Kumar Aditya in :gh:`94597`.) + + pathlib ------- diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py index 7fc75cd17ef7..bdffc032e318 100644 --- a/Lib/asyncio/unix_events.py +++ b/Lib/asyncio/unix_events.py @@ -1022,6 +1022,13 @@ class SafeChildWatcher(BaseChildWatcher): big number of children (O(n) each time SIGCHLD is raised) """ + def __init__(self): + super().__init__() + warnings._deprecated("SafeChildWatcher", + "{name!r} is deprecated as of Python 3.12 and will be " + "removed in Python {remove}.", + remove=(3, 14)) + def close(self): self._callbacks.clear() super().close() @@ -1100,6 +1107,10 @@ def __init__(self): self._lock = threading.Lock() self._zombies = {} self._forks = 0 + warnings._deprecated("FastChildWatcher", + "{name!r} is deprecated as of Python 3.12 and will be " + "removed in Python {remove}.", + remove=(3, 14)) def close(self): self._callbacks.clear() @@ -1212,6 +1223,10 @@ class MultiLoopChildWatcher(AbstractChildWatcher): def __init__(self): self._callbacks = {} self._saved_sighandler = None + warnings._deprecated("MultiLoopChildWatcher", + "{name!r} is deprecated as of Python 3.12 and will be " + "removed in Python {remove}.", + remove=(3, 14)) def is_active(self): return self._saved_sighandler is not None diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py index 80d7152128c4..98b55dec37f4 100644 --- a/Lib/test/test_asyncio/test_events.py +++ b/Lib/test/test_asyncio/test_events.py @@ -22,7 +22,7 @@ import unittest from unittest import mock import weakref - +import warnings if sys.platform not in ('win32', 'vxworks'): import tty @@ -2055,7 +2055,9 @@ def test_remove_fds_after_closing(self): class UnixEventLoopTestsMixin(EventLoopTestsMixin): def setUp(self): super().setUp() - watcher = asyncio.SafeChildWatcher() + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + watcher = asyncio.SafeChildWatcher() watcher.attach_loop(self.loop) asyncio.set_child_watcher(watcher) @@ -2652,7 +2654,9 @@ def setUp(self): asyncio.set_event_loop(self.loop) if sys.platform != 'win32': - watcher = asyncio.SafeChildWatcher() + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + watcher = asyncio.SafeChildWatcher() watcher.attach_loop(self.loop) asyncio.set_child_watcher(watcher) diff --git a/Lib/test/test_asyncio/test_streams.py b/Lib/test/test_asyncio/test_streams.py index 0c49099bc499..8fb9313e09dd 100644 --- a/Lib/test/test_asyncio/test_streams.py +++ b/Lib/test/test_asyncio/test_streams.py @@ -9,6 +9,7 @@ import threading import unittest from unittest import mock +import warnings from test.support import socket_helper try: import ssl @@ -791,8 +792,9 @@ def test_read_all_from_pipe_reader(self): protocol = asyncio.StreamReaderProtocol(reader, loop=self.loop) transport, _ = self.loop.run_until_complete( self.loop.connect_read_pipe(lambda: protocol, pipe)) - - watcher = asyncio.SafeChildWatcher() + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + watcher = asyncio.SafeChildWatcher() watcher.attach_loop(self.loop) try: asyncio.set_child_watcher(watcher) diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py index 6ba889407b80..915ad5587f0a 100644 --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -4,7 +4,6 @@ import sys import unittest import warnings -import functools from unittest import mock import asyncio @@ -31,19 +30,6 @@ 'sys.stdout.buffer.write(data)'))] - at functools.cache -def _has_pidfd_support(): - if not hasattr(os, 'pidfd_open'): - return False - - try: - os.close(os.pidfd_open(os.getpid())) - except OSError: - return False - - return True - - def tearDownModule(): asyncio.set_event_loop_policy(None) @@ -688,7 +674,7 @@ def setUp(self): self.loop = policy.new_event_loop() self.set_event_loop(self.loop) - watcher = self.Watcher() + watcher = self._get_watcher() watcher.attach_loop(self.loop) policy.set_child_watcher(watcher) @@ -703,32 +689,38 @@ def tearDown(self): class SubprocessThreadedWatcherTests(SubprocessWatcherMixin, test_utils.TestCase): - Watcher = unix_events.ThreadedChildWatcher - - @unittest.skip("bpo-38323: MultiLoopChildWatcher has a race condition \ - and these tests can hang the test suite") - class SubprocessMultiLoopWatcherTests(SubprocessWatcherMixin, - test_utils.TestCase): - - Watcher = unix_events.MultiLoopChildWatcher + def _get_watcher(self): + return unix_events.ThreadedChildWatcher() class SubprocessSafeWatcherTests(SubprocessWatcherMixin, test_utils.TestCase): - Watcher = unix_events.SafeChildWatcher + def _get_watcher(self): + with self.assertWarns(DeprecationWarning): + return unix_events.SafeChildWatcher() + + class MultiLoopChildWatcherTests(test_utils.TestCase): + + def test_warns(self): + with self.assertWarns(DeprecationWarning): + unix_events.MultiLoopChildWatcher() class SubprocessFastWatcherTests(SubprocessWatcherMixin, test_utils.TestCase): - Watcher = unix_events.FastChildWatcher + def _get_watcher(self): + with self.assertWarns(DeprecationWarning): + return unix_events.FastChildWatcher() @unittest.skipUnless( - _has_pidfd_support(), + unix_events.can_use_pidfd(), "operating system does not support pidfds", ) class SubprocessPidfdWatcherTests(SubprocessWatcherMixin, test_utils.TestCase): - Watcher = unix_events.PidfdChildWatcher + + def _get_watcher(self): + return unix_events.PidfdChildWatcher() class GenericWatcherTests(test_utils.TestCase): @@ -758,7 +750,7 @@ async def execute(): @unittest.skipUnless( - _has_pidfd_support(), + unix_events.can_use_pidfd(), "operating system does not support pidfds", ) def test_create_subprocess_with_pidfd(self): diff --git a/Lib/test/test_asyncio/test_unix_events.py b/Lib/test/test_asyncio/test_unix_events.py index 03fb5e649d8e..025da0f20ed4 100644 --- a/Lib/test/test_asyncio/test_unix_events.py +++ b/Lib/test/test_asyncio/test_unix_events.py @@ -12,6 +12,7 @@ import threading import unittest from unittest import mock +import warnings from test.support import os_helper from test.support import socket_helper @@ -1686,12 +1687,16 @@ def test_close(self, m_waitpid): class SafeChildWatcherTests (ChildWatcherTestsMixin, test_utils.TestCase): def create_watcher(self): - return asyncio.SafeChildWatcher() + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + return asyncio.SafeChildWatcher() class FastChildWatcherTests (ChildWatcherTestsMixin, test_utils.TestCase): def create_watcher(self): - return asyncio.FastChildWatcher() + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + return asyncio.FastChildWatcher() class PolicyTests(unittest.TestCase): @@ -1724,7 +1729,9 @@ def test_get_default_child_watcher(self): def test_get_child_watcher_after_set(self): policy = self.create_policy() - watcher = asyncio.FastChildWatcher() + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + watcher = asyncio.FastChildWatcher() policy.set_child_watcher(watcher) self.assertIs(policy._watcher, watcher) @@ -1745,7 +1752,9 @@ def f(): policy.get_event_loop().close() policy = self.create_policy() - policy.set_child_watcher(asyncio.SafeChildWatcher()) + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + policy.set_child_watcher(asyncio.SafeChildWatcher()) th = threading.Thread(target=f) th.start() @@ -1757,7 +1766,9 @@ def test_child_watcher_replace_mainloop_existing(self): # Explicitly setup SafeChildWatcher, # default ThreadedChildWatcher has no _loop property - watcher = asyncio.SafeChildWatcher() + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + watcher = asyncio.SafeChildWatcher() policy.set_child_watcher(watcher) watcher.attach_loop(loop) diff --git a/Misc/NEWS.d/next/Library/2022-10-08-06-59-46.gh-issue-94597.TsS0oT.rst b/Misc/NEWS.d/next/Library/2022-10-08-06-59-46.gh-issue-94597.TsS0oT.rst new file mode 100644 index 000000000000..f504ccf39ec9 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-08-06-59-46.gh-issue-94597.TsS0oT.rst @@ -0,0 +1 @@ +The child watcher classes :class:`~asyncio.MultiLoopChildWatcher`, :class:`~asyncio.FastChildWatcher` and :class:`~asyncio.SafeChildWatcher` are deprecated and will be removed in Python 3.14. Patch by Kumar Aditya. From webhook-mailer at python.org Sat Oct 8 18:17:00 2022 From: webhook-mailer at python.org (ezio-melotti) Date: Sat, 08 Oct 2022 22:17:00 -0000 Subject: [Python-checkins] Fix link to Lifecycle of a Pull Request in CONTRIBUTING (#98102) Message-ID: https://github.com/python/cpython/commit/3378ebb933b00e1b95f1112511aa2cfb597a4ebf commit: 3378ebb933b00e1b95f1112511aa2cfb597a4ebf branch: main author: Jacob Walls committer: ezio-melotti date: 2022-10-09T00:16:52+02:00 summary: Fix link to Lifecycle of a Pull Request in CONTRIBUTING (#98102) * Fix link to Lifecycle of a Pull Request in CONTRIBUTING * Remove trailing backslash. Co-authored-by: Ezio Melotti files: M .github/CONTRIBUTING.rst diff --git a/.github/CONTRIBUTING.rst b/.github/CONTRIBUTING.rst index 627f57070d20..f4affee76e1d 100644 --- a/.github/CONTRIBUTING.rst +++ b/.github/CONTRIBUTING.rst @@ -38,7 +38,7 @@ also suggestions on how you can most effectively help the project. Please be aware that our workflow does deviate slightly from the typical GitHub project. Details on how to properly submit a pull request are covered in -`Lifecycle of a Pull Request `_. +`Lifecycle of a Pull Request `_. We utilize various bots and status checks to help with this, so do follow the comments they leave and their "Details" links, respectively. The key points of our workflow that are not covered by a bot or status check are: From webhook-mailer at python.org Sat Oct 8 18:18:51 2022 From: webhook-mailer at python.org (miss-islington) Date: Sat, 08 Oct 2022 22:18:51 -0000 Subject: [Python-checkins] Fix link to Lifecycle of a Pull Request in CONTRIBUTING (GH-98102) Message-ID: https://github.com/python/cpython/commit/c86ee93d752d548550168cea68115398cc80d697 commit: c86ee93d752d548550168cea68115398cc80d697 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-08T15:18:44-07:00 summary: Fix link to Lifecycle of a Pull Request in CONTRIBUTING (GH-98102) * Fix link to Lifecycle of a Pull Request in CONTRIBUTING * Remove trailing backslash. Co-authored-by: Ezio Melotti (cherry picked from commit 3378ebb933b00e1b95f1112511aa2cfb597a4ebf) Co-authored-by: Jacob Walls files: M .github/CONTRIBUTING.rst diff --git a/.github/CONTRIBUTING.rst b/.github/CONTRIBUTING.rst index 31d8e8578ffa..2b0fa72ef3f9 100644 --- a/.github/CONTRIBUTING.rst +++ b/.github/CONTRIBUTING.rst @@ -38,7 +38,7 @@ also suggestions on how you can most effectively help the project. Please be aware that our workflow does deviate slightly from the typical GitHub project. Details on how to properly submit a pull request are covered in -`Lifecycle of a Pull Request `_. +`Lifecycle of a Pull Request `_. We utilize various bots and status checks to help with this, so do follow the comments they leave and their "Details" links, respectively. The key points of our workflow that are not covered by a bot or status check are: From webhook-mailer at python.org Sat Oct 8 18:19:53 2022 From: webhook-mailer at python.org (miss-islington) Date: Sat, 08 Oct 2022 22:19:53 -0000 Subject: [Python-checkins] Fix link to Lifecycle of a Pull Request in CONTRIBUTING (GH-98102) Message-ID: https://github.com/python/cpython/commit/afed44897804019f2601de2cf63d79be5d071d0e commit: afed44897804019f2601de2cf63d79be5d071d0e branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-08T15:19:48-07:00 summary: Fix link to Lifecycle of a Pull Request in CONTRIBUTING (GH-98102) * Fix link to Lifecycle of a Pull Request in CONTRIBUTING * Remove trailing backslash. Co-authored-by: Ezio Melotti (cherry picked from commit 3378ebb933b00e1b95f1112511aa2cfb597a4ebf) Co-authored-by: Jacob Walls files: M .github/CONTRIBUTING.rst diff --git a/.github/CONTRIBUTING.rst b/.github/CONTRIBUTING.rst index 627f57070d20..f4affee76e1d 100644 --- a/.github/CONTRIBUTING.rst +++ b/.github/CONTRIBUTING.rst @@ -38,7 +38,7 @@ also suggestions on how you can most effectively help the project. Please be aware that our workflow does deviate slightly from the typical GitHub project. Details on how to properly submit a pull request are covered in -`Lifecycle of a Pull Request `_. +`Lifecycle of a Pull Request `_. We utilize various bots and status checks to help with this, so do follow the comments they leave and their "Details" links, respectively. The key points of our workflow that are not covered by a bot or status check are: From webhook-mailer at python.org Sat Oct 8 21:54:29 2022 From: webhook-mailer at python.org (rhettinger) Date: Sun, 09 Oct 2022 01:54:29 -0000 Subject: [Python-checkins] Minor edits to the Descriptor HowTo Guide (GH-24901) Message-ID: https://github.com/python/cpython/commit/2d2e01aa4cb72db8dabcd04e87f1e60b3597267e commit: 2d2e01aa4cb72db8dabcd04e87f1e60b3597267e branch: main author: G?ry Ogam committer: rhettinger date: 2022-10-08T20:54:21-05:00 summary: Minor edits to the Descriptor HowTo Guide (GH-24901) Co-authored-by: Raymond Hettinger files: M Doc/howto/descriptor.rst diff --git a/Doc/howto/descriptor.rst b/Doc/howto/descriptor.rst index 91a6c31c33b8..74710d9b3fc2 100644 --- a/Doc/howto/descriptor.rst +++ b/Doc/howto/descriptor.rst @@ -847,7 +847,7 @@ afterwards, :meth:`__set_name__` will need to be called manually. ORM example ----------- -The following code is simplified skeleton showing how data descriptors could +The following code is a simplified skeleton showing how data descriptors could be used to implement an `object relational mapping `_. @@ -1535,6 +1535,8 @@ by member descriptors: def __get__(self, obj, objtype=None): 'Emulate member_get() in Objects/descrobject.c' # Also see PyMember_GetOne() in Python/structmember.c + if obj is None: + return self value = obj._slotvalues[self.offset] if value is null: raise AttributeError(self.name) @@ -1563,13 +1565,13 @@ variables: class Type(type): 'Simulate how the type metaclass adds member objects for slots' - def __new__(mcls, clsname, bases, mapping): + def __new__(mcls, clsname, bases, mapping, **kwargs): 'Emulate type_new() in Objects/typeobject.c' # type_new() calls PyTypeReady() which calls add_methods() slot_names = mapping.get('slot_names', []) for offset, name in enumerate(slot_names): mapping[name] = Member(name, clsname, offset) - return type.__new__(mcls, clsname, bases, mapping) + return type.__new__(mcls, clsname, bases, mapping, **kwargs) The :meth:`object.__new__` method takes care of creating instances that have slots instead of an instance dictionary. Here is a rough simulation in pure @@ -1580,7 +1582,7 @@ Python: class Object: 'Simulate how object.__new__() allocates memory for __slots__' - def __new__(cls, *args): + def __new__(cls, *args, **kwargs): 'Emulate object_new() in Objects/typeobject.c' inst = super().__new__(cls) if hasattr(cls, 'slot_names'): @@ -1593,7 +1595,7 @@ Python: cls = type(self) if hasattr(cls, 'slot_names') and name not in cls.slot_names: raise AttributeError( - f'{type(self).__name__!r} object has no attribute {name!r}' + f'{cls.__name__!r} object has no attribute {name!r}' ) super().__setattr__(name, value) @@ -1602,7 +1604,7 @@ Python: cls = type(self) if hasattr(cls, 'slot_names') and name not in cls.slot_names: raise AttributeError( - f'{type(self).__name__!r} object has no attribute {name!r}' + f'{cls.__name__!r} object has no attribute {name!r}' ) super().__delattr__(name) From webhook-mailer at python.org Sat Oct 8 22:03:31 2022 From: webhook-mailer at python.org (miss-islington) Date: Sun, 09 Oct 2022 02:03:31 -0000 Subject: [Python-checkins] Minor edits to the Descriptor HowTo Guide (GH-24901) Message-ID: https://github.com/python/cpython/commit/6554598236a8267c9ab9cb6802a9e99e68f3c750 commit: 6554598236a8267c9ab9cb6802a9e99e68f3c750 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-08T19:03:25-07:00 summary: Minor edits to the Descriptor HowTo Guide (GH-24901) Co-authored-by: Raymond Hettinger (cherry picked from commit 2d2e01aa4cb72db8dabcd04e87f1e60b3597267e) Co-authored-by: G?ry Ogam files: M Doc/howto/descriptor.rst diff --git a/Doc/howto/descriptor.rst b/Doc/howto/descriptor.rst index 91a6c31c33b8..74710d9b3fc2 100644 --- a/Doc/howto/descriptor.rst +++ b/Doc/howto/descriptor.rst @@ -847,7 +847,7 @@ afterwards, :meth:`__set_name__` will need to be called manually. ORM example ----------- -The following code is simplified skeleton showing how data descriptors could +The following code is a simplified skeleton showing how data descriptors could be used to implement an `object relational mapping `_. @@ -1535,6 +1535,8 @@ by member descriptors: def __get__(self, obj, objtype=None): 'Emulate member_get() in Objects/descrobject.c' # Also see PyMember_GetOne() in Python/structmember.c + if obj is None: + return self value = obj._slotvalues[self.offset] if value is null: raise AttributeError(self.name) @@ -1563,13 +1565,13 @@ variables: class Type(type): 'Simulate how the type metaclass adds member objects for slots' - def __new__(mcls, clsname, bases, mapping): + def __new__(mcls, clsname, bases, mapping, **kwargs): 'Emulate type_new() in Objects/typeobject.c' # type_new() calls PyTypeReady() which calls add_methods() slot_names = mapping.get('slot_names', []) for offset, name in enumerate(slot_names): mapping[name] = Member(name, clsname, offset) - return type.__new__(mcls, clsname, bases, mapping) + return type.__new__(mcls, clsname, bases, mapping, **kwargs) The :meth:`object.__new__` method takes care of creating instances that have slots instead of an instance dictionary. Here is a rough simulation in pure @@ -1580,7 +1582,7 @@ Python: class Object: 'Simulate how object.__new__() allocates memory for __slots__' - def __new__(cls, *args): + def __new__(cls, *args, **kwargs): 'Emulate object_new() in Objects/typeobject.c' inst = super().__new__(cls) if hasattr(cls, 'slot_names'): @@ -1593,7 +1595,7 @@ Python: cls = type(self) if hasattr(cls, 'slot_names') and name not in cls.slot_names: raise AttributeError( - f'{type(self).__name__!r} object has no attribute {name!r}' + f'{cls.__name__!r} object has no attribute {name!r}' ) super().__setattr__(name, value) @@ -1602,7 +1604,7 @@ Python: cls = type(self) if hasattr(cls, 'slot_names') and name not in cls.slot_names: raise AttributeError( - f'{type(self).__name__!r} object has no attribute {name!r}' + f'{cls.__name__!r} object has no attribute {name!r}' ) super().__delattr__(name) From webhook-mailer at python.org Sat Oct 8 22:16:15 2022 From: webhook-mailer at python.org (rhettinger) Date: Sun, 09 Oct 2022 02:16:15 -0000 Subject: [Python-checkins] [3.10] Minor edits to the Descriptor HowTo Guide (GH-24901) (GH-98114) Message-ID: https://github.com/python/cpython/commit/820ef62833bd2d84a141adedd9a05998595d6b6d commit: 820ef62833bd2d84a141adedd9a05998595d6b6d branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: rhettinger date: 2022-10-08T21:16:10-05:00 summary: [3.10] Minor edits to the Descriptor HowTo Guide (GH-24901) (GH-98114) files: M Doc/howto/descriptor.rst diff --git a/Doc/howto/descriptor.rst b/Doc/howto/descriptor.rst index 6e7719e03f07..0c6f4888a2db 100644 --- a/Doc/howto/descriptor.rst +++ b/Doc/howto/descriptor.rst @@ -847,7 +847,7 @@ afterwards, :meth:`__set_name__` will need to be called manually. ORM example ----------- -The following code is simplified skeleton showing how data descriptors could +The following code is a simplified skeleton showing how data descriptors could be used to implement an `object relational mapping `_. @@ -1533,6 +1533,8 @@ by member descriptors: def __get__(self, obj, objtype=None): 'Emulate member_get() in Objects/descrobject.c' # Also see PyMember_GetOne() in Python/structmember.c + if obj is None: + return self value = obj._slotvalues[self.offset] if value is null: raise AttributeError(self.name) @@ -1561,13 +1563,13 @@ variables: class Type(type): 'Simulate how the type metaclass adds member objects for slots' - def __new__(mcls, clsname, bases, mapping): + def __new__(mcls, clsname, bases, mapping, **kwargs): 'Emulate type_new() in Objects/typeobject.c' # type_new() calls PyTypeReady() which calls add_methods() slot_names = mapping.get('slot_names', []) for offset, name in enumerate(slot_names): mapping[name] = Member(name, clsname, offset) - return type.__new__(mcls, clsname, bases, mapping) + return type.__new__(mcls, clsname, bases, mapping, **kwargs) The :meth:`object.__new__` method takes care of creating instances that have slots instead of an instance dictionary. Here is a rough simulation in pure @@ -1578,7 +1580,7 @@ Python: class Object: 'Simulate how object.__new__() allocates memory for __slots__' - def __new__(cls, *args): + def __new__(cls, *args, **kwargs): 'Emulate object_new() in Objects/typeobject.c' inst = super().__new__(cls) if hasattr(cls, 'slot_names'): @@ -1591,7 +1593,7 @@ Python: cls = type(self) if hasattr(cls, 'slot_names') and name not in cls.slot_names: raise AttributeError( - f'{type(self).__name__!r} object has no attribute {name!r}' + f'{cls.__name__!r} object has no attribute {name!r}' ) super().__setattr__(name, value) @@ -1600,7 +1602,7 @@ Python: cls = type(self) if hasattr(cls, 'slot_names') and name not in cls.slot_names: raise AttributeError( - f'{type(self).__name__!r} object has no attribute {name!r}' + f'{cls.__name__!r} object has no attribute {name!r}' ) super().__delattr__(name) From webhook-mailer at python.org Sun Oct 9 07:16:44 2022 From: webhook-mailer at python.org (corona10) Date: Sun, 09 Oct 2022 11:16:44 -0000 Subject: [Python-checkins] gh-97841: Add methoddef for _filters_mutated (gh-98115) Message-ID: https://github.com/python/cpython/commit/a04656ec32bd5f3684ea18b195f76000df4962eb commit: a04656ec32bd5f3684ea18b195f76000df4962eb branch: main author: Dong-hee Na committer: corona10 date: 2022-10-09T20:16:33+09:00 summary: gh-97841: Add methoddef for _filters_mutated (gh-98115) files: M Python/_warnings.c M Python/clinic/_warnings.c.h diff --git a/Python/_warnings.c b/Python/_warnings.c index 0d4c50f769b0..b46fbdca9db3 100644 --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -1086,8 +1086,14 @@ warnings_warn_explicit_impl(PyObject *module, PyObject *message, return returned; } +/*[clinic input] +_filters_mutated as warnings_filters_mutated + +[clinic start generated code]*/ + static PyObject * -warnings_filters_mutated(PyObject *self, PyObject *Py_UNUSED(args)) +warnings_filters_mutated_impl(PyObject *module) +/*[clinic end generated code: output=8ce517abd12b88f4 input=35ecbf08ee2491b2]*/ { PyInterpreterState *interp = get_current_interp(); if (interp == NULL) { @@ -1344,8 +1350,7 @@ _PyErr_WarnUnawaitedCoroutine(PyObject *coro) static PyMethodDef warnings_functions[] = { WARNINGS_WARN_METHODDEF WARNINGS_WARN_EXPLICIT_METHODDEF - {"_filters_mutated", _PyCFunction_CAST(warnings_filters_mutated), METH_NOARGS, - NULL}, + WARNINGS_FILTERS_MUTATED_METHODDEF /* XXX(brett.cannon): add showwarning? */ /* XXX(brett.cannon): Reasonable to add formatwarning? */ {NULL, NULL} /* sentinel */ diff --git a/Python/clinic/_warnings.c.h b/Python/clinic/_warnings.c.h index 13ebbf45b8e1..8838a42afc1c 100644 --- a/Python/clinic/_warnings.c.h +++ b/Python/clinic/_warnings.c.h @@ -199,4 +199,21 @@ warnings_warn_explicit(PyObject *module, PyObject *const *args, Py_ssize_t nargs exit: return return_value; } -/*[clinic end generated code: output=2eac4fabc87a4d56 input=a9049054013a1b77]*/ + +PyDoc_STRVAR(warnings_filters_mutated__doc__, +"_filters_mutated($module, /)\n" +"--\n" +"\n"); + +#define WARNINGS_FILTERS_MUTATED_METHODDEF \ + {"_filters_mutated", (PyCFunction)warnings_filters_mutated, METH_NOARGS, warnings_filters_mutated__doc__}, + +static PyObject * +warnings_filters_mutated_impl(PyObject *module); + +static PyObject * +warnings_filters_mutated(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return warnings_filters_mutated_impl(module); +} +/*[clinic end generated code: output=0d264d1ddfc37100 input=a9049054013a1b77]*/ From webhook-mailer at python.org Sun Oct 9 07:21:16 2022 From: webhook-mailer at python.org (serhiy-storchaka) Date: Sun, 09 Oct 2022 11:21:16 -0000 Subject: [Python-checkins] [3.10] Add more syslog tests (GH-97953). (GH-98101) Message-ID: https://github.com/python/cpython/commit/4d7d91f941f32b167ac2eab3d393be646d4ed706 commit: 4d7d91f941f32b167ac2eab3d393be646d4ed706 branch: 3.10 author: Serhiy Storchaka committer: serhiy-storchaka date: 2022-10-09T14:21:10+03:00 summary: [3.10] Add more syslog tests (GH-97953). (GH-98101) (cherry picked from commit cae7d1d7a713f8267daf5e4f2fff5cb1dad02c7c) files: M Lib/test/audit-tests.py M Lib/test/test_audit.py M Lib/test/test_syslog.py M Modules/syslogmodule.c diff --git a/Lib/test/audit-tests.py b/Lib/test/audit-tests.py index ccec9fedc446..b781b9940465 100644 --- a/Lib/test/audit-tests.py +++ b/Lib/test/audit-tests.py @@ -408,6 +408,27 @@ def hook(event, *args): raise RuntimeError("Expected sqlite3.load_extension to fail") +def test_syslog(): + import syslog + + def hook(event, args): + if event.startswith("syslog."): + print(event, *args) + + sys.addaudithook(hook) + syslog.openlog('python') + syslog.syslog('test') + syslog.setlogmask(syslog.LOG_DEBUG) + syslog.closelog() + # implicit open + syslog.syslog('test2') + # open with default ident + syslog.openlog(logoption=syslog.LOG_NDELAY, facility=syslog.LOG_LOCAL0) + sys.argv = None + syslog.openlog() + syslog.closelog() + + if __name__ == "__main__": from test.support import suppress_msvcrt_asserts diff --git a/Lib/test/test_audit.py b/Lib/test/test_audit.py index 04c9d6b85539..cea452ddce51 100644 --- a/Lib/test/test_audit.py +++ b/Lib/test/test_audit.py @@ -16,6 +16,8 @@ class AuditTest(unittest.TestCase): + maxDiff = None + def do_test(self, *args): with subprocess.Popen( [sys.executable, "-X utf8", AUDIT_TESTS_PY, *args], @@ -170,5 +172,29 @@ def test_sqlite3(self): self.assertEqual(actual, expected) + def test_syslog(self): + syslog = import_helper.import_module("syslog") + + returncode, events, stderr = self.run_python("test_syslog") + if returncode: + self.fail(stderr) + + if support.verbose: + print('Events:', *events, sep='\n ') + + self.assertSequenceEqual( + events, + [('syslog.openlog', ' ', f'python 0 {syslog.LOG_USER}'), + ('syslog.syslog', ' ', f'{syslog.LOG_INFO} test'), + ('syslog.setlogmask', ' ', f'{syslog.LOG_DEBUG}'), + ('syslog.closelog', '', ''), + ('syslog.syslog', ' ', f'{syslog.LOG_INFO} test2'), + ('syslog.openlog', ' ', f'audit-tests.py 0 {syslog.LOG_USER}'), + ('syslog.openlog', ' ', f'audit-tests.py {syslog.LOG_NDELAY} {syslog.LOG_LOCAL0}'), + ('syslog.openlog', ' ', f'None 0 {syslog.LOG_USER}'), + ('syslog.closelog', '', '')] + ) + + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_syslog.py b/Lib/test/test_syslog.py index fe09bd39f8b7..b3ba2aba1da3 100644 --- a/Lib/test/test_syslog.py +++ b/Lib/test/test_syslog.py @@ -1,5 +1,9 @@ -from test.support import import_helper +from test.support import import_helper, threading_helper syslog = import_helper.import_module("syslog") #skip if not supported +from test import support +import sys +import threading +import time import unittest # XXX(nnorwitz): This test sucks. I don't know of a platform independent way @@ -8,6 +12,9 @@ class Test(unittest.TestCase): + def tearDown(self): + syslog.closelog() + def test_openlog(self): syslog.openlog('python') # Issue #6697. @@ -18,22 +25,58 @@ def test_syslog(self): syslog.syslog('test message from python test_syslog') syslog.syslog(syslog.LOG_ERR, 'test error from python test_syslog') + def test_syslog_implicit_open(self): + syslog.closelog() # Make sure log is closed + syslog.syslog('test message from python test_syslog') + syslog.syslog(syslog.LOG_ERR, 'test error from python test_syslog') + def test_closelog(self): syslog.openlog('python') syslog.closelog() + syslog.closelog() # idempotent operation def test_setlogmask(self): - syslog.setlogmask(syslog.LOG_DEBUG) + mask = syslog.LOG_UPTO(syslog.LOG_WARNING) + oldmask = syslog.setlogmask(mask) + self.assertEqual(syslog.setlogmask(0), mask) + self.assertEqual(syslog.setlogmask(oldmask), mask) def test_log_mask(self): - syslog.LOG_MASK(syslog.LOG_INFO) - - def test_log_upto(self): - syslog.LOG_UPTO(syslog.LOG_INFO) + mask = syslog.LOG_UPTO(syslog.LOG_WARNING) + self.assertTrue(mask & syslog.LOG_MASK(syslog.LOG_WARNING)) + self.assertTrue(mask & syslog.LOG_MASK(syslog.LOG_ERR)) + self.assertFalse(mask & syslog.LOG_MASK(syslog.LOG_INFO)) def test_openlog_noargs(self): syslog.openlog() syslog.syslog('test message from python test_syslog') + def test_syslog_threaded(self): + start = threading.Event() + stop = False + def opener(): + start.wait(10) + i = 1 + while not stop: + syslog.openlog(f'python-test-{i}') # new string object + i += 1 + def logger(): + start.wait(10) + while not stop: + syslog.syslog('test message from python test_syslog') + + orig_si = sys.getswitchinterval() + support.setswitchinterval(1e-9) + try: + threads = [threading.Thread(target=opener)] + threads += [threading.Thread(target=logger) for k in range(10)] + with threading_helper.start_threads(threads): + start.set() + time.sleep(0.1) + stop = True + finally: + sys.setswitchinterval(orig_si) + + if __name__ == "__main__": unittest.main() diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index 729986a5549e..bfa2ca2b653b 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -235,7 +235,7 @@ syslog_setlogmask(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "l;mask for priority", &maskpri)) return NULL; - if (PySys_Audit("syslog.setlogmask", "(O)", args ? args : Py_None) < 0) { + if (PySys_Audit("syslog.setlogmask", "l", maskpri) < 0) { return NULL; } omaskpri = setlogmask(maskpri); From webhook-mailer at python.org Sun Oct 9 10:02:45 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Sun, 09 Oct 2022 14:02:45 -0000 Subject: [Python-checkins] [3.10] gh-94808: Cover `PyObject_PyBytes` case with custom `__bytes__` method (GH-96610) (#98121) Message-ID: https://github.com/python/cpython/commit/ccb56804fd4a0b6d6d21325c2dd11ef16077eca6 commit: ccb56804fd4a0b6d6d21325c2dd11ef16077eca6 branch: 3.10 author: Nikita Sobolev committer: JelleZijlstra date: 2022-10-09T07:02:39-07:00 summary: [3.10] gh-94808: Cover `PyObject_PyBytes` case with custom `__bytes__` method (GH-96610) (#98121) Co-authored-by: Jelle Zijlstra . Co-authored-by: Nikita Sobolev (cherry picked from commit e39ae6bef2c357a88e232dcab2e4b4c0f367544b) files: M Lib/test/test_long.py diff --git a/Lib/test/test_long.py b/Lib/test/test_long.py index c97842b5bfd2..f8a62077a4fb 100644 --- a/Lib/test/test_long.py +++ b/Lib/test/test_long.py @@ -1350,6 +1350,26 @@ def __init__(self, value): self.assertEqual(i, 1) self.assertEqual(getattr(i, 'foo', 'none'), 'bar') + class ValidBytes: + def __bytes__(self): + return b'\x01' + class InvalidBytes: + def __bytes__(self): + return 'abc' + class MissingBytes: ... + class RaisingBytes: + def __bytes__(self): + 1 / 0 + + for byte_order in ('big', 'little'): + self.assertEqual(int.from_bytes(ValidBytes(), byte_order), 1) + self.assertRaises( + TypeError, int.from_bytes, InvalidBytes(), byte_order) + self.assertRaises( + TypeError, int.from_bytes, MissingBytes(), byte_order) + self.assertRaises( + ZeroDivisionError, int.from_bytes, RaisingBytes(), byte_order) + def test_access_to_nonexistent_digit_0(self): # http://bugs.python.org/issue14630: A bug in _PyLong_Copy meant that # ob_digit[0] was being incorrectly accessed for instances of a From webhook-mailer at python.org Sun Oct 9 18:29:41 2022 From: webhook-mailer at python.org (ezio-melotti) Date: Sun, 09 Oct 2022 22:29:41 -0000 Subject: [Python-checkins] Update whatsnew instructions for GitHub (#98124) Message-ID: https://github.com/python/cpython/commit/f1879690aa0498ffc4427c95aed94e1ca629e072 commit: f1879690aa0498ffc4427c95aed94e1ca629e072 branch: main author: Carl Meyer committer: ezio-melotti date: 2022-10-10T00:29:25+02:00 summary: Update whatsnew instructions for GitHub (#98124) files: M Doc/whatsnew/3.12.rst diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 903533261006..f8122ed1dc44 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -37,11 +37,11 @@ * Credit the author of a patch or bugfix. Just the name is sufficient; the e-mail address isn't necessary. - * It's helpful to add the bug/patch number as a comment: + * It's helpful to add the issue number as a comment: XXX Describe the transmogrify() function added to the socket module. - (Contributed by P.Y. Developer in :issue:`12345`.) + (Contributed by P.Y. Developer in :gh:`12345`.) This saves the maintainer the effort of going through the VCS log when researching a change. From webhook-mailer at python.org Sun Oct 9 20:51:12 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Mon, 10 Oct 2022 00:51:12 -0000 Subject: [Python-checkins] gh-56133: copyreg docs: Clarify function/constructor parameter (#95497) Message-ID: https://github.com/python/cpython/commit/281a3f18cc2afac0fa92c75e807775971e531711 commit: 281a3f18cc2afac0fa92c75e807775971e531711 branch: main author: Stanley <46876382+slateny at users.noreply.github.com> committer: JelleZijlstra date: 2022-10-09T17:51:02-07:00 summary: gh-56133: copyreg docs: Clarify function/constructor parameter (#95497) files: M Doc/library/copyreg.rst diff --git a/Doc/library/copyreg.rst b/Doc/library/copyreg.rst index dc35965be3e4..866b180f4bc3 100644 --- a/Doc/library/copyreg.rst +++ b/Doc/library/copyreg.rst @@ -25,20 +25,17 @@ Such constructors may be factory functions or class instances. hence not valid as a constructor), raises :exc:`TypeError`. -.. function:: pickle(type, function, constructor=None) +.. function:: pickle(type, function, constructor_ob=None) Declares that *function* should be used as a "reduction" function for objects of type *type*. *function* should return either a string or a tuple - containing two or three elements. + containing two or three elements. See the :attr:`~pickle.Pickler.dispatch_table` + for more details on the interface of *function*. - The optional *constructor* parameter, if provided, is a callable object which - can be used to reconstruct the object when called with the tuple of arguments - returned by *function* at pickling time. A :exc:`TypeError` is raised if the - *constructor* is not callable. + The *constructor_ob* parameter is a legacy feature and is now ignored, but if + passed it must be a callable. - See the :mod:`pickle` module for more details on the interface - expected of *function* and *constructor*. Note that the - :attr:`~pickle.Pickler.dispatch_table` attribute of a pickler + Note that the :attr:`~pickle.Pickler.dispatch_table` attribute of a pickler object or subclass of :class:`pickle.Pickler` can also be used for declaring reduction functions. From webhook-mailer at python.org Sun Oct 9 20:56:03 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Mon, 10 Oct 2022 00:56:03 -0000 Subject: [Python-checkins] Fix types in buffer/memoryview docs (#98118) Message-ID: https://github.com/python/cpython/commit/c459fedf7cfd5dadf72e088d789c7375b3a6e093 commit: c459fedf7cfd5dadf72e088d789c7375b3a6e093 branch: main author: da-woods committer: JelleZijlstra date: 2022-10-09T17:55:53-07:00 summary: Fix types in buffer/memoryview docs (#98118) The definition of obj in the `Py_buffer` struct is as a PyObject* https://github.com/python/cpython/blob/ec091bd47e2f968b0d1631b9a8104283a7beeb1b/Include/pybuffer.h#L22 PyMemoryView_GET_BASE returns `.obj` - thus its return type should be a PyObject* (or at least a void*). It definitely doesn't return `Py_buffer` files: M Doc/c-api/buffer.rst M Doc/c-api/memoryview.rst diff --git a/Doc/c-api/buffer.rst b/Doc/c-api/buffer.rst index 05e131d06b90..a04062fb2a68 100644 --- a/Doc/c-api/buffer.rst +++ b/Doc/c-api/buffer.rst @@ -99,7 +99,7 @@ a buffer, see :c:func:`PyObject_GetBuffer`. For :term:`contiguous` arrays, the value points to the beginning of the memory block. - .. c:member:: void *obj + .. c:member:: PyObject *obj A new reference to the exporting object. The reference is owned by the consumer and automatically decremented and set to ``NULL`` by diff --git a/Doc/c-api/memoryview.rst b/Doc/c-api/memoryview.rst index 4d94b3f545f3..ebd5c7760437 100644 --- a/Doc/c-api/memoryview.rst +++ b/Doc/c-api/memoryview.rst @@ -55,7 +55,7 @@ any other object. *mview* **must** be a memoryview instance; this macro doesn't check its type, you must do it yourself or you will risk crashes. -.. c:function:: Py_buffer *PyMemoryView_GET_BASE(PyObject *mview) +.. c:function:: PyObject *PyMemoryView_GET_BASE(PyObject *mview) Return either a pointer to the exporting object that the memoryview is based on or ``NULL`` if the memoryview has been created by one of the functions From webhook-mailer at python.org Sun Oct 9 21:02:05 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 10 Oct 2022 01:02:05 -0000 Subject: [Python-checkins] gh-56133: copyreg docs: Clarify function/constructor parameter (GH-95497) Message-ID: https://github.com/python/cpython/commit/6211bb2cf876a05c7b77239d4af39039b0459b8e commit: 6211bb2cf876a05c7b77239d4af39039b0459b8e branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-09T18:02:00-07:00 summary: gh-56133: copyreg docs: Clarify function/constructor parameter (GH-95497) (cherry picked from commit 281a3f18cc2afac0fa92c75e807775971e531711) Co-authored-by: Stanley <46876382+slateny at users.noreply.github.com> files: M Doc/library/copyreg.rst diff --git a/Doc/library/copyreg.rst b/Doc/library/copyreg.rst index dc35965be3e4..866b180f4bc3 100644 --- a/Doc/library/copyreg.rst +++ b/Doc/library/copyreg.rst @@ -25,20 +25,17 @@ Such constructors may be factory functions or class instances. hence not valid as a constructor), raises :exc:`TypeError`. -.. function:: pickle(type, function, constructor=None) +.. function:: pickle(type, function, constructor_ob=None) Declares that *function* should be used as a "reduction" function for objects of type *type*. *function* should return either a string or a tuple - containing two or three elements. + containing two or three elements. See the :attr:`~pickle.Pickler.dispatch_table` + for more details on the interface of *function*. - The optional *constructor* parameter, if provided, is a callable object which - can be used to reconstruct the object when called with the tuple of arguments - returned by *function* at pickling time. A :exc:`TypeError` is raised if the - *constructor* is not callable. + The *constructor_ob* parameter is a legacy feature and is now ignored, but if + passed it must be a callable. - See the :mod:`pickle` module for more details on the interface - expected of *function* and *constructor*. Note that the - :attr:`~pickle.Pickler.dispatch_table` attribute of a pickler + Note that the :attr:`~pickle.Pickler.dispatch_table` attribute of a pickler object or subclass of :class:`pickle.Pickler` can also be used for declaring reduction functions. From webhook-mailer at python.org Sun Oct 9 21:02:54 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 10 Oct 2022 01:02:54 -0000 Subject: [Python-checkins] Fix types in buffer/memoryview docs (GH-98118) Message-ID: https://github.com/python/cpython/commit/03ea515f33b3073d2c680b5a7786ea603076eb6d commit: 03ea515f33b3073d2c680b5a7786ea603076eb6d branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-09T18:02:49-07:00 summary: Fix types in buffer/memoryview docs (GH-98118) The definition of obj in the `Py_buffer` struct is as a PyObject* https://github.com/python/cpython/blob/ec091bd47e2f968b0d1631b9a8104283a7beeb1b/Include/pybuffer.hGH-L22 PyMemoryView_GET_BASE returns `.obj` - thus its return type should be a PyObject* (or at least a void*). It definitely doesn't return `Py_buffer` (cherry picked from commit c459fedf7cfd5dadf72e088d789c7375b3a6e093) Co-authored-by: da-woods files: M Doc/c-api/buffer.rst M Doc/c-api/memoryview.rst diff --git a/Doc/c-api/buffer.rst b/Doc/c-api/buffer.rst index e32719373cc7..e3b49472991a 100644 --- a/Doc/c-api/buffer.rst +++ b/Doc/c-api/buffer.rst @@ -99,7 +99,7 @@ a buffer, see :c:func:`PyObject_GetBuffer`. For :term:`contiguous` arrays, the value points to the beginning of the memory block. - .. c:member:: void *obj + .. c:member:: PyObject *obj A new reference to the exporting object. The reference is owned by the consumer and automatically decremented and set to ``NULL`` by diff --git a/Doc/c-api/memoryview.rst b/Doc/c-api/memoryview.rst index 24f8c935302e..94ee8123e575 100644 --- a/Doc/c-api/memoryview.rst +++ b/Doc/c-api/memoryview.rst @@ -55,7 +55,7 @@ any other object. *mview* **must** be a memoryview instance; this macro doesn't check its type, you must do it yourself or you will risk crashes. -.. c:function:: Py_buffer *PyMemoryView_GET_BASE(PyObject *mview) +.. c:function:: PyObject *PyMemoryView_GET_BASE(PyObject *mview) Return either a pointer to the exporting object that the memoryview is based on or ``NULL`` if the memoryview has been created by one of the functions From webhook-mailer at python.org Sun Oct 9 21:03:59 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 10 Oct 2022 01:03:59 -0000 Subject: [Python-checkins] Fix types in buffer/memoryview docs (GH-98118) Message-ID: https://github.com/python/cpython/commit/4172e09c3a93f95874cccd3d008e9d036472d859 commit: 4172e09c3a93f95874cccd3d008e9d036472d859 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-09T18:03:53-07:00 summary: Fix types in buffer/memoryview docs (GH-98118) The definition of obj in the `Py_buffer` struct is as a PyObject* https://github.com/python/cpython/blob/ec091bd47e2f968b0d1631b9a8104283a7beeb1b/Include/pybuffer.hGH-L22 PyMemoryView_GET_BASE returns `.obj` - thus its return type should be a PyObject* (or at least a void*). It definitely doesn't return `Py_buffer` (cherry picked from commit c459fedf7cfd5dadf72e088d789c7375b3a6e093) Co-authored-by: da-woods files: M Doc/c-api/buffer.rst M Doc/c-api/memoryview.rst diff --git a/Doc/c-api/buffer.rst b/Doc/c-api/buffer.rst index 05e131d06b90..a04062fb2a68 100644 --- a/Doc/c-api/buffer.rst +++ b/Doc/c-api/buffer.rst @@ -99,7 +99,7 @@ a buffer, see :c:func:`PyObject_GetBuffer`. For :term:`contiguous` arrays, the value points to the beginning of the memory block. - .. c:member:: void *obj + .. c:member:: PyObject *obj A new reference to the exporting object. The reference is owned by the consumer and automatically decremented and set to ``NULL`` by diff --git a/Doc/c-api/memoryview.rst b/Doc/c-api/memoryview.rst index 4d94b3f545f3..ebd5c7760437 100644 --- a/Doc/c-api/memoryview.rst +++ b/Doc/c-api/memoryview.rst @@ -55,7 +55,7 @@ any other object. *mview* **must** be a memoryview instance; this macro doesn't check its type, you must do it yourself or you will risk crashes. -.. c:function:: Py_buffer *PyMemoryView_GET_BASE(PyObject *mview) +.. c:function:: PyObject *PyMemoryView_GET_BASE(PyObject *mview) Return either a pointer to the exporting object that the memoryview is based on or ``NULL`` if the memoryview has been created by one of the functions From webhook-mailer at python.org Sun Oct 9 21:32:02 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Mon, 10 Oct 2022 01:32:02 -0000 Subject: [Python-checkins] gh-98083: Fix URLs in `README.rst` (#98082) Message-ID: https://github.com/python/cpython/commit/fc342c62e0debb194d60e79b37e346bf8d940d7a commit: fc342c62e0debb194d60e79b37e346bf8d940d7a branch: main author: Tiger committer: JelleZijlstra date: 2022-10-09T18:31:53-07:00 summary: gh-98083: Fix URLs in `README.rst` (#98082) files: M README.rst diff --git a/README.rst b/README.rst index 4ae5dfd1bb25..8227ae748d39 100644 --- a/README.rst +++ b/README.rst @@ -65,7 +65,7 @@ Building a complete Python installation requires the use of various additional third-party libraries, depending on your build platform and configure options. Not all standard library modules are buildable or useable on all platforms. Refer to the -`Install dependencies `_ +`Install dependencies `_ section of the `Developer Guide`_ for current detailed information on dependencies for various Linux distributions and macOS. @@ -135,7 +135,7 @@ What's New We have a comprehensive overview of the changes in the `What's New in Python 3.12 `_ document. For a more detailed change log, read `Misc/NEWS -`_, but a full +`_, but a full accounting of changes can only be gleaned from the `commit history `_. @@ -189,7 +189,7 @@ your environment, you can `file a bug report `_ and include relevant output from that command to show the issue. -See `Running & Writing Tests `_ +See `Running & Writing Tests `_ for more on running tests. Installing multiple versions From webhook-mailer at python.org Sun Oct 9 21:34:04 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 10 Oct 2022 01:34:04 -0000 Subject: [Python-checkins] gh-98083: Fix URLs in `README.rst` (GH-98082) Message-ID: https://github.com/python/cpython/commit/21b13c24ba4cf4aa990b1b5404992b179976a506 commit: 21b13c24ba4cf4aa990b1b5404992b179976a506 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-09T18:33:59-07:00 summary: gh-98083: Fix URLs in `README.rst` (GH-98082) (cherry picked from commit fc342c62e0debb194d60e79b37e346bf8d940d7a) Co-authored-by: Tiger files: M README.rst diff --git a/README.rst b/README.rst index 2e7eb04000d7..26239787b836 100644 --- a/README.rst +++ b/README.rst @@ -65,7 +65,7 @@ Building a complete Python installation requires the use of various additional third-party libraries, depending on your build platform and configure options. Not all standard library modules are buildable or useable on all platforms. Refer to the -`Install dependencies `_ +`Install dependencies `_ section of the `Developer Guide`_ for current detailed information on dependencies for various Linux distributions and macOS. @@ -135,7 +135,7 @@ What's New We have a comprehensive overview of the changes in the `What's New in Python 3.11 `_ document. For a more detailed change log, read `Misc/NEWS -`_, but a full +`_, but a full accounting of changes can only be gleaned from the `commit history `_. @@ -189,7 +189,7 @@ your environment, you can `file a bug report `_ and include relevant output from that command to show the issue. -See `Running & Writing Tests `_ +See `Running & Writing Tests `_ for more on running tests. Installing multiple versions From webhook-mailer at python.org Sun Oct 9 21:34:58 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 10 Oct 2022 01:34:58 -0000 Subject: [Python-checkins] gh-56133: copyreg docs: Clarify function/constructor parameter (GH-95497) Message-ID: https://github.com/python/cpython/commit/ac0a19b62ae137c2c9f53fbba8ba3f769acf34dc commit: ac0a19b62ae137c2c9f53fbba8ba3f769acf34dc branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-09T18:34:53-07:00 summary: gh-56133: copyreg docs: Clarify function/constructor parameter (GH-95497) (cherry picked from commit 281a3f18cc2afac0fa92c75e807775971e531711) Co-authored-by: Stanley <46876382+slateny at users.noreply.github.com> files: M Doc/library/copyreg.rst diff --git a/Doc/library/copyreg.rst b/Doc/library/copyreg.rst index dc35965be3e4..866b180f4bc3 100644 --- a/Doc/library/copyreg.rst +++ b/Doc/library/copyreg.rst @@ -25,20 +25,17 @@ Such constructors may be factory functions or class instances. hence not valid as a constructor), raises :exc:`TypeError`. -.. function:: pickle(type, function, constructor=None) +.. function:: pickle(type, function, constructor_ob=None) Declares that *function* should be used as a "reduction" function for objects of type *type*. *function* should return either a string or a tuple - containing two or three elements. + containing two or three elements. See the :attr:`~pickle.Pickler.dispatch_table` + for more details on the interface of *function*. - The optional *constructor* parameter, if provided, is a callable object which - can be used to reconstruct the object when called with the tuple of arguments - returned by *function* at pickling time. A :exc:`TypeError` is raised if the - *constructor* is not callable. + The *constructor_ob* parameter is a legacy feature and is now ignored, but if + passed it must be a callable. - See the :mod:`pickle` module for more details on the interface - expected of *function* and *constructor*. Note that the - :attr:`~pickle.Pickler.dispatch_table` attribute of a pickler + Note that the :attr:`~pickle.Pickler.dispatch_table` attribute of a pickler object or subclass of :class:`pickle.Pickler` can also be used for declaring reduction functions. From webhook-mailer at python.org Sun Oct 9 21:59:16 2022 From: webhook-mailer at python.org (orsenthil) Date: Mon, 10 Oct 2022 01:59:16 -0000 Subject: [Python-checkins] bpo-43564: preserve original exception in args of FTP URLError (#24938) Message-ID: https://github.com/python/cpython/commit/ad817cd5c44416da3752ebf9baf16d650703275c commit: ad817cd5c44416da3752ebf9baf16d650703275c branch: main author: Carl Meyer committer: orsenthil date: 2022-10-09T18:59:07-07:00 summary: bpo-43564: preserve original exception in args of FTP URLError (#24938) * bpo-43564: preserve original error in args of FTP URLError * Add NEWS blurb Co-authored-by: Carl Meyer files: A Misc/NEWS.d/next/Library/2022-10-09-12-12-38.gh-issue-87730.ClgP3f.rst M Lib/urllib/request.py diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py index e2d5b8c5c59a..278aa3a14bfe 100644 --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -1582,7 +1582,7 @@ def ftp_open(self, req): headers = email.message_from_string(headers) return addinfourl(fp, headers, req.full_url) except ftplib.all_errors as exp: - raise URLError(f'ftp error: {exp}') from exp + raise URLError(exp) from exp def connect_ftp(self, user, passwd, host, port, dirs, timeout): return ftpwrapper(user, passwd, host, port, dirs, timeout, diff --git a/Misc/NEWS.d/next/Library/2022-10-09-12-12-38.gh-issue-87730.ClgP3f.rst b/Misc/NEWS.d/next/Library/2022-10-09-12-12-38.gh-issue-87730.ClgP3f.rst new file mode 100644 index 000000000000..6c63fa4928c6 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-09-12-12-38.gh-issue-87730.ClgP3f.rst @@ -0,0 +1,3 @@ +Wrap network errors consistently in urllib FTP support, so the test suite +doesn't fail when a network is available but the public internet is not +reachable. From webhook-mailer at python.org Mon Oct 10 01:09:26 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 10 Oct 2022 05:09:26 -0000 Subject: [Python-checkins] bpo-43564: preserve original exception in args of FTP URLError (GH-24938) Message-ID: https://github.com/python/cpython/commit/1d05b58e83a05316b384e77ea6330d3c814ee4a4 commit: 1d05b58e83a05316b384e77ea6330d3c814ee4a4 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-09T22:09:12-07:00 summary: bpo-43564: preserve original exception in args of FTP URLError (GH-24938) * bpo-43564: preserve original error in args of FTP URLError * Add NEWS blurb Co-authored-by: Carl Meyer (cherry picked from commit ad817cd5c44416da3752ebf9baf16d650703275c) Co-authored-by: Carl Meyer files: A Misc/NEWS.d/next/Library/2022-10-09-12-12-38.gh-issue-87730.ClgP3f.rst M Lib/urllib/request.py diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py index 6d580a434a7b..73ad0127ecc9 100644 --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -1579,7 +1579,7 @@ def ftp_open(self, req): headers = email.message_from_string(headers) return addinfourl(fp, headers, req.full_url) except ftplib.all_errors as exp: - raise URLError(f'ftp error: {exp}') from exp + raise URLError(exp) from exp def connect_ftp(self, user, passwd, host, port, dirs, timeout): return ftpwrapper(user, passwd, host, port, dirs, timeout, diff --git a/Misc/NEWS.d/next/Library/2022-10-09-12-12-38.gh-issue-87730.ClgP3f.rst b/Misc/NEWS.d/next/Library/2022-10-09-12-12-38.gh-issue-87730.ClgP3f.rst new file mode 100644 index 000000000000..6c63fa4928c6 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-09-12-12-38.gh-issue-87730.ClgP3f.rst @@ -0,0 +1,3 @@ +Wrap network errors consistently in urllib FTP support, so the test suite +doesn't fail when a network is available but the public internet is not +reachable. From webhook-mailer at python.org Mon Oct 10 02:37:11 2022 From: webhook-mailer at python.org (orsenthil) Date: Mon, 10 Oct 2022 06:37:11 -0000 Subject: [Python-checkins] [3.10] bpo-43564: preserve original exception in args of FTP URLError (GH-24938) (#98138) Message-ID: https://github.com/python/cpython/commit/1ae7abf6b2f410feee02286a1b2179f2c6e88abd commit: 1ae7abf6b2f410feee02286a1b2179f2c6e88abd branch: 3.10 author: Senthil Kumaran committer: orsenthil date: 2022-10-09T23:36:51-07:00 summary: [3.10] bpo-43564: preserve original exception in args of FTP URLError (GH-24938) (#98138) * bpo-43564: preserve original error in args of FTP URLError * Add NEWS blurb Co-authored-by: Carl Meyer . (cherry picked from commit ad817cd5c44416da3752ebf9baf16d650703275c) Co-authored-by: Carl Meyer Co-authored-by: Carl Meyer files: A Misc/NEWS.d/next/Library/2022-10-09-12-12-38.gh-issue-87730.ClgP3f.rst M Lib/urllib/request.py diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py index 320163be63ad..76fdd719cdaa 100644 --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -1579,8 +1579,7 @@ def ftp_open(self, req): headers = email.message_from_string(headers) return addinfourl(fp, headers, req.full_url) except ftplib.all_errors as exp: - exc = URLError('ftp error: %r' % exp) - raise exc.with_traceback(sys.exc_info()[2]) + raise URLError(exp) from exp def connect_ftp(self, user, passwd, host, port, dirs, timeout): return ftpwrapper(user, passwd, host, port, dirs, timeout, diff --git a/Misc/NEWS.d/next/Library/2022-10-09-12-12-38.gh-issue-87730.ClgP3f.rst b/Misc/NEWS.d/next/Library/2022-10-09-12-12-38.gh-issue-87730.ClgP3f.rst new file mode 100644 index 000000000000..6c63fa4928c6 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-09-12-12-38.gh-issue-87730.ClgP3f.rst @@ -0,0 +1,3 @@ +Wrap network errors consistently in urllib FTP support, so the test suite +doesn't fail when a network is available but the public internet is not +reachable. From webhook-mailer at python.org Mon Oct 10 03:01:25 2022 From: webhook-mailer at python.org (JulienPalard) Date: Mon, 10 Oct 2022 07:01:25 -0000 Subject: [Python-checkins] doc: remove a misleading statement. (GH-98093) Message-ID: https://github.com/python/cpython/commit/571e23d99157ed7ad67ca2334a396fc9ddbe07ec commit: 571e23d99157ed7ad67ca2334a396fc9ddbe07ec branch: main author: Julien Palard committer: JulienPalard date: 2022-10-10T09:01:16+02:00 summary: doc: remove a misleading statement. (GH-98093) files: M Doc/tutorial/introduction.rst diff --git a/Doc/tutorial/introduction.rst b/Doc/tutorial/introduction.rst index ba0f47705297..558b1c3eec60 100644 --- a/Doc/tutorial/introduction.rst +++ b/Doc/tutorial/introduction.rst @@ -70,8 +70,8 @@ the ones with a fractional part (e.g. ``5.0``, ``1.6``) have type :class:`float`. We will see more about numeric types later in the tutorial. Division (``/``) always returns a float. To do :term:`floor division` and -get an integer result (discarding any fractional result) you can use the ``//`` -operator; to calculate the remainder you can use ``%``:: +get an integer result you can use the ``//`` operator; to calculate +the remainder you can use ``%``:: >>> 17 / 3 # classic division returns a float 5.666666666666667 From webhook-mailer at python.org Mon Oct 10 04:50:53 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 10 Oct 2022 08:50:53 -0000 Subject: [Python-checkins] doc: remove a misleading statement. (GH-98093) Message-ID: https://github.com/python/cpython/commit/a2f728038e79bfc90fa30821ab11ef9b46a5a3fd commit: a2f728038e79bfc90fa30821ab11ef9b46a5a3fd branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-10T01:50:26-07:00 summary: doc: remove a misleading statement. (GH-98093) (cherry picked from commit 571e23d99157ed7ad67ca2334a396fc9ddbe07ec) Co-authored-by: Julien Palard files: M Doc/tutorial/introduction.rst diff --git a/Doc/tutorial/introduction.rst b/Doc/tutorial/introduction.rst index ba0f47705297..558b1c3eec60 100644 --- a/Doc/tutorial/introduction.rst +++ b/Doc/tutorial/introduction.rst @@ -70,8 +70,8 @@ the ones with a fractional part (e.g. ``5.0``, ``1.6``) have type :class:`float`. We will see more about numeric types later in the tutorial. Division (``/``) always returns a float. To do :term:`floor division` and -get an integer result (discarding any fractional result) you can use the ``//`` -operator; to calculate the remainder you can use ``%``:: +get an integer result you can use the ``//`` operator; to calculate +the remainder you can use ``%``:: >>> 17 / 3 # classic division returns a float 5.666666666666667 From webhook-mailer at python.org Mon Oct 10 04:50:53 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 10 Oct 2022 08:50:53 -0000 Subject: [Python-checkins] doc: remove a misleading statement. (GH-98093) Message-ID: https://github.com/python/cpython/commit/8827b95e80302ef19d19561fdcd81c6efde2ecdb commit: 8827b95e80302ef19d19561fdcd81c6efde2ecdb branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-10T01:50:17-07:00 summary: doc: remove a misleading statement. (GH-98093) (cherry picked from commit 571e23d99157ed7ad67ca2334a396fc9ddbe07ec) Co-authored-by: Julien Palard files: M Doc/tutorial/introduction.rst diff --git a/Doc/tutorial/introduction.rst b/Doc/tutorial/introduction.rst index ba0f47705297..558b1c3eec60 100644 --- a/Doc/tutorial/introduction.rst +++ b/Doc/tutorial/introduction.rst @@ -70,8 +70,8 @@ the ones with a fractional part (e.g. ``5.0``, ``1.6``) have type :class:`float`. We will see more about numeric types later in the tutorial. Division (``/``) always returns a float. To do :term:`floor division` and -get an integer result (discarding any fractional result) you can use the ``//`` -operator; to calculate the remainder you can use ``%``:: +get an integer result you can use the ``//`` operator; to calculate +the remainder you can use ``%``:: >>> 17 / 3 # classic division returns a float 5.666666666666667 From webhook-mailer at python.org Mon Oct 10 09:43:41 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Mon, 10 Oct 2022 13:43:41 -0000 Subject: [Python-checkins] gh-83940: os docs: Improve wording for getenv/getenvb (#98113) Message-ID: https://github.com/python/cpython/commit/187e853690908ca2af19a0701ca7529b43d05df9 commit: 187e853690908ca2af19a0701ca7529b43d05df9 branch: main author: Stanley <46876382+slateny at users.noreply.github.com> committer: JelleZijlstra date: 2022-10-10T06:43:01-07:00 summary: gh-83940: os docs: Improve wording for getenv/getenvb (#98113) files: M Doc/library/os.rst diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 8727f811def1..43066fa1e13d 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -304,8 +304,8 @@ process and user. .. function:: getenv(key, default=None) - Return the value of the environment variable *key* if it exists, or - *default* if it doesn't. *key*, *default* and the result are str. Note that + Return the value of the environment variable *key* as a string if it exists, or + *default* if it doesn't. *key* is a string. Note that since :func:`getenv` uses :data:`os.environ`, the mapping of :func:`getenv` is similarly also captured on import, and the function may not reflect future environment changes. @@ -319,8 +319,8 @@ process and user. .. function:: getenvb(key, default=None) - Return the value of the environment variable *key* if it exists, or - *default* if it doesn't. *key*, *default* and the result are bytes. Note that + Return the value of the environment variable *key* as bytes if it exists, or + *default* if it doesn't. *key* must be bytes. Note that since :func:`getenvb` uses :data:`os.environb`, the mapping of :func:`getenvb` is similarly also captured on import, and the function may not reflect future environment changes. From webhook-mailer at python.org Mon Oct 10 10:01:11 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 10 Oct 2022 14:01:11 -0000 Subject: [Python-checkins] gh-83940: os docs: Improve wording for getenv/getenvb (GH-98113) Message-ID: https://github.com/python/cpython/commit/fc14f1a80d17385571516805603780601e7ed698 commit: fc14f1a80d17385571516805603780601e7ed698 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-10T07:01:05-07:00 summary: gh-83940: os docs: Improve wording for getenv/getenvb (GH-98113) (cherry picked from commit 187e853690908ca2af19a0701ca7529b43d05df9) Co-authored-by: Stanley <46876382+slateny at users.noreply.github.com> files: M Doc/library/os.rst diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 833779166910..9311bf187f0b 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -304,8 +304,8 @@ process and user. .. function:: getenv(key, default=None) - Return the value of the environment variable *key* if it exists, or - *default* if it doesn't. *key*, *default* and the result are str. Note that + Return the value of the environment variable *key* as a string if it exists, or + *default* if it doesn't. *key* is a string. Note that since :func:`getenv` uses :data:`os.environ`, the mapping of :func:`getenv` is similarly also captured on import, and the function may not reflect future environment changes. @@ -319,8 +319,8 @@ process and user. .. function:: getenvb(key, default=None) - Return the value of the environment variable *key* if it exists, or - *default* if it doesn't. *key*, *default* and the result are bytes. Note that + Return the value of the environment variable *key* as bytes if it exists, or + *default* if it doesn't. *key* must be bytes. Note that since :func:`getenvb` uses :data:`os.environb`, the mapping of :func:`getenvb` is similarly also captured on import, and the function may not reflect future environment changes. From webhook-mailer at python.org Mon Oct 10 10:01:23 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 10 Oct 2022 14:01:23 -0000 Subject: [Python-checkins] gh-83940: os docs: Improve wording for getenv/getenvb (GH-98113) Message-ID: https://github.com/python/cpython/commit/de745870e600e38fe7c753c461d22e9debad7f66 commit: de745870e600e38fe7c753c461d22e9debad7f66 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-10T07:01:17-07:00 summary: gh-83940: os docs: Improve wording for getenv/getenvb (GH-98113) (cherry picked from commit 187e853690908ca2af19a0701ca7529b43d05df9) Co-authored-by: Stanley <46876382+slateny at users.noreply.github.com> files: M Doc/library/os.rst diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 58f01e97459c..8753132429d6 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -291,8 +291,8 @@ process and user. .. function:: getenv(key, default=None) - Return the value of the environment variable *key* if it exists, or - *default* if it doesn't. *key*, *default* and the result are str. Note that + Return the value of the environment variable *key* as a string if it exists, or + *default* if it doesn't. *key* is a string. Note that since :func:`getenv` uses :data:`os.environ`, the mapping of :func:`getenv` is similarly also captured on import, and the function may not reflect future environment changes. @@ -306,8 +306,8 @@ process and user. .. function:: getenvb(key, default=None) - Return the value of the environment variable *key* if it exists, or - *default* if it doesn't. *key*, *default* and the result are bytes. Note that + Return the value of the environment variable *key* as bytes if it exists, or + *default* if it doesn't. *key* must be bytes. Note that since :func:`getenvb` uses :data:`os.environb`, the mapping of :func:`getenvb` is similarly also captured on import, and the function may not reflect future environment changes. From webhook-mailer at python.org Mon Oct 10 11:29:07 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Mon, 10 Oct 2022 15:29:07 -0000 Subject: [Python-checkins] gh-94808: Add coverage for bytesarray_setitem (#95802) Message-ID: https://github.com/python/cpython/commit/dfcdee4a18ece6f7c4fe1aa5830ee861f8b15b24 commit: dfcdee4a18ece6f7c4fe1aa5830ee861f8b15b24 branch: main author: Michael Droettboom committer: JelleZijlstra date: 2022-10-10T08:28:41-07:00 summary: gh-94808: Add coverage for bytesarray_setitem (#95802) files: M Lib/test/test_bytes.py M Modules/_testcapimodule.c diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py index 53ba1ad6f591..7c62b722059d 100644 --- a/Lib/test/test_bytes.py +++ b/Lib/test/test_bytes.py @@ -1225,6 +1225,8 @@ class SubBytes(bytes): class ByteArrayTest(BaseBytesTest, unittest.TestCase): type2test = bytearray + _testcapi = import_helper.import_module('_testcapi') + def test_getitem_error(self): b = bytearray(b'python') msg = "bytearray indices must be integers or slices" @@ -1317,47 +1319,73 @@ def by(s): self.assertEqual(re.findall(br"\w+", b), [by("Hello"), by("world")]) def test_setitem(self): - b = bytearray([1, 2, 3]) - b[1] = 100 - self.assertEqual(b, bytearray([1, 100, 3])) - b[-1] = 200 - self.assertEqual(b, bytearray([1, 100, 200])) - b[0] = Indexable(10) - self.assertEqual(b, bytearray([10, 100, 200])) - try: - b[3] = 0 - self.fail("Didn't raise IndexError") - except IndexError: - pass - try: - b[-10] = 0 - self.fail("Didn't raise IndexError") - except IndexError: - pass - try: - b[0] = 256 - self.fail("Didn't raise ValueError") - except ValueError: - pass - try: - b[0] = Indexable(-1) - self.fail("Didn't raise ValueError") - except ValueError: - pass - try: - b[0] = None - self.fail("Didn't raise TypeError") - except TypeError: - pass + def setitem_as_mapping(b, i, val): + b[i] = val + + def setitem_as_sequence(b, i, val): + self._testcapi.sequence_setitem(b, i, val) + + def do_tests(setitem): + b = bytearray([1, 2, 3]) + setitem(b, 1, 100) + self.assertEqual(b, bytearray([1, 100, 3])) + setitem(b, -1, 200) + self.assertEqual(b, bytearray([1, 100, 200])) + setitem(b, 0, Indexable(10)) + self.assertEqual(b, bytearray([10, 100, 200])) + try: + setitem(b, 3, 0) + self.fail("Didn't raise IndexError") + except IndexError: + pass + try: + setitem(b, -10, 0) + self.fail("Didn't raise IndexError") + except IndexError: + pass + try: + setitem(b, 0, 256) + self.fail("Didn't raise ValueError") + except ValueError: + pass + try: + setitem(b, 0, Indexable(-1)) + self.fail("Didn't raise ValueError") + except ValueError: + pass + try: + setitem(b, 0, None) + self.fail("Didn't raise TypeError") + except TypeError: + pass + + with self.subTest("tp_as_mapping"): + do_tests(setitem_as_mapping) + + with self.subTest("tp_as_sequence"): + do_tests(setitem_as_sequence) def test_delitem(self): - b = bytearray(range(10)) - del b[0] - self.assertEqual(b, bytearray(range(1, 10))) - del b[-1] - self.assertEqual(b, bytearray(range(1, 9))) - del b[4] - self.assertEqual(b, bytearray([1, 2, 3, 4, 6, 7, 8])) + def del_as_mapping(b, i): + del b[i] + + def del_as_sequence(b, i): + self._testcapi.sequence_delitem(b, i) + + def do_tests(delete): + b = bytearray(range(10)) + delete(b, 0) + self.assertEqual(b, bytearray(range(1, 10))) + delete(b, -1) + self.assertEqual(b, bytearray(range(1, 9))) + delete(b, 4) + self.assertEqual(b, bytearray([1, 2, 3, 4, 6, 7, 8])) + + with self.subTest("tp_as_mapping"): + do_tests(del_as_mapping) + + with self.subTest("tp_as_sequence"): + do_tests(del_as_sequence) def test_setslice(self): b = bytearray(range(10)) @@ -1729,6 +1757,8 @@ def test_repeat_after_setslice(self): self.assertEqual(b3, b'xcxcxc') def test_mutating_index(self): + # See gh-91153 + class Boom: def __index__(self): b.clear() @@ -1740,10 +1770,9 @@ def __index__(self): b[0] = Boom() with self.subTest("tp_as_sequence"): - _testcapi = import_helper.import_module('_testcapi') b = bytearray(b'Now you see me...') with self.assertRaises(IndexError): - _testcapi.sequence_setitem(b, 0, Boom()) + self._testcapi.sequence_setitem(b, 0, Boom()) class AssortedBytesTest(unittest.TestCase): diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 173d7c2cb805..95c67fc95e89 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -4846,6 +4846,20 @@ sequence_setitem(PyObject *self, PyObject *args) } +static PyObject * +sequence_delitem(PyObject *self, PyObject *args) +{ + Py_ssize_t i; + PyObject *seq; + if (!PyArg_ParseTuple(args, "On", &seq, &i)) { + return NULL; + } + if (PySequence_DelItem(seq, i)) { + return NULL; + } + Py_RETURN_NONE; +} + static PyObject * hasattr_string(PyObject *self, PyObject* args) { @@ -5885,6 +5899,7 @@ static PyMethodDef TestMethods[] = { {"write_unraisable_exc", test_write_unraisable_exc, METH_VARARGS}, {"sequence_getitem", sequence_getitem, METH_VARARGS}, {"sequence_setitem", sequence_setitem, METH_VARARGS}, + {"sequence_delitem", sequence_delitem, METH_VARARGS}, {"hasattr_string", hasattr_string, METH_VARARGS}, {"meth_varargs", meth_varargs, METH_VARARGS}, {"meth_varargs_keywords", _PyCFunction_CAST(meth_varargs_keywords), METH_VARARGS|METH_KEYWORDS}, From webhook-mailer at python.org Mon Oct 10 12:12:45 2022 From: webhook-mailer at python.org (mdickinson) Date: Mon, 10 Oct 2022 16:12:45 -0000 Subject: [Python-checkins] gh-96821: Fix undefined behaviour in `audioop.c` (#96923) Message-ID: https://github.com/python/cpython/commit/553d3c10172254b190078c50eb9f8e60522c8f41 commit: 553d3c10172254b190078c50eb9f8e60522c8f41 branch: main author: Matthias G?rgens committer: mdickinson date: 2022-10-10T17:12:29+01:00 summary: gh-96821: Fix undefined behaviour in `audioop.c` (#96923) * gh-96821: Fix undefined behaviour in `audioop.c` Left-shifting negative numbers is undefined behaviour. Fortunately, multiplication works just as well, is defined behaviour, and gets compiled to the same machine code as before by optimizing compilers. Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> files: A Misc/NEWS.d/next/Core and Builtins/2022-09-19-03-35-01.gh-issue-96821.izK6JA.rst M Modules/audioop.c diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-19-03-35-01.gh-issue-96821.izK6JA.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-19-03-35-01.gh-issue-96821.izK6JA.rst new file mode 100644 index 000000000000..73d0c76f0297 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-09-19-03-35-01.gh-issue-96821.izK6JA.rst @@ -0,0 +1 @@ +Fix undefined behaviour in ``audioop.c``. diff --git a/Modules/audioop.c b/Modules/audioop.c index d74e634ac448..c29a3e8df409 100644 --- a/Modules/audioop.c +++ b/Modules/audioop.c @@ -59,6 +59,8 @@ static const int16_t seg_uend[8] = { static int16_t search(int16_t val, const int16_t *table, int size) { + assert(0 <= size); + assert(size < INT16_MAX); int i; for (i = 0; i < size; i++) { @@ -170,6 +172,7 @@ st_14linear2ulaw(int16_t pcm_val) /* 2's complement (14-bit range) */ if (seg >= 8) /* out of range, return maximum value. */ return (unsigned char) (0x7F ^ mask); else { + assert(seg >= 0); uval = (unsigned char) (seg << 4) | ((pcm_val >> (seg + 1)) & 0xF); return (uval ^ mask); } @@ -300,13 +303,13 @@ static const int stepsizeTable[89] = { #ifdef WORDS_BIGENDIAN #define GETINT24(cp, i) ( \ ((unsigned char *)(cp) + (i))[2] + \ - (((unsigned char *)(cp) + (i))[1] << 8) + \ - (((signed char *)(cp) + (i))[0] << 16) ) + (((unsigned char *)(cp) + (i))[1] * (1 << 8)) + \ + (((signed char *)(cp) + (i))[0] * (1 << 16)) ) #else #define GETINT24(cp, i) ( \ ((unsigned char *)(cp) + (i))[0] + \ - (((unsigned char *)(cp) + (i))[1] << 8) + \ - (((signed char *)(cp) + (i))[2] << 16) ) + (((unsigned char *)(cp) + (i))[1] * (1 << 8)) + \ + (((signed char *)(cp) + (i))[2] * (1 << 16)) ) #endif @@ -347,10 +350,10 @@ static const int stepsizeTable[89] = { } while(0) -#define GETSAMPLE32(size, cp, i) ( \ - (size == 1) ? (int)GETINT8((cp), (i)) << 24 : \ - (size == 2) ? (int)GETINT16((cp), (i)) << 16 : \ - (size == 3) ? (int)GETINT24((cp), (i)) << 8 : \ +#define GETSAMPLE32(size, cp, i) ( \ + (size == 1) ? (int)GETINT8((cp), (i)) * (1 << 24) : \ + (size == 2) ? (int)GETINT16((cp), (i)) * (1 << 16) : \ + (size == 3) ? (int)GETINT24((cp), (i)) * (1 << 8) : \ (int)GETINT32((cp), (i))) #define SETSAMPLE32(size, cp, i, val) do { \ @@ -1558,7 +1561,7 @@ audioop_ulaw2lin_impl(PyObject *module, Py_buffer *fragment, int width) cp = fragment->buf; for (i = 0; i < fragment->len*width; i += width) { - int val = st_ulaw2linear16(*cp++) << 16; + int val = st_ulaw2linear16(*cp++) * (1 << 16); SETSAMPLE32(width, ncp, i, val); } return rv; @@ -1632,7 +1635,7 @@ audioop_alaw2lin_impl(PyObject *module, Py_buffer *fragment, int width) cp = fragment->buf; for (i = 0; i < fragment->len*width; i += width) { - val = st_alaw2linear16(*cp++) << 16; + val = st_alaw2linear16(*cp++) * (1 << 16); SETSAMPLE32(width, ncp, i, val); } return rv; @@ -1757,7 +1760,7 @@ audioop_lin2adpcm_impl(PyObject *module, Py_buffer *fragment, int width, /* Step 6 - Output value */ if ( bufferstep ) { - outputbuffer = (delta << 4) & 0xf0; + outputbuffer = (delta * (1 << 4)) & 0xf0; } else { *ncp++ = (delta & 0x0f) | outputbuffer; } @@ -1875,7 +1878,7 @@ audioop_adpcm2lin_impl(PyObject *module, Py_buffer *fragment, int width, step = stepsizeTable[index]; /* Step 6 - Output value */ - SETSAMPLE32(width, ncp, i, valpred << 16); + SETSAMPLE32(width, ncp, i, valpred * (1 << 16)); } rv = Py_BuildValue("(O(ii))", str, valpred, index); From webhook-mailer at python.org Mon Oct 10 14:28:02 2022 From: webhook-mailer at python.org (vsajip) Date: Mon, 10 Oct 2022 18:28:02 -0000 Subject: [Python-checkins] gh-88452: Add a warning about non-portability of environments. (GH-98155) Message-ID: https://github.com/python/cpython/commit/6a757da080121c4add61931ae46389b3f3e990a1 commit: 6a757da080121c4add61931ae46389b3f3e990a1 branch: main author: Vinay Sajip committer: vsajip date: 2022-10-10T19:27:52+01:00 summary: gh-88452: Add a warning about non-portability of environments. (GH-98155) files: M Doc/library/venv.rst diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst index 06810612acba..40eccdec16b3 100644 --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -85,6 +85,19 @@ Creating virtual environments without there needing to be any reference to its virtual environment in ``PATH``. +.. warning:: Because scripts installed in environments should not expect the + environment to be activated, their shebang lines contain the absolute paths + to their environment's interpreters. Because of this, environments are + inherently non-portable, in the general case. You should always have a + simple means of recreating an environment (for example, if you have a + requirements file ``requirements.txt``, you can invoke ``pip install -r + requirements.txt`` using the environment's ``pip`` to install all of the + packages needed by the environment). If for any reason you need to move the + environment to a new location, you should recreate it at the desired + location and delete the one at the old location. If you move an environment + because you moved a parent directory of it, you should recreate the + environment in its new location. Otherwise, software installed into the + environment may not work as expected. .. _venv-api: From webhook-mailer at python.org Mon Oct 10 15:37:42 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 10 Oct 2022 19:37:42 -0000 Subject: [Python-checkins] ci: add GitHub token permissions (GH-92999) Message-ID: https://github.com/python/cpython/commit/126929760a758748ebe1c71176c299ed888e8d10 commit: 126929760a758748ebe1c71176c299ed888e8d10 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-10T12:37:37-07:00 summary: ci: add GitHub token permissions (GH-92999) (cherry picked from commit b96e20c1d9be4e6d5ea3e48c9c97e5ecd02f6055) Co-authored-by: Varun Sharma files: M .github/workflows/build.yml M .github/workflows/build_msi.yml M .github/workflows/doc.yml M .github/workflows/new-bugs-announce-notifier.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bb08b2ff62d5..3576eff6e352 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,6 +22,9 @@ on: - '3.8' - '3.7' +permissions: + contents: read + jobs: check_source: name: 'Check for source changes' diff --git a/.github/workflows/build_msi.yml b/.github/workflows/build_msi.yml index ec18735e9b9f..6044ae0f7c29 100644 --- a/.github/workflows/build_msi.yml +++ b/.github/workflows/build_msi.yml @@ -23,6 +23,9 @@ on: paths: - 'Tools/msi/**' +permissions: + contents: read + jobs: build_win32: name: 'Windows (x86) Installer' diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index 73a6a50520e0..e06f21671b5a 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -25,6 +25,9 @@ on: - 'Misc/**' - '.github/workflows/doc.yml' +permissions: + contents: read + jobs: build_doc: name: 'Docs' diff --git a/.github/workflows/new-bugs-announce-notifier.yml b/.github/workflows/new-bugs-announce-notifier.yml index 8cd834419f00..b2b63472d834 100644 --- a/.github/workflows/new-bugs-announce-notifier.yml +++ b/.github/workflows/new-bugs-announce-notifier.yml @@ -5,6 +5,9 @@ on: types: - opened +permissions: + issues: read + jobs: notify-new-bugs-announce: runs-on: ubuntu-latest @@ -39,7 +42,7 @@ jobs: assignee : issue.data.assignees.map(assignee => { return assignee.login }), body : issue.data.body }; - + const data = { from: "CPython Issues ", to: "new-bugs-announce at python.org", From webhook-mailer at python.org Mon Oct 10 15:46:14 2022 From: webhook-mailer at python.org (ezio-melotti) Date: Mon, 10 Oct 2022 19:46:14 -0000 Subject: [Python-checkins] [3.10] ci: add GitHub token permissions (GH-92999) (#98161) Message-ID: https://github.com/python/cpython/commit/64ce2cba9890b4b8522760090286a756cbefa33f commit: 64ce2cba9890b4b8522760090286a756cbefa33f branch: 3.10 author: Ezio Melotti committer: ezio-melotti date: 2022-10-10T21:46:09+02:00 summary: [3.10] ci: add GitHub token permissions (GH-92999) (#98161) * ci: add GitHub token permissions (#92999) (cherry picked from commit b96e20c1d9be4e6d5ea3e48c9c97e5ecd02f6055) * [3.10] ci: add GitHub token permissions (GH-92999). (cherry picked from commit b96e20c1d9be4e6d5ea3e48c9c97e5ecd02f6055) Co-authored-by: Varun Sharma Co-authored-by: Varun Sharma files: M .github/workflows/build.yml M .github/workflows/build_msi.yml M .github/workflows/doc.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1545ae87dca0..c0744ce5033f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,6 +19,9 @@ on: - 3.8 - 3.7 +permissions: + contents: read + jobs: check_source: name: 'Check for source changes' diff --git a/.github/workflows/build_msi.yml b/.github/workflows/build_msi.yml index 201098a63579..04917ff184aa 100644 --- a/.github/workflows/build_msi.yml +++ b/.github/workflows/build_msi.yml @@ -20,6 +20,9 @@ on: paths: - 'Tools/msi/**' +permissions: + contents: read + jobs: build_win32: name: 'Windows (x86) Installer' diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index e2501589d6e6..eb4884a48732 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -20,6 +20,9 @@ on: - 'Doc/**' - 'Misc/**' +permissions: + contents: read + jobs: build_doc: name: 'Docs' From webhook-mailer at python.org Mon Oct 10 16:09:35 2022 From: webhook-mailer at python.org (vsajip) Date: Mon, 10 Oct 2022 20:09:35 -0000 Subject: [Python-checkins] [3.10] gh-88452: Add a warning about non-portability of environments. (GH-98155) (GH-98156) Message-ID: https://github.com/python/cpython/commit/bf6b52ebade9ed779c0a0482f35cb00e062616b1 commit: bf6b52ebade9ed779c0a0482f35cb00e062616b1 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: vsajip date: 2022-10-10T21:09:27+01:00 summary: [3.10] gh-88452: Add a warning about non-portability of environments. (GH-98155) (GH-98156) files: M Doc/library/venv.rst diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst index 127a8717cf7d..fe5e4c0c9cb5 100644 --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -84,6 +84,19 @@ Creating virtual environments without there needing to be any reference to its virtual environment in ``PATH``. +.. warning:: Because scripts installed in environments should not expect the + environment to be activated, their shebang lines contain the absolute paths + to their environment's interpreters. Because of this, environments are + inherently non-portable, in the general case. You should always have a + simple means of recreating an environment (for example, if you have a + requirements file ``requirements.txt``, you can invoke ``pip install -r + requirements.txt`` using the environment's ``pip`` to install all of the + packages needed by the environment). If for any reason you need to move the + environment to a new location, you should recreate it at the desired + location and delete the one at the old location. If you move an environment + because you moved a parent directory of it, you should recreate the + environment in its new location. Otherwise, software installed into the + environment may not work as expected. .. _venv-api: From webhook-mailer at python.org Mon Oct 10 16:10:09 2022 From: webhook-mailer at python.org (vsajip) Date: Mon, 10 Oct 2022 20:10:09 -0000 Subject: [Python-checkins] [3.11] gh-88452: Add a warning about non-portability of environments. (GH-98155) (GH-98157) Message-ID: https://github.com/python/cpython/commit/5c0d4c261972b7be6099c944d058847685f25033 commit: 5c0d4c261972b7be6099c944d058847685f25033 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: vsajip date: 2022-10-10T21:10:04+01:00 summary: [3.11] gh-88452: Add a warning about non-portability of environments. (GH-98155) (GH-98157) files: M Doc/library/venv.rst diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst index 3fa1046ae979..3bed25645a92 100644 --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -85,6 +85,19 @@ Creating virtual environments without there needing to be any reference to its virtual environment in ``PATH``. +.. warning:: Because scripts installed in environments should not expect the + environment to be activated, their shebang lines contain the absolute paths + to their environment's interpreters. Because of this, environments are + inherently non-portable, in the general case. You should always have a + simple means of recreating an environment (for example, if you have a + requirements file ``requirements.txt``, you can invoke ``pip install -r + requirements.txt`` using the environment's ``pip`` to install all of the + packages needed by the environment). If for any reason you need to move the + environment to a new location, you should recreate it at the desired + location and delete the one at the old location. If you move an environment + because you moved a parent directory of it, you should recreate the + environment in its new location. Otherwise, software installed into the + environment may not work as expected. .. _venv-api: From webhook-mailer at python.org Mon Oct 10 16:16:38 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 10 Oct 2022 20:16:38 -0000 Subject: [Python-checkins] Auto-cancel old builds when new commit pushed to branch (GH-98009) Message-ID: https://github.com/python/cpython/commit/9d44ca51830ea1ead1e6e5641f9dc22fa108e2dc commit: 9d44ca51830ea1ead1e6e5641f9dc22fa108e2dc branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-10T13:16:32-07:00 summary: Auto-cancel old builds when new commit pushed to branch (GH-98009) * Auto-cancel old builds when new commit pushed to branch * Add a fallback Co-authored-by: Ezio Melotti * Use the same group for all workflows. Co-authored-by: Ezio Melotti (cherry picked from commit 75751f4aa5d70f65856645a9128fd42d92d6692c) Co-authored-by: Hugo van Kemenade files: M .github/workflows/build.yml M .github/workflows/build_msi.yml M .github/workflows/doc.yml M .github/workflows/verify-ensurepip-wheels.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3576eff6e352..8a535831a605 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -25,6 +25,10 @@ on: permissions: contents: read +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + jobs: check_source: name: 'Check for source changes' diff --git a/.github/workflows/build_msi.yml b/.github/workflows/build_msi.yml index 6044ae0f7c29..5243dbba5f6b 100644 --- a/.github/workflows/build_msi.yml +++ b/.github/workflows/build_msi.yml @@ -26,6 +26,10 @@ on: permissions: contents: read +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + jobs: build_win32: name: 'Windows (x86) Installer' diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index e06f21671b5a..af5c5d0ad2e2 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -28,6 +28,10 @@ on: permissions: contents: read +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + jobs: build_doc: name: 'Docs' diff --git a/.github/workflows/verify-ensurepip-wheels.yml b/.github/workflows/verify-ensurepip-wheels.yml index 61e3d1adf534..9f4754f912b0 100644 --- a/.github/workflows/verify-ensurepip-wheels.yml +++ b/.github/workflows/verify-ensurepip-wheels.yml @@ -16,6 +16,10 @@ on: permissions: contents: read +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + jobs: verify: runs-on: ubuntu-latest From webhook-mailer at python.org Mon Oct 10 16:26:44 2022 From: webhook-mailer at python.org (ezio-melotti) Date: Mon, 10 Oct 2022 20:26:44 -0000 Subject: [Python-checkins] [3.10] Auto-cancel old builds when new commit pushed to branch (GH-98009) (#98163) Message-ID: https://github.com/python/cpython/commit/428bd028b3e6dceea2385f488491340be665b125 commit: 428bd028b3e6dceea2385f488491340be665b125 branch: 3.10 author: Ezio Melotti committer: ezio-melotti date: 2022-10-10T22:26:38+02:00 summary: [3.10] Auto-cancel old builds when new commit pushed to branch (GH-98009) (#98163) * Auto-cancel old builds when new commit pushed to branch * Add a fallback Co-authored-by: Ezio Melotti * Use the same group for all workflows. Co-authored-by: Ezio Melotti (cherry picked from commit 75751f4aa5d70f65856645a9128fd42d92d6692c) Co-authored-by: Hugo van Kemenade Co-authored-by: Hugo van Kemenade files: M .github/workflows/build.yml M .github/workflows/build_msi.yml M .github/workflows/doc.yml M .github/workflows/verify-ensurepip-wheels.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c0744ce5033f..ba23c72586d4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,6 +22,10 @@ on: permissions: contents: read +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + jobs: check_source: name: 'Check for source changes' diff --git a/.github/workflows/build_msi.yml b/.github/workflows/build_msi.yml index 04917ff184aa..0eba92e1c844 100644 --- a/.github/workflows/build_msi.yml +++ b/.github/workflows/build_msi.yml @@ -23,6 +23,10 @@ on: permissions: contents: read +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + jobs: build_win32: name: 'Windows (x86) Installer' diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index eb4884a48732..3bc280be95f3 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -23,6 +23,10 @@ on: permissions: contents: read +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + jobs: build_doc: name: 'Docs' diff --git a/.github/workflows/verify-ensurepip-wheels.yml b/.github/workflows/verify-ensurepip-wheels.yml index 61e3d1adf534..9f4754f912b0 100644 --- a/.github/workflows/verify-ensurepip-wheels.yml +++ b/.github/workflows/verify-ensurepip-wheels.yml @@ -16,6 +16,10 @@ on: permissions: contents: read +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + jobs: verify: runs-on: ubuntu-latest From webhook-mailer at python.org Mon Oct 10 18:14:45 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 10 Oct 2022 22:14:45 -0000 Subject: [Python-checkins] gh-44098: Release the GIL during mmap on Unix (GH-98146) Message-ID: https://github.com/python/cpython/commit/f871e9a7bb4eb823da481b99052636763ec8e710 commit: f871e9a7bb4eb823da481b99052636763ec8e710 branch: main author: Shantanu <12621235+hauntsaninja at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-10T15:14:31-07:00 summary: gh-44098: Release the GIL during mmap on Unix (GH-98146) This seems pretty straightforward. The issue mentions other calls in mmapmodule that we could release the GIL on, but those are in methods where we'd need to be careful to ensure that something sensible happens if those are called concurrently. In prior art, note that #12073 released the GIL for munmap. In a toy benchmark, I see the speedup you'd expect from doing this. Automerge-Triggered-By: GH:gvanrossum files: A Misc/NEWS.d/next/Library/2022-10-10-09-52-21.gh-issue-44098.okcqJt.rst M Modules/mmapmodule.c diff --git a/Misc/NEWS.d/next/Library/2022-10-10-09-52-21.gh-issue-44098.okcqJt.rst b/Misc/NEWS.d/next/Library/2022-10-10-09-52-21.gh-issue-44098.okcqJt.rst new file mode 100644 index 000000000000..4efea4a7c4fc --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-10-09-52-21.gh-issue-44098.okcqJt.rst @@ -0,0 +1 @@ +Release the GIL when creating :class:`mmap.mmap` objects on Unix. diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index 5c05aa738ef5..fdce783fdec5 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -1318,9 +1318,9 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict) } } - m_obj->data = mmap(NULL, map_size, - prot, flags, - fd, offset); + Py_BEGIN_ALLOW_THREADS + m_obj->data = mmap(NULL, map_size, prot, flags, fd, offset); + Py_END_ALLOW_THREADS if (devzero != -1) { close(devzero); From webhook-mailer at python.org Mon Oct 10 23:26:21 2022 From: webhook-mailer at python.org (Fidget-Spinner) Date: Tue, 11 Oct 2022 03:26:21 -0000 Subject: [Python-checkins] gh-95756: Lazily created cached co_* attrs (GH-97791) Message-ID: https://github.com/python/cpython/commit/b399115ef18945f7526492225d72a512048ad20d commit: b399115ef18945f7526492225d72a512048ad20d branch: main author: Ken Jin committer: Fidget-Spinner date: 2022-10-11T11:26:08+08:00 summary: gh-95756: Lazily created cached co_* attrs (GH-97791) files: A Misc/NEWS.d/next/C API/2022-10-03-20-33-24.gh-issue-95756.SSmXlG.rst M Include/cpython/code.h M Objects/codeobject.c M Objects/frameobject.c M Tools/scripts/deepfreeze.py diff --git a/Include/cpython/code.h b/Include/cpython/code.h index 7ce69022557a..893ff934d3d8 100644 --- a/Include/cpython/code.h +++ b/Include/cpython/code.h @@ -32,6 +32,13 @@ typedef uint16_t _Py_CODEUNIT; #define _Py_SET_OPCODE(word, opcode) \ do { ((unsigned char *)&(word))[0] = (opcode); } while (0) +typedef struct { + PyObject *_co_code; + PyObject *_co_varnames; + PyObject *_co_cellvars; + PyObject *_co_freevars; +} _PyCoCached; + // To avoid repeating ourselves in deepfreeze.py, all PyCodeObject members are // defined in this macro: #define _PyCode_DEF(SIZE) { \ @@ -90,7 +97,7 @@ typedef uint16_t _Py_CODEUNIT; PyObject *co_qualname; /* unicode (qualname, for reference) */ \ PyObject *co_linetable; /* bytes object that holds location info */ \ PyObject *co_weakreflist; /* to support weakrefs to code objects */ \ - PyObject *_co_code; /* cached co_code object/attribute */ \ + _PyCoCached *_co_cached; /* cached co_* attributes */ \ int _co_firsttraceable; /* index of first traceable instruction */ \ char *_co_linearray; /* array of line offsets */ \ /* Scratch space for extra data relating to the code object. \ diff --git a/Misc/NEWS.d/next/C API/2022-10-03-20-33-24.gh-issue-95756.SSmXlG.rst b/Misc/NEWS.d/next/C API/2022-10-03-20-33-24.gh-issue-95756.SSmXlG.rst new file mode 100644 index 000000000000..b5c78c16e86d --- /dev/null +++ b/Misc/NEWS.d/next/C API/2022-10-03-20-33-24.gh-issue-95756.SSmXlG.rst @@ -0,0 +1 @@ +Lazily create and cache ``co_`` attributes for better performance for code getters. diff --git a/Objects/codeobject.c b/Objects/codeobject.c index 14d1d00684ae..7a0080c08c7b 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -150,7 +150,22 @@ validate_and_copy_tuple(PyObject *tup) return newtuple; } +static int +init_co_cached(PyCodeObject *self) { + if (self->_co_cached == NULL) { + self->_co_cached = PyMem_New(_PyCoCached, 1); + if (self->_co_cached == NULL) { + PyErr_NoMemory(); + return -1; + } + self->_co_cached->_co_code = NULL; + self->_co_cached->_co_cellvars = NULL; + self->_co_cached->_co_freevars = NULL; + self->_co_cached->_co_varnames = NULL; + } + return 0; +} /****************** * _PyCode_New() ******************/ @@ -336,7 +351,7 @@ init_code(PyCodeObject *co, struct _PyCodeConstructor *con) /* not set */ co->co_weakreflist = NULL; co->co_extra = NULL; - co->_co_code = NULL; + co->_co_cached = NULL; co->co_warmup = QUICKENING_INITIAL_WARMUP_VALUE; co->_co_linearray_entry_size = 0; @@ -1384,10 +1399,31 @@ _PyCode_SetExtra(PyObject *code, Py_ssize_t index, void *extra) * other PyCodeObject accessor functions ******************/ +static PyObject * +get_cached_locals(PyCodeObject *co, PyObject **cached_field, + _PyLocals_Kind kind, int num) +{ + assert(cached_field != NULL); + assert(co->_co_cached != NULL); + if (*cached_field != NULL) { + return Py_NewRef(*cached_field); + } + assert(*cached_field == NULL); + PyObject *varnames = get_localsplus_names(co, kind, num); + if (varnames == NULL) { + return NULL; + } + *cached_field = Py_NewRef(varnames); + return varnames; +} + PyObject * _PyCode_GetVarnames(PyCodeObject *co) { - return get_localsplus_names(co, CO_FAST_LOCAL, co->co_nlocals); + if (init_co_cached(co)) { + return NULL; + } + return get_cached_locals(co, &co->_co_cached->_co_varnames, CO_FAST_LOCAL, co->co_nlocals); } PyObject * @@ -1399,7 +1435,10 @@ PyCode_GetVarnames(PyCodeObject *code) PyObject * _PyCode_GetCellvars(PyCodeObject *co) { - return get_localsplus_names(co, CO_FAST_CELL, co->co_ncellvars); + if (init_co_cached(co)) { + return NULL; + } + return get_cached_locals(co, &co->_co_cached->_co_cellvars, CO_FAST_CELL, co->co_ncellvars); } PyObject * @@ -1411,7 +1450,10 @@ PyCode_GetCellvars(PyCodeObject *code) PyObject * _PyCode_GetFreevars(PyCodeObject *co) { - return get_localsplus_names(co, CO_FAST_FREE, co->co_nfreevars); + if (init_co_cached(co)) { + return NULL; + } + return get_cached_locals(co, &co->_co_cached->_co_freevars, CO_FAST_FREE, co->co_nfreevars); } PyObject * @@ -1437,8 +1479,11 @@ deopt_code(_Py_CODEUNIT *instructions, Py_ssize_t len) PyObject * _PyCode_GetCode(PyCodeObject *co) { - if (co->_co_code != NULL) { - return Py_NewRef(co->_co_code); + if (init_co_cached(co)) { + return NULL; + } + if (co->_co_cached->_co_code != NULL) { + return Py_NewRef(co->_co_cached->_co_code); } PyObject *code = PyBytes_FromStringAndSize((const char *)_PyCode_CODE(co), _PyCode_NBYTES(co)); @@ -1446,8 +1491,8 @@ _PyCode_GetCode(PyCodeObject *co) return NULL; } deopt_code((_Py_CODEUNIT *)PyBytes_AS_STRING(code), Py_SIZE(co)); - assert(co->_co_code == NULL); - co->_co_code = Py_NewRef(code); + assert(co->_co_cached->_co_code == NULL); + co->_co_cached->_co_code = Py_NewRef(code); return code; } @@ -1606,7 +1651,13 @@ code_dealloc(PyCodeObject *co) Py_XDECREF(co->co_qualname); Py_XDECREF(co->co_linetable); Py_XDECREF(co->co_exceptiontable); - Py_XDECREF(co->_co_code); + if (co->_co_cached != NULL) { + Py_XDECREF(co->_co_cached->_co_code); + Py_XDECREF(co->_co_cached->_co_cellvars); + Py_XDECREF(co->_co_cached->_co_freevars); + Py_XDECREF(co->_co_cached->_co_varnames); + PyMem_Free(co->_co_cached); + } if (co->co_weakreflist != NULL) { PyObject_ClearWeakRefs((PyObject*)co); } @@ -2181,7 +2232,13 @@ _PyStaticCode_Dealloc(PyCodeObject *co) deopt_code(_PyCode_CODE(co), Py_SIZE(co)); co->co_warmup = QUICKENING_INITIAL_WARMUP_VALUE; PyMem_Free(co->co_extra); - Py_CLEAR(co->_co_code); + if (co->_co_cached != NULL) { + Py_CLEAR(co->_co_cached->_co_code); + Py_CLEAR(co->_co_cached->_co_cellvars); + Py_CLEAR(co->_co_cached->_co_freevars); + Py_CLEAR(co->_co_cached->_co_varnames); + PyMem_Free(co->_co_cached); + } co->co_extra = NULL; if (co->co_weakreflist != NULL) { PyObject_ClearWeakRefs((PyObject *)co); diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 6a51a946ef35..bd1608e0d75a 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -645,9 +645,12 @@ add_load_fast_null_checks(PyCodeObject *co) } i += _PyOpcode_Caches[_PyOpcode_Deopt[opcode]]; } - if (changed) { + if (changed && co->_co_cached != NULL) { // invalidate cached co_code object - Py_CLEAR(co->_co_code); + Py_CLEAR(co->_co_cached->_co_code); + Py_CLEAR(co->_co_cached->_co_cellvars); + Py_CLEAR(co->_co_cached->_co_freevars); + Py_CLEAR(co->_co_cached->_co_varnames); } } diff --git a/Tools/scripts/deepfreeze.py b/Tools/scripts/deepfreeze.py index d9c6030fc17c..28ac2b12f92f 100644 --- a/Tools/scripts/deepfreeze.py +++ b/Tools/scripts/deepfreeze.py @@ -276,7 +276,7 @@ def generate_code(self, name: str, code: types.CodeType) -> str: self.write(f".co_name = {co_name},") self.write(f".co_qualname = {co_qualname},") self.write(f".co_linetable = {co_linetable},") - self.write(f"._co_code = NULL,") + self.write(f"._co_cached = NULL,") self.write("._co_linearray = NULL,") self.write(f".co_code_adaptive = {co_code_adaptive},") for i, op in enumerate(code.co_code[::2]): From webhook-mailer at python.org Tue Oct 11 03:38:04 2022 From: webhook-mailer at python.org (ned-deily) Date: Tue, 11 Oct 2022 07:38:04 -0000 Subject: [Python-checkins] 3.7.15 Message-ID: https://github.com/python/cpython/commit/9de83ce9704ba065626f483abf6c21b7b829104e commit: 9de83ce9704ba065626f483abf6c21b7b829104e branch: 3.7 author: Ned Deily committer: ned-deily date: 2022-10-10T05:34:53-07:00 summary: 3.7.15 files: A Misc/NEWS.d/3.7.15.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-16-19-02-40.gh-issue-95778.cJmnst.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-21-14-38-31.gh-issue-96848.WuoLzU.rst D Misc/NEWS.d/next/Library/2022-09-22-14-35-02.gh-issue-97005.yf21Q7.rst D Misc/NEWS.d/next/Security/2022-09-28-12-10-57.gh-issue-97612.y6NvOQ.rst D Misc/NEWS.d/next/Security/2022-09-28-17-09-37.gh-issue-97616.K1e3Xs.rst D Misc/NEWS.d/next/Windows/2022-09-07-00-11-33.gh-issue-96577.kV4K_1.rst M Include/patchlevel.h M Lib/pydoc_data/topics.py M README.rst diff --git a/Include/patchlevel.h b/Include/patchlevel.h index b94e1e4cb613..b53f33adb662 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -18,12 +18,12 @@ /*--start constants--*/ #define PY_MAJOR_VERSION 3 #define PY_MINOR_VERSION 7 -#define PY_MICRO_VERSION 14 +#define PY_MICRO_VERSION 15 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL #define PY_RELEASE_SERIAL 0 /* Version as a string */ -#define PY_VERSION "3.7.14+" +#define PY_VERSION "3.7.15" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py index 9a7c705f230f..95eb9d4b6744 100644 --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Autogenerated by Sphinx on Tue Sep 6 02:37:38 2022 +# Autogenerated by Sphinx on Mon Oct 10 05:27:13 2022 topics = {'assert': 'The "assert" statement\n' '**********************\n' '\n' diff --git a/Misc/NEWS.d/3.7.15.rst b/Misc/NEWS.d/3.7.15.rst new file mode 100644 index 000000000000..8e82ae0ea011 --- /dev/null +++ b/Misc/NEWS.d/3.7.15.rst @@ -0,0 +1,61 @@ +.. date: 2022-09-28-17-09-37 +.. gh-issue: 97616 +.. nonce: K1e3Xs +.. release date: 2022-10-10 +.. section: Security + +Fix multiplying a list by an integer (``list *= int``): detect the integer +overflow when the new allocated length is close to the maximum size. Issue +reported by Jordan Limor. Patch by Victor Stinner. + +.. + +.. date: 2022-09-28-12-10-57 +.. gh-issue: 97612 +.. nonce: y6NvOQ +.. section: Security + +Fix a shell code injection vulnerability in the +``get-remote-certificate.py`` example script. The script no longer uses a +shell to run ``openssl`` commands. Issue reported and initial fix by Caleb +Shortt. Patch by Victor Stinner. + +.. + +.. date: 2022-09-21-14-38-31 +.. gh-issue: 96848 +.. nonce: WuoLzU +.. section: Core and Builtins + +Fix command line parsing: reject :option:`-X int_max_str_digits <-X>` option +with no value (invalid) when the :envvar:`PYTHONINTMAXSTRDIGITS` environment +variable is set to a valid limit. Patch by Victor Stinner. + +.. + +.. date: 2022-09-16-19-02-40 +.. gh-issue: 95778 +.. nonce: cJmnst +.. section: Core and Builtins + +When :exc:`ValueError` is raised if an integer is larger than the limit, +mention the :func:`sys.set_int_max_str_digits` function in the error +message. Patch by Victor Stinner. + +.. + +.. date: 2022-09-22-14-35-02 +.. gh-issue: 97005 +.. nonce: yf21Q7 +.. section: Library + +Update bundled libexpat to 2.4.9 + +.. + +.. date: 2022-09-07-00-11-33 +.. gh-issue: 96577 +.. nonce: kV4K_1 +.. section: Windows + +Fixes a potential buffer overrun in :mod:`msilib`. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-16-19-02-40.gh-issue-95778.cJmnst.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-16-19-02-40.gh-issue-95778.cJmnst.rst deleted file mode 100644 index ebf63778a605..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-16-19-02-40.gh-issue-95778.cJmnst.rst +++ /dev/null @@ -1,3 +0,0 @@ -When :exc:`ValueError` is raised if an integer is larger than the limit, -mention the :func:`sys.set_int_max_str_digits` function in the error message. -Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-21-14-38-31.gh-issue-96848.WuoLzU.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-21-14-38-31.gh-issue-96848.WuoLzU.rst deleted file mode 100644 index a9b04ce87d4d..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-21-14-38-31.gh-issue-96848.WuoLzU.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix command line parsing: reject :option:`-X int_max_str_digits <-X>` option -with no value (invalid) when the :envvar:`PYTHONINTMAXSTRDIGITS` environment -variable is set to a valid limit. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Library/2022-09-22-14-35-02.gh-issue-97005.yf21Q7.rst b/Misc/NEWS.d/next/Library/2022-09-22-14-35-02.gh-issue-97005.yf21Q7.rst deleted file mode 100644 index d57999aa29b7..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-22-14-35-02.gh-issue-97005.yf21Q7.rst +++ /dev/null @@ -1 +0,0 @@ -Update bundled libexpat to 2.4.9 diff --git a/Misc/NEWS.d/next/Security/2022-09-28-12-10-57.gh-issue-97612.y6NvOQ.rst b/Misc/NEWS.d/next/Security/2022-09-28-12-10-57.gh-issue-97612.y6NvOQ.rst deleted file mode 100644 index 2f113492d42d..000000000000 --- a/Misc/NEWS.d/next/Security/2022-09-28-12-10-57.gh-issue-97612.y6NvOQ.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix a shell code injection vulnerability in the ``get-remote-certificate.py`` -example script. The script no longer uses a shell to run ``openssl`` commands. -Issue reported and initial fix by Caleb Shortt. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Security/2022-09-28-17-09-37.gh-issue-97616.K1e3Xs.rst b/Misc/NEWS.d/next/Security/2022-09-28-17-09-37.gh-issue-97616.K1e3Xs.rst deleted file mode 100644 index 721427fe6465..000000000000 --- a/Misc/NEWS.d/next/Security/2022-09-28-17-09-37.gh-issue-97616.K1e3Xs.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix multiplying a list by an integer (``list *= int``): detect the integer -overflow when the new allocated length is close to the maximum size. Issue -reported by Jordan Limor. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Windows/2022-09-07-00-11-33.gh-issue-96577.kV4K_1.rst b/Misc/NEWS.d/next/Windows/2022-09-07-00-11-33.gh-issue-96577.kV4K_1.rst deleted file mode 100644 index 6025e5ce4130..000000000000 --- a/Misc/NEWS.d/next/Windows/2022-09-07-00-11-33.gh-issue-96577.kV4K_1.rst +++ /dev/null @@ -1 +0,0 @@ -Fixes a potential buffer overrun in :mod:`msilib`. diff --git a/README.rst b/README.rst index 6e1d9c4c580a..aff3d1cbc752 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -This is Python version 3.7.14+ -============================== +This is Python version 3.7.15 +============================= .. image:: https://travis-ci.org/python/cpython.svg?branch=3.7 :alt: CPython build status on Travis CI From webhook-mailer at python.org Tue Oct 11 04:08:07 2022 From: webhook-mailer at python.org (vstinner) Date: Tue, 11 Oct 2022 08:08:07 -0000 Subject: [Python-checkins] gh-97669: Remove outdated example scripts (#97675) (#98167) Message-ID: https://github.com/python/cpython/commit/e0ae9ddffe0a708d0d3f5b8cc10488d466fc43c4 commit: e0ae9ddffe0a708d0d3f5b8cc10488d466fc43c4 branch: main author: Victor Stinner committer: vstinner date: 2022-10-11T10:07:57+02:00 summary: gh-97669: Remove outdated example scripts (#97675) (#98167) Remove outdated example scripts of the Tools/scripts/ directory: * gprof2html.py * md5sum.py * nm2def.py * pathfix.py * win_add2path.py Remove test_gprof2html, test_md5sum and test_pathfix of test_tools. files: D Lib/test/test_tools/test_gprof2html.py D Lib/test/test_tools/test_md5sum.py D Lib/test/test_tools/test_pathfix.py D Tools/scripts/gprof2html.py D Tools/scripts/md5sum.py D Tools/scripts/nm2def.py D Tools/scripts/pathfix.py D Tools/scripts/win_add2path.py M Lib/test/test_tools/test_sundry.py M PCbuild/lib.pyproj M Tools/scripts/README diff --git a/Lib/test/test_tools/test_gprof2html.py b/Lib/test/test_tools/test_gprof2html.py deleted file mode 100644 index 7cceb8faf8e5..000000000000 --- a/Lib/test/test_tools/test_gprof2html.py +++ /dev/null @@ -1,35 +0,0 @@ -"""Tests for the gprof2html script in the Tools directory.""" - -import os -import sys -import unittest -from unittest import mock -import tempfile - -from test.test_tools import skip_if_missing, import_tool - -skip_if_missing() - -class Gprof2htmlTests(unittest.TestCase): - - def setUp(self): - self.gprof = import_tool('gprof2html') - oldargv = sys.argv - def fixup(): - sys.argv = oldargv - self.addCleanup(fixup) - sys.argv = [] - - def test_gprof(self): - # Issue #14508: this used to fail with a NameError. - with mock.patch.object(self.gprof, 'webbrowser') as wmock, \ - tempfile.TemporaryDirectory() as tmpdir: - fn = os.path.join(tmpdir, 'abc') - open(fn, 'wb').close() - sys.argv = ['gprof2html', fn] - self.gprof.main() - self.assertTrue(wmock.open.called) - - -if __name__ == '__main__': - unittest.main() diff --git a/Lib/test/test_tools/test_md5sum.py b/Lib/test/test_tools/test_md5sum.py deleted file mode 100644 index 710461f88197..000000000000 --- a/Lib/test/test_tools/test_md5sum.py +++ /dev/null @@ -1,78 +0,0 @@ -"""Tests for the md5sum script in the Tools directory.""" - -import os -import unittest -from test.support import os_helper -from test.support import hashlib_helper -from test.support.script_helper import assert_python_ok, assert_python_failure - -from test.test_tools import scriptsdir, skip_if_missing - -skip_if_missing() - - at hashlib_helper.requires_hashdigest('md5', openssl=True) -class MD5SumTests(unittest.TestCase): - @classmethod - def setUpClass(cls): - cls.script = os.path.join(scriptsdir, 'md5sum.py') - os.mkdir(os_helper.TESTFN_ASCII) - cls.fodder = os.path.join(os_helper.TESTFN_ASCII, 'md5sum.fodder') - with open(cls.fodder, 'wb') as f: - f.write(b'md5sum\r\ntest file\r\n') - cls.fodder_md5 = b'd38dae2eb1ab346a292ef6850f9e1a0d' - cls.fodder_textmode_md5 = b'a8b07894e2ca3f2a4c3094065fa6e0a5' - - @classmethod - def tearDownClass(cls): - os_helper.rmtree(os_helper.TESTFN_ASCII) - - def test_noargs(self): - rc, out, err = assert_python_ok(self.script) - self.assertEqual(rc, 0) - self.assertTrue( - out.startswith(b'd41d8cd98f00b204e9800998ecf8427e ')) - self.assertFalse(err) - - def test_checksum_fodder(self): - rc, out, err = assert_python_ok(self.script, self.fodder) - self.assertEqual(rc, 0) - self.assertTrue(out.startswith(self.fodder_md5)) - for part in self.fodder.split(os.path.sep): - self.assertIn(part.encode(), out) - self.assertFalse(err) - - def test_dash_l(self): - rc, out, err = assert_python_ok(self.script, '-l', self.fodder) - self.assertEqual(rc, 0) - self.assertIn(self.fodder_md5, out) - parts = self.fodder.split(os.path.sep) - self.assertIn(parts[-1].encode(), out) - self.assertNotIn(parts[-2].encode(), out) - - def test_dash_t(self): - rc, out, err = assert_python_ok(self.script, '-t', self.fodder) - self.assertEqual(rc, 0) - self.assertTrue(out.startswith(self.fodder_textmode_md5)) - self.assertNotIn(self.fodder_md5, out) - - def test_dash_s(self): - rc, out, err = assert_python_ok(self.script, '-s', '512', self.fodder) - self.assertEqual(rc, 0) - self.assertIn(self.fodder_md5, out) - - def test_multiple_files(self): - rc, out, err = assert_python_ok(self.script, self.fodder, self.fodder) - self.assertEqual(rc, 0) - lines = out.splitlines() - self.assertEqual(len(lines), 2) - self.assertEqual(*lines) - - def test_usage(self): - rc, out, err = assert_python_failure(self.script, '-h') - self.assertEqual(rc, 2) - self.assertEqual(out, b'') - self.assertGreater(err, b'') - - -if __name__ == '__main__': - unittest.main() diff --git a/Lib/test/test_tools/test_pathfix.py b/Lib/test/test_tools/test_pathfix.py deleted file mode 100644 index aa754bc479b4..000000000000 --- a/Lib/test/test_tools/test_pathfix.py +++ /dev/null @@ -1,131 +0,0 @@ -import os -import subprocess -import sys -import unittest -from test.support import os_helper -from test.test_tools import scriptsdir, skip_if_missing - - -# need Tools/script/ directory: skip if run on Python installed on the system -skip_if_missing() - - -class TestPathfixFunctional(unittest.TestCase): - script = os.path.join(scriptsdir, 'pathfix.py') - - def setUp(self): - self.addCleanup(os_helper.unlink, os_helper.TESTFN) - - def pathfix(self, shebang, pathfix_flags, exitcode=0, stdout='', stderr='', - directory=''): - if directory: - # bpo-38347: Test filename should contain lowercase, uppercase, - # "-", "_" and digits. - filename = os.path.join(directory, 'script-A_1.py') - pathfix_arg = directory - else: - filename = os_helper.TESTFN - pathfix_arg = filename - - with open(filename, 'w', encoding='utf8') as f: - f.write(f'{shebang}\n' + 'print("Hello world")\n') - - encoding = sys.getfilesystemencoding() - proc = subprocess.run( - [sys.executable, self.script, - *pathfix_flags, '-n', pathfix_arg], - env={**os.environ, 'PYTHONIOENCODING': encoding}, - capture_output=True) - - if stdout == '' and proc.returncode == 0: - stdout = f'{filename}: updating\n' - self.assertEqual(proc.returncode, exitcode, proc) - self.assertEqual(proc.stdout.decode(encoding), stdout.replace('\n', os.linesep), proc) - self.assertEqual(proc.stderr.decode(encoding), stderr.replace('\n', os.linesep), proc) - - with open(filename, 'r', encoding='utf8') as f: - output = f.read() - - lines = output.split('\n') - self.assertEqual(lines[1:], ['print("Hello world")', '']) - new_shebang = lines[0] - - if proc.returncode != 0: - self.assertEqual(shebang, new_shebang) - - return new_shebang - - def test_recursive(self): - tmpdir = os_helper.TESTFN + '.d' - self.addCleanup(os_helper.rmtree, tmpdir) - os.mkdir(tmpdir) - expected_stderr = f"recursedown('{os.path.basename(tmpdir)}')\n" - self.assertEqual( - self.pathfix( - '#! /usr/bin/env python', - ['-i', '/usr/bin/python3'], - directory=tmpdir, - stderr=expected_stderr), - '#! /usr/bin/python3') - - def test_pathfix(self): - self.assertEqual( - self.pathfix( - '#! /usr/bin/env python', - ['-i', '/usr/bin/python3']), - '#! /usr/bin/python3') - self.assertEqual( - self.pathfix( - '#! /usr/bin/env python -R', - ['-i', '/usr/bin/python3']), - '#! /usr/bin/python3') - - def test_pathfix_keeping_flags(self): - self.assertEqual( - self.pathfix( - '#! /usr/bin/env python -R', - ['-i', '/usr/bin/python3', '-k']), - '#! /usr/bin/python3 -R') - self.assertEqual( - self.pathfix( - '#! /usr/bin/env python', - ['-i', '/usr/bin/python3', '-k']), - '#! /usr/bin/python3') - - def test_pathfix_adding_flag(self): - self.assertEqual( - self.pathfix( - '#! /usr/bin/env python', - ['-i', '/usr/bin/python3', '-a', 's']), - '#! /usr/bin/python3 -s') - self.assertEqual( - self.pathfix( - '#! /usr/bin/env python -S', - ['-i', '/usr/bin/python3', '-a', 's']), - '#! /usr/bin/python3 -s') - self.assertEqual( - self.pathfix( - '#! /usr/bin/env python -V', - ['-i', '/usr/bin/python3', '-a', 'v', '-k']), - '#! /usr/bin/python3 -vV') - self.assertEqual( - self.pathfix( - '#! /usr/bin/env python', - ['-i', '/usr/bin/python3', '-a', 'Rs']), - '#! /usr/bin/python3 -Rs') - self.assertEqual( - self.pathfix( - '#! /usr/bin/env python -W default', - ['-i', '/usr/bin/python3', '-a', 's', '-k']), - '#! /usr/bin/python3 -sW default') - - def test_pathfix_adding_errors(self): - self.pathfix( - '#! /usr/bin/env python -E', - ['-i', '/usr/bin/python3', '-a', 'W default', '-k'], - exitcode=2, - stderr="-a option doesn't support whitespaces") - - -if __name__ == '__main__': - unittest.main() diff --git a/Lib/test/test_tools/test_sundry.py b/Lib/test/test_tools/test_sundry.py index ed03c2f75a3a..04e38acdb348 100644 --- a/Lib/test/test_tools/test_sundry.py +++ b/Lib/test/test_tools/test_sundry.py @@ -19,15 +19,13 @@ class TestSundryScripts(unittest.TestCase): # added for a script it should be added to the allowlist below. # scripts that have independent tests. - allowlist = ['reindent', 'pdeps', 'gprof2html', 'md5sum'] + allowlist = ['reindent'] # scripts that can't be imported without running denylist = ['make_ctype'] - # scripts that use windows-only modules - windows_only = ['win_add2path'] # denylisted for other reasons other = ['2to3'] - skiplist = denylist + allowlist + windows_only + other + skiplist = denylist + allowlist + other def test_sundry(self): old_modules = import_helper.modules_setup() @@ -45,11 +43,6 @@ def test_sundry(self): # Unload all modules loaded in this test import_helper.modules_cleanup(*old_modules) - @unittest.skipIf(sys.platform != "win32", "Windows-only test") - def test_sundry_windows(self): - for name in self.windows_only: - import_tool(name) - if __name__ == '__main__': unittest.main() diff --git a/PCbuild/lib.pyproj b/PCbuild/lib.pyproj index 9934dc577bf3..daa202119102 100644 --- a/PCbuild/lib.pyproj +++ b/PCbuild/lib.pyproj @@ -1334,9 +1334,7 @@ - - diff --git a/Tools/scripts/README b/Tools/scripts/README index 70ea5f4cd0fe..2fcceccc075e 100644 --- a/Tools/scripts/README +++ b/Tools/scripts/README @@ -4,20 +4,11 @@ useful while building, extending or managing Python. 2to3 Main script for running the 2to3 conversion tool abitype.py Converts a C file to use the PEP 384 type definition API combinerefs.py A helper for analyzing PYTHONDUMPREFS output -diff.py Print file diffs in context, unified, or ndiff formats -gprof2html.py Transform gprof(1) output into useful HTML idle3 Main program to start IDLE -md5sum.py Print MD5 checksums of argument files -ndiff.py Intelligent diff between text files (Tim Peters) -nm2def.py Create a template for PC/python_nt.def (Marc Lemburg) -parseentities.py Utility for parsing HTML entity definitions parse_html5_entities.py Utility for parsing HTML5 entity definitions patchcheck.py Perform common checks and cleanup before committing -pathfix.py Change #!/usr/local/bin/python into something else -ptags.py Create vi tags file for Python modules pydoc3 Python documentation browser reindent.py Change .py files to use 4-space indents run_tests.py Run the test suite with more sensible default options stable_abi.py Stable ABI checks and file generators. untabify.py Replace tabs with spaces in argument files -win_add2path.py Add Python to the search path on Windows diff --git a/Tools/scripts/gprof2html.py b/Tools/scripts/gprof2html.py deleted file mode 100755 index bf0530ef3e43..000000000000 --- a/Tools/scripts/gprof2html.py +++ /dev/null @@ -1,87 +0,0 @@ -#! /usr/bin/env python3 - -"""Transform gprof(1) output into useful HTML.""" - -import html -import os -import re -import sys -import webbrowser - -header = """\ - - - gprof output (%s) - - -
    -"""
    -
    -trailer = """\
    -
    - - -""" - -def add_escapes(filename): - with open(filename, encoding="utf-8") as fp: - for line in fp: - yield html.escape(line) - -def gprof2html(input, output, filename): - output.write(header % filename) - for line in input: - output.write(line) - if line.startswith(" time"): - break - labels = {} - for line in input: - m = re.match(r"(.* )(\w+)\n", line) - if not m: - output.write(line) - break - stuff, fname = m.group(1, 2) - labels[fname] = fname - output.write('%s%s\n' % - (stuff, fname, fname, fname)) - for line in input: - output.write(line) - if line.startswith("index % time"): - break - for line in input: - m = re.match(r"(.* )(\w+)(( <cycle.*>)? \[\d+\])\n", line) - if not m: - output.write(line) - if line.startswith("Index by function name"): - break - continue - prefix, fname, suffix = m.group(1, 2, 3) - if fname not in labels: - output.write(line) - continue - if line.startswith("["): - output.write('%s%s%s\n' % - (prefix, fname, fname, fname, suffix)) - else: - output.write('%s%s%s\n' % - (prefix, fname, fname, suffix)) - for line in input: - for part in re.findall(r"(\w+(?:\.c)?|\W+)", line): - if part in labels: - part = '%s' % (part, part) - output.write(part) - output.write(trailer) - - -def main(): - filename = "gprof.out" - if sys.argv[1:]: - filename = sys.argv[1] - outputfilename = filename + ".html" - input = add_escapes(filename) - with open(outputfilename, "w", encoding="utf-8") as output: - gprof2html(input, output, filename) - webbrowser.open("file:" + os.path.abspath(outputfilename)) - -if __name__ == '__main__': - main() diff --git a/Tools/scripts/md5sum.py b/Tools/scripts/md5sum.py deleted file mode 100755 index f910576377aa..000000000000 --- a/Tools/scripts/md5sum.py +++ /dev/null @@ -1,93 +0,0 @@ -#! /usr/bin/env python3 - -"""Python utility to print MD5 checksums of argument files. -""" - - -bufsize = 8096 -fnfilter = None -rmode = 'rb' - -usage = """ -usage: md5sum.py [-b] [-t] [-l] [-s bufsize] [file ...] --b : read files in binary mode (default) --t : read files in text mode (you almost certainly don't want this!) --l : print last pathname component only --s bufsize: read buffer size (default %d) -file ... : files to sum; '-' or no files means stdin -""" % bufsize - -import io -import sys -import os -import getopt -from hashlib import md5 - -def sum(*files): - sts = 0 - if files and isinstance(files[-1], io.IOBase): - out, files = files[-1], files[:-1] - else: - out = sys.stdout - if len(files) == 1 and not isinstance(files[0], str): - files = files[0] - for f in files: - if isinstance(f, str): - if f == '-': - sts = printsumfp(sys.stdin, '', out) or sts - else: - sts = printsum(f, out) or sts - else: - sts = sum(f, out) or sts - return sts - -def printsum(filename, out=sys.stdout): - try: - fp = open(filename, rmode) - except IOError as msg: - sys.stderr.write('%s: Can\'t open: %s\n' % (filename, msg)) - return 1 - with fp: - if fnfilter: - filename = fnfilter(filename) - sts = printsumfp(fp, filename, out) - return sts - -def printsumfp(fp, filename, out=sys.stdout): - m = md5() - try: - while 1: - data = fp.read(bufsize) - if not data: - break - if isinstance(data, str): - data = data.encode(fp.encoding) - m.update(data) - except IOError as msg: - sys.stderr.write('%s: I/O error: %s\n' % (filename, msg)) - return 1 - out.write('%s %s\n' % (m.hexdigest(), filename)) - return 0 - -def main(args = sys.argv[1:], out=sys.stdout): - global fnfilter, rmode, bufsize - try: - opts, args = getopt.getopt(args, 'blts:') - except getopt.error as msg: - sys.stderr.write('%s: %s\n%s' % (sys.argv[0], msg, usage)) - return 2 - for o, a in opts: - if o == '-l': - fnfilter = os.path.basename - elif o == '-b': - rmode = 'rb' - elif o == '-t': - rmode = 'r' - elif o == '-s': - bufsize = int(a) - if not args: - args = ['-'] - return sum(args, out) - -if __name__ == '__main__' or __name__ == sys.argv[0]: - sys.exit(main(sys.argv[1:], sys.stdout)) diff --git a/Tools/scripts/nm2def.py b/Tools/scripts/nm2def.py deleted file mode 100755 index a885ebd6fecc..000000000000 --- a/Tools/scripts/nm2def.py +++ /dev/null @@ -1,104 +0,0 @@ -#! /usr/bin/env python3 -"""nm2def.py - -Helpers to extract symbols from Unix libs and auto-generate -Windows definition files from them. Depends on nm(1). Tested -on Linux and Solaris only (-p option to nm is for Solaris only). - -By Marc-Andre Lemburg, Aug 1998. - -Additional notes: the output of nm is supposed to look like this: - -acceler.o: -000001fd T PyGrammar_AddAccelerators - U PyGrammar_FindDFA -00000237 T PyGrammar_RemoveAccelerators - U _IO_stderr_ - U exit - U fprintf - U free - U malloc - U printf - -grammar1.o: -00000000 T PyGrammar_FindDFA -00000034 T PyGrammar_LabelRepr - U _PyParser_TokenNames - U abort - U printf - U sprintf - -... - -Even if this isn't the default output of your nm, there is generally an -option to produce this format (since it is the original v7 Unix format). - -""" -import os, sys - -PYTHONLIB = 'libpython%d.%d.a' % sys.version_info[:2] -PC_PYTHONLIB = 'Python%d%d.dll' % sys.version_info[:2] -NM = 'nm -p -g %s' # For Linux, use "nm -g %s" - -def symbols(lib=PYTHONLIB,types=('T','C','D')): - - with os.popen(NM % lib) as pipe: - lines = pipe.readlines() - lines = [s.strip() for s in lines] - symbols = {} - for line in lines: - if len(line) == 0 or ':' in line: - continue - items = line.split() - if len(items) != 3: - continue - address, type, name = items - if type not in types: - continue - symbols[name] = address,type - return symbols - -def export_list(symbols): - - data = [] - code = [] - for name,(addr,type) in symbols.items(): - if type in ('C','D'): - data.append('\t'+name) - else: - code.append('\t'+name) - data.sort() - data.append('') - code.sort() - return ' DATA\n'.join(data)+'\n'+'\n'.join(code) - -# Definition file template -DEF_TEMPLATE = """\ -EXPORTS -%s -""" - -# Special symbols that have to be included even though they don't -# pass the filter -SPECIALS = ( - ) - -def filter_Python(symbols,specials=SPECIALS): - - for name in list(symbols.keys()): - if name[:2] == 'Py' or name[:3] == '_Py': - pass - elif name not in specials: - del symbols[name] - -def main(): - - s = symbols(PYTHONLIB) - filter_Python(s) - exports = export_list(s) - f = sys.stdout # open('PC/python_nt.def','w') - f.write(DEF_TEMPLATE % (exports)) - # f.close() - -if __name__ == '__main__': - main() diff --git a/Tools/scripts/pathfix.py b/Tools/scripts/pathfix.py deleted file mode 100755 index f957b1154717..000000000000 --- a/Tools/scripts/pathfix.py +++ /dev/null @@ -1,225 +0,0 @@ -#!/usr/bin/env python3 - -# Change the #! line (shebang) occurring in Python scripts. The new interpreter -# pathname must be given with a -i option. -# -# Command line arguments are files or directories to be processed. -# Directories are searched recursively for files whose name looks -# like a python module. -# Symbolic links are always ignored (except as explicit directory -# arguments). -# The original file is kept as a back-up (with a "~" attached to its name), -# -n flag can be used to disable this. - -# Sometimes you may find shebangs with flags such as `#! /usr/bin/env python -si`. -# Normally, pathfix overwrites the entire line, including the flags. -# To change interpreter and keep flags from the original shebang line, use -k. -# If you want to keep flags and add to them one single literal flag, use option -a. - - -# Undoubtedly you can do this using find and sed or perl, but this is -# a nice example of Python code that recurses down a directory tree -# and uses regular expressions. Also note several subtleties like -# preserving the file's mode and avoiding to even write a temp file -# when no changes are needed for a file. -# -# NB: by changing only the function fixfile() you can turn this -# into a program for a different change to Python programs... - -import sys -import os -from stat import * -import getopt - -err = sys.stderr.write -dbg = err -rep = sys.stdout.write - -new_interpreter = None -preserve_timestamps = False -create_backup = True -keep_flags = False -add_flags = b'' - - -def main(): - global new_interpreter - global preserve_timestamps - global create_backup - global keep_flags - global add_flags - - usage = ('usage: %s -i /interpreter -p -n -k -a file-or-directory ...\n' % - sys.argv[0]) - try: - opts, args = getopt.getopt(sys.argv[1:], 'i:a:kpn') - except getopt.error as msg: - err(str(msg) + '\n') - err(usage) - sys.exit(2) - for o, a in opts: - if o == '-i': - new_interpreter = a.encode() - if o == '-p': - preserve_timestamps = True - if o == '-n': - create_backup = False - if o == '-k': - keep_flags = True - if o == '-a': - add_flags = a.encode() - if b' ' in add_flags: - err("-a option doesn't support whitespaces") - sys.exit(2) - if not new_interpreter or not new_interpreter.startswith(b'/') or \ - not args: - err('-i option or file-or-directory missing\n') - err(usage) - sys.exit(2) - bad = 0 - for arg in args: - if os.path.isdir(arg): - if recursedown(arg): bad = 1 - elif os.path.islink(arg): - err(arg + ': will not process symbolic links\n') - bad = 1 - else: - if fix(arg): bad = 1 - sys.exit(bad) - - -def ispython(name): - return name.endswith('.py') - - -def recursedown(dirname): - dbg('recursedown(%r)\n' % (dirname,)) - bad = 0 - try: - names = os.listdir(dirname) - except OSError as msg: - err('%s: cannot list directory: %r\n' % (dirname, msg)) - return 1 - names.sort() - subdirs = [] - for name in names: - if name in (os.curdir, os.pardir): continue - fullname = os.path.join(dirname, name) - if os.path.islink(fullname): pass - elif os.path.isdir(fullname): - subdirs.append(fullname) - elif ispython(name): - if fix(fullname): bad = 1 - for fullname in subdirs: - if recursedown(fullname): bad = 1 - return bad - - -def fix(filename): -## dbg('fix(%r)\n' % (filename,)) - try: - f = open(filename, 'rb') - except IOError as msg: - err('%s: cannot open: %r\n' % (filename, msg)) - return 1 - with f: - line = f.readline() - fixed = fixline(line) - if line == fixed: - rep(filename+': no change\n') - return - head, tail = os.path.split(filename) - tempname = os.path.join(head, '@' + tail) - try: - g = open(tempname, 'wb') - except IOError as msg: - err('%s: cannot create: %r\n' % (tempname, msg)) - return 1 - with g: - rep(filename + ': updating\n') - g.write(fixed) - BUFSIZE = 8*1024 - while 1: - buf = f.read(BUFSIZE) - if not buf: break - g.write(buf) - - # Finishing touch -- move files - - mtime = None - atime = None - # First copy the file's mode to the temp file - try: - statbuf = os.stat(filename) - mtime = statbuf.st_mtime - atime = statbuf.st_atime - os.chmod(tempname, statbuf[ST_MODE] & 0o7777) - except OSError as msg: - err('%s: warning: chmod failed (%r)\n' % (tempname, msg)) - # Then make a backup of the original file as filename~ - if create_backup: - try: - os.rename(filename, filename + '~') - except OSError as msg: - err('%s: warning: backup failed (%r)\n' % (filename, msg)) - else: - try: - os.remove(filename) - except OSError as msg: - err('%s: warning: removing failed (%r)\n' % (filename, msg)) - # Now move the temp file to the original file - try: - os.rename(tempname, filename) - except OSError as msg: - err('%s: rename failed (%r)\n' % (filename, msg)) - return 1 - if preserve_timestamps: - if atime and mtime: - try: - os.utime(filename, (atime, mtime)) - except OSError as msg: - err('%s: reset of timestamp failed (%r)\n' % (filename, msg)) - return 1 - # Return success - return 0 - - -def parse_shebang(shebangline): - shebangline = shebangline.rstrip(b'\n') - start = shebangline.find(b' -') - if start == -1: - return b'' - return shebangline[start:] - - -def populate_flags(shebangline): - old_flags = b'' - if keep_flags: - old_flags = parse_shebang(shebangline) - if old_flags: - old_flags = old_flags[2:] - if not (old_flags or add_flags): - return b'' - # On Linux, the entire string following the interpreter name - # is passed as a single argument to the interpreter. - # e.g. "#! /usr/bin/python3 -W Error -s" runs "/usr/bin/python3 "-W Error -s" - # so shebang should have single '-' where flags are given and - # flag might need argument for that reasons adding new flags is - # between '-' and original flags - # e.g. #! /usr/bin/python3 -sW Error - return b' -' + add_flags + old_flags - - -def fixline(line): - if not line.startswith(b'#!'): - return line - - if b"python" not in line: - return line - - flags = populate_flags(line) - return b'#! ' + new_interpreter + flags + b'\n' - - -if __name__ == '__main__': - main() diff --git a/Tools/scripts/win_add2path.py b/Tools/scripts/win_add2path.py deleted file mode 100644 index 1c9aedc5ed8d..000000000000 --- a/Tools/scripts/win_add2path.py +++ /dev/null @@ -1,58 +0,0 @@ -"""Add Python to the search path on Windows - -This is a simple script to add Python to the Windows search path. It -modifies the current user (HKCU) tree of the registry. - -Copyright (c) 2008 by Christian Heimes -Licensed to PSF under a Contributor Agreement. -""" - -import sys -import site -import os -import winreg - -HKCU = winreg.HKEY_CURRENT_USER -ENV = "Environment" -PATH = "PATH" -DEFAULT = "%PATH%" - -def modify(): - pythonpath = os.path.dirname(os.path.normpath(sys.executable)) - scripts = os.path.join(pythonpath, "Scripts") - appdata = os.environ["APPDATA"] - if hasattr(site, "USER_SITE"): - usersite = site.USER_SITE.replace(appdata, "%APPDATA%") - userpath = os.path.dirname(usersite) - userscripts = os.path.join(userpath, "Scripts") - else: - userscripts = None - - with winreg.CreateKey(HKCU, ENV) as key: - try: - envpath = winreg.QueryValueEx(key, PATH)[0] - except OSError: - envpath = DEFAULT - - paths = [envpath] - for path in (pythonpath, scripts, userscripts): - if path and path not in envpath and os.path.isdir(path): - paths.append(path) - - envpath = os.pathsep.join(paths) - winreg.SetValueEx(key, PATH, 0, winreg.REG_EXPAND_SZ, envpath) - return paths, envpath - -def main(): - paths, envpath = modify() - if len(paths) > 1: - print("Path(s) added:") - print('\n'.join(paths[1:])) - else: - print("No path was added") - print("\nPATH is now:\n%s\n" % envpath) - print("Expanded:") - print(winreg.ExpandEnvironmentStrings(envpath)) - -if __name__ == '__main__': - main() From webhook-mailer at python.org Tue Oct 11 05:27:58 2022 From: webhook-mailer at python.org (nanjekyejoannah) Date: Tue, 11 Oct 2022 09:27:58 -0000 Subject: [Python-checkins] gh-71616: Add note to warn against general translation of saxutils.escape() (#93450) Message-ID: https://github.com/python/cpython/commit/f0a680007f345a46bcd187b952a929c7068c1da8 commit: f0a680007f345a46bcd187b952a929c7068c1da8 branch: main author: Stanley <46876382+slateny at users.noreply.github.com> committer: nanjekyejoannah <33177550+nanjekyejoannah at users.noreply.github.com> date: 2022-10-11T05:27:49-04:00 summary: gh-71616: Add note to warn against general translation of saxutils.escape() (#93450) * Add note to warn against general translation of saxutils.escape() * Use more direct wording files: M Doc/library/xml.sax.utils.rst diff --git a/Doc/library/xml.sax.utils.rst b/Doc/library/xml.sax.utils.rst index e46fefdf9975..ab4606bcf9fe 100644 --- a/Doc/library/xml.sax.utils.rst +++ b/Doc/library/xml.sax.utils.rst @@ -25,6 +25,11 @@ or as base classes. replaced with its corresponding value. The characters ``'&'``, ``'<'`` and ``'>'`` are always escaped, even if *entities* is provided. + .. note:: + + This function should only be used to escape characters that + can't be used directly in XML. Do not use this function as a general + string translation function. .. function:: unescape(data, entities={}) From webhook-mailer at python.org Tue Oct 11 07:19:24 2022 From: webhook-mailer at python.org (vstinner) Date: Tue, 11 Oct 2022 11:19:24 -0000 Subject: [Python-checkins] gh-97669: Remove abitype.py and pep384_macrocheck.py (#98165) Message-ID: https://github.com/python/cpython/commit/454a6d61bc569b45cad163601d745bb304b53bde commit: 454a6d61bc569b45cad163601d745bb304b53bde branch: main author: Victor Stinner committer: vstinner date: 2022-10-11T13:18:53+02:00 summary: gh-97669: Remove abitype.py and pep384_macrocheck.py (#98165) Remove abitype.py and pep384_macrocheck.py scripts of Tools/scripts/. files: D Tools/scripts/abitype.py D Tools/scripts/pep384_macrocheck.py M Tools/scripts/README diff --git a/Tools/scripts/README b/Tools/scripts/README index 2fcceccc075e..9943d4c42fc4 100644 --- a/Tools/scripts/README +++ b/Tools/scripts/README @@ -2,7 +2,6 @@ This directory contains a collection of executable Python scripts that are useful while building, extending or managing Python. 2to3 Main script for running the 2to3 conversion tool -abitype.py Converts a C file to use the PEP 384 type definition API combinerefs.py A helper for analyzing PYTHONDUMPREFS output idle3 Main program to start IDLE parse_html5_entities.py Utility for parsing HTML5 entity definitions diff --git a/Tools/scripts/abitype.py b/Tools/scripts/abitype.py deleted file mode 100755 index d6a74a1fe641..000000000000 --- a/Tools/scripts/abitype.py +++ /dev/null @@ -1,202 +0,0 @@ -#!/usr/bin/env python3 -# This script converts a C file to use the PEP 384 type definition API -# Usage: abitype.py < old_code > new_code -import re, sys - -###### Replacement of PyTypeObject static instances ############## - -# classify each token, giving it a one-letter code: -# S: static -# T: PyTypeObject -# I: ident -# W: whitespace -# =, {, }, ; : themselves -def classify(): - res = [] - for t,v in tokens: - if t == 'other' and v in "={};": - res.append(v) - elif t == 'ident': - if v == 'PyTypeObject': - res.append('T') - elif v == 'static': - res.append('S') - else: - res.append('I') - elif t == 'ws': - res.append('W') - else: - res.append('.') - return ''.join(res) - -# Obtain a list of fields of a PyTypeObject, in declaration order, -# skipping ob_base -# All comments are dropped from the variable (which are typically -# just the slot names, anyway), and information is discarded whether -# the original type was static. -def get_fields(start, real_end): - pos = start - # static? - if tokens[pos][1] == 'static': - pos += 2 - # PyTypeObject - pos += 2 - # name - name = tokens[pos][1] - pos += 1 - while tokens[pos][1] != '{': - pos += 1 - pos += 1 - # PyVarObject_HEAD_INIT - while tokens[pos][0] in ('ws', 'comment'): - pos += 1 - if tokens[pos][1] != 'PyVarObject_HEAD_INIT': - raise Exception('%s has no PyVarObject_HEAD_INIT' % name) - while tokens[pos][1] != ')': - pos += 1 - pos += 1 - # field definitions: various tokens, comma-separated - fields = [] - while True: - while tokens[pos][0] in ('ws', 'comment'): - pos += 1 - end = pos - while tokens[end][1] not in ',}': - if tokens[end][1] == '(': - nesting = 1 - while nesting: - end += 1 - if tokens[end][1] == '(': nesting+=1 - if tokens[end][1] == ')': nesting-=1 - end += 1 - assert end < real_end - # join field, excluding separator and trailing ws - end1 = end-1 - while tokens[end1][0] in ('ws', 'comment'): - end1 -= 1 - fields.append(''.join(t[1] for t in tokens[pos:end1+1])) - if tokens[end][1] == '}': - break - pos = end+1 - return name, fields - -# List of type slots as of Python 3.2, omitting ob_base -typeslots = [ - 'tp_name', - 'tp_basicsize', - 'tp_itemsize', - 'tp_dealloc', - 'tp_print', - 'tp_getattr', - 'tp_setattr', - 'tp_reserved', - 'tp_repr', - 'tp_as_number', - 'tp_as_sequence', - 'tp_as_mapping', - 'tp_hash', - 'tp_call', - 'tp_str', - 'tp_getattro', - 'tp_setattro', - 'tp_as_buffer', - 'tp_flags', - 'tp_doc', - 'tp_traverse', - 'tp_clear', - 'tp_richcompare', - 'tp_weaklistoffset', - 'tp_iter', - 'iternextfunc', - 'tp_methods', - 'tp_members', - 'tp_getset', - 'tp_base', - 'tp_dict', - 'tp_descr_get', - 'tp_descr_set', - 'tp_dictoffset', - 'tp_init', - 'tp_alloc', - 'tp_new', - 'tp_free', - 'tp_is_gc', - 'tp_bases', - 'tp_mro', - 'tp_cache', - 'tp_subclasses', - 'tp_weaklist', - 'tp_del', - 'tp_version_tag', -] - -# Generate a PyType_Spec definition -def make_slots(name, fields): - res = [] - res.append('static PyType_Slot %s_slots[] = {' % name) - # defaults for spec - spec = { 'tp_itemsize':'0' } - for i, val in enumerate(fields): - if val.endswith('0'): - continue - if typeslots[i] in ('tp_name', 'tp_doc', 'tp_basicsize', - 'tp_itemsize', 'tp_flags'): - spec[typeslots[i]] = val - continue - res.append(' {Py_%s, %s},' % (typeslots[i], val)) - res.append('};') - res.append('static PyType_Spec %s_spec = {' % name) - res.append(' %s,' % spec['tp_name']) - res.append(' %s,' % spec['tp_basicsize']) - res.append(' %s,' % spec['tp_itemsize']) - res.append(' %s,' % spec['tp_flags']) - res.append(' %s_slots,' % name) - res.append('};\n') - return '\n'.join(res) - - -if __name__ == '__main__': - - ############ Simplistic C scanner ################################## - tokenizer = re.compile( - r"(?P#.*\n)" - r"|(?P/\*.*?\*/)" - r"|(?P[a-zA-Z_][a-zA-Z0-9_]*)" - r"|(?P[ \t\n]+)" - r"|(?P.)", - re.MULTILINE) - - tokens = [] - source = sys.stdin.read() - pos = 0 - while pos != len(source): - m = tokenizer.match(source, pos) - tokens.append([m.lastgroup, m.group()]) - pos += len(tokens[-1][1]) - if tokens[-1][0] == 'preproc': - # continuation lines are considered - # only in preprocess statements - while tokens[-1][1].endswith('\\\n'): - nl = source.find('\n', pos) - if nl == -1: - line = source[pos:] - else: - line = source[pos:nl+1] - tokens[-1][1] += line - pos += len(line) - - # Main loop: replace all static PyTypeObjects until - # there are none left. - while 1: - c = classify() - m = re.search('(SW)?TWIW?=W?{.*?};', c) - if not m: - break - start = m.start() - end = m.end() - name, fields = get_fields(start, end) - tokens[start:end] = [('',make_slots(name, fields))] - - # Output result to stdout - for t, v in tokens: - sys.stdout.write(v) diff --git a/Tools/scripts/pep384_macrocheck.py b/Tools/scripts/pep384_macrocheck.py deleted file mode 100644 index ab9dd7c972aa..000000000000 --- a/Tools/scripts/pep384_macrocheck.py +++ /dev/null @@ -1,148 +0,0 @@ -""" -pep384_macrocheck.py - -This program tries to locate errors in the relevant Python header -files where macros access type fields when they are reachable from -the limited API. - -The idea is to search macros with the string "->tp_" in it. -When the macro name does not begin with an underscore, -then we have found a dormant error. - -Christian Tismer -2018-06-02 -""" - -import sys -import os -import re - - -DEBUG = False - -def dprint(*args, **kw): - if DEBUG: - print(*args, **kw) - -def parse_headerfiles(startpath): - """ - Scan all header files which are reachable fronm Python.h - """ - search = "Python.h" - name = os.path.join(startpath, search) - if not os.path.exists(name): - raise ValueError("file {} was not found in {}\n" - "Please give the path to Python's include directory." - .format(search, startpath)) - errors = 0 - with open(name) as python_h: - while True: - line = python_h.readline() - if not line: - break - found = re.match(r'^\s*#\s*include\s*"(\w+\.h)"', line) - if not found: - continue - include = found.group(1) - dprint("Scanning", include) - name = os.path.join(startpath, include) - if not os.path.exists(name): - name = os.path.join(startpath, "../PC", include) - errors += parse_file(name) - return errors - -def ifdef_level_gen(): - """ - Scan lines for #ifdef and track the level. - """ - level = 0 - ifdef_pattern = r"^\s*#\s*if" # covers ifdef and ifndef as well - endif_pattern = r"^\s*#\s*endif" - while True: - line = yield level - if re.match(ifdef_pattern, line): - level += 1 - elif re.match(endif_pattern, line): - level -= 1 - -def limited_gen(): - """ - Scan lines for Py_LIMITED_API yes(1) no(-1) or nothing (0) - """ - limited = [0] # nothing - unlimited_pattern = r"^\s*#\s*ifndef\s+Py_LIMITED_API" - limited_pattern = "|".join([ - r"^\s*#\s*ifdef\s+Py_LIMITED_API", - r"^\s*#\s*(el)?if\s+!\s*defined\s*\(\s*Py_LIMITED_API\s*\)\s*\|\|", - r"^\s*#\s*(el)?if\s+defined\s*\(\s*Py_LIMITED_API" - ]) - else_pattern = r"^\s*#\s*else" - ifdef_level = ifdef_level_gen() - status = next(ifdef_level) - wait_for = -1 - while True: - line = yield limited[-1] - new_status = ifdef_level.send(line) - dir = new_status - status - status = new_status - if dir == 1: - if re.match(unlimited_pattern, line): - limited.append(-1) - wait_for = status - 1 - elif re.match(limited_pattern, line): - limited.append(1) - wait_for = status - 1 - elif dir == -1: - # this must have been an endif - if status == wait_for: - limited.pop() - wait_for = -1 - else: - # it could be that we have an elif - if re.match(limited_pattern, line): - limited.append(1) - wait_for = status - 1 - elif re.match(else_pattern, line): - limited.append(-limited.pop()) # negate top - -def parse_file(fname): - errors = 0 - with open(fname) as f: - lines = f.readlines() - type_pattern = r"^.*?->\s*tp_" - define_pattern = r"^\s*#\s*define\s+(\w+)" - limited = limited_gen() - status = next(limited) - for nr, line in enumerate(lines): - status = limited.send(line) - line = line.rstrip() - dprint(fname, nr, status, line) - if status != -1: - if re.match(define_pattern, line): - name = re.match(define_pattern, line).group(1) - if not name.startswith("_"): - # found a candidate, check it! - macro = line + "\n" - idx = nr - while line.endswith("\\"): - idx += 1 - line = lines[idx].rstrip() - macro += line + "\n" - if re.match(type_pattern, macro, re.DOTALL): - # this type field can reach the limited API - report(fname, nr + 1, macro) - errors += 1 - return errors - -def report(fname, nr, macro): - f = sys.stderr - print(fname + ":" + str(nr), file=f) - print(macro, file=f) - -if __name__ == "__main__": - p = sys.argv[1] if sys.argv[1:] else "../../Include" - errors = parse_headerfiles(p) - if errors: - # somehow it makes sense to raise a TypeError :-) - raise TypeError("These {} locations contradict the limited API." - .format(errors)) From webhook-mailer at python.org Tue Oct 11 09:15:26 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 11 Oct 2022 13:15:26 -0000 Subject: [Python-checkins] Upgrade ccache-action to one using Node 16 (#98166) Message-ID: https://github.com/python/cpython/commit/ad8e297b7297dfdc34fad53b589b31d0920150ab commit: ad8e297b7297dfdc34fad53b589b31d0920150ab branch: main author: Michael Droettboom committer: ambv date: 2022-10-11T15:15:14+02:00 summary: Upgrade ccache-action to one using Node 16 (#98166) Github Actions has deprecated the use of Node 12, and will be turning it off by summer 2023. https://github.blog/changelog/2022-09-22-github-actions-all-actions-will-begin-running-on-node16-instead-of-node12/ files: M .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8f5676eec08e..f782d394a57b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -73,7 +73,7 @@ jobs: - name: Add ccache to PATH run: echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV - name: Configure ccache action - uses: hendrikmuhs/ccache-action at v1 + uses: hendrikmuhs/ccache-action at v1.2 - name: Check Autoconf version 2.69 and aclocal 1.16.3 run: | grep "Generated by GNU Autoconf 2.69" configure @@ -202,7 +202,7 @@ jobs: run: | echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV - name: Configure ccache action - uses: hendrikmuhs/ccache-action at v1 + uses: hendrikmuhs/ccache-action at v1.2 - name: Setup directory envs for out-of-tree builds run: | echo "CPYTHON_RO_SRCDIR=$(realpath -m ${GITHUB_WORKSPACE}/../cpython-ro-srcdir)" >> $GITHUB_ENV @@ -265,7 +265,7 @@ jobs: run: | echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV - name: Configure ccache action - uses: hendrikmuhs/ccache-action at v1 + uses: hendrikmuhs/ccache-action at v1.2 - name: Configure CPython run: ./configure --with-pydebug --with-openssl=$OPENSSL_DIR - name: Build CPython @@ -309,7 +309,7 @@ jobs: run: | echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV - name: Configure ccache action - uses: hendrikmuhs/ccache-action at v1 + uses: hendrikmuhs/ccache-action at v1.2 - name: Configure CPython run: ./configure --with-address-sanitizer --without-pymalloc - name: Build CPython From webhook-mailer at python.org Tue Oct 11 09:32:04 2022 From: webhook-mailer at python.org (JulienPalard) Date: Tue, 11 Oct 2022 13:32:04 -0000 Subject: [Python-checkins] gh-86404: Doc: Drop now unused make suspicious and rstlint. (GH-98179) Message-ID: https://github.com/python/cpython/commit/4067c6d7fe9b0b266367aafa8cde71e2761cb764 commit: 4067c6d7fe9b0b266367aafa8cde71e2761cb764 branch: main author: Julien Palard committer: JulienPalard date: 2022-10-11T15:31:33+02:00 summary: gh-86404: Doc: Drop now unused make suspicious and rstlint. (GH-98179) They have been replaced by [sphinx-lint](https://github.com/sphinx-contrib/sphinx-lint). files: A Misc/NEWS.d/next/Documentation/2022-10-11-09-40-50.gh-issue-86404.dEAb8W.rst D Doc/tools/extensions/suspicious.py D Doc/tools/rstlint.py D Doc/tools/susp-ignored.csv M Doc/Makefile M Doc/README.rst M Doc/make.bat M Doc/tools/extensions/pyspecific.py M Doc/whatsnew/3.12.rst diff --git a/Doc/Makefile b/Doc/Makefile index 5b6a95813abe..f52087409a04 100644 --- a/Doc/Makefile +++ b/Doc/Makefile @@ -22,7 +22,7 @@ ALLSPHINXOPTS = -b $(BUILDER) -d build/doctrees $(PAPEROPT_$(PAPER)) -j auto \ $(SPHINXOPTS) $(SPHINXERRORHANDLING) . build/$(BUILDER) $(SOURCES) .PHONY: help build html htmlhelp latex text texinfo changes linkcheck \ - suspicious coverage doctest pydoc-topics htmlview clean dist check serve \ + coverage doctest pydoc-topics htmlview clean dist check serve \ autobuild-dev autobuild-stable venv help: @@ -42,7 +42,6 @@ help: @echo " doctest to run doctests in the documentation" @echo " pydoc-topics to regenerate the pydoc topics file" @echo " dist to create a \"dist\" directory with archived docs for download" - @echo " suspicious to check for suspicious markup in output text" @echo " check to run a check for frequent markup errors" build: @@ -110,18 +109,6 @@ linkcheck: "or in build/$(BUILDER)/output.txt"; \ false; } -suspicious: BUILDER = suspicious -suspicious: - @$(MAKE) build BUILDER=$(BUILDER) || { \ - echo "Suspicious check complete; look for any errors in the above output" \ - "or in build/$(BUILDER)/suspicious.csv. If all issues are false" \ - "positives, append that file to tools/susp-ignored.csv."; \ - false; } - @echo "? make suspicious is deprecated and will be removed soon." - @echo "? Use:" - @echo "? make check" - @echo "? instead." - coverage: BUILDER = coverage coverage: build @echo "Coverage finished; see c.txt and python.txt in build/coverage" diff --git a/Doc/README.rst b/Doc/README.rst index d67cad79916b..a3bb5fa5445c 100644 --- a/Doc/README.rst +++ b/Doc/README.rst @@ -93,9 +93,6 @@ Available make targets are: plain text documentation for the labels defined in ``tools/pyspecific.py`` -- pydoc needs these to show topic and keyword help. -* "suspicious", which checks the parsed markup for text that looks like - malformed and thus unconverted reST. - * "check", which checks for frequent markup errors. * "serve", which serves the build/html directory on port 8000. diff --git a/Doc/make.bat b/Doc/make.bat index 4f0b3c11f4fa..87d8359ef112 100644 --- a/Doc/make.bat +++ b/Doc/make.bat @@ -109,7 +109,7 @@ echo.always available include: echo. echo. Provided by Sphinx: echo. html, htmlhelp, latex, text -echo. suspicious, linkcheck, changes, doctest +echo. linkcheck, changes, doctest echo. Provided by this script: echo. clean, check, htmlview echo. diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py index 8c3aa47ad1c7..3b9f7442f75b 100644 --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -37,10 +37,6 @@ from sphinx.domains.python import PyClassmember as PyMethod from sphinx.domains.python import PyModulelevel as PyFunction -# Support for checking for suspicious markup - -import suspicious - ISSUE_URI = 'https://bugs.python.org/issue?@action=redirect&bpo=%s' GH_ISSUE_URI = 'https://github.com/python/cpython/issues/%s' @@ -686,7 +682,6 @@ def setup(app): app.add_directive('audit-event-table', AuditEventListDirective) app.add_directive('deprecated-removed', DeprecatedRemoved) app.add_builder(PydocTopicsBuilder) - app.add_builder(suspicious.CheckSuspiciousMarkupBuilder) app.add_object_type('opcode', 'opcode', '%s (opcode)', parse_opcode_signature) app.add_object_type('pdbcommand', 'pdbcmd', '%s (pdb command)', parse_pdb_command) app.add_object_type('2to3fixer', '2to3fixer', '%s (2to3 fixer)') diff --git a/Doc/tools/extensions/suspicious.py b/Doc/tools/extensions/suspicious.py deleted file mode 100644 index 2d581a8a6c3d..000000000000 --- a/Doc/tools/extensions/suspicious.py +++ /dev/null @@ -1,251 +0,0 @@ -""" -Try to detect suspicious constructs, resembling markup -that has leaked into the final output. - -Suspicious lines are reported in a comma-separated-file, -``suspicious.csv``, located in the output directory. - -The file is utf-8 encoded, and each line contains four fields: - - * document name (normalized) - * line number in the source document - * problematic text - * complete line showing the problematic text in context - -It is common to find many false positives. To avoid reporting them -again and again, they may be added to the ``ignored.csv`` file -(located in the configuration directory). The file has the same -format as ``suspicious.csv`` with a few differences: - - - each line defines a rule; if the rule matches, the issue - is ignored. - - line number may be empty (that is, nothing between the - commas: ",,"). In this case, line numbers are ignored (the - rule matches anywhere in the file). - - the last field does not have to be a complete line; some - surrounding text (never more than a line) is enough for - context. - -Rules are processed sequentially. A rule matches when: - - * document names are the same - * problematic texts are the same - * line numbers are close to each other (5 lines up or down) - * the rule text is completely contained into the source line - -The simplest way to create the ignored.csv file is by copying -undesired entries from suspicious.csv (possibly trimming the last -field.) - -Copyright 2009 Gabriel A. Genellina - -""" - -import os -import re -import csv - -from docutils import nodes -from sphinx.builders import Builder -import sphinx.util - -detect_all = re.compile(r''' - ::(?=[^=])| # two :: (but NOT ::=) - :[a-zA-Z][a-zA-Z0-9]+| # :foo - `| # ` (seldom used by itself) - (? don't care - self.issue = issue # the markup fragment that triggered this rule - self.line = line # text of the container element (single line only) - self.used = False - - def __repr__(self): - return '{0.docname},,{0.issue},{0.line}'.format(self) - - - -class dialect(csv.excel): - """Our dialect: uses only linefeed as newline.""" - lineterminator = '\n' - - -class CheckSuspiciousMarkupBuilder(Builder): - """ - Checks for possibly invalid markup that may leak into the output. - """ - name = 'suspicious' - logger = sphinx.util.logging.getLogger("CheckSuspiciousMarkupBuilder") - - def init(self): - # create output file - self.log_file_name = os.path.join(self.outdir, 'suspicious.csv') - open(self.log_file_name, 'w').close() - # load database of previously ignored issues - self.load_rules(os.path.join(os.path.dirname(__file__), '..', - 'susp-ignored.csv')) - - def get_outdated_docs(self): - return self.env.found_docs - - def get_target_uri(self, docname, typ=None): - return '' - - def prepare_writing(self, docnames): - pass - - def write_doc(self, docname, doctree): - # set when any issue is encountered in this document - self.any_issue = False - self.docname = docname - visitor = SuspiciousVisitor(doctree, self) - doctree.walk(visitor) - - def finish(self): - unused_rules = [rule for rule in self.rules if not rule.used] - if unused_rules: - self.logger.warning( - 'Found %s/%s unused rules: %s' % ( - len(unused_rules), len(self.rules), - '\n'.join(repr(rule) for rule in unused_rules), - ) - ) - return - - def check_issue(self, line, lineno, issue): - if not self.is_ignored(line, lineno, issue): - self.report_issue(line, lineno, issue) - - def is_ignored(self, line, lineno, issue): - """Determine whether this issue should be ignored.""" - docname = self.docname - for rule in self.rules: - if rule.docname != docname: continue - if rule.issue != issue: continue - # Both lines must match *exactly*. This is rather strict, - # and probably should be improved. - # Doing fuzzy matches with levenshtein distance could work, - # but that means bringing other libraries... - # Ok, relax that requirement: just check if the rule fragment - # is contained in the document line - if rule.line not in line: continue - # Check both line numbers. If they're "near" - # this rule matches. (lineno=None means "don't care") - if (rule.lineno is not None) and \ - abs(rule.lineno - lineno) > 5: continue - # if it came this far, the rule matched - rule.used = True - return True - return False - - def report_issue(self, text, lineno, issue): - self.any_issue = True - self.write_log_entry(lineno, issue, text) - self.logger.warning('[%s:%d] "%s" found in "%-.120s"' % - (self.docname, lineno, issue, text)) - self.app.statuscode = 1 - - def write_log_entry(self, lineno, issue, text): - f = open(self.log_file_name, 'a') - writer = csv.writer(f, dialect) - writer.writerow([self.docname, lineno, issue, text.strip()]) - f.close() - - def load_rules(self, filename): - """Load database of previously ignored issues. - - A csv file, with exactly the same format as suspicious.csv - Fields: document name (normalized), line number, issue, surrounding text - """ - self.logger.info("loading ignore rules... ", nonl=1) - self.rules = rules = [] - try: - f = open(filename, 'r') - except IOError: - return - for i, row in enumerate(csv.reader(f)): - if len(row) != 4: - raise ValueError( - "wrong format in %s, line %d: %s" % (filename, i+1, row)) - docname, lineno, issue, text = row - if lineno: - lineno = int(lineno) - else: - lineno = None - rule = Rule(docname, lineno, issue, text) - rules.append(rule) - f.close() - self.logger.info('done, %d rules loaded' % len(self.rules)) - - -def get_lineno(node): - """Obtain line number information for a node.""" - lineno = None - while lineno is None and node: - node = node.parent - lineno = node.line - return lineno - - -def extract_line(text, index): - """text may be a multiline string; extract - only the line containing the given character index. - - >>> extract_line("abc\ndefgh\ni", 6) - >>> 'defgh' - >>> for i in (0, 2, 3, 4, 10): - ... print extract_line("abc\ndefgh\ni", i) - abc - abc - abc - defgh - defgh - i - """ - p = text.rfind('\n', 0, index) + 1 - q = text.find('\n', index) - if q < 0: - q = len(text) - return text[p:q] - - -class SuspiciousVisitor(nodes.GenericNodeVisitor): - - lastlineno = 0 - - def __init__(self, document, builder): - nodes.GenericNodeVisitor.__init__(self, document) - self.builder = builder - - def default_visit(self, node): - if isinstance(node, (nodes.Text, nodes.image)): # direct text containers - text = node.astext() - # lineno seems to go backwards sometimes (?) - self.lastlineno = lineno = max(get_lineno(node) or 0, self.lastlineno) - seen = set() # don't report the same issue more than only once per line - for match in detect_all(text): - issue = match.group() - line = extract_line(text, match.start()) - if (issue, line) not in seen: - self.builder.check_issue(line, lineno, issue) - seen.add((issue, line)) - - unknown_visit = default_visit - - def visit_document(self, node): - self.lastlineno = 0 - - def visit_comment(self, node): - # ignore comments -- too much false positives. - # (although doing this could miss some errors; - # there were two sections "commented-out" by mistake - # in the Python docs that would not be caught) - raise nodes.SkipNode diff --git a/Doc/tools/rstlint.py b/Doc/tools/rstlint.py deleted file mode 100644 index 4ea68ef3b030..000000000000 --- a/Doc/tools/rstlint.py +++ /dev/null @@ -1,408 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -# Check for stylistic and formal issues in .rst and .py -# files included in the documentation. -# -# 01/2009, Georg Brandl - -# TODO: - wrong versions in versionadded/changed -# - wrong markup after versionchanged directive - -import os -import re -import sys -import getopt -from string import ascii_letters -from os.path import join, splitext, abspath, exists -from collections import defaultdict - -directives = [ - # standard docutils ones - 'admonition', 'attention', 'caution', 'class', 'compound', 'container', - 'contents', 'csv-table', 'danger', 'date', 'default-role', 'epigraph', - 'error', 'figure', 'footer', 'header', 'highlights', 'hint', 'image', - 'important', 'include', 'line-block', 'list-table', 'meta', 'note', - 'parsed-literal', 'pull-quote', 'raw', 'replace', - 'restructuredtext-test-directive', 'role', 'rubric', 'sectnum', 'sidebar', - 'table', 'target-notes', 'tip', 'title', 'topic', 'unicode', 'warning', - # Sphinx and Python docs custom ones - 'acks', 'attribute', 'autoattribute', 'autoclass', 'autodata', - 'autoexception', 'autofunction', 'automethod', 'automodule', - 'availability', 'centered', 'cfunction', 'class', 'classmethod', 'cmacro', - 'cmdoption', 'cmember', 'code-block', 'confval', 'cssclass', 'ctype', - 'currentmodule', 'cvar', 'data', 'decorator', 'decoratormethod', - 'deprecated-removed', 'deprecated(?!-removed)', 'describe', 'directive', - 'doctest', 'envvar', 'event', 'exception', 'function', 'glossary', - 'highlight', 'highlightlang', 'impl-detail', 'index', 'literalinclude', - 'method', 'miscnews', 'module', 'moduleauthor', 'opcode', 'pdbcommand', - 'productionlist', 'program', 'role', 'sectionauthor', 'seealso', - 'sourcecode', 'staticmethod', 'tabularcolumns', 'testcode', 'testoutput', - 'testsetup', 'toctree', 'todo', 'todolist', 'versionadded', - 'versionchanged' -] - -roles = [ - "(? 81: - # don't complain about tables, links and function signatures - if line.lstrip()[0] not in '+|' and \ - 'http://' not in line and \ - not line.lstrip().startswith(('.. function', - '.. method', - '.. cfunction')): - yield lno+1, "line too long" - - - at checker('.html', severity=2, falsepositives=True) -def check_leaked_markup(fn, lines): - """Check HTML files for leaked reST markup; this only works if - the HTML files have been built. - """ - for lno, line in enumerate(lines): - if leaked_markup_re.search(line): - yield lno+1, 'possibly leaked markup: %r' % line - - -def hide_literal_blocks(lines): - """Tool to remove literal blocks from given lines. - - It yields empty lines in place of blocks, so line numbers are - still meaningful. - """ - in_block = False - for line in lines: - if line.endswith("::\n"): - in_block = True - elif in_block: - if line == "\n" or line.startswith(" "): - line = "\n" - else: - in_block = False - yield line - - -def type_of_explicit_markup(line): - if re.match(fr'\.\. {all_directives}::', line): - return 'directive' - if re.match(r'\.\. \[[0-9]+\] ', line): - return 'footnote' - if re.match(r'\.\. \[[^\]]+\] ', line): - return 'citation' - if re.match(r'\.\. _.*[^_]: ', line): - return 'target' - if re.match(r'\.\. \|[^\|]*\| ', line): - return 'substitution_definition' - return 'comment' - - -def hide_comments(lines): - """Tool to remove comments from given lines. - - It yields empty lines in place of comments, so line numbers are - still meaningful. - """ - in_multiline_comment = False - for line in lines: - if line == "..\n": - in_multiline_comment = True - elif in_multiline_comment: - if line == "\n" or line.startswith(" "): - line = "\n" - else: - in_multiline_comment = False - if line.startswith(".. ") and type_of_explicit_markup(line) == 'comment': - line = "\n" - yield line - - - - at checker(".rst", severity=2) -def check_missing_surrogate_space_on_plural(fn, lines): - r"""Check for missing 'backslash-space' between a code sample a letter. - - Good: ``Point``\ s - Bad: ``Point``s - """ - in_code_sample = False - check_next_one = False - for lno, line in enumerate(hide_comments(hide_literal_blocks(lines))): - tokens = line.split("``") - for token_no, token in enumerate(tokens): - if check_next_one: - if token[0] in ascii_letters: - yield lno + 1, f"Missing backslash-space between code sample and {token!r}." - check_next_one = False - if token_no == len(tokens) - 1: - continue - if in_code_sample: - check_next_one = True - in_code_sample = not in_code_sample - -def main(argv): - usage = '''\ -Usage: %s [-v] [-f] [-s sev] [-i path]* [path] - -Options: -v verbose (print all checked file names) - -f enable checkers that yield many false positives - -s sev only show problems with severity >= sev - -i path ignore subdir or file path -''' % argv[0] - try: - gopts, args = getopt.getopt(argv[1:], 'vfs:i:') - except getopt.GetoptError: - print(usage) - return 2 - - verbose = False - severity = 1 - ignore = [] - falsepos = False - for opt, val in gopts: - if opt == '-v': - verbose = True - elif opt == '-f': - falsepos = True - elif opt == '-s': - severity = int(val) - elif opt == '-i': - ignore.append(abspath(val)) - - if len(args) == 0: - path = '.' - elif len(args) == 1: - path = args[0] - else: - print(usage) - return 2 - - if not exists(path): - print('Error: path %s does not exist' % path) - return 2 - - count = defaultdict(int) - - print("""? rstlint.py is no longer maintained here and will be removed -? in a future release. -? Please use https://pypi.org/p/sphinx-lint instead. -""") - - for root, dirs, files in os.walk(path): - # ignore subdirs in ignore list - if abspath(root) in ignore: - del dirs[:] - continue - - for fn in files: - fn = join(root, fn) - if fn[:2] == './': - fn = fn[2:] - - # ignore files in ignore list - if abspath(fn) in ignore: - continue - - ext = splitext(fn)[1] - checkerlist = checkers.get(ext, None) - if not checkerlist: - continue - - if verbose: - print('Checking %s...' % fn) - - try: - with open(fn, 'r', encoding='utf-8') as f: - lines = list(f) - except (IOError, OSError) as err: - print('%s: cannot open: %s' % (fn, err)) - count[4] += 1 - continue - - for checker in checkerlist: - if checker.falsepositives and not falsepos: - continue - csev = checker.severity - if csev >= severity: - for lno, msg in checker(fn, lines): - print('[%d] %s:%d: %s' % (csev, fn, lno, msg)) - count[csev] += 1 - if verbose: - print() - if not count: - if severity > 1: - print('No problems with severity >= %d found.' % severity) - else: - print('No problems found.') - else: - for severity in sorted(count): - number = count[severity] - print('%d problem%s with severity %d found.' % - (number, number > 1 and 's' or '', severity)) - return int(bool(count)) - - -if __name__ == '__main__': - sys.exit(main(sys.argv)) diff --git a/Doc/tools/susp-ignored.csv b/Doc/tools/susp-ignored.csv deleted file mode 100644 index 0dba0744b5fe..000000000000 --- a/Doc/tools/susp-ignored.csv +++ /dev/null @@ -1,400 +0,0 @@ -c-api/arg,,:ref,"PyArg_ParseTuple(args, ""O|O:ref"", &object, &callback)" -c-api/list,,:high,list[low:high] -c-api/sequence,,:i2,del o[i1:i2] -c-api/sequence,,:i2,o[i1:i2] -c-api/tuple,,:high,p[low:high] -c-api/unicode,,:end,str[start:end] -c-api/unicode,,:start,unicode[start:start+length] -distutils/examples,,`,This is the description of the ``foobar`` package. -distutils/setupscript,,::, -extending/embedding,,:numargs,"if(!PyArg_ParseTuple(args, "":numargs""))" -extending/extending,,:myfunction,"PyArg_ParseTuple(args, ""D:myfunction"", &c);" -extending/extending,,:set,"if (PyArg_ParseTuple(args, ""O:set_callback"", &temp)) {" -extending/newtypes,,:call,"if (!PyArg_ParseTuple(args, ""sss:call"", &arg1, &arg2, &arg3)) {" -faq/programming,,:chr,">=4.0) or 1+f(xc,yc,x*x-y*y+xc,2.0*x*y+yc,k-1,f):f(xc,yc,x,y,k,f):chr(" -faq/programming,,:reduce,"print((lambda Ru,Ro,Iu,Io,IM,Sx,Sy:reduce(lambda x,y:x+y,map(lambda y," -faq/programming,,:reduce,"Sx=Sx,Sy=Sy:reduce(lambda x,y:x+y,map(lambda x,xc=Ru,yc=yc,Ru=Ru,Ro=Ro," -faq/windows,,:d48eceb,"Python 3.6.4 (v3.6.4:d48eceb, Dec 19 2017, 06:04:45) [MSC v.1900 32 bit (Intel)] on win32" -howto/curses,,:black,"colors when it activates color mode. They are: 0:black, 1:red," -howto/curses,,:red,"colors when it activates color mode. They are: 0:black, 1:red," -howto/curses,,:green,"2:green, 3:yellow, 4:blue, 5:magenta, 6:cyan, and 7:white. The" -howto/curses,,:yellow,"2:green, 3:yellow, 4:blue, 5:magenta, 6:cyan, and 7:white. The" -howto/curses,,:blue,"2:green, 3:yellow, 4:blue, 5:magenta, 6:cyan, and 7:white. The" -howto/curses,,:magenta,"2:green, 3:yellow, 4:blue, 5:magenta, 6:cyan, and 7:white. The" -howto/curses,,:cyan,"2:green, 3:yellow, 4:blue, 5:magenta, 6:cyan, and 7:white. The" -howto/curses,,:white,"2:green, 3:yellow, 4:blue, 5:magenta, 6:cyan, and 7:white. The" -howto/descriptor,,:root,"INFO:root" -howto/descriptor,,:Updating,"root:Updating" -howto/descriptor,,:Accessing,"root:Accessing" -howto/instrumentation,,::,python$target:::function-entry -howto/instrumentation,,:function,python$target:::function-entry -howto/instrumentation,,::,python$target:::function-return -howto/instrumentation,,:function,python$target:::function-return -howto/instrumentation,,:call,156641360502280 function-entry:call_stack.py:start:23 -howto/instrumentation,,:start,156641360502280 function-entry:call_stack.py:start:23 -howto/instrumentation,,:function,156641360518804 function-entry: call_stack.py:function_1:1 -howto/instrumentation,,:function,156641360532797 function-entry: call_stack.py:function_3:9 -howto/instrumentation,,:function,156641360546807 function-return: call_stack.py:function_3:10 -howto/instrumentation,,:function,156641360563367 function-return: call_stack.py:function_1:2 -howto/instrumentation,,:function,156641360578365 function-entry: call_stack.py:function_2:5 -howto/instrumentation,,:function,156641360591757 function-entry: call_stack.py:function_1:1 -howto/instrumentation,,:function,156641360605556 function-entry: call_stack.py:function_3:9 -howto/instrumentation,,:function,156641360617482 function-return: call_stack.py:function_3:10 -howto/instrumentation,,:function,156641360629814 function-return: call_stack.py:function_1:2 -howto/instrumentation,,:function,156641360642285 function-return: call_stack.py:function_2:6 -howto/instrumentation,,:function,156641360656770 function-entry: call_stack.py:function_3:9 -howto/instrumentation,,:function,156641360669707 function-return: call_stack.py:function_3:10 -howto/instrumentation,,:function,156641360687853 function-entry: call_stack.py:function_4:13 -howto/instrumentation,,:function,156641360700719 function-return: call_stack.py:function_4:14 -howto/instrumentation,,:function,156641360719640 function-entry: call_stack.py:function_5:18 -howto/instrumentation,,:function,156641360732567 function-return: call_stack.py:function_5:21 -howto/instrumentation,,:call,156641360747370 function-return:call_stack.py:start:28 -howto/instrumentation,,:start,156641360747370 function-return:call_stack.py:start:28 -howto/ipaddress,,:DB8,>>> ipaddress.ip_address('2001:DB8::1') -howto/ipaddress,,::,>>> ipaddress.ip_address('2001:DB8::1') -howto/ipaddress,,:db8,IPv6Address('2001:db8::1') -howto/ipaddress,,::,IPv6Address('2001:db8::1') -howto/ipaddress,,::,IPv6Address('::1') -howto/ipaddress,,:db8,>>> ipaddress.ip_network('2001:db8::0/96') -howto/ipaddress,,::,>>> ipaddress.ip_network('2001:db8::0/96') -howto/ipaddress,,:db8,IPv6Network('2001:db8::/96') -howto/ipaddress,,::,IPv6Network('2001:db8::/96') -howto/ipaddress,,:db8,IPv6Network('2001:db8::/128') -howto/ipaddress,,::,IPv6Network('2001:db8::/128') -howto/ipaddress,,:db8,IPv6Interface('2001:db8::1/96') -howto/ipaddress,,::,IPv6Interface('2001:db8::1/96') -howto/ipaddress,,:db8,>>> addr6 = ipaddress.ip_address('2001:db8::1') -howto/ipaddress,,::,>>> addr6 = ipaddress.ip_address('2001:db8::1') -howto/ipaddress,,:db8,>>> host6 = ipaddress.ip_interface('2001:db8::1/96') -howto/ipaddress,,::,>>> host6 = ipaddress.ip_interface('2001:db8::1/96') -howto/ipaddress,,:db8,>>> net6 = ipaddress.ip_network('2001:db8::0/96') -howto/ipaddress,,::,>>> net6 = ipaddress.ip_network('2001:db8::0/96') -howto/ipaddress,,:ffff,IPv6Address('ffff:ffff:ffff:ffff:ffff:ffff::') -howto/ipaddress,,::,IPv6Address('ffff:ffff:ffff:ffff:ffff:ffff::') -howto/ipaddress,,::,IPv6Address('::ffff:ffff') -howto/ipaddress,,:ffff,IPv6Address('::ffff:ffff') -howto/ipaddress,,:db8,'2001:db8::/96' -howto/ipaddress,,::,'2001:db8::/96' -howto/ipaddress,,:db8,>>> ipaddress.ip_interface('2001:db8::1/96') -howto/ipaddress,,::,>>> ipaddress.ip_interface('2001:db8::1/96') -howto/ipaddress,,:db8,'2001:db8::1' -howto/ipaddress,,::,'2001:db8::1' -howto/ipaddress,,:db8,IPv6Address('2001:db8::ffff:ffff') -howto/ipaddress,,::,IPv6Address('2001:db8::ffff:ffff') -howto/ipaddress,,:ffff,IPv6Address('2001:db8::ffff:ffff') -howto/logging,,:And,"WARNING:And this, too" -howto/logging,,:And,"WARNING:root:And this, too" -howto/logging,,:And,"ERROR:root:And non-ASCII stuff, too, like " -howto/logging,,:Doing,INFO:root:Doing something -howto/logging,,:Finished,INFO:root:Finished -howto/logging,,:logger,severity:logger name:message -howto/logging,,:Look,WARNING:root:Look before you leap! -howto/logging,,:message,severity:logger name:message -howto/logging,,:root,DEBUG:root:This message should go to the log file -howto/logging,,:root,INFO:root:Doing something -howto/logging,,:root,INFO:root:Finished -howto/logging,,:root,INFO:root:So should this -howto/logging,,:root,"ERROR:root:And non-ASCII stuff, too, like " -howto/logging,,:root,INFO:root:Started -howto/logging,,:root,"WARNING:root:And this, too" -howto/logging,,:root,WARNING:root:Look before you leap! -howto/logging,,:root,WARNING:root:Watch out! -howto/logging,,:So,INFO:root:So should this -howto/logging,,:So,INFO:So should this -howto/logging,,:Started,INFO:root:Started -howto/logging,,:This,DEBUG:root:This message should go to the log file -howto/logging,,:This,DEBUG:This message should appear on the console -howto/logging,,:Watch,WARNING:root:Watch out! -howto/pyporting,,::,Programming Language :: Python :: 2 -howto/pyporting,,::,Programming Language :: Python :: 3 -howto/regex,,::, -howto/regex,,:foo,(?:foo) -howto/urllib2,,:password,"""joe:password at example.com""" -library/__main__,,`, -library/ast,,:upper,lower:upper -library/ast,,:step,lower:upper:step -library/audioop,,:ipos,"# factor = audioop.findfactor(in_test[ipos*2:ipos*2+len(out_test)]," -library/configparser,,:home,my_dir: ${Common:home_dir}/twosheds -library/configparser,,:option,${section:option} -library/configparser,,:path,python_dir: ${Frameworks:path}/Python/Versions/${Frameworks:Python} -library/configparser,,:Python,python_dir: ${Frameworks:path}/Python/Versions/${Frameworks:Python} -library/configparser,,:system,path: ${Common:system_dir}/Library/Frameworks/ -library/datetime,,:MM, -library/datetime,,:SS, -library/decimal,,:optional,"trailneg:optional trailing minus indicator" -library/difflib,,:ahi,a[alo:ahi] -library/difflib,,:bhi,b[blo:bhi] -library/difflib,,:i1, -library/difflib,,:i2, -library/difflib,,:j2, -library/doctest,,`,``factorial`` from the ``example`` module: -library/doctest,,`,The ``example`` module -library/doctest,,`,Using ``factorial`` -library/exceptions,,:err,err.object[err.start:err.end] -library/functions,,:step,a[start:stop:step] -library/functions,,:stop,"a[start:stop, i]" -library/functions,,:stop,a[start:stop:step] -library/hashlib,,:LEAF,"h00 = blake2b(buf[0:LEAF_SIZE], fanout=FANOUT, depth=DEPTH," -library/http.client,,:port,host:port -library/http.cookies,,`,!#$%&'*+-.^_`|~: -library/imaplib,,:MM,"""DD-Mmm-YYYY HH:MM:SS" -library/imaplib,,:SS,"""DD-Mmm-YYYY HH:MM:SS" -library/inspect,,:int,">>> def foo(a, *, b:int, **kwargs):" -library/inspect,,:int,"'(a, *, b:int, **kwargs)'" -library/inspect,,:int,'b:int' -library/ipaddress,,:db8,>>> ipaddress.ip_address('2001:db8::') -library/ipaddress,,::,>>> ipaddress.ip_address('2001:db8::') -library/ipaddress,,:db8,IPv6Address('2001:db8::') -library/ipaddress,,::,IPv6Address('2001:db8::') -library/ipaddress,,:db8,>>> ipaddress.IPv6Address('2001:db8::1000') -library/ipaddress,,::,>>> ipaddress.IPv6Address('2001:db8::1000') -library/ipaddress,,:db8,'2001:db8::1000' -library/ipaddress,,::,'2001:db8::1000' -library/ipaddress,,:db8,">>> f'{ipaddress.IPv6Address(""2001:db8::1000""):s}'" -library/ipaddress,,::,">>> f'{ipaddress.IPv6Address(""2001:db8::1000""):s}'" -library/ipaddress,,::,IPv6Address('ff02::5678%1') -library/ipaddress,,::,fe80::1234 -library/ipaddress,,:db8,">>> ipaddress.ip_address(""2001:db8::1"").reverse_pointer" -library/ipaddress,,::,">>> ipaddress.ip_address(""2001:db8::1"").reverse_pointer" -library/ipaddress,,::,"""::abc:7:def""" -library/ipaddress,,:def,"""::abc:7:def""" -library/ipaddress,,::,::FFFF/96 -library/ipaddress,,::,2002::/16 -library/ipaddress,,::,2001::/32 -library/ipaddress,,::,>>> str(ipaddress.IPv6Address('::1')) -library/ipaddress,,::,'::1' -library/ipaddress,,:ff00,ffff:ff00:: -library/ipaddress,,:db00,2001:db00::0/24 -library/ipaddress,,::,2001:db00::0/24 -library/ipaddress,,:db00,2001:db00::0/ffff:ff00:: -library/ipaddress,,::,2001:db00::0/ffff:ff00:: -library/itertools,,:step,elements from seq[start:stop:step] -library/itertools,,::,kernel = tuple(kernel)[::-1] -library/itertools,,:stop,elements from seq[start:stop:step] -library/logging.handlers,,:port,host:port -library/logging,,:root,WARNING:root:Watch out! -library/logging,,:Watch,WARNING:root:Watch out! -library/mmap,,:i2,obj[i1:i2] -library/multiprocessing,,`,# Add more tasks using `put()` -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 -library/multiprocessing,,`,# register the generator function baz; use `GeneratorProxy` to make proxies -library/nntplib,,:bytes,:bytes -library/nntplib,,:lines,:lines -library/optparse,,:len,"del parser.rargs[:len(value)]" -library/os.path,,:foo,c:foo -library/pathlib,,:bar,">>> PureWindowsPath('c:/Windows', 'd:bar')" -library/pathlib,,:bar,PureWindowsPath('d:bar') -library/pathlib,,:Program,>>> PureWindowsPath('c:Program Files/').root -library/pathlib,,:Program,>>> PureWindowsPath('c:Program Files/').anchor -library/pdb,,:lineno,filename:lineno -library/pickle,,:memory,"conn = sqlite3.connect("":memory:"")" -library/posix,,`,"CFLAGS=""`getconf LFS_CFLAGS`"" OPT=""-g -O2 $CFLAGS""" -library/pprint,,::,"'Programming Language :: Python :: 2.6'," -library/pprint,,::,"'Programming Language :: Python :: 2.7'," -library/pprint,,::,"'classifiers': ['Development Status :: 3 - Alpha'," -library/pprint,,::,"'Intended Audience :: Developers'," -library/pprint,,::,"'License :: OSI Approved :: MIT License'," -library/pprint,,::,"'Programming Language :: Python :: 2'," -library/pprint,,::,"'Programming Language :: Python :: 3'," -library/pprint,,::,"'Programming Language :: Python :: 3.2'," -library/pprint,,::,"'Programming Language :: Python :: 3.3'," -library/pprint,,::,"'Programming Language :: Python :: 3.4'," -library/pprint,,::,"'Topic :: Software Development :: Build Tools']," -library/profile,,:lineno,filename:lineno(function) -library/pyexpat,,:elem1, -library/pyexpat,,:py,"xmlns:py = ""http://www.python.org/ns/"">" -library/random,,:len,new_diff = mean(combined[:len(drug)]) - mean(combined[len(drug):]) -library/readline,,:bind,"python:bind -v" -library/readline,,:bind,"python:bind ^I rl_complete" -library/smtplib,,:port,method must support that as well as a regular host:port -library/socket,,::,'5aef:2b::8' -library/socket,,:can,"return (can_id, can_dlc, data[:can_dlc])" -library/socket,,:len,fds.frombytes(cmsg_data[:len(cmsg_data) - (len(cmsg_data) % fds.itemsize)]) -library/sqlite3,,:year,"cur.execute(""select * from lang where first_appeared=:year"", {""year"": 1972})" -library/sqlite3,,:memory, -library/sqlite3,,:template,"con = sqlite3.connect(""file:template.db?mode=ro"", uri=True)" -library/sqlite3,,:nosuchdb,"con = sqlite3.connect(""file:nosuchdb.db?mode=rw"", uri=True)" -library/sqlite3,,:mem1,"con1 = sqlite3.connect(""file:mem1?mode=memory&cache=shared"", uri=True)" -library/sqlite3,,:mem1,"con2 = sqlite3.connect(""file:mem1?mode=memory&cache=shared"", uri=True)" -library/ssl,,:My,"Organizational Unit Name (eg, section) []:My Group" -library/ssl,,:My,"Organization Name (eg, company) [Internet Widgits Pty Ltd]:My Organization, Inc." -library/ssl,,:myserver,"Common Name (eg, YOUR name) []:myserver.mygroup.myorganization.com" -library/ssl,,:MyState,State or Province Name (full name) [Some-State]:MyState -library/ssl,,:ops,Email Address []:ops at myserver.mygroup.myorganization.com -library/ssl,,:Some,"Locality Name (eg, city) []:Some City" -library/ssl,,:US,Country Name (2 letter code) [AU]:US -library/stdtypes,,:end,s[start:end] -library/stdtypes,,::,>>> hash(v[::-2]) == hash(b'abcefg'[::-2]) -library/stdtypes,,:len,s[len(s):len(s)] -library/stdtypes,,::,>>> y = m[::2] -library/stdtypes,,::,>>> z = y[::-2] -library/string,,`,"!""#$%&'()*+,-./:;<=>?@[\]^_`{|}~" -library/tarfile,,:bz2, -library/tarfile,,:compression,filemode[:compression] -library/tarfile,,:gz, -library/tarfile,,:xz,'a:xz' -library/tarfile,,:xz,'r:xz' -library/tarfile,,:xz,'w:xz' -library/time,,:mm, -library/time,,:ss, -library/tracemalloc,,:limit,"for index, stat in enumerate(top_stats[:limit], 1):" -library/turtle,,::,Example:: -library/unittest,,:foo,"self.assertEqual(cm.output, ['INFO:foo:first message'," -library/unittest,,:first,"self.assertEqual(cm.output, ['INFO:foo:first message'," -library/unittest,,:foo,'ERROR:foo.bar:second message']) -library/unittest,,:second,'ERROR:foo.bar:second message']) -library/urllib.request,,:close,Connection:close -library/urllib.request,,:port,:port -library/urllib.request,,:lang,"xmlns=""http://www.w3.org/1999/xhtml"" xml:lang=""en"" lang=""en"">\n\n\n" -library/urllib.request,,:password,"""joe:password at python.org""" -library/urllib.parse,,:scheme, -library/urllib.parse,,:scheme,URL:scheme://host/path -library/uuid,,:uuid,urn:uuid:12345678-1234-5678-1234-567812345678 -library/venv,,:param,":param nodist: If true, setuptools and pip are not installed into the" -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 virtual environment -library/xmlrpc.client,,:nil,ex:nil -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 -license,,`,"``Software''), to deal in the Software without restriction, including" -license,,`,"THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND," -license,,`,* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND -license,,`,THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -license,,`,* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY -license,,`,THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND -license,,:zooko,mailto:zooko at zooko.com -reference/expressions,,:index,x[index:index] -reference/lexical_analysis,,`,$ ? ` -reference/lexical_analysis,,:fileencoding,# vim:fileencoding= -tutorial/datastructures,,:value,It is also possible to delete a key:value -tutorial/datastructures,,:value,key:value pairs within the braces adds initial key:value pairs -tutorial/stdlib2,,:config,"logging.warning('Warning:config file %s not found', 'server.conf')" -tutorial/stdlib2,,:config,WARNING:root:Warning:config file server.conf not found -tutorial/stdlib2,,:Critical,CRITICAL:root:Critical error -- shutting down -tutorial/stdlib2,,:Error,ERROR:root:Error occurred -tutorial/stdlib2,,:root,CRITICAL:root:Critical error -- shutting down -tutorial/stdlib2,,:root,ERROR:root:Error occurred -tutorial/stdlib2,,:root,WARNING:root:Warning:config file server.conf not found -tutorial/stdlib2,,:start,extra = data[start:start+extra_size] -tutorial/stdlib2,,:start,"fields = struct.unpack('>> urlparse.urlparse('http://[1080::8:800:200C:417A]/foo') -whatsnew/2.7,,:Sunday,'2009:4:Sunday' -whatsnew/2.7,,:Cookie,"export PYTHONWARNINGS=all,error:::Cookie:0" -whatsnew/2.7,,::,"export PYTHONWARNINGS=all,error:::Cookie:0" -whatsnew/3.2,,:affe,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," -whatsnew/3.2,,:affe,>>> urllib.parse.urlparse('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/') -whatsnew/3.2,,:beef,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," -whatsnew/3.2,,:beef,>>> urllib.parse.urlparse('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/') -whatsnew/3.2,,:cafe,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," -whatsnew/3.2,,:cafe,>>> urllib.parse.urlparse('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/') -whatsnew/3.2,,:deaf,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," -whatsnew/3.2,,:deaf,>>> urllib.parse.urlparse('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/') -whatsnew/3.2,,:directory,${buildout:directory}/downloads/dist -whatsnew/3.2,,::,"$ export PYTHONWARNINGS='ignore::RuntimeWarning::,once::UnicodeWarning::'" -whatsnew/3.2,,:feed,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," -whatsnew/3.2,,:feed,>>> urllib.parse.urlparse('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/') -whatsnew/3.2,,:gz,">>> with tarfile.open(name='myarchive.tar.gz', mode='w:gz') as tf:" -whatsnew/3.2,,:location,zope9-location = ${zope9:location} -whatsnew/3.2,,:prefix,zope-conf = ${custom:prefix}/etc/zope.conf -library/re,,`,!#$%&'*+-.^_`|~: -library/re,,`,!\#\$%\&'\*\+\-\.\^_`\|\~: -library/tarfile,,:xz,'x:xz' -library/warnings,,:message,action:message:category:module:line -library/warnings,,:category,action:message:category:module:line -library/warnings,,:module,action:message:category:module:line -library/warnings,,:line,action:message:category:module:line -library/warnings,,::,error::ResourceWarning -library/warnings,,::,default::DeprecationWarning -library/warnings,,::,default:::mymodule -library/warnings,,:mymodule,default:::mymodule -library/warnings,,::,error:::mymodule -library/warnings,,:mymodule,error:::mymodule -library/warnings,,::,ignore::DeprecationWarning -library/warnings,,::,ignore::PendingDeprecationWarning -library/warnings,,::,ignore::ImportWarning -library/warnings,,::,ignore::ResourceWarning -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/xml.etree.elementtree,,:xi, -library/xml.etree.elementtree,,:include, -library/xml.etree.elementtree,,:include, Copyright (c) . -library/zipapp,,:main,"$ python -m zipapp myapp -m ""myapp:main""" -library/zipapp,,:fn,"pkg.mod:fn" -library/zipapp,,:callable,"pkg.module:callable" -library/stdtypes,,::,>>> m[::2].tolist() -whatsnew/3.5,,:root,'WARNING:root:warning\n' -whatsnew/3.5,,:warning,'WARNING:root:warning\n' -whatsnew/3.5,,::,>>> addr6 = ipaddress.IPv6Address('::1') -whatsnew/3.5,,:root,ERROR:root:exception -whatsnew/3.5,,:exception,ERROR:root:exception -whatsnew/changelog,,`,'`' -whatsnew/changelog,,:end,str[start:end] -library/binascii,,`,'`' -library/uu,,`,'`' -whatsnew/3.7,,`,'`' -whatsnew/3.7,,::,error::BytesWarning -whatsnew/changelog,,::,error::BytesWarning -whatsnew/changelog,,::,default::BytesWarning -whatsnew/changelog,,::,default::DeprecationWarning -library/importlib.metadata,,:main,"EntryPoint(name='wheel', value='wheel.cli:main', group='console_scripts')" -library/importlib.metadata,,`,loading the metadata for packages for the indicated ``context``. -library/re,,`,"`" -library/typing,,`,# Type of ``val`` is narrowed to ``str`` -library/typing,,`,"# Else, type of ``val`` is narrowed to ``float``." -library/typing,,`,# Type of ``val`` is narrowed to ``list[str]``. -library/typing,,`,# Type of ``val`` remains as ``list[object]``. -library/tkinter,,::,ttk::frame .frm -padding 10 -library/tkinter,,::,"grid [ttk::label .frm.lbl -text ""Hello World!""] -column 0 -row 0" -library/tkinter,,::,"grid [ttk::button .frm.btn -text ""Quit"" -command ""destroy .""] -column 1 -row 0" -library/tkinter,,::,ttk::frame -library/tkinter,,::,ttk::button -library/tkinter,,::,ttk::widget -reference/compound_stmts,,:exc,subclass of :exc:`BaseExceptionGroup`. It is not possible to mix except -reference/compound_stmts,,`,subclass of :exc:`BaseExceptionGroup`. It is not possible to mix except -reference/compound_stmts,,:keyword,"and except* in the same :keyword:`try`. :keyword:`break`," -reference/compound_stmts,,`,"and except* in the same :keyword:`try`. :keyword:`break`," -reference/compound_stmts,,:keyword,:keyword:`continue` and :keyword:`return` cannot appear in an except* -reference/compound_stmts,,`,:keyword:`continue` and :keyword:`return` cannot appear in an except* -whatsnew/changelog,,:CON,": os.path.abspath(?C:CON?) is now fixed to return ?\.CON?, not" -whatsnew/changelog,,::,Lib/email/mime/nonmultipart.py::MIMENonMultipart -library/typing,,`,"assert_type(name, str) # OK, inferred type of `name` is `str`" -library/typing,,`,# after which we hope the inferred type will be `int` -whatsnew/changelog,,:company,-V:company/tag -library/typing,,`,# are located in the `typing_extensions` backports package. -library/dis,490,:TOS,TOS = TOS2[TOS1:TOS] -library/dis,497,:TOS,TOS2[TOS1:TOS] = TOS3 diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index f8122ed1dc44..ebc490691e30 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -468,6 +468,11 @@ Removed * ``importlib.util.set_package`` has been removed. (Contributed by Brett Cannon in :gh:`65961`.) +* Removed the ``suspicious`` rule from the documentation Makefile, and + removed ``Doc/tools/rstlint.py``, both in favor of `sphinx-lint + `_. + (Contributed by Julien Palard in :gh:`98179`.) + Porting to Python 3.12 ====================== diff --git a/Misc/NEWS.d/next/Documentation/2022-10-11-09-40-50.gh-issue-86404.dEAb8W.rst b/Misc/NEWS.d/next/Documentation/2022-10-11-09-40-50.gh-issue-86404.dEAb8W.rst new file mode 100644 index 000000000000..de7b09216711 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2022-10-11-09-40-50.gh-issue-86404.dEAb8W.rst @@ -0,0 +1,3 @@ +Deprecated tools ``make suspicious`` and ``rstlint.py`` are now removed. +They have been replaced by `spinx-lint +`_. From webhook-mailer at python.org Tue Oct 11 11:11:57 2022 From: webhook-mailer at python.org (Fidget-Spinner) Date: Tue, 11 Oct 2022 15:11:57 -0000 Subject: [Python-checkins] gh-95756: Free and NULL-out code caches when needed (GH-98181) Message-ID: https://github.com/python/cpython/commit/7ec2e279fea3b340f642cff888bfa45368f5ded0 commit: 7ec2e279fea3b340f642cff888bfa45368f5ded0 branch: main author: Ken Jin committer: Fidget-Spinner date: 2022-10-11T23:11:46+08:00 summary: gh-95756: Free and NULL-out code caches when needed (GH-98181) files: M Objects/codeobject.c M Objects/frameobject.c diff --git a/Objects/codeobject.c b/Objects/codeobject.c index 7a0080c08c7b..8920b1db2cad 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -2238,6 +2238,7 @@ _PyStaticCode_Dealloc(PyCodeObject *co) Py_CLEAR(co->_co_cached->_co_freevars); Py_CLEAR(co->_co_cached->_co_varnames); PyMem_Free(co->_co_cached); + co->_co_cached = NULL; } co->co_extra = NULL; if (co->co_weakreflist != NULL) { diff --git a/Objects/frameobject.c b/Objects/frameobject.c index bd1608e0d75a..8b4494a5fe82 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -651,6 +651,8 @@ add_load_fast_null_checks(PyCodeObject *co) Py_CLEAR(co->_co_cached->_co_cellvars); Py_CLEAR(co->_co_cached->_co_freevars); Py_CLEAR(co->_co_cached->_co_varnames); + PyMem_Free(co->_co_cached); + co->_co_cached = NULL; } } From webhook-mailer at python.org Tue Oct 11 11:39:49 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 11 Oct 2022 15:39:49 -0000 Subject: [Python-checkins] Python 3.9.15 Message-ID: https://github.com/python/cpython/commit/7e2815419663a2f82abf6c5e1f848fd1de7c8033 commit: 7e2815419663a2f82abf6c5e1f848fd1de7c8033 branch: 3.9 author: ?ukasz Langa committer: ambv date: 2022-10-11T16:48:37+02:00 summary: Python 3.9.15 files: A Misc/NEWS.d/3.9.15.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-16-19-02-40.gh-issue-95778.cJmnst.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-21-14-38-31.gh-issue-96848.WuoLzU.rst D Misc/NEWS.d/next/Library/2022-09-22-14-35-02.gh-issue-97005.yf21Q7.rst D Misc/NEWS.d/next/Security/2022-09-28-12-10-57.gh-issue-97612.y6NvOQ.rst D Misc/NEWS.d/next/Security/2022-09-28-17-09-37.gh-issue-97616.K1e3Xs.rst D Misc/NEWS.d/next/Windows/2022-09-07-00-11-33.gh-issue-96577.kV4K_1.rst D Misc/NEWS.d/next/macOS/2022-10-05-15-26-58.gh-issue-97897.Rf-C6u.rst M Include/patchlevel.h M Lib/pydoc_data/topics.py M README.rst diff --git a/Include/patchlevel.h b/Include/patchlevel.h index c72092dcc629..a30fa4aaa8a1 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -18,12 +18,12 @@ /*--start constants--*/ #define PY_MAJOR_VERSION 3 #define PY_MINOR_VERSION 9 -#define PY_MICRO_VERSION 14 +#define PY_MICRO_VERSION 15 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL #define PY_RELEASE_SERIAL 0 /* Version as a string */ -#define PY_VERSION "3.9.14+" +#define PY_VERSION "3.9.15" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py index bfb5db0f9175..c06cf32c74ef 100644 --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Autogenerated by Sphinx on Tue Sep 6 19:25:22 2022 +# Autogenerated by Sphinx on Tue Oct 11 16:45:32 2022 topics = {'assert': 'The "assert" statement\n' '**********************\n' '\n' diff --git a/Misc/NEWS.d/3.9.15.rst b/Misc/NEWS.d/3.9.15.rst new file mode 100644 index 000000000000..7d2736c1cd39 --- /dev/null +++ b/Misc/NEWS.d/3.9.15.rst @@ -0,0 +1,75 @@ +.. date: 2022-09-28-17-09-37 +.. gh-issue: 97616 +.. nonce: K1e3Xs +.. release date: 2022-10-11 +.. section: Security + +Fix multiplying a list by an integer (``list *= int``): detect the integer +overflow when the new allocated length is close to the maximum size. Issue +reported by Jordan Limor. Patch by Victor Stinner. + +.. + +.. date: 2022-09-28-12-10-57 +.. gh-issue: 97612 +.. nonce: y6NvOQ +.. section: Security + +Fix a shell code injection vulnerability in the +``get-remote-certificate.py`` example script. The script no longer uses a +shell to run ``openssl`` commands. Issue reported and initial fix by Caleb +Shortt. Patch by Victor Stinner. + +.. + +.. date: 2022-09-21-14-38-31 +.. gh-issue: 96848 +.. nonce: WuoLzU +.. section: Core and Builtins + +Fix command line parsing: reject :option:`-X int_max_str_digits <-X>` option +with no value (invalid) when the :envvar:`PYTHONINTMAXSTRDIGITS` environment +variable is set to a valid limit. Patch by Victor Stinner. + +.. + +.. date: 2022-09-16-19-02-40 +.. gh-issue: 95778 +.. nonce: cJmnst +.. section: Core and Builtins + +When :exc:`ValueError` is raised if an integer is larger than the limit, +mention the :func:`sys.set_int_max_str_digits` function in the error +message. Patch by Victor Stinner. + +.. + +.. date: 2022-09-22-14-35-02 +.. gh-issue: 97005 +.. nonce: yf21Q7 +.. section: Library + +Update bundled libexpat to 2.4.9 + +.. + +.. date: 2022-09-07-00-11-33 +.. gh-issue: 96577 +.. nonce: kV4K_1 +.. section: Windows + +Fixes a potential buffer overrun in :mod:`msilib`. + +.. + +.. date: 2022-10-05-15-26-58 +.. gh-issue: 97897 +.. nonce: Rf-C6u +.. section: macOS + +The macOS 13 SDK includes support for the ``mkfifoat`` and ``mknodat`` +system calls. Using the ``dir_fd`` option with either :func:`os.mkfifo` or +:func:`os.mknod` could result in a segfault if cpython is built with the +macOS 13 SDK but run on an earlier version of macOS. Prevent this by adding +runtime support for detection of these system calls ("weaklinking") as is +done for other newer syscalls on macOS. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-16-19-02-40.gh-issue-95778.cJmnst.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-16-19-02-40.gh-issue-95778.cJmnst.rst deleted file mode 100644 index ebf63778a605..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-16-19-02-40.gh-issue-95778.cJmnst.rst +++ /dev/null @@ -1,3 +0,0 @@ -When :exc:`ValueError` is raised if an integer is larger than the limit, -mention the :func:`sys.set_int_max_str_digits` function in the error message. -Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-21-14-38-31.gh-issue-96848.WuoLzU.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-21-14-38-31.gh-issue-96848.WuoLzU.rst deleted file mode 100644 index a9b04ce87d4d..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-21-14-38-31.gh-issue-96848.WuoLzU.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix command line parsing: reject :option:`-X int_max_str_digits <-X>` option -with no value (invalid) when the :envvar:`PYTHONINTMAXSTRDIGITS` environment -variable is set to a valid limit. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Library/2022-09-22-14-35-02.gh-issue-97005.yf21Q7.rst b/Misc/NEWS.d/next/Library/2022-09-22-14-35-02.gh-issue-97005.yf21Q7.rst deleted file mode 100644 index d57999aa29b7..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-22-14-35-02.gh-issue-97005.yf21Q7.rst +++ /dev/null @@ -1 +0,0 @@ -Update bundled libexpat to 2.4.9 diff --git a/Misc/NEWS.d/next/Security/2022-09-28-12-10-57.gh-issue-97612.y6NvOQ.rst b/Misc/NEWS.d/next/Security/2022-09-28-12-10-57.gh-issue-97612.y6NvOQ.rst deleted file mode 100644 index 2f113492d42d..000000000000 --- a/Misc/NEWS.d/next/Security/2022-09-28-12-10-57.gh-issue-97612.y6NvOQ.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix a shell code injection vulnerability in the ``get-remote-certificate.py`` -example script. The script no longer uses a shell to run ``openssl`` commands. -Issue reported and initial fix by Caleb Shortt. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Security/2022-09-28-17-09-37.gh-issue-97616.K1e3Xs.rst b/Misc/NEWS.d/next/Security/2022-09-28-17-09-37.gh-issue-97616.K1e3Xs.rst deleted file mode 100644 index 721427fe6465..000000000000 --- a/Misc/NEWS.d/next/Security/2022-09-28-17-09-37.gh-issue-97616.K1e3Xs.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix multiplying a list by an integer (``list *= int``): detect the integer -overflow when the new allocated length is close to the maximum size. Issue -reported by Jordan Limor. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Windows/2022-09-07-00-11-33.gh-issue-96577.kV4K_1.rst b/Misc/NEWS.d/next/Windows/2022-09-07-00-11-33.gh-issue-96577.kV4K_1.rst deleted file mode 100644 index 6025e5ce4130..000000000000 --- a/Misc/NEWS.d/next/Windows/2022-09-07-00-11-33.gh-issue-96577.kV4K_1.rst +++ /dev/null @@ -1 +0,0 @@ -Fixes a potential buffer overrun in :mod:`msilib`. diff --git a/Misc/NEWS.d/next/macOS/2022-10-05-15-26-58.gh-issue-97897.Rf-C6u.rst b/Misc/NEWS.d/next/macOS/2022-10-05-15-26-58.gh-issue-97897.Rf-C6u.rst deleted file mode 100644 index 0d21e98b37c5..000000000000 --- a/Misc/NEWS.d/next/macOS/2022-10-05-15-26-58.gh-issue-97897.Rf-C6u.rst +++ /dev/null @@ -1,6 +0,0 @@ -The macOS 13 SDK includes support for the ``mkfifoat`` and ``mknodat`` system calls. -Using the ``dir_fd`` option with either :func:`os.mkfifo` or :func:`os.mknod` could result in a -segfault if cpython is built with the macOS 13 SDK but run on an earlier -version of macOS. Prevent this by adding runtime support for detection of -these system calls ("weaklinking") as is done for other newer syscalls on -macOS. diff --git a/README.rst b/README.rst index ae3e983b5fef..d78b6bc9e86f 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -This is Python version 3.9.14 +This is Python version 3.9.15 ============================= .. image:: https://travis-ci.org/python/cpython.svg?branch=3.9 From webhook-mailer at python.org Tue Oct 11 12:00:20 2022 From: webhook-mailer at python.org (vstinner) Date: Tue, 11 Oct 2022 16:00:20 -0000 Subject: [Python-checkins] gh-97982: Remove asciilib_count() (#98164) Message-ID: https://github.com/python/cpython/commit/df3a6d9beb8a7a3fe87a6d4126384fd3e0213853 commit: df3a6d9beb8a7a3fe87a6d4126384fd3e0213853 branch: main author: Victor Stinner committer: vstinner date: 2022-10-11T17:59:58+02:00 summary: gh-97982: Remove asciilib_count() (#98164) asciilib_count() is the same than ucs1lib_count(): the code is not specialized for ASCII strings, so it's not worth it to have a separated function. Remove asciilib_count() function. files: M Objects/stringlib/count.h M Objects/unicodeobject.c diff --git a/Objects/stringlib/count.h b/Objects/stringlib/count.h index f48500bf561f..e20edcd104b1 100644 --- a/Objects/stringlib/count.h +++ b/Objects/stringlib/count.h @@ -4,6 +4,11 @@ #error must include "stringlib/fastsearch.h" before including this module #endif +// gh-97982: Implementing asciilib_count() is not worth it, FASTSEARCH() does +// not specialize the code for ASCII strings. Use ucs1lib_count() for ASCII and +// UCS1 strings: it's the same than asciilib_count(). +#if !STRINGLIB_IS_UNICODE || STRINGLIB_MAX_CHAR > 0x7Fu + Py_LOCAL_INLINE(Py_ssize_t) STRINGLIB(count)(const STRINGLIB_CHAR* str, Py_ssize_t str_len, const STRINGLIB_CHAR* sub, Py_ssize_t sub_len, @@ -24,4 +29,4 @@ STRINGLIB(count)(const STRINGLIB_CHAR* str, Py_ssize_t str_len, return count; } - +#endif diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index bd169ed71421..51e660afba08 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -9000,16 +9000,10 @@ PyUnicode_Count(PyObject *str, switch (kind1) { case PyUnicode_1BYTE_KIND: - if (PyUnicode_IS_ASCII(str) && PyUnicode_IS_ASCII(substr)) - result = asciilib_count( - ((const Py_UCS1*)buf1) + start, end - start, - buf2, len2, PY_SSIZE_T_MAX - ); - else - result = ucs1lib_count( - ((const Py_UCS1*)buf1) + start, end - start, - buf2, len2, PY_SSIZE_T_MAX - ); + result = ucs1lib_count( + ((const Py_UCS1*)buf1) + start, end - start, + buf2, len2, PY_SSIZE_T_MAX + ); break; case PyUnicode_2BYTE_KIND: result = ucs2lib_count( @@ -9904,10 +9898,7 @@ anylib_count(int kind, PyObject *sstr, const void* sbuf, Py_ssize_t slen, { switch (kind) { case PyUnicode_1BYTE_KIND: - if (PyUnicode_IS_ASCII(sstr) && PyUnicode_IS_ASCII(str1)) - return asciilib_count(sbuf, slen, buf1, len1, maxcount); - else - return ucs1lib_count(sbuf, slen, buf1, len1, maxcount); + return ucs1lib_count(sbuf, slen, buf1, len1, maxcount); case PyUnicode_2BYTE_KIND: return ucs2lib_count(sbuf, slen, buf1, len1, maxcount); case PyUnicode_4BYTE_KIND: From webhook-mailer at python.org Tue Oct 11 12:14:04 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Tue, 11 Oct 2022 16:14:04 -0000 Subject: [Python-checkins] gh-98172: Fix formatting in `except*` docs (#98173) Message-ID: https://github.com/python/cpython/commit/5ecf961640192a2192383aa20e1e93dcdf23c9b6 commit: 5ecf961640192a2192383aa20e1e93dcdf23c9b6 branch: main author: Jelle Zijlstra committer: JelleZijlstra date: 2022-10-11T09:13:56-07:00 summary: gh-98172: Fix formatting in `except*` docs (#98173) files: M Doc/reference/compound_stmts.rst diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index d914686c0a1a..896348183643 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -363,18 +363,17 @@ one :keyword:`!except*` clause, the first that matches it. :: +-+---------------- 1 ---------------- | ValueError: 1 +------------------------------------ - >>> - - Any remaining exceptions that were not handled by any :keyword:`!except*` - clause are re-raised at the end, combined into an exception group along with - all exceptions that were raised from within :keyword:`!except*` clauses. - - An :keyword:`!except*` clause must have a matching type, - and this type cannot be a subclass of :exc:`BaseExceptionGroup`. - It is not possible to mix :keyword:`except` and :keyword:`!except*` - in the same :keyword:`try`. - :keyword:`break`, :keyword:`continue` and :keyword:`return` - cannot appear in an :keyword:`!except*` clause. + +Any remaining exceptions that were not handled by any :keyword:`!except*` +clause are re-raised at the end, combined into an exception group along with +all exceptions that were raised from within :keyword:`!except*` clauses. + +An :keyword:`!except*` clause must have a matching type, +and this type cannot be a subclass of :exc:`BaseExceptionGroup`. +It is not possible to mix :keyword:`except` and :keyword:`!except*` +in the same :keyword:`try`. +:keyword:`break`, :keyword:`continue` and :keyword:`return` +cannot appear in an :keyword:`!except*` clause. .. index:: From webhook-mailer at python.org Tue Oct 11 12:22:10 2022 From: webhook-mailer at python.org (miss-islington) Date: Tue, 11 Oct 2022 16:22:10 -0000 Subject: [Python-checkins] gh-98172: Fix formatting in `except*` docs (GH-98173) Message-ID: https://github.com/python/cpython/commit/9b12084aca1a2072f0333dbc562e52d8dc0235bd commit: 9b12084aca1a2072f0333dbc562e52d8dc0235bd branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-11T09:22:04-07:00 summary: gh-98172: Fix formatting in `except*` docs (GH-98173) (cherry picked from commit 5ecf961640192a2192383aa20e1e93dcdf23c9b6) Co-authored-by: Jelle Zijlstra files: M Doc/reference/compound_stmts.rst diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index d914686c0a1a..896348183643 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -363,18 +363,17 @@ one :keyword:`!except*` clause, the first that matches it. :: +-+---------------- 1 ---------------- | ValueError: 1 +------------------------------------ - >>> - - Any remaining exceptions that were not handled by any :keyword:`!except*` - clause are re-raised at the end, combined into an exception group along with - all exceptions that were raised from within :keyword:`!except*` clauses. - - An :keyword:`!except*` clause must have a matching type, - and this type cannot be a subclass of :exc:`BaseExceptionGroup`. - It is not possible to mix :keyword:`except` and :keyword:`!except*` - in the same :keyword:`try`. - :keyword:`break`, :keyword:`continue` and :keyword:`return` - cannot appear in an :keyword:`!except*` clause. + +Any remaining exceptions that were not handled by any :keyword:`!except*` +clause are re-raised at the end, combined into an exception group along with +all exceptions that were raised from within :keyword:`!except*` clauses. + +An :keyword:`!except*` clause must have a matching type, +and this type cannot be a subclass of :exc:`BaseExceptionGroup`. +It is not possible to mix :keyword:`except` and :keyword:`!except*` +in the same :keyword:`try`. +:keyword:`break`, :keyword:`continue` and :keyword:`return` +cannot appear in an :keyword:`!except*` clause. .. index:: From webhook-mailer at python.org Tue Oct 11 13:28:12 2022 From: webhook-mailer at python.org (pablogsal) Date: Tue, 11 Oct 2022 17:28:12 -0000 Subject: [Python-checkins] Python 3.10.8 Message-ID: https://github.com/python/cpython/commit/aaaf5174241496afca7ce4d4584570190ff972fe commit: aaaf5174241496afca7ce4d4584570190ff972fe branch: 3.10 author: Pablo Galindo committer: pablogsal date: 2022-10-11T12:21:44+01:00 summary: Python 3.10.8 files: A Misc/NEWS.d/3.10.8.rst D Misc/NEWS.d/next/Build/2022-09-11-14-23-49.gh-issue-96729.W4uBWL.rst D Misc/NEWS.d/next/Core and Builtins/2020-11-15-02-08-43.bpo-42316.LqdkWK.rst D Misc/NEWS.d/next/Core and Builtins/2022-08-28-10-51-19.gh-issue-96352.jTLD2d.rst D Misc/NEWS.d/next/Core and Builtins/2022-08-29-13-06-58.gh-issue-95196.eGRR4b.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-06-16-22-13.gh-issue-96611.14wIX8.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-07-13-38-37.gh-issue-96641.wky0Fc.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-13-12-06-46.gh-issue-96678.NqGFyb.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-16-12-36-13.gh-issue-96864.PLU3i8.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-16-16-54-35.gh-issue-96387.GRzewg.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-16-19-02-40.gh-issue-95778.cJmnst.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-18-08-47-40.gh-issue-96821.Co2iOq.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-20-11-06-45.gh-issue-95921.dkcRQn.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-21-14-38-31.gh-issue-96848.WuoLzU.rst D Misc/NEWS.d/next/Core and Builtins/2022-10-01-08-55-09.gh-issue-97591.pw6kkH.rst D Misc/NEWS.d/next/Core and Builtins/2022-10-05-17-02-22.gh-issue-97943.LYAWlE.rst D Misc/NEWS.d/next/Core and Builtins/2022-10-06-15-45-57.gh-issue-96078.fS-6mU.rst D Misc/NEWS.d/next/Documentation/2022-05-20-18-42-10.gh-issue-93031.c2RdJe.rst D Misc/NEWS.d/next/Documentation/2022-08-12-01-12-52.gh-issue-95588.PA0FI7.rst D Misc/NEWS.d/next/Documentation/2022-10-02-10-58-52.gh-issue-97741.39l023.rst D Misc/NEWS.d/next/Library/2022-04-15-11-29-38.gh-issue-91539.7WgVuA.rst D Misc/NEWS.d/next/Library/2022-05-19-22-34-42.gh-issue-92986.e6uKxj.rst D Misc/NEWS.d/next/Library/2022-05-25-15-57-39.gh-issue-90155.YMstB5.rst D Misc/NEWS.d/next/Library/2022-07-09-08-55-04.gh-issue-74116.0XwYC1.rst D Misc/NEWS.d/next/Library/2022-07-22-09-09-08.gh-issue-91212.53O8Ab.rst D Misc/NEWS.d/next/Library/2022-08-20-10-31-01.gh-issue-96052.a6FhaD.rst D Misc/NEWS.d/next/Library/2022-08-27-14-38-49.gh-issue-90467.VOOB0p.rst D Misc/NEWS.d/next/Library/2022-08-29-12-35-28.gh-issue-96073.WaGstf.rst D Misc/NEWS.d/next/Library/2022-09-07-22-49-37.gh-issue-96652.YqOKxI.rst D Misc/NEWS.d/next/Library/2022-09-15-00-37-33.gh-issue-96741.4b6czN.rst D Misc/NEWS.d/next/Library/2022-09-17-13-15-10.gh-issue-96819.6RfqM7.rst D Misc/NEWS.d/next/Library/2022-09-22-11-50-29.gh-issue-85760.DETTPd.rst D Misc/NEWS.d/next/Library/2022-09-22-14-35-02.gh-issue-97005.yf21Q7.rst D Misc/NEWS.d/next/Library/2022-09-25-20-42-33.gh-issue-73588.uVtjEA.rst D Misc/NEWS.d/next/Library/2022-09-25-23-24-52.gh-issue-97545.HZLSNt.rst D Misc/NEWS.d/next/Library/2022-09-29-08-15-55.gh-issue-97639.JSjWYW.rst D Misc/NEWS.d/next/Library/2022-09-29-23-22-24.gh-issue-97592.tpJg_J.rst D Misc/NEWS.d/next/Library/2022-09-30-15-56-20.gh-issue-96827.lzy1iw.rst D Misc/NEWS.d/next/Library/2022-10-04-07-55-19.gh-issue-97825.mNdv1l.rst D Misc/NEWS.d/next/Library/2022-10-09-12-12-38.gh-issue-87730.ClgP3f.rst D Misc/NEWS.d/next/Security/2022-04-27-18-25-30.gh-issue-68966.gjS8zs.rst D Misc/NEWS.d/next/Security/2022-09-28-12-10-57.gh-issue-97612.y6NvOQ.rst D Misc/NEWS.d/next/Security/2022-09-28-17-09-37.gh-issue-97616.K1e3Xs.rst D Misc/NEWS.d/next/Windows/2022-09-07-00-11-33.gh-issue-96577.kV4K_1.rst D Misc/NEWS.d/next/Windows/2022-09-29-23-08-49.gh-issue-90989.no89Q2.rst D Misc/NEWS.d/next/Windows/2022-10-02-11-59-23.gh-issue-97728.dIdlPE.rst D Misc/NEWS.d/next/macOS/2022-10-05-15-26-58.gh-issue-97897.Rf-C6u.rst M Include/patchlevel.h M Lib/pydoc_data/topics.py M README.rst diff --git a/Include/patchlevel.h b/Include/patchlevel.h index 55ebf59188a2..273caa978cc8 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -18,12 +18,12 @@ /*--start constants--*/ #define PY_MAJOR_VERSION 3 #define PY_MINOR_VERSION 10 -#define PY_MICRO_VERSION 7 +#define PY_MICRO_VERSION 8 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL #define PY_RELEASE_SERIAL 0 /* Version as a string */ -#define PY_VERSION "3.10.7+" +#define PY_VERSION "3.10.8" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py index 198bd7c264a3..34bb19eaf50c 100644 --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Autogenerated by Sphinx on Mon Sep 5 13:02:42 2022 +# Autogenerated by Sphinx on Tue Oct 11 12:21:26 2022 topics = {'assert': 'The "assert" statement\n' '**********************\n' '\n' @@ -1674,10 +1674,26 @@ 'If the syntax "**expression" appears in the function call,\n' '"expression" must evaluate to a *mapping*, the contents of which ' 'are\n' - 'treated as additional keyword arguments. If a keyword is already\n' - 'present (as an explicit keyword argument, or from another ' - 'unpacking),\n' - 'a "TypeError" exception is raised.\n' + 'treated as additional keyword arguments. If a parameter matching a ' + 'key\n' + 'has already been given a value (by an explicit keyword argument, ' + 'or\n' + 'from another unpacking), a "TypeError" exception is raised.\n' + '\n' + 'When "**expression" is used, each key in this mapping must be a\n' + 'string. Each value from the mapping is assigned to the first ' + 'formal\n' + 'parameter eligible for keyword assignment whose name is equal to ' + 'the\n' + 'key. A key need not be a Python identifier (e.g. ""max-temp ?F"" ' + 'is\n' + 'acceptable, although it will not match any formal parameter that ' + 'could\n' + 'be declared). If there is no match to a formal parameter the ' + 'key-value\n' + 'pair is collected by the "**" parameter, if there is one, or if ' + 'there\n' + 'is not, a "TypeError" exception is raised.\n' '\n' 'Formal parameters using the syntax "*identifier" or "**identifier"\n' 'cannot be used as positional argument slots or as keyword argument\n' @@ -12768,7 +12784,7 @@ ' 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' + 'char\n' ' type; instead, every code point in the string is ' 'represented\n' ' as a string object with length "1". The built-in ' diff --git a/Misc/NEWS.d/3.10.8.rst b/Misc/NEWS.d/3.10.8.rst new file mode 100644 index 000000000000..382b6186eb96 --- /dev/null +++ b/Misc/NEWS.d/3.10.8.rst @@ -0,0 +1,474 @@ +.. date: 2022-09-28-17-09-37 +.. gh-issue: 97616 +.. nonce: K1e3Xs +.. release date: 2022-10-11 +.. section: Security + +Fix multiplying a list by an integer (``list *= int``): detect the integer +overflow when the new allocated length is close to the maximum size. Issue +reported by Jordan Limor. Patch by Victor Stinner. + +.. + +.. date: 2022-09-28-12-10-57 +.. gh-issue: 97612 +.. nonce: y6NvOQ +.. section: Security + +Fix a shell code injection vulnerability in the +``get-remote-certificate.py`` example script. The script no longer uses a +shell to run ``openssl`` commands. Issue reported and initial fix by Caleb +Shortt. Patch by Victor Stinner. + +.. + +.. date: 2022-04-27-18-25-30 +.. gh-issue: 68966 +.. nonce: gjS8zs +.. section: Security + +The deprecated mailcap module now refuses to inject unsafe text (filenames, +MIME types, parameters) into shell commands. Instead of using such text, it +will warn and act as if a match was not found (or for test commands, as if +the test failed). + +.. + +.. date: 2022-10-06-15-45-57 +.. gh-issue: 96078 +.. nonce: fS-6mU +.. section: Core and Builtins + +:func:`os.sched_yield` now release the GIL while calling sched_yield(2). +Patch by Dong-hee Na. + +.. + +.. date: 2022-10-05-17-02-22 +.. gh-issue: 97943 +.. nonce: LYAWlE +.. section: Core and Builtins + +Bugfix: :func:`PyFunction_GetAnnotations` should return a borrowed +reference. It was returning a new reference. + +.. + +.. date: 2022-10-01-08-55-09 +.. gh-issue: 97591 +.. nonce: pw6kkH +.. section: Core and Builtins + +Fixed a missing incref/decref pair in `Exception.__setstate__()`. Patch by +Ofey Chan. + +.. + +.. date: 2022-09-21-14-38-31 +.. gh-issue: 96848 +.. nonce: WuoLzU +.. section: Core and Builtins + +Fix command line parsing: reject :option:`-X int_max_str_digits <-X>` option +with no value (invalid) when the :envvar:`PYTHONINTMAXSTRDIGITS` environment +variable is set to a valid limit. Patch by Victor Stinner. + +.. + +.. date: 2022-09-20-11-06-45 +.. gh-issue: 95921 +.. nonce: dkcRQn +.. section: Core and Builtins + +Fix overly-broad source position information for chained comparisons used as +branching conditions. + +.. + +.. date: 2022-09-18-08-47-40 +.. gh-issue: 96821 +.. nonce: Co2iOq +.. section: Core and Builtins + +Fix undefined behaviour in ``_testcapimodule.c``. + +.. + +.. date: 2022-09-16-19-02-40 +.. gh-issue: 95778 +.. nonce: cJmnst +.. section: Core and Builtins + +When :exc:`ValueError` is raised if an integer is larger than the limit, +mention the :func:`sys.set_int_max_str_digits` function in the error +message. Patch by Victor Stinner. + +.. + +.. date: 2022-09-16-16-54-35 +.. gh-issue: 96387 +.. nonce: GRzewg +.. section: Core and Builtins + +At Python exit, sometimes a thread holding the GIL can wait forever for a +thread (usually a daemon thread) which requested to drop the GIL, whereas +the thread already exited. To fix the race condition, the thread which +requested the GIL drop now resets its request before exiting. Issue +discovered and analyzed by Mingliang ZHAO. Patch by Victor Stinner. + +.. + +.. date: 2022-09-16-12-36-13 +.. gh-issue: 96864 +.. nonce: PLU3i8 +.. section: Core and Builtins + +Fix a possible assertion failure, fatal error, or :exc:`SystemError` if a +line tracing event raises an exception while opcode tracing is enabled. + +.. + +.. date: 2022-09-13-12-06-46 +.. gh-issue: 96678 +.. nonce: NqGFyb +.. section: Core and Builtins + +Fix undefined behaviour in C code of null pointer arithmetic. + +.. + +.. date: 2022-09-07-13-38-37 +.. gh-issue: 96641 +.. nonce: wky0Fc +.. section: Core and Builtins + +Do not expose ``KeyWrapper`` in :mod:`_functools`. + +.. + +.. date: 2022-09-06-16-22-13 +.. gh-issue: 96611 +.. nonce: 14wIX8 +.. section: Core and Builtins + +When loading a file with invalid UTF-8 inside a multi-line string, a correct +SyntaxError is emitted. + +.. + +.. date: 2022-08-29-13-06-58 +.. gh-issue: 95196 +.. nonce: eGRR4b +.. section: Core and Builtins + +Disable incorrect pickling of the C implemented classmethod descriptors. + +.. + +.. date: 2022-08-28-10-51-19 +.. gh-issue: 96352 +.. nonce: jTLD2d +.. section: Core and Builtins + +Fix :exc:`AttributeError` missing ``name`` and ``obj`` attributes in +:meth:`object.__getattribute__`. Patch by Philip Georgi. + +.. + +.. bpo: 42316 +.. date: 2020-11-15-02-08-43 +.. nonce: LqdkWK +.. section: Core and Builtins + +Document some places where an assignment expression needs parentheses. + +.. + +.. date: 2022-10-09-12-12-38 +.. gh-issue: 87730 +.. nonce: ClgP3f +.. section: Library + +Wrap network errors consistently in urllib FTP support, so the test suite +doesn't fail when a network is available but the public internet is not +reachable. + +.. + +.. date: 2022-10-04-07-55-19 +.. gh-issue: 97825 +.. nonce: mNdv1l +.. section: Library + +Fixes :exc:`AttributeError` when :meth:`subprocess.check_output` is used +with argument ``input=None`` and either of the arguments *encoding* or +*errors* are used. + +.. + +.. date: 2022-09-30-15-56-20 +.. gh-issue: 96827 +.. nonce: lzy1iw +.. section: Library + +Avoid spurious tracebacks from :mod:`asyncio` when default executor cleanup +is delayed until after the event loop is closed (e.g. as the result of a +keyboard interrupt). + +.. + +.. date: 2022-09-29-23-22-24 +.. gh-issue: 97592 +.. nonce: tpJg_J +.. section: Library + +Avoid a crash in the C version of +:meth:`asyncio.Future.remove_done_callback` when an evil argument is passed. + +.. + +.. date: 2022-09-29-08-15-55 +.. gh-issue: 97639 +.. nonce: JSjWYW +.. section: Library + +Remove ``tokenize.NL`` check from :mod:`tabnanny`. + +.. + +.. date: 2022-09-25-23-24-52 +.. gh-issue: 97545 +.. nonce: HZLSNt +.. section: Library + +Make Semaphore run faster. + +.. + +.. date: 2022-09-25-20-42-33 +.. gh-issue: 73588 +.. nonce: uVtjEA +.. section: Library + +Fix generation of the default name of :class:`tkinter.Checkbutton`. +Previously, checkbuttons in different parent widgets could have the same +short name and share the same state if arguments "name" and "variable" are +not specified. Now they are globally unique. + +.. + +.. date: 2022-09-22-14-35-02 +.. gh-issue: 97005 +.. nonce: yf21Q7 +.. section: Library + +Update bundled libexpat to 2.4.9 + +.. + +.. date: 2022-09-22-11-50-29 +.. gh-issue: 85760 +.. nonce: DETTPd +.. section: Library + +Fix race condition in :mod:`asyncio` where +:meth:`~asyncio.SubprocessProtocol.process_exited` called before the +:meth:`~asyncio.SubprocessProtocol.pipe_data_received` leading to +inconsistent output. Patch by Kumar Aditya. + +.. + +.. date: 2022-09-17-13-15-10 +.. gh-issue: 96819 +.. nonce: 6RfqM7 +.. section: Library + +Fixed check in :mod:`multiprocessing.resource_tracker` that guarantees that +the length of a write to a pipe is not greater than ``PIPE_BUF``. + +.. + +.. date: 2022-09-15-00-37-33 +.. gh-issue: 96741 +.. nonce: 4b6czN +.. section: Library + +Corrected type annotation for dataclass attribute +``pstats.FunctionProfile.ncalls`` to be ``str``. + +.. + +.. date: 2022-09-07-22-49-37 +.. gh-issue: 96652 +.. nonce: YqOKxI +.. section: Library + +Fix the faulthandler implementation of ``faulthandler.register(signal, +chain=True)`` if the ``sigaction()`` function is not available: don't call +the previous signal handler if it's NULL. Patch by Victor Stinner. + +.. + +.. date: 2022-08-29-12-35-28 +.. gh-issue: 96073 +.. nonce: WaGstf +.. section: Library + +In :mod:`inspect`, fix overeager replacement of "``typing.``" in formatting +annotations. + +.. + +.. date: 2022-08-27-14-38-49 +.. gh-issue: 90467 +.. nonce: VOOB0p +.. section: Library + +Fix :class:`asyncio.streams.StreamReaderProtocol` to keep a strong reference +to the created task, so that it's not garbage collected + +.. + +.. date: 2022-08-20-10-31-01 +.. gh-issue: 96052 +.. nonce: a6FhaD +.. section: Library + +Fix handling compiler warnings (SyntaxWarning and DeprecationWarning) in +:func:`codeop.compile_command` when checking for incomplete input. +Previously it emitted warnings and raised a SyntaxError. Now it always +returns ``None`` for incomplete input without emitting any warnings. + +.. + +.. date: 2022-07-22-09-09-08 +.. gh-issue: 91212 +.. nonce: 53O8Ab +.. section: Library + +Fixed flickering of the turtle window when the tracer is turned off. Patch +by Shin-myoung-serp. + +.. + +.. date: 2022-07-09-08-55-04 +.. gh-issue: 74116 +.. nonce: 0XwYC1 +.. section: Library + +Allow :meth:`asyncio.StreamWriter.drain` to be awaited concurrently by +multiple tasks. Patch by Kumar Aditya. + +.. + +.. date: 2022-05-25-15-57-39 +.. gh-issue: 90155 +.. nonce: YMstB5 +.. section: Library + +Fix broken :class:`asyncio.Semaphore` when acquire is cancelled. + +.. + +.. date: 2022-05-19-22-34-42 +.. gh-issue: 92986 +.. nonce: e6uKxj +.. section: Library + +Fix :func:`ast.unparse` when ``ImportFrom.level`` is None + +.. + +.. date: 2022-04-15-11-29-38 +.. gh-issue: 91539 +.. nonce: 7WgVuA +.. section: Library + +Improve performance of ``urllib.request.getproxies_environment`` when there +are many environment variables + +.. + +.. date: 2022-10-02-10-58-52 +.. gh-issue: 97741 +.. nonce: 39l023 +.. section: Documentation + +Fix ``!`` in c domain ref target syntax via a ``conf.py`` patch, so it works +as intended to disable ref target resolution. + +.. + +.. date: 2022-08-12-01-12-52 +.. gh-issue: 95588 +.. nonce: PA0FI7 +.. section: Documentation + +Clarified the conflicting advice given in the :mod:`ast` documentation about +:func:`ast.literal_eval` being "safe" for use on untrusted input while at +the same time warning that it can crash the process. The latter statement is +true and is deemed unfixable without a large amount of work unsuitable for a +bugfix. So we keep the warning and no longer claim that ``literal_eval`` is +safe. + +.. + +.. date: 2022-05-20-18-42-10 +.. gh-issue: 93031 +.. nonce: c2RdJe +.. section: Documentation + +Update tutorial introduction output to use 3.10+ SyntaxError invalid range. + +.. + +.. date: 2022-09-11-14-23-49 +.. gh-issue: 96729 +.. nonce: W4uBWL +.. section: Build + +Ensure that Windows releases built with ``Tools\msi\buildrelease.bat`` are +upgradable to and from official Python releases. + +.. + +.. date: 2022-10-02-11-59-23 +.. gh-issue: 97728 +.. nonce: dIdlPE +.. section: Windows + +Fix possible crashes caused by the use of uninitialized variables when pass +invalid arguments in :func:`os.system` on Windows and in Windows-specific +modules (like ``winreg``). + +.. + +.. date: 2022-09-29-23-08-49 +.. gh-issue: 90989 +.. nonce: no89Q2 +.. section: Windows + +Clarify some text in the Windows installer. + +.. + +.. date: 2022-09-07-00-11-33 +.. gh-issue: 96577 +.. nonce: kV4K_1 +.. section: Windows + +Fixes a potential buffer overrun in :mod:`msilib`. + +.. + +.. date: 2022-10-05-15-26-58 +.. gh-issue: 97897 +.. nonce: Rf-C6u +.. section: macOS + +The macOS 13 SDK includes support for the ``mkfifoat`` and ``mknodat`` +system calls. Using the ``dir_fd`` option with either :func:`os.mkfifo` or +:func:`os.mknod` could result in a segfault if cpython is built with the +macOS 13 SDK but run on an earlier version of macOS. Prevent this by adding +runtime support for detection of these system calls ("weaklinking") as is +done for other newer syscalls on macOS. diff --git a/Misc/NEWS.d/next/Build/2022-09-11-14-23-49.gh-issue-96729.W4uBWL.rst b/Misc/NEWS.d/next/Build/2022-09-11-14-23-49.gh-issue-96729.W4uBWL.rst deleted file mode 100644 index b67cd200e2d3..000000000000 --- a/Misc/NEWS.d/next/Build/2022-09-11-14-23-49.gh-issue-96729.W4uBWL.rst +++ /dev/null @@ -1,2 +0,0 @@ -Ensure that Windows releases built with ``Tools\msi\buildrelease.bat`` are -upgradable to and from official Python releases. diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-11-15-02-08-43.bpo-42316.LqdkWK.rst b/Misc/NEWS.d/next/Core and Builtins/2020-11-15-02-08-43.bpo-42316.LqdkWK.rst deleted file mode 100644 index ea997800bf07..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-11-15-02-08-43.bpo-42316.LqdkWK.rst +++ /dev/null @@ -1 +0,0 @@ -Document some places where an assignment expression needs parentheses. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-08-28-10-51-19.gh-issue-96352.jTLD2d.rst b/Misc/NEWS.d/next/Core and Builtins/2022-08-28-10-51-19.gh-issue-96352.jTLD2d.rst deleted file mode 100644 index 25ab9678715a..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-08-28-10-51-19.gh-issue-96352.jTLD2d.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix :exc:`AttributeError` missing ``name`` and ``obj`` attributes in -:meth:`object.__getattribute__`. Patch by Philip Georgi. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-08-29-13-06-58.gh-issue-95196.eGRR4b.rst b/Misc/NEWS.d/next/Core and Builtins/2022-08-29-13-06-58.gh-issue-95196.eGRR4b.rst deleted file mode 100644 index 37534fa17525..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-08-29-13-06-58.gh-issue-95196.eGRR4b.rst +++ /dev/null @@ -1 +0,0 @@ -Disable incorrect pickling of the C implemented classmethod descriptors. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-06-16-22-13.gh-issue-96611.14wIX8.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-06-16-22-13.gh-issue-96611.14wIX8.rst deleted file mode 100644 index 08bd409bc9f9..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-06-16-22-13.gh-issue-96611.14wIX8.rst +++ /dev/null @@ -1,2 +0,0 @@ -When loading a file with invalid UTF-8 inside a multi-line string, a correct -SyntaxError is emitted. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-07-13-38-37.gh-issue-96641.wky0Fc.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-07-13-38-37.gh-issue-96641.wky0Fc.rst deleted file mode 100644 index 51faca8716fb..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-07-13-38-37.gh-issue-96641.wky0Fc.rst +++ /dev/null @@ -1 +0,0 @@ -Do not expose ``KeyWrapper`` in :mod:`_functools`. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-13-12-06-46.gh-issue-96678.NqGFyb.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-13-12-06-46.gh-issue-96678.NqGFyb.rst deleted file mode 100644 index bdd33c8d2ca9..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-13-12-06-46.gh-issue-96678.NqGFyb.rst +++ /dev/null @@ -1 +0,0 @@ -Fix undefined behaviour in C code of null pointer arithmetic. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-16-12-36-13.gh-issue-96864.PLU3i8.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-16-12-36-13.gh-issue-96864.PLU3i8.rst deleted file mode 100644 index c0d41ae7d21e..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-16-12-36-13.gh-issue-96864.PLU3i8.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a possible assertion failure, fatal error, or :exc:`SystemError` if a -line tracing event raises an exception while opcode tracing is enabled. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-16-16-54-35.gh-issue-96387.GRzewg.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-16-16-54-35.gh-issue-96387.GRzewg.rst deleted file mode 100644 index 611ab94bc636..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-16-16-54-35.gh-issue-96387.GRzewg.rst +++ /dev/null @@ -1,5 +0,0 @@ -At Python exit, sometimes a thread holding the GIL can wait forever for a -thread (usually a daemon thread) which requested to drop the GIL, whereas -the thread already exited. To fix the race condition, the thread which -requested the GIL drop now resets its request before exiting. Issue -discovered and analyzed by Mingliang ZHAO. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-16-19-02-40.gh-issue-95778.cJmnst.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-16-19-02-40.gh-issue-95778.cJmnst.rst deleted file mode 100644 index ebf63778a605..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-16-19-02-40.gh-issue-95778.cJmnst.rst +++ /dev/null @@ -1,3 +0,0 @@ -When :exc:`ValueError` is raised if an integer is larger than the limit, -mention the :func:`sys.set_int_max_str_digits` function in the error message. -Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-18-08-47-40.gh-issue-96821.Co2iOq.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-18-08-47-40.gh-issue-96821.Co2iOq.rst deleted file mode 100644 index 4fd0532e827d..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-18-08-47-40.gh-issue-96821.Co2iOq.rst +++ /dev/null @@ -1 +0,0 @@ -Fix undefined behaviour in ``_testcapimodule.c``. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-20-11-06-45.gh-issue-95921.dkcRQn.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-20-11-06-45.gh-issue-95921.dkcRQn.rst deleted file mode 100644 index 0c8b704c9510..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-20-11-06-45.gh-issue-95921.dkcRQn.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix overly-broad source position information for chained comparisons used as -branching conditions. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-21-14-38-31.gh-issue-96848.WuoLzU.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-21-14-38-31.gh-issue-96848.WuoLzU.rst deleted file mode 100644 index a9b04ce87d4d..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-21-14-38-31.gh-issue-96848.WuoLzU.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix command line parsing: reject :option:`-X int_max_str_digits <-X>` option -with no value (invalid) when the :envvar:`PYTHONINTMAXSTRDIGITS` environment -variable is set to a valid limit. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-01-08-55-09.gh-issue-97591.pw6kkH.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-01-08-55-09.gh-issue-97591.pw6kkH.rst deleted file mode 100644 index d3a5867db7fc..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-10-01-08-55-09.gh-issue-97591.pw6kkH.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixed a missing incref/decref pair in `Exception.__setstate__()`. -Patch by Ofey Chan. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-05-17-02-22.gh-issue-97943.LYAWlE.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-05-17-02-22.gh-issue-97943.LYAWlE.rst deleted file mode 100644 index 9b4a421a9d47..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-10-05-17-02-22.gh-issue-97943.LYAWlE.rst +++ /dev/null @@ -1,2 +0,0 @@ -Bugfix: :func:`PyFunction_GetAnnotations` should return a borrowed -reference. It was returning a new reference. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-06-15-45-57.gh-issue-96078.fS-6mU.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-06-15-45-57.gh-issue-96078.fS-6mU.rst deleted file mode 100644 index d1f949c6e13a..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-10-06-15-45-57.gh-issue-96078.fS-6mU.rst +++ /dev/null @@ -1,2 +0,0 @@ -:func:`os.sched_yield` now release the GIL while calling sched_yield(2). -Patch by Dong-hee Na. diff --git a/Misc/NEWS.d/next/Documentation/2022-05-20-18-42-10.gh-issue-93031.c2RdJe.rst b/Misc/NEWS.d/next/Documentation/2022-05-20-18-42-10.gh-issue-93031.c2RdJe.rst deleted file mode 100644 index c46b45d2433c..000000000000 --- a/Misc/NEWS.d/next/Documentation/2022-05-20-18-42-10.gh-issue-93031.c2RdJe.rst +++ /dev/null @@ -1 +0,0 @@ -Update tutorial introduction output to use 3.10+ SyntaxError invalid range. diff --git a/Misc/NEWS.d/next/Documentation/2022-08-12-01-12-52.gh-issue-95588.PA0FI7.rst b/Misc/NEWS.d/next/Documentation/2022-08-12-01-12-52.gh-issue-95588.PA0FI7.rst deleted file mode 100644 index c070bbc19517..000000000000 --- a/Misc/NEWS.d/next/Documentation/2022-08-12-01-12-52.gh-issue-95588.PA0FI7.rst +++ /dev/null @@ -1,6 +0,0 @@ -Clarified the conflicting advice given in the :mod:`ast` documentation about -:func:`ast.literal_eval` being "safe" for use on untrusted input while at -the same time warning that it can crash the process. The latter statement is -true and is deemed unfixable without a large amount of work unsuitable for a -bugfix. So we keep the warning and no longer claim that ``literal_eval`` is -safe. diff --git a/Misc/NEWS.d/next/Documentation/2022-10-02-10-58-52.gh-issue-97741.39l023.rst b/Misc/NEWS.d/next/Documentation/2022-10-02-10-58-52.gh-issue-97741.39l023.rst deleted file mode 100644 index 8da9c92f6fd8..000000000000 --- a/Misc/NEWS.d/next/Documentation/2022-10-02-10-58-52.gh-issue-97741.39l023.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix ``!`` in c domain ref target syntax via a ``conf.py`` patch, so it works -as intended to disable ref target resolution. diff --git a/Misc/NEWS.d/next/Library/2022-04-15-11-29-38.gh-issue-91539.7WgVuA.rst b/Misc/NEWS.d/next/Library/2022-04-15-11-29-38.gh-issue-91539.7WgVuA.rst deleted file mode 100644 index 16d61f1b9110..000000000000 --- a/Misc/NEWS.d/next/Library/2022-04-15-11-29-38.gh-issue-91539.7WgVuA.rst +++ /dev/null @@ -1 +0,0 @@ -Improve performance of ``urllib.request.getproxies_environment`` when there are many environment variables diff --git a/Misc/NEWS.d/next/Library/2022-05-19-22-34-42.gh-issue-92986.e6uKxj.rst b/Misc/NEWS.d/next/Library/2022-05-19-22-34-42.gh-issue-92986.e6uKxj.rst deleted file mode 100644 index 691c0dd3759f..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-19-22-34-42.gh-issue-92986.e6uKxj.rst +++ /dev/null @@ -1 +0,0 @@ -Fix :func:`ast.unparse` when ``ImportFrom.level`` is None diff --git a/Misc/NEWS.d/next/Library/2022-05-25-15-57-39.gh-issue-90155.YMstB5.rst b/Misc/NEWS.d/next/Library/2022-05-25-15-57-39.gh-issue-90155.YMstB5.rst deleted file mode 100644 index 8def76914eda..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-25-15-57-39.gh-issue-90155.YMstB5.rst +++ /dev/null @@ -1 +0,0 @@ -Fix broken :class:`asyncio.Semaphore` when acquire is cancelled. diff --git a/Misc/NEWS.d/next/Library/2022-07-09-08-55-04.gh-issue-74116.0XwYC1.rst b/Misc/NEWS.d/next/Library/2022-07-09-08-55-04.gh-issue-74116.0XwYC1.rst deleted file mode 100644 index 33782598745b..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-09-08-55-04.gh-issue-74116.0XwYC1.rst +++ /dev/null @@ -1 +0,0 @@ -Allow :meth:`asyncio.StreamWriter.drain` to be awaited concurrently by multiple tasks. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Library/2022-07-22-09-09-08.gh-issue-91212.53O8Ab.rst b/Misc/NEWS.d/next/Library/2022-07-22-09-09-08.gh-issue-91212.53O8Ab.rst deleted file mode 100644 index 8552f51196b5..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-22-09-09-08.gh-issue-91212.53O8Ab.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed flickering of the turtle window when the tracer is turned off. Patch by Shin-myoung-serp. diff --git a/Misc/NEWS.d/next/Library/2022-08-20-10-31-01.gh-issue-96052.a6FhaD.rst b/Misc/NEWS.d/next/Library/2022-08-20-10-31-01.gh-issue-96052.a6FhaD.rst deleted file mode 100644 index c190fb7dbcb9..000000000000 --- a/Misc/NEWS.d/next/Library/2022-08-20-10-31-01.gh-issue-96052.a6FhaD.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix handling compiler warnings (SyntaxWarning and DeprecationWarning) in -:func:`codeop.compile_command` when checking for incomplete input. -Previously it emitted warnings and raised a SyntaxError. Now it always -returns ``None`` for incomplete input without emitting any warnings. diff --git a/Misc/NEWS.d/next/Library/2022-08-27-14-38-49.gh-issue-90467.VOOB0p.rst b/Misc/NEWS.d/next/Library/2022-08-27-14-38-49.gh-issue-90467.VOOB0p.rst deleted file mode 100644 index 282c0e76a8c8..000000000000 --- a/Misc/NEWS.d/next/Library/2022-08-27-14-38-49.gh-issue-90467.VOOB0p.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix :class:`asyncio.streams.StreamReaderProtocol` to keep a strong reference -to the created task, so that it's not garbage collected diff --git a/Misc/NEWS.d/next/Library/2022-08-29-12-35-28.gh-issue-96073.WaGstf.rst b/Misc/NEWS.d/next/Library/2022-08-29-12-35-28.gh-issue-96073.WaGstf.rst deleted file mode 100644 index 8f20588c4c58..000000000000 --- a/Misc/NEWS.d/next/Library/2022-08-29-12-35-28.gh-issue-96073.WaGstf.rst +++ /dev/null @@ -1 +0,0 @@ -In :mod:`inspect`, fix overeager replacement of "``typing.``" in formatting annotations. diff --git a/Misc/NEWS.d/next/Library/2022-09-07-22-49-37.gh-issue-96652.YqOKxI.rst b/Misc/NEWS.d/next/Library/2022-09-07-22-49-37.gh-issue-96652.YqOKxI.rst deleted file mode 100644 index 1d04db7b2a25..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-07-22-49-37.gh-issue-96652.YqOKxI.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix the faulthandler implementation of ``faulthandler.register(signal, -chain=True)`` if the ``sigaction()`` function is not available: don't call -the previous signal handler if it's NULL. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Library/2022-09-15-00-37-33.gh-issue-96741.4b6czN.rst b/Misc/NEWS.d/next/Library/2022-09-15-00-37-33.gh-issue-96741.4b6czN.rst deleted file mode 100644 index e7f53311e589..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-15-00-37-33.gh-issue-96741.4b6czN.rst +++ /dev/null @@ -1 +0,0 @@ -Corrected type annotation for dataclass attribute ``pstats.FunctionProfile.ncalls`` to be ``str``. diff --git a/Misc/NEWS.d/next/Library/2022-09-17-13-15-10.gh-issue-96819.6RfqM7.rst b/Misc/NEWS.d/next/Library/2022-09-17-13-15-10.gh-issue-96819.6RfqM7.rst deleted file mode 100644 index 07b62a883b85..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-17-13-15-10.gh-issue-96819.6RfqM7.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed check in :mod:`multiprocessing.resource_tracker` that guarantees that the length of a write to a pipe is not greater than ``PIPE_BUF``. diff --git a/Misc/NEWS.d/next/Library/2022-09-22-11-50-29.gh-issue-85760.DETTPd.rst b/Misc/NEWS.d/next/Library/2022-09-22-11-50-29.gh-issue-85760.DETTPd.rst deleted file mode 100644 index af8ae2026f16..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-22-11-50-29.gh-issue-85760.DETTPd.rst +++ /dev/null @@ -1 +0,0 @@ -Fix race condition in :mod:`asyncio` where :meth:`~asyncio.SubprocessProtocol.process_exited` called before the :meth:`~asyncio.SubprocessProtocol.pipe_data_received` leading to inconsistent output. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Library/2022-09-22-14-35-02.gh-issue-97005.yf21Q7.rst b/Misc/NEWS.d/next/Library/2022-09-22-14-35-02.gh-issue-97005.yf21Q7.rst deleted file mode 100644 index d57999aa29b7..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-22-14-35-02.gh-issue-97005.yf21Q7.rst +++ /dev/null @@ -1 +0,0 @@ -Update bundled libexpat to 2.4.9 diff --git a/Misc/NEWS.d/next/Library/2022-09-25-20-42-33.gh-issue-73588.uVtjEA.rst b/Misc/NEWS.d/next/Library/2022-09-25-20-42-33.gh-issue-73588.uVtjEA.rst deleted file mode 100644 index d8a0e690e291..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-25-20-42-33.gh-issue-73588.uVtjEA.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix generation of the default name of :class:`tkinter.Checkbutton`. -Previously, checkbuttons in different parent widgets could have the same -short name and share the same state if arguments "name" and "variable" are -not specified. Now they are globally unique. diff --git a/Misc/NEWS.d/next/Library/2022-09-25-23-24-52.gh-issue-97545.HZLSNt.rst b/Misc/NEWS.d/next/Library/2022-09-25-23-24-52.gh-issue-97545.HZLSNt.rst deleted file mode 100644 index a53902ea670b..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-25-23-24-52.gh-issue-97545.HZLSNt.rst +++ /dev/null @@ -1 +0,0 @@ -Make Semaphore run faster. diff --git a/Misc/NEWS.d/next/Library/2022-09-29-08-15-55.gh-issue-97639.JSjWYW.rst b/Misc/NEWS.d/next/Library/2022-09-29-08-15-55.gh-issue-97639.JSjWYW.rst deleted file mode 100644 index 65c3105f3bc3..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-29-08-15-55.gh-issue-97639.JSjWYW.rst +++ /dev/null @@ -1 +0,0 @@ -Remove ``tokenize.NL`` check from :mod:`tabnanny`. diff --git a/Misc/NEWS.d/next/Library/2022-09-29-23-22-24.gh-issue-97592.tpJg_J.rst b/Misc/NEWS.d/next/Library/2022-09-29-23-22-24.gh-issue-97592.tpJg_J.rst deleted file mode 100644 index aa245cf94400..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-29-23-22-24.gh-issue-97592.tpJg_J.rst +++ /dev/null @@ -1 +0,0 @@ -Avoid a crash in the C version of :meth:`asyncio.Future.remove_done_callback` when an evil argument is passed. diff --git a/Misc/NEWS.d/next/Library/2022-09-30-15-56-20.gh-issue-96827.lzy1iw.rst b/Misc/NEWS.d/next/Library/2022-09-30-15-56-20.gh-issue-96827.lzy1iw.rst deleted file mode 100644 index 159ab32ffbfc..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-30-15-56-20.gh-issue-96827.lzy1iw.rst +++ /dev/null @@ -1 +0,0 @@ -Avoid spurious tracebacks from :mod:`asyncio` when default executor cleanup is delayed until after the event loop is closed (e.g. as the result of a keyboard interrupt). diff --git a/Misc/NEWS.d/next/Library/2022-10-04-07-55-19.gh-issue-97825.mNdv1l.rst b/Misc/NEWS.d/next/Library/2022-10-04-07-55-19.gh-issue-97825.mNdv1l.rst deleted file mode 100644 index 4633dce7b663..000000000000 --- a/Misc/NEWS.d/next/Library/2022-10-04-07-55-19.gh-issue-97825.mNdv1l.rst +++ /dev/null @@ -1 +0,0 @@ -Fixes :exc:`AttributeError` when :meth:`subprocess.check_output` is used with argument ``input=None`` and either of the arguments *encoding* or *errors* are used. diff --git a/Misc/NEWS.d/next/Library/2022-10-09-12-12-38.gh-issue-87730.ClgP3f.rst b/Misc/NEWS.d/next/Library/2022-10-09-12-12-38.gh-issue-87730.ClgP3f.rst deleted file mode 100644 index 6c63fa4928c6..000000000000 --- a/Misc/NEWS.d/next/Library/2022-10-09-12-12-38.gh-issue-87730.ClgP3f.rst +++ /dev/null @@ -1,3 +0,0 @@ -Wrap network errors consistently in urllib FTP support, so the test suite -doesn't fail when a network is available but the public internet is not -reachable. diff --git a/Misc/NEWS.d/next/Security/2022-04-27-18-25-30.gh-issue-68966.gjS8zs.rst b/Misc/NEWS.d/next/Security/2022-04-27-18-25-30.gh-issue-68966.gjS8zs.rst deleted file mode 100644 index da81a1f6993d..000000000000 --- a/Misc/NEWS.d/next/Security/2022-04-27-18-25-30.gh-issue-68966.gjS8zs.rst +++ /dev/null @@ -1,4 +0,0 @@ -The deprecated mailcap module now refuses to inject unsafe text (filenames, -MIME types, parameters) into shell commands. Instead of using such text, it -will warn and act as if a match was not found (or for test commands, as if -the test failed). diff --git a/Misc/NEWS.d/next/Security/2022-09-28-12-10-57.gh-issue-97612.y6NvOQ.rst b/Misc/NEWS.d/next/Security/2022-09-28-12-10-57.gh-issue-97612.y6NvOQ.rst deleted file mode 100644 index 2f113492d42d..000000000000 --- a/Misc/NEWS.d/next/Security/2022-09-28-12-10-57.gh-issue-97612.y6NvOQ.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix a shell code injection vulnerability in the ``get-remote-certificate.py`` -example script. The script no longer uses a shell to run ``openssl`` commands. -Issue reported and initial fix by Caleb Shortt. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Security/2022-09-28-17-09-37.gh-issue-97616.K1e3Xs.rst b/Misc/NEWS.d/next/Security/2022-09-28-17-09-37.gh-issue-97616.K1e3Xs.rst deleted file mode 100644 index 721427fe6465..000000000000 --- a/Misc/NEWS.d/next/Security/2022-09-28-17-09-37.gh-issue-97616.K1e3Xs.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix multiplying a list by an integer (``list *= int``): detect the integer -overflow when the new allocated length is close to the maximum size. Issue -reported by Jordan Limor. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Windows/2022-09-07-00-11-33.gh-issue-96577.kV4K_1.rst b/Misc/NEWS.d/next/Windows/2022-09-07-00-11-33.gh-issue-96577.kV4K_1.rst deleted file mode 100644 index 6025e5ce4130..000000000000 --- a/Misc/NEWS.d/next/Windows/2022-09-07-00-11-33.gh-issue-96577.kV4K_1.rst +++ /dev/null @@ -1 +0,0 @@ -Fixes a potential buffer overrun in :mod:`msilib`. diff --git a/Misc/NEWS.d/next/Windows/2022-09-29-23-08-49.gh-issue-90989.no89Q2.rst b/Misc/NEWS.d/next/Windows/2022-09-29-23-08-49.gh-issue-90989.no89Q2.rst deleted file mode 100644 index 34fffdf9a97b..000000000000 --- a/Misc/NEWS.d/next/Windows/2022-09-29-23-08-49.gh-issue-90989.no89Q2.rst +++ /dev/null @@ -1 +0,0 @@ -Clarify some text in the Windows installer. diff --git a/Misc/NEWS.d/next/Windows/2022-10-02-11-59-23.gh-issue-97728.dIdlPE.rst b/Misc/NEWS.d/next/Windows/2022-10-02-11-59-23.gh-issue-97728.dIdlPE.rst deleted file mode 100644 index 2a6a253a52ae..000000000000 --- a/Misc/NEWS.d/next/Windows/2022-10-02-11-59-23.gh-issue-97728.dIdlPE.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix possible crashes caused by the use of uninitialized variables when pass -invalid arguments in :func:`os.system` on Windows and in Windows-specific -modules (like ``winreg``). diff --git a/Misc/NEWS.d/next/macOS/2022-10-05-15-26-58.gh-issue-97897.Rf-C6u.rst b/Misc/NEWS.d/next/macOS/2022-10-05-15-26-58.gh-issue-97897.Rf-C6u.rst deleted file mode 100644 index 0d21e98b37c5..000000000000 --- a/Misc/NEWS.d/next/macOS/2022-10-05-15-26-58.gh-issue-97897.Rf-C6u.rst +++ /dev/null @@ -1,6 +0,0 @@ -The macOS 13 SDK includes support for the ``mkfifoat`` and ``mknodat`` system calls. -Using the ``dir_fd`` option with either :func:`os.mkfifo` or :func:`os.mknod` could result in a -segfault if cpython is built with the macOS 13 SDK but run on an earlier -version of macOS. Prevent this by adding runtime support for detection of -these system calls ("weaklinking") as is done for other newer syscalls on -macOS. diff --git a/README.rst b/README.rst index 934ae45b3cf0..986940dbb5d8 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -This is Python version 3.10.7 +This is Python version 3.10.8 ============================= .. image:: https://travis-ci.com/python/cpython.svg?branch=master From webhook-mailer at python.org Tue Oct 11 14:09:30 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 11 Oct 2022 18:09:30 -0000 Subject: [Python-checkins] Python 3.8.15 Message-ID: https://github.com/python/cpython/commit/44adf8a80a6e27a394094c99ec0fba8e7124bd7e commit: 44adf8a80a6e27a394094c99ec0fba8e7124bd7e branch: 3.8 author: ?ukasz Langa committer: ambv date: 2022-10-11T17:42:49+02:00 summary: Python 3.8.15 files: A Misc/NEWS.d/3.8.15.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-16-19-02-40.gh-issue-95778.cJmnst.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-21-14-38-31.gh-issue-96848.WuoLzU.rst D Misc/NEWS.d/next/Library/2022-09-22-14-35-02.gh-issue-97005.yf21Q7.rst D Misc/NEWS.d/next/Security/2022-09-28-12-10-57.gh-issue-97612.y6NvOQ.rst D Misc/NEWS.d/next/Security/2022-09-28-17-09-37.gh-issue-97616.K1e3Xs.rst D Misc/NEWS.d/next/Windows/2022-09-07-00-11-33.gh-issue-96577.kV4K_1.rst M Include/patchlevel.h M Lib/pydoc_data/topics.py M README.rst diff --git a/Include/patchlevel.h b/Include/patchlevel.h index c9bf506ea3a6..cf370392fb92 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -18,12 +18,12 @@ /*--start constants--*/ #define PY_MAJOR_VERSION 3 #define PY_MINOR_VERSION 8 -#define PY_MICRO_VERSION 14 +#define PY_MICRO_VERSION 15 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL #define PY_RELEASE_SERIAL 0 /* Version as a string */ -#define PY_VERSION "3.8.14+" +#define PY_VERSION "3.8.15" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py index 0373077652fc..ccd085f780eb 100644 --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Autogenerated by Sphinx on Tue Sep 6 20:52:30 2022 +# Autogenerated by Sphinx on Tue Oct 11 17:41:15 2022 topics = {'assert': 'The "assert" statement\n' '**********************\n' '\n' diff --git a/Misc/NEWS.d/3.8.15.rst b/Misc/NEWS.d/3.8.15.rst new file mode 100644 index 000000000000..9e5f12aeba2c --- /dev/null +++ b/Misc/NEWS.d/3.8.15.rst @@ -0,0 +1,61 @@ +.. date: 2022-09-28-17-09-37 +.. gh-issue: 97616 +.. nonce: K1e3Xs +.. release date: 2022-10-11 +.. section: Security + +Fix multiplying a list by an integer (``list *= int``): detect the integer +overflow when the new allocated length is close to the maximum size. Issue +reported by Jordan Limor. Patch by Victor Stinner. + +.. + +.. date: 2022-09-28-12-10-57 +.. gh-issue: 97612 +.. nonce: y6NvOQ +.. section: Security + +Fix a shell code injection vulnerability in the +``get-remote-certificate.py`` example script. The script no longer uses a +shell to run ``openssl`` commands. Issue reported and initial fix by Caleb +Shortt. Patch by Victor Stinner. + +.. + +.. date: 2022-09-21-14-38-31 +.. gh-issue: 96848 +.. nonce: WuoLzU +.. section: Core and Builtins + +Fix command line parsing: reject :option:`-X int_max_str_digits <-X>` option +with no value (invalid) when the :envvar:`PYTHONINTMAXSTRDIGITS` environment +variable is set to a valid limit. Patch by Victor Stinner. + +.. + +.. date: 2022-09-16-19-02-40 +.. gh-issue: 95778 +.. nonce: cJmnst +.. section: Core and Builtins + +When :exc:`ValueError` is raised if an integer is larger than the limit, +mention the :func:`sys.set_int_max_str_digits` function in the error +message. Patch by Victor Stinner. + +.. + +.. date: 2022-09-22-14-35-02 +.. gh-issue: 97005 +.. nonce: yf21Q7 +.. section: Library + +Update bundled libexpat to 2.4.9 + +.. + +.. date: 2022-09-07-00-11-33 +.. gh-issue: 96577 +.. nonce: kV4K_1 +.. section: Windows + +Fixes a potential buffer overrun in :mod:`msilib`. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-16-19-02-40.gh-issue-95778.cJmnst.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-16-19-02-40.gh-issue-95778.cJmnst.rst deleted file mode 100644 index ebf63778a605..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-16-19-02-40.gh-issue-95778.cJmnst.rst +++ /dev/null @@ -1,3 +0,0 @@ -When :exc:`ValueError` is raised if an integer is larger than the limit, -mention the :func:`sys.set_int_max_str_digits` function in the error message. -Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-21-14-38-31.gh-issue-96848.WuoLzU.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-21-14-38-31.gh-issue-96848.WuoLzU.rst deleted file mode 100644 index a9b04ce87d4d..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-21-14-38-31.gh-issue-96848.WuoLzU.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix command line parsing: reject :option:`-X int_max_str_digits <-X>` option -with no value (invalid) when the :envvar:`PYTHONINTMAXSTRDIGITS` environment -variable is set to a valid limit. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Library/2022-09-22-14-35-02.gh-issue-97005.yf21Q7.rst b/Misc/NEWS.d/next/Library/2022-09-22-14-35-02.gh-issue-97005.yf21Q7.rst deleted file mode 100644 index d57999aa29b7..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-22-14-35-02.gh-issue-97005.yf21Q7.rst +++ /dev/null @@ -1 +0,0 @@ -Update bundled libexpat to 2.4.9 diff --git a/Misc/NEWS.d/next/Security/2022-09-28-12-10-57.gh-issue-97612.y6NvOQ.rst b/Misc/NEWS.d/next/Security/2022-09-28-12-10-57.gh-issue-97612.y6NvOQ.rst deleted file mode 100644 index 2f113492d42d..000000000000 --- a/Misc/NEWS.d/next/Security/2022-09-28-12-10-57.gh-issue-97612.y6NvOQ.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix a shell code injection vulnerability in the ``get-remote-certificate.py`` -example script. The script no longer uses a shell to run ``openssl`` commands. -Issue reported and initial fix by Caleb Shortt. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Security/2022-09-28-17-09-37.gh-issue-97616.K1e3Xs.rst b/Misc/NEWS.d/next/Security/2022-09-28-17-09-37.gh-issue-97616.K1e3Xs.rst deleted file mode 100644 index 721427fe6465..000000000000 --- a/Misc/NEWS.d/next/Security/2022-09-28-17-09-37.gh-issue-97616.K1e3Xs.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix multiplying a list by an integer (``list *= int``): detect the integer -overflow when the new allocated length is close to the maximum size. Issue -reported by Jordan Limor. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Windows/2022-09-07-00-11-33.gh-issue-96577.kV4K_1.rst b/Misc/NEWS.d/next/Windows/2022-09-07-00-11-33.gh-issue-96577.kV4K_1.rst deleted file mode 100644 index 6025e5ce4130..000000000000 --- a/Misc/NEWS.d/next/Windows/2022-09-07-00-11-33.gh-issue-96577.kV4K_1.rst +++ /dev/null @@ -1 +0,0 @@ -Fixes a potential buffer overrun in :mod:`msilib`. diff --git a/README.rst b/README.rst index cc914b0a8c55..f244a926fa79 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -This is Python version 3.8.14 +This is Python version 3.8.15 ============================= .. image:: https://travis-ci.org/python/cpython.svg?branch=3.8 From webhook-mailer at python.org Tue Oct 11 14:09:33 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 11 Oct 2022 18:09:33 -0000 Subject: [Python-checkins] Post 3.8.15 Message-ID: https://github.com/python/cpython/commit/4f1364ca032dac87ef08988ec89d682efc7fa6d2 commit: 4f1364ca032dac87ef08988ec89d682efc7fa6d2 branch: 3.8 author: ?ukasz Langa committer: ambv date: 2022-10-11T20:09:14+02:00 summary: Post 3.8.15 files: M Include/patchlevel.h diff --git a/Include/patchlevel.h b/Include/patchlevel.h index cf370392fb92..04b2eb8ad3fc 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -23,7 +23,7 @@ #define PY_RELEASE_SERIAL 0 /* Version as a string */ -#define PY_VERSION "3.8.15" +#define PY_VERSION "3.8.15+" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. From webhook-mailer at python.org Tue Oct 11 16:27:19 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 11 Oct 2022 20:27:19 -0000 Subject: [Python-checkins] [3.7] gh-68966: Make mailcap refuse to match unsafe filenames/types/params (GH-91993) (GH-98191) Message-ID: https://github.com/python/cpython/commit/6e8e9e7c030b6236ff220362944cba1b93c84bc4 commit: 6e8e9e7c030b6236ff220362944cba1b93c84bc4 branch: 3.7 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-11T22:27:14+02:00 summary: [3.7] gh-68966: Make mailcap refuse to match unsafe filenames/types/params (GH-91993) (GH-98191) gh-68966: Make mailcap refuse to match unsafe filenames/types/params (GH-91993) (cherry picked from commit b9509ba7a9c668b984dab876c7926fe1dc5aa0ba) Co-authored-by: Petr Viktorin files: A Misc/NEWS.d/next/Security/2022-04-27-18-25-30.gh-issue-68966.gjS8zs.rst M Doc/library/mailcap.rst M Lib/mailcap.py M Lib/test/test_mailcap.py diff --git a/Doc/library/mailcap.rst b/Doc/library/mailcap.rst index bf9639bdaca5..a75857be623e 100644 --- a/Doc/library/mailcap.rst +++ b/Doc/library/mailcap.rst @@ -54,6 +54,18 @@ standard. However, mailcap files are supported on most Unix systems. use) to determine whether or not the mailcap line applies. :func:`findmatch` will automatically check such conditions and skip the entry if the check fails. + .. versionchanged:: 3.11 + + To prevent security issues with shell metacharacters (symbols that have + special effects in a shell command line), ``findmatch`` will refuse + to inject ASCII characters other than alphanumerics and ``@+=:,./-_`` + into the returned command line. + + If a disallowed character appears in *filename*, ``findmatch`` will always + return ``(None, None)`` as if no entry was found. + If such a character appears elsewhere (a value in *plist* or in *MIMEtype*), + ``findmatch`` will ignore all mailcap entries which use that value. + A :mod:`warning ` will be raised in either case. .. function:: getcaps() diff --git a/Lib/mailcap.py b/Lib/mailcap.py index bd0fc0981c8c..dcd4b449e828 100644 --- a/Lib/mailcap.py +++ b/Lib/mailcap.py @@ -2,6 +2,7 @@ import os import warnings +import re __all__ = ["getcaps","findmatch"] @@ -13,6 +14,11 @@ def lineno_sort_key(entry): else: return 1, 0 +_find_unsafe = re.compile(r'[^\xa1-\U0010FFFF\w at +=:,./-]').search + +class UnsafeMailcapInput(Warning): + """Warning raised when refusing unsafe input""" + # Part 1: top-level interface. @@ -165,15 +171,22 @@ def findmatch(caps, MIMEtype, key='view', filename="/dev/null", plist=[]): entry to use. """ + if _find_unsafe(filename): + msg = "Refusing to use mailcap with filename %r. Use a safe temporary filename." % (filename,) + warnings.warn(msg, UnsafeMailcapInput) + return None, None entries = lookup(caps, MIMEtype, key) # XXX This code should somehow check for the needsterminal flag. for e in entries: if 'test' in e: test = subst(e['test'], filename, plist) + if test is None: + continue if test and os.system(test) != 0: continue command = subst(e[key], MIMEtype, filename, plist) - return command, e + if command is not None: + return command, e return None, None def lookup(caps, MIMEtype, key=None): @@ -206,6 +219,10 @@ def subst(field, MIMEtype, filename, plist=[]): elif c == 's': res = res + filename elif c == 't': + if _find_unsafe(MIMEtype): + msg = "Refusing to substitute MIME type %r into a shell command." % (MIMEtype,) + warnings.warn(msg, UnsafeMailcapInput) + return None res = res + MIMEtype elif c == '{': start = i @@ -213,7 +230,12 @@ def subst(field, MIMEtype, filename, plist=[]): i = i+1 name = field[start:i] i = i+1 - res = res + findparam(name, plist) + param = findparam(name, plist) + if _find_unsafe(param): + msg = "Refusing to substitute parameter %r (%s) into a shell command" % (param, name) + warnings.warn(msg, UnsafeMailcapInput) + return None + res = res + param # XXX To do: # %n == number of parts if type is multipart/* # %F == list of alternating type and filename for parts diff --git a/Lib/test/test_mailcap.py b/Lib/test/test_mailcap.py index c08423c67073..920283d9a2e3 100644 --- a/Lib/test/test_mailcap.py +++ b/Lib/test/test_mailcap.py @@ -121,7 +121,8 @@ def test_subst(self): (["", "audio/*", "foo.txt"], ""), (["echo foo", "audio/*", "foo.txt"], "echo foo"), (["echo %s", "audio/*", "foo.txt"], "echo foo.txt"), - (["echo %t", "audio/*", "foo.txt"], "echo audio/*"), + (["echo %t", "audio/*", "foo.txt"], None), + (["echo %t", "audio/wav", "foo.txt"], "echo audio/wav"), (["echo \\%t", "audio/*", "foo.txt"], "echo %t"), (["echo foo", "audio/*", "foo.txt", plist], "echo foo"), (["echo %{total}", "audio/*", "foo.txt", plist], "echo 3") @@ -205,7 +206,10 @@ def test_findmatch(self): ('"An audio fragment"', audio_basic_entry)), ([c, "audio/*"], {"filename": fname}, - ("/usr/local/bin/showaudio audio/*", audio_entry)), + (None, None)), + ([c, "audio/wav"], + {"filename": fname}, + ("/usr/local/bin/showaudio audio/wav", audio_entry)), ([c, "message/external-body"], {"plist": plist}, ("showexternal /dev/null default john python.org /tmp foo bar", message_entry)) diff --git a/Misc/NEWS.d/next/Security/2022-04-27-18-25-30.gh-issue-68966.gjS8zs.rst b/Misc/NEWS.d/next/Security/2022-04-27-18-25-30.gh-issue-68966.gjS8zs.rst new file mode 100644 index 000000000000..da81a1f6993d --- /dev/null +++ b/Misc/NEWS.d/next/Security/2022-04-27-18-25-30.gh-issue-68966.gjS8zs.rst @@ -0,0 +1,4 @@ +The deprecated mailcap module now refuses to inject unsafe text (filenames, +MIME types, parameters) into shell commands. Instead of using such text, it +will warn and act as if a match was not found (or for test commands, as if +the test failed). From webhook-mailer at python.org Tue Oct 11 17:13:23 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 11 Oct 2022 21:13:23 -0000 Subject: [Python-checkins] [3.9] gh-68966: Make mailcap refuse to match unsafe filenames/types/params (GH-91993) (#98190) Message-ID: https://github.com/python/cpython/commit/c59a16e2c7495a90e6d23a48ec98623f3fb1e176 commit: c59a16e2c7495a90e6d23a48ec98623f3fb1e176 branch: 3.9 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-11T23:13:18+02:00 summary: [3.9] gh-68966: Make mailcap refuse to match unsafe filenames/types/params (GH-91993) (#98190) gh-68966: Make mailcap refuse to match unsafe filenames/types/params (GH-91993) (cherry picked from commit b9509ba7a9c668b984dab876c7926fe1dc5aa0ba) Co-authored-by: Petr Viktorin files: A Misc/NEWS.d/next/Security/2022-04-27-18-25-30.gh-issue-68966.gjS8zs.rst M Doc/library/mailcap.rst M Lib/mailcap.py M Lib/test/test_mailcap.py diff --git a/Doc/library/mailcap.rst b/Doc/library/mailcap.rst index a22b5b9c9e7b..7aa3380fecae 100644 --- a/Doc/library/mailcap.rst +++ b/Doc/library/mailcap.rst @@ -60,6 +60,18 @@ standard. However, mailcap files are supported on most Unix systems. use) to determine whether or not the mailcap line applies. :func:`findmatch` will automatically check such conditions and skip the entry if the check fails. + .. versionchanged:: 3.11 + + To prevent security issues with shell metacharacters (symbols that have + special effects in a shell command line), ``findmatch`` will refuse + to inject ASCII characters other than alphanumerics and ``@+=:,./-_`` + into the returned command line. + + If a disallowed character appears in *filename*, ``findmatch`` will always + return ``(None, None)`` as if no entry was found. + If such a character appears elsewhere (a value in *plist* or in *MIMEtype*), + ``findmatch`` will ignore all mailcap entries which use that value. + A :mod:`warning ` will be raised in either case. .. function:: getcaps() diff --git a/Lib/mailcap.py b/Lib/mailcap.py index ae416a8e9fb2..444c6408b54c 100644 --- a/Lib/mailcap.py +++ b/Lib/mailcap.py @@ -2,6 +2,7 @@ import os import warnings +import re __all__ = ["getcaps","findmatch"] @@ -13,6 +14,11 @@ def lineno_sort_key(entry): else: return 1, 0 +_find_unsafe = re.compile(r'[^\xa1-\U0010FFFF\w at +=:,./-]').search + +class UnsafeMailcapInput(Warning): + """Warning raised when refusing unsafe input""" + # Part 1: top-level interface. @@ -165,15 +171,22 @@ def findmatch(caps, MIMEtype, key='view', filename="/dev/null", plist=[]): entry to use. """ + if _find_unsafe(filename): + msg = "Refusing to use mailcap with filename %r. Use a safe temporary filename." % (filename,) + warnings.warn(msg, UnsafeMailcapInput) + return None, None entries = lookup(caps, MIMEtype, key) # XXX This code should somehow check for the needsterminal flag. for e in entries: if 'test' in e: test = subst(e['test'], filename, plist) + if test is None: + continue if test and os.system(test) != 0: continue command = subst(e[key], MIMEtype, filename, plist) - return command, e + if command is not None: + return command, e return None, None def lookup(caps, MIMEtype, key=None): @@ -206,6 +219,10 @@ def subst(field, MIMEtype, filename, plist=[]): elif c == 's': res = res + filename elif c == 't': + if _find_unsafe(MIMEtype): + msg = "Refusing to substitute MIME type %r into a shell command." % (MIMEtype,) + warnings.warn(msg, UnsafeMailcapInput) + return None res = res + MIMEtype elif c == '{': start = i @@ -213,7 +230,12 @@ def subst(field, MIMEtype, filename, plist=[]): i = i+1 name = field[start:i] i = i+1 - res = res + findparam(name, plist) + param = findparam(name, plist) + if _find_unsafe(param): + msg = "Refusing to substitute parameter %r (%s) into a shell command" % (param, name) + warnings.warn(msg, UnsafeMailcapInput) + return None + res = res + param # XXX To do: # %n == number of parts if type is multipart/* # %F == list of alternating type and filename for parts diff --git a/Lib/test/test_mailcap.py b/Lib/test/test_mailcap.py index c08423c67073..920283d9a2e3 100644 --- a/Lib/test/test_mailcap.py +++ b/Lib/test/test_mailcap.py @@ -121,7 +121,8 @@ def test_subst(self): (["", "audio/*", "foo.txt"], ""), (["echo foo", "audio/*", "foo.txt"], "echo foo"), (["echo %s", "audio/*", "foo.txt"], "echo foo.txt"), - (["echo %t", "audio/*", "foo.txt"], "echo audio/*"), + (["echo %t", "audio/*", "foo.txt"], None), + (["echo %t", "audio/wav", "foo.txt"], "echo audio/wav"), (["echo \\%t", "audio/*", "foo.txt"], "echo %t"), (["echo foo", "audio/*", "foo.txt", plist], "echo foo"), (["echo %{total}", "audio/*", "foo.txt", plist], "echo 3") @@ -205,7 +206,10 @@ def test_findmatch(self): ('"An audio fragment"', audio_basic_entry)), ([c, "audio/*"], {"filename": fname}, - ("/usr/local/bin/showaudio audio/*", audio_entry)), + (None, None)), + ([c, "audio/wav"], + {"filename": fname}, + ("/usr/local/bin/showaudio audio/wav", audio_entry)), ([c, "message/external-body"], {"plist": plist}, ("showexternal /dev/null default john python.org /tmp foo bar", message_entry)) diff --git a/Misc/NEWS.d/next/Security/2022-04-27-18-25-30.gh-issue-68966.gjS8zs.rst b/Misc/NEWS.d/next/Security/2022-04-27-18-25-30.gh-issue-68966.gjS8zs.rst new file mode 100644 index 000000000000..da81a1f6993d --- /dev/null +++ b/Misc/NEWS.d/next/Security/2022-04-27-18-25-30.gh-issue-68966.gjS8zs.rst @@ -0,0 +1,4 @@ +The deprecated mailcap module now refuses to inject unsafe text (filenames, +MIME types, parameters) into shell commands. Instead of using such text, it +will warn and act as if a match was not found (or for test commands, as if +the test failed). From webhook-mailer at python.org Tue Oct 11 17:13:48 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 11 Oct 2022 21:13:48 -0000 Subject: [Python-checkins] [3.8] gh-96710: Make the test timing more lenient for the int/str DoS regression test. (GH-96717) (#98197) Message-ID: https://github.com/python/cpython/commit/a44cc0a895590e9292193c46d344a14c511e7f33 commit: a44cc0a895590e9292193c46d344a14c511e7f33 branch: 3.8 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-11T23:13:43+02:00 summary: [3.8] gh-96710: Make the test timing more lenient for the int/str DoS regression test. (GH-96717) (#98197) gh-96710: Make the test timing more lenient for the int/str DoS regression test. (GH-96717) A regression would still absolutely fail and even a flaky pass isn't harmful as it'd fail most of the time across our N system test runs. Windows has a low resolution timer and CI systems are prone to odd timing so this just gives more leeway to avoid flakiness. (cherry picked from commit 11e3548fd1d3445ccde971d613633b58d73c3016) Co-authored-by: Gregory P. Smith files: M Lib/test/test_int.py diff --git a/Lib/test/test_int.py b/Lib/test/test_int.py index cbbddf50637c..a8bb99a9e656 100644 --- a/Lib/test/test_int.py +++ b/Lib/test/test_int.py @@ -644,7 +644,8 @@ def test_denial_of_service_prevented_int_to_str(self): self.assertEqual(len(huge_decimal), digits) # Ensuring that we chose a slow enough conversion to measure. # It takes 0.1 seconds on a Zen based cloud VM in an opt build. - if seconds_to_convert < 0.005: + # Some OSes have a low res 1/64s timer, skip if hard to measure. + if seconds_to_convert < 1/64: raise unittest.SkipTest('"slow" conversion took only ' f'{seconds_to_convert} seconds.') @@ -656,7 +657,7 @@ def test_denial_of_service_prevented_int_to_str(self): str(huge_int) seconds_to_fail_huge = get_time() - start self.assertIn('conversion', str(err.exception)) - self.assertLess(seconds_to_fail_huge, seconds_to_convert/8) + self.assertLessEqual(seconds_to_fail_huge, seconds_to_convert/2) # Now we test that a conversion that would take 30x as long also fails # in a similarly fast fashion. @@ -667,7 +668,7 @@ def test_denial_of_service_prevented_int_to_str(self): str(extra_huge_int) seconds_to_fail_extra_huge = get_time() - start self.assertIn('conversion', str(err.exception)) - self.assertLess(seconds_to_fail_extra_huge, seconds_to_convert/8) + self.assertLess(seconds_to_fail_extra_huge, seconds_to_convert/2) def test_denial_of_service_prevented_str_to_int(self): """Regression test: ensure we fail before performing O(N**2) work.""" @@ -685,7 +686,8 @@ def test_denial_of_service_prevented_str_to_int(self): seconds_to_convert = get_time() - start # Ensuring that we chose a slow enough conversion to measure. # It takes 0.1 seconds on a Zen based cloud VM in an opt build. - if seconds_to_convert < 0.005: + # Some OSes have a low res 1/64s timer, skip if hard to measure. + if seconds_to_convert < 1/64: raise unittest.SkipTest('"slow" conversion took only ' f'{seconds_to_convert} seconds.') @@ -695,7 +697,7 @@ def test_denial_of_service_prevented_str_to_int(self): int(huge) seconds_to_fail_huge = get_time() - start self.assertIn('conversion', str(err.exception)) - self.assertLess(seconds_to_fail_huge, seconds_to_convert/8) + self.assertLessEqual(seconds_to_fail_huge, seconds_to_convert/2) # Now we test that a conversion that would take 30x as long also fails # in a similarly fast fashion. @@ -706,7 +708,7 @@ def test_denial_of_service_prevented_str_to_int(self): int(extra_huge) seconds_to_fail_extra_huge = get_time() - start self.assertIn('conversion', str(err.exception)) - self.assertLess(seconds_to_fail_extra_huge, seconds_to_convert/8) + self.assertLessEqual(seconds_to_fail_extra_huge, seconds_to_convert/2) def test_power_of_two_bases_unlimited(self): """The limit does not apply to power of 2 bases.""" From webhook-mailer at python.org Tue Oct 11 17:14:00 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 11 Oct 2022 21:14:00 -0000 Subject: [Python-checkins] [3.9] gh-96710: Make the test timing more lenient for the int/str DoS regression test. (GH-96717) (#98196) Message-ID: https://github.com/python/cpython/commit/157a8b8edda05ce54852429b3ee8dfc58c3c562e commit: 157a8b8edda05ce54852429b3ee8dfc58c3c562e branch: 3.9 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-11T23:13:54+02:00 summary: [3.9] gh-96710: Make the test timing more lenient for the int/str DoS regression test. (GH-96717) (#98196) gh-96710: Make the test timing more lenient for the int/str DoS regression test. (GH-96717) A regression would still absolutely fail and even a flaky pass isn't harmful as it'd fail most of the time across our N system test runs. Windows has a low resolution timer and CI systems are prone to odd timing so this just gives more leeway to avoid flakiness. (cherry picked from commit 11e3548fd1d3445ccde971d613633b58d73c3016) Co-authored-by: Gregory P. Smith files: M Lib/test/test_int.py diff --git a/Lib/test/test_int.py b/Lib/test/test_int.py index cbbddf50637c..a8bb99a9e656 100644 --- a/Lib/test/test_int.py +++ b/Lib/test/test_int.py @@ -644,7 +644,8 @@ def test_denial_of_service_prevented_int_to_str(self): self.assertEqual(len(huge_decimal), digits) # Ensuring that we chose a slow enough conversion to measure. # It takes 0.1 seconds on a Zen based cloud VM in an opt build. - if seconds_to_convert < 0.005: + # Some OSes have a low res 1/64s timer, skip if hard to measure. + if seconds_to_convert < 1/64: raise unittest.SkipTest('"slow" conversion took only ' f'{seconds_to_convert} seconds.') @@ -656,7 +657,7 @@ def test_denial_of_service_prevented_int_to_str(self): str(huge_int) seconds_to_fail_huge = get_time() - start self.assertIn('conversion', str(err.exception)) - self.assertLess(seconds_to_fail_huge, seconds_to_convert/8) + self.assertLessEqual(seconds_to_fail_huge, seconds_to_convert/2) # Now we test that a conversion that would take 30x as long also fails # in a similarly fast fashion. @@ -667,7 +668,7 @@ def test_denial_of_service_prevented_int_to_str(self): str(extra_huge_int) seconds_to_fail_extra_huge = get_time() - start self.assertIn('conversion', str(err.exception)) - self.assertLess(seconds_to_fail_extra_huge, seconds_to_convert/8) + self.assertLess(seconds_to_fail_extra_huge, seconds_to_convert/2) def test_denial_of_service_prevented_str_to_int(self): """Regression test: ensure we fail before performing O(N**2) work.""" @@ -685,7 +686,8 @@ def test_denial_of_service_prevented_str_to_int(self): seconds_to_convert = get_time() - start # Ensuring that we chose a slow enough conversion to measure. # It takes 0.1 seconds on a Zen based cloud VM in an opt build. - if seconds_to_convert < 0.005: + # Some OSes have a low res 1/64s timer, skip if hard to measure. + if seconds_to_convert < 1/64: raise unittest.SkipTest('"slow" conversion took only ' f'{seconds_to_convert} seconds.') @@ -695,7 +697,7 @@ def test_denial_of_service_prevented_str_to_int(self): int(huge) seconds_to_fail_huge = get_time() - start self.assertIn('conversion', str(err.exception)) - self.assertLess(seconds_to_fail_huge, seconds_to_convert/8) + self.assertLessEqual(seconds_to_fail_huge, seconds_to_convert/2) # Now we test that a conversion that would take 30x as long also fails # in a similarly fast fashion. @@ -706,7 +708,7 @@ def test_denial_of_service_prevented_str_to_int(self): int(extra_huge) seconds_to_fail_extra_huge = get_time() - start self.assertIn('conversion', str(err.exception)) - self.assertLess(seconds_to_fail_extra_huge, seconds_to_convert/8) + self.assertLessEqual(seconds_to_fail_extra_huge, seconds_to_convert/2) def test_power_of_two_bases_unlimited(self): """The limit does not apply to power of 2 bases.""" From webhook-mailer at python.org Tue Oct 11 17:14:11 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 11 Oct 2022 21:14:11 -0000 Subject: [Python-checkins] [3.7] gh-96710: Make the test timing more lenient for the int/str DoS regression test. (GH-96717) (#98195) Message-ID: https://github.com/python/cpython/commit/e7fe11186504ec59937a3364cf62e76848d32361 commit: e7fe11186504ec59937a3364cf62e76848d32361 branch: 3.7 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-11T23:14:05+02:00 summary: [3.7] gh-96710: Make the test timing more lenient for the int/str DoS regression test. (GH-96717) (#98195) gh-96710: Make the test timing more lenient for the int/str DoS regression test. (GH-96717) A regression would still absolutely fail and even a flaky pass isn't harmful as it'd fail most of the time across our N system test runs. Windows has a low resolution timer and CI systems are prone to odd timing so this just gives more leeway to avoid flakiness. (cherry picked from commit 11e3548fd1d3445ccde971d613633b58d73c3016) Co-authored-by: Gregory P. Smith files: M Lib/test/test_int.py diff --git a/Lib/test/test_int.py b/Lib/test/test_int.py index 98ba847e7d00..436d2df4ca88 100644 --- a/Lib/test/test_int.py +++ b/Lib/test/test_int.py @@ -589,7 +589,8 @@ def test_denial_of_service_prevented_int_to_str(self): self.assertEqual(len(huge_decimal), digits) # Ensuring that we chose a slow enough conversion to measure. # It takes 0.1 seconds on a Zen based cloud VM in an opt build. - if seconds_to_convert < 0.005: + # Some OSes have a low res 1/64s timer, skip if hard to measure. + if seconds_to_convert < 1/64: raise unittest.SkipTest('"slow" conversion took only ' f'{seconds_to_convert} seconds.') @@ -601,7 +602,7 @@ def test_denial_of_service_prevented_int_to_str(self): str(huge_int) seconds_to_fail_huge = get_time() - start self.assertIn('conversion', str(err.exception)) - self.assertLess(seconds_to_fail_huge, seconds_to_convert/8) + self.assertLessEqual(seconds_to_fail_huge, seconds_to_convert/2) # Now we test that a conversion that would take 30x as long also fails # in a similarly fast fashion. @@ -612,7 +613,7 @@ def test_denial_of_service_prevented_int_to_str(self): str(extra_huge_int) seconds_to_fail_extra_huge = get_time() - start self.assertIn('conversion', str(err.exception)) - self.assertLess(seconds_to_fail_extra_huge, seconds_to_convert/8) + self.assertLess(seconds_to_fail_extra_huge, seconds_to_convert/2) def test_denial_of_service_prevented_str_to_int(self): """Regression test: ensure we fail before performing O(N**2) work.""" @@ -630,7 +631,8 @@ def test_denial_of_service_prevented_str_to_int(self): seconds_to_convert = get_time() - start # Ensuring that we chose a slow enough conversion to measure. # It takes 0.1 seconds on a Zen based cloud VM in an opt build. - if seconds_to_convert < 0.005: + # Some OSes have a low res 1/64s timer, skip if hard to measure. + if seconds_to_convert < 1/64: raise unittest.SkipTest('"slow" conversion took only ' f'{seconds_to_convert} seconds.') @@ -640,7 +642,7 @@ def test_denial_of_service_prevented_str_to_int(self): int(huge) seconds_to_fail_huge = get_time() - start self.assertIn('conversion', str(err.exception)) - self.assertLess(seconds_to_fail_huge, seconds_to_convert/8) + self.assertLessEqual(seconds_to_fail_huge, seconds_to_convert/2) # Now we test that a conversion that would take 30x as long also fails # in a similarly fast fashion. @@ -651,7 +653,7 @@ def test_denial_of_service_prevented_str_to_int(self): int(extra_huge) seconds_to_fail_extra_huge = get_time() - start self.assertIn('conversion', str(err.exception)) - self.assertLess(seconds_to_fail_extra_huge, seconds_to_convert/8) + self.assertLessEqual(seconds_to_fail_extra_huge, seconds_to_convert/2) def test_power_of_two_bases_unlimited(self): """The limit does not apply to power of 2 bases.""" From webhook-mailer at python.org Tue Oct 11 17:58:09 2022 From: webhook-mailer at python.org (ambv) Date: Tue, 11 Oct 2022 21:58:09 -0000 Subject: [Python-checkins] [3.8] gh-68966: Make mailcap refuse to match unsafe filenames/types/params (GH-91993) (#98192) Message-ID: https://github.com/python/cpython/commit/0a4f650347fdcfd82d094ab2134ca89584f4e877 commit: 0a4f650347fdcfd82d094ab2134ca89584f4e877 branch: 3.8 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-11T23:58:03+02:00 summary: [3.8] gh-68966: Make mailcap refuse to match unsafe filenames/types/params (GH-91993) (#98192) gh-68966: Make mailcap refuse to match unsafe filenames/types/params (GH-91993) (cherry picked from commit b9509ba7a9c668b984dab876c7926fe1dc5aa0ba) Co-authored-by: Petr Viktorin Co-authored-by: ?ukasz Langa files: A Misc/NEWS.d/next/Security/2022-04-27-18-25-30.gh-issue-68966.gjS8zs.rst M Doc/library/mailcap.rst M Lib/mailcap.py M Lib/test/test_mailcap.py diff --git a/Doc/library/mailcap.rst b/Doc/library/mailcap.rst index bf9639bdaca5..a75857be623e 100644 --- a/Doc/library/mailcap.rst +++ b/Doc/library/mailcap.rst @@ -54,6 +54,18 @@ standard. However, mailcap files are supported on most Unix systems. use) to determine whether or not the mailcap line applies. :func:`findmatch` will automatically check such conditions and skip the entry if the check fails. + .. versionchanged:: 3.11 + + To prevent security issues with shell metacharacters (symbols that have + special effects in a shell command line), ``findmatch`` will refuse + to inject ASCII characters other than alphanumerics and ``@+=:,./-_`` + into the returned command line. + + If a disallowed character appears in *filename*, ``findmatch`` will always + return ``(None, None)`` as if no entry was found. + If such a character appears elsewhere (a value in *plist* or in *MIMEtype*), + ``findmatch`` will ignore all mailcap entries which use that value. + A :mod:`warning ` will be raised in either case. .. function:: getcaps() diff --git a/Lib/mailcap.py b/Lib/mailcap.py index bd0fc0981c8c..dcd4b449e828 100644 --- a/Lib/mailcap.py +++ b/Lib/mailcap.py @@ -2,6 +2,7 @@ import os import warnings +import re __all__ = ["getcaps","findmatch"] @@ -13,6 +14,11 @@ def lineno_sort_key(entry): else: return 1, 0 +_find_unsafe = re.compile(r'[^\xa1-\U0010FFFF\w at +=:,./-]').search + +class UnsafeMailcapInput(Warning): + """Warning raised when refusing unsafe input""" + # Part 1: top-level interface. @@ -165,15 +171,22 @@ def findmatch(caps, MIMEtype, key='view', filename="/dev/null", plist=[]): entry to use. """ + if _find_unsafe(filename): + msg = "Refusing to use mailcap with filename %r. Use a safe temporary filename." % (filename,) + warnings.warn(msg, UnsafeMailcapInput) + return None, None entries = lookup(caps, MIMEtype, key) # XXX This code should somehow check for the needsterminal flag. for e in entries: if 'test' in e: test = subst(e['test'], filename, plist) + if test is None: + continue if test and os.system(test) != 0: continue command = subst(e[key], MIMEtype, filename, plist) - return command, e + if command is not None: + return command, e return None, None def lookup(caps, MIMEtype, key=None): @@ -206,6 +219,10 @@ def subst(field, MIMEtype, filename, plist=[]): elif c == 's': res = res + filename elif c == 't': + if _find_unsafe(MIMEtype): + msg = "Refusing to substitute MIME type %r into a shell command." % (MIMEtype,) + warnings.warn(msg, UnsafeMailcapInput) + return None res = res + MIMEtype elif c == '{': start = i @@ -213,7 +230,12 @@ def subst(field, MIMEtype, filename, plist=[]): i = i+1 name = field[start:i] i = i+1 - res = res + findparam(name, plist) + param = findparam(name, plist) + if _find_unsafe(param): + msg = "Refusing to substitute parameter %r (%s) into a shell command" % (param, name) + warnings.warn(msg, UnsafeMailcapInput) + return None + res = res + param # XXX To do: # %n == number of parts if type is multipart/* # %F == list of alternating type and filename for parts diff --git a/Lib/test/test_mailcap.py b/Lib/test/test_mailcap.py index c08423c67073..920283d9a2e3 100644 --- a/Lib/test/test_mailcap.py +++ b/Lib/test/test_mailcap.py @@ -121,7 +121,8 @@ def test_subst(self): (["", "audio/*", "foo.txt"], ""), (["echo foo", "audio/*", "foo.txt"], "echo foo"), (["echo %s", "audio/*", "foo.txt"], "echo foo.txt"), - (["echo %t", "audio/*", "foo.txt"], "echo audio/*"), + (["echo %t", "audio/*", "foo.txt"], None), + (["echo %t", "audio/wav", "foo.txt"], "echo audio/wav"), (["echo \\%t", "audio/*", "foo.txt"], "echo %t"), (["echo foo", "audio/*", "foo.txt", plist], "echo foo"), (["echo %{total}", "audio/*", "foo.txt", plist], "echo 3") @@ -205,7 +206,10 @@ def test_findmatch(self): ('"An audio fragment"', audio_basic_entry)), ([c, "audio/*"], {"filename": fname}, - ("/usr/local/bin/showaudio audio/*", audio_entry)), + (None, None)), + ([c, "audio/wav"], + {"filename": fname}, + ("/usr/local/bin/showaudio audio/wav", audio_entry)), ([c, "message/external-body"], {"plist": plist}, ("showexternal /dev/null default john python.org /tmp foo bar", message_entry)) diff --git a/Misc/NEWS.d/next/Security/2022-04-27-18-25-30.gh-issue-68966.gjS8zs.rst b/Misc/NEWS.d/next/Security/2022-04-27-18-25-30.gh-issue-68966.gjS8zs.rst new file mode 100644 index 000000000000..da81a1f6993d --- /dev/null +++ b/Misc/NEWS.d/next/Security/2022-04-27-18-25-30.gh-issue-68966.gjS8zs.rst @@ -0,0 +1,4 @@ +The deprecated mailcap module now refuses to inject unsafe text (filenames, +MIME types, parameters) into shell commands. Instead of using such text, it +will warn and act as if a match was not found (or for test commands, as if +the test failed). From webhook-mailer at python.org Tue Oct 11 19:46:09 2022 From: webhook-mailer at python.org (gvanrossum) Date: Tue, 11 Oct 2022 23:46:09 -0000 Subject: [Python-checkins] Fix some incorrect indentation around the main switch (#98177) Message-ID: https://github.com/python/cpython/commit/f5d71073e61b69b3ab331736fd69dc6324405775 commit: f5d71073e61b69b3ab331736fd69dc6324405775 branch: main author: Guido van Rossum committer: gvanrossum date: 2022-10-11T16:45:53-07:00 summary: Fix some incorrect indentation around the main switch (#98177) The `}` marked with `/* End instructions */` is the end of the switch. There is another pair of `{}` around the switch, which is vestigial from ancient times when it was `for (;;) { switch (opcode) { ... } }`. All `DISPATCH` macro calls should be inside that pair. files: M Python/ceval.c diff --git a/Python/ceval.c b/Python/ceval.c index ee1babaaf444..a112f8bebb5a 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1152,12 +1152,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int { /* Start instructions */ -#if USE_COMPUTED_GOTOS - { -#else +#if !USE_COMPUTED_GOTOS dispatch_opcode: - switch (opcode) { + switch (opcode) #endif + { /* BEWARE! It is essential that any operation that fails must goto error @@ -5102,23 +5101,23 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int /* Specialization misses */ miss: - { - STAT_INC(opcode, miss); - opcode = _PyOpcode_Deopt[opcode]; - STAT_INC(opcode, miss); - /* The counter is always the first cache entry: */ - _Py_CODEUNIT *counter = (_Py_CODEUNIT *)next_instr; - *counter -= 1; - if (*counter == 0) { - int adaptive_opcode = _PyOpcode_Adaptive[opcode]; - assert(adaptive_opcode); - _Py_SET_OPCODE(next_instr[-1], adaptive_opcode); - STAT_INC(opcode, deopt); - *counter = adaptive_counter_start(); - } - next_instr--; - DISPATCH_GOTO(); - } + { + STAT_INC(opcode, miss); + opcode = _PyOpcode_Deopt[opcode]; + STAT_INC(opcode, miss); + /* The counter is always the first cache entry: */ + _Py_CODEUNIT *counter = (_Py_CODEUNIT *)next_instr; + *counter -= 1; + if (*counter == 0) { + int adaptive_opcode = _PyOpcode_Adaptive[opcode]; + assert(adaptive_opcode); + _Py_SET_OPCODE(next_instr[-1], adaptive_opcode); + STAT_INC(opcode, deopt); + *counter = adaptive_counter_start(); + } + next_instr--; + DISPATCH_GOTO(); + } unbound_local_error: { From webhook-mailer at python.org Tue Oct 11 22:38:07 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Wed, 12 Oct 2022 02:38:07 -0000 Subject: [Python-checkins] gh-96130: Rephrase use of "typecheck" verb for clarity (#98144) Message-ID: https://github.com/python/cpython/commit/ed6344eed043eaaa41d11c1176c25aa79de64ef4 commit: ed6344eed043eaaa41d11c1176c25aa79de64ef4 branch: main author: Shantanu <12621235+hauntsaninja at users.noreply.github.com> committer: JelleZijlstra date: 2022-10-11T19:37:58-07:00 summary: gh-96130: Rephrase use of "typecheck" verb for clarity (#98144) I'm sympathetic to the issue report, especially in case this helps clarify to new users that Python itself does not do type checking at runtime files: M Doc/library/typing.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index f63d61eb1ea3..fee55becc7f5 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -105,7 +105,7 @@ A type alias is defined by assigning the type to the alias. In this example, def scale(scalar: float, vector: Vector) -> Vector: return [scalar * num for num in vector] - # typechecks; a list of floats qualifies as a Vector. + # passes type checking; a list of floats qualifies as a Vector. new_vector = scale(2.0, [1.0, -4.2, 5.4]) Type aliases are useful for simplifying complex type signatures. For example:: @@ -147,10 +147,10 @@ of the original type. This is useful in helping catch logical errors:: def get_user_name(user_id: UserId) -> str: ... - # typechecks + # passes type checking user_a = get_user_name(UserId(42351)) - # does not typecheck; an int is not a UserId + # fails type checking; an int is not a UserId user_b = get_user_name(-1) You may still perform all ``int`` operations on a variable of type ``UserId``, @@ -176,7 +176,7 @@ It is invalid to create a subtype of ``Derived``:: UserId = NewType('UserId', int) - # Fails at runtime and does not typecheck + # Fails at runtime and does not pass type checking class AdminUserId(UserId): pass However, it is possible to create a :class:`NewType` based on a 'derived' ``NewType``:: @@ -463,12 +463,12 @@ value of type :data:`Any` and assign it to any variable:: s = a # OK def foo(item: Any) -> int: - # Typechecks; 'item' could be any type, + # Passes type checking; 'item' could be any type, # and that type might have a 'bar' method item.bar() ... -Notice that no typechecking is performed when assigning a value of type +Notice that no type checking is performed when assigning a value of type :data:`Any` to a more precise type. For example, the static type checker did not report an error when assigning ``a`` to ``s`` even though ``s`` was declared to be of type :class:`str` and receives an :class:`int` value at @@ -500,20 +500,20 @@ reject almost all operations on it, and assigning it to a variable (or using it as a return value) of a more specialized type is a type error. For example:: def hash_a(item: object) -> int: - # Fails; an object does not have a 'magic' method. + # Fails type checking; an object does not have a 'magic' method. item.magic() ... def hash_b(item: Any) -> int: - # Typechecks + # Passes type checking item.magic() ... - # Typechecks, since ints and strs are subclasses of object + # Passes type checking, since ints and strs are subclasses of object hash_a(42) hash_a("foo") - # Typechecks, since Any is compatible with all types + # Passes type checking, since Any is compatible with all types hash_b(42) hash_b("foo") From webhook-mailer at python.org Tue Oct 11 22:41:16 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Wed, 12 Oct 2022 02:41:16 -0000 Subject: [Python-checkins] gh-95276: Add callable entry to the glossary (#95738) Message-ID: https://github.com/python/cpython/commit/e3bf125c81d5da0734429c1cb6ae75e6086e35ae commit: e3bf125c81d5da0734429c1cb6ae75e6086e35ae branch: main author: MonadChains committer: JelleZijlstra date: 2022-10-11T19:41:08-07:00 summary: gh-95276: Add callable entry to the glossary (#95738) files: M Doc/glossary.rst diff --git a/Doc/glossary.rst b/Doc/glossary.rst index 9385b8ddd13d..59f9426f6031 100644 --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -210,6 +210,16 @@ Glossary A list of bytecode instructions can be found in the documentation for :ref:`the dis module `. + callable + A callable is an object that can be called, possibly with a set + of arguments (see :term:`argument`), with the following syntax:: + + callable(argument1, argument2, ...) + + A :term:`function`, and by extension a :term:`method`, is a callable. + An instance of a class that implements the :meth:`~object.__call__` + method is also a callable. + callback A subroutine function which is passed as an argument to be executed at some point in the future. From webhook-mailer at python.org Tue Oct 11 22:45:49 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 12 Oct 2022 02:45:49 -0000 Subject: [Python-checkins] gh-96130: Rephrase use of "typecheck" verb for clarity (GH-98144) Message-ID: https://github.com/python/cpython/commit/d22c35dfffe738eccb45244037407588328cf828 commit: d22c35dfffe738eccb45244037407588328cf828 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-11T19:45:44-07:00 summary: gh-96130: Rephrase use of "typecheck" verb for clarity (GH-98144) I'm sympathetic to the issue report, especially in case this helps clarify to new users that Python itself does not do type checking at runtime (cherry picked from commit ed6344eed043eaaa41d11c1176c25aa79de64ef4) Co-authored-by: Shantanu <12621235+hauntsaninja at users.noreply.github.com> files: M Doc/library/typing.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index b75aa333f73e..070f3006e20c 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -105,7 +105,7 @@ A type alias is defined by assigning the type to the alias. In this example, def scale(scalar: float, vector: Vector) -> Vector: return [scalar * num for num in vector] - # typechecks; a list of floats qualifies as a Vector. + # passes type checking; a list of floats qualifies as a Vector. new_vector = scale(2.0, [1.0, -4.2, 5.4]) Type aliases are useful for simplifying complex type signatures. For example:: @@ -147,10 +147,10 @@ of the original type. This is useful in helping catch logical errors:: def get_user_name(user_id: UserId) -> str: ... - # typechecks + # passes type checking user_a = get_user_name(UserId(42351)) - # does not typecheck; an int is not a UserId + # fails type checking; an int is not a UserId user_b = get_user_name(-1) You may still perform all ``int`` operations on a variable of type ``UserId``, @@ -176,7 +176,7 @@ It is invalid to create a subtype of ``Derived``:: UserId = NewType('UserId', int) - # Fails at runtime and does not typecheck + # Fails at runtime and does not pass type checking class AdminUserId(UserId): pass However, it is possible to create a :class:`NewType` based on a 'derived' ``NewType``:: @@ -463,12 +463,12 @@ value of type :data:`Any` and assign it to any variable:: s = a # OK def foo(item: Any) -> int: - # Typechecks; 'item' could be any type, + # Passes type checking; 'item' could be any type, # and that type might have a 'bar' method item.bar() ... -Notice that no typechecking is performed when assigning a value of type +Notice that no type checking is performed when assigning a value of type :data:`Any` to a more precise type. For example, the static type checker did not report an error when assigning ``a`` to ``s`` even though ``s`` was declared to be of type :class:`str` and receives an :class:`int` value at @@ -500,20 +500,20 @@ reject almost all operations on it, and assigning it to a variable (or using it as a return value) of a more specialized type is a type error. For example:: def hash_a(item: object) -> int: - # Fails; an object does not have a 'magic' method. + # Fails type checking; an object does not have a 'magic' method. item.magic() ... def hash_b(item: Any) -> int: - # Typechecks + # Passes type checking item.magic() ... - # Typechecks, since ints and strs are subclasses of object + # Passes type checking, since ints and strs are subclasses of object hash_a(42) hash_a("foo") - # Typechecks, since Any is compatible with all types + # Passes type checking, since Any is compatible with all types hash_b(42) hash_b("foo") From webhook-mailer at python.org Tue Oct 11 22:48:45 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 12 Oct 2022 02:48:45 -0000 Subject: [Python-checkins] gh-96130: Rephrase use of "typecheck" verb for clarity (GH-98144) Message-ID: https://github.com/python/cpython/commit/48447d44edbc661503f2e2ea30f811632926d37c commit: 48447d44edbc661503f2e2ea30f811632926d37c branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-11T19:48:39-07:00 summary: gh-96130: Rephrase use of "typecheck" verb for clarity (GH-98144) I'm sympathetic to the issue report, especially in case this helps clarify to new users that Python itself does not do type checking at runtime (cherry picked from commit ed6344eed043eaaa41d11c1176c25aa79de64ef4) Co-authored-by: Shantanu <12621235+hauntsaninja at users.noreply.github.com> files: M Doc/library/typing.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 2600ac311821..c1cf899203c8 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -91,7 +91,7 @@ A type alias is defined by assigning the type to the alias. In this example, def scale(scalar: float, vector: Vector) -> Vector: return [scalar * num for num in vector] - # typechecks; a list of floats qualifies as a Vector. + # passes type checking; a list of floats qualifies as a Vector. new_vector = scale(2.0, [1.0, -4.2, 5.4]) Type aliases are useful for simplifying complex type signatures. For example:: @@ -133,10 +133,10 @@ of the original type. This is useful in helping catch logical errors:: def get_user_name(user_id: UserId) -> str: ... - # typechecks + # passes type checking user_a = get_user_name(UserId(42351)) - # does not typecheck; an int is not a UserId + # fails type checking; an int is not a UserId user_b = get_user_name(-1) You may still perform all ``int`` operations on a variable of type ``UserId``, @@ -162,7 +162,7 @@ It is invalid to create a subtype of ``Derived``:: UserId = NewType('UserId', int) - # Fails at runtime and does not typecheck + # Fails at runtime and does not pass type checking class AdminUserId(UserId): pass However, it is possible to create a :class:`NewType` based on a 'derived' ``NewType``:: @@ -449,12 +449,12 @@ value of type :data:`Any` and assign it to any variable:: s = a # OK def foo(item: Any) -> int: - # Typechecks; 'item' could be any type, + # Passes type checking; 'item' could be any type, # and that type might have a 'bar' method item.bar() ... -Notice that no typechecking is performed when assigning a value of type +Notice that no type checking is performed when assigning a value of type :data:`Any` to a more precise type. For example, the static type checker did not report an error when assigning ``a`` to ``s`` even though ``s`` was declared to be of type :class:`str` and receives an :class:`int` value at @@ -486,20 +486,20 @@ reject almost all operations on it, and assigning it to a variable (or using it as a return value) of a more specialized type is a type error. For example:: def hash_a(item: object) -> int: - # Fails; an object does not have a 'magic' method. + # Fails type checking; an object does not have a 'magic' method. item.magic() ... def hash_b(item: Any) -> int: - # Typechecks + # Passes type checking item.magic() ... - # Typechecks, since ints and strs are subclasses of object + # Passes type checking, since ints and strs are subclasses of object hash_a(42) hash_a("foo") - # Typechecks, since Any is compatible with all types + # Passes type checking, since Any is compatible with all types hash_b(42) hash_b("foo") From webhook-mailer at python.org Tue Oct 11 22:49:28 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 12 Oct 2022 02:49:28 -0000 Subject: [Python-checkins] gh-95276: Add callable entry to the glossary (GH-95738) Message-ID: https://github.com/python/cpython/commit/f94e6b4c42db0d73b910fc6a78f04afd7bbf7ad8 commit: f94e6b4c42db0d73b910fc6a78f04afd7bbf7ad8 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-11T19:49:23-07:00 summary: gh-95276: Add callable entry to the glossary (GH-95738) (cherry picked from commit e3bf125c81d5da0734429c1cb6ae75e6086e35ae) Co-authored-by: MonadChains files: M Doc/glossary.rst diff --git a/Doc/glossary.rst b/Doc/glossary.rst index aa9768f0353c..c4231e772878 100644 --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -210,6 +210,16 @@ Glossary A list of bytecode instructions can be found in the documentation for :ref:`the dis module `. + callable + A callable is an object that can be called, possibly with a set + of arguments (see :term:`argument`), with the following syntax:: + + callable(argument1, argument2, ...) + + A :term:`function`, and by extension a :term:`method`, is a callable. + An instance of a class that implements the :meth:`~object.__call__` + method is also a callable. + callback A subroutine function which is passed as an argument to be executed at some point in the future. From webhook-mailer at python.org Tue Oct 11 22:50:30 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 12 Oct 2022 02:50:30 -0000 Subject: [Python-checkins] gh-95276: Add callable entry to the glossary (GH-95738) Message-ID: https://github.com/python/cpython/commit/9e666bc6402ef608d57a9bf1790d7768e916262b commit: 9e666bc6402ef608d57a9bf1790d7768e916262b branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-11T19:50:25-07:00 summary: gh-95276: Add callable entry to the glossary (GH-95738) (cherry picked from commit e3bf125c81d5da0734429c1cb6ae75e6086e35ae) Co-authored-by: MonadChains files: M Doc/glossary.rst diff --git a/Doc/glossary.rst b/Doc/glossary.rst index 9385b8ddd13d..59f9426f6031 100644 --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -210,6 +210,16 @@ Glossary A list of bytecode instructions can be found in the documentation for :ref:`the dis module `. + callable + A callable is an object that can be called, possibly with a set + of arguments (see :term:`argument`), with the following syntax:: + + callable(argument1, argument2, ...) + + A :term:`function`, and by extension a :term:`method`, is a callable. + An instance of a class that implements the :meth:`~object.__call__` + method is also a callable. + callback A subroutine function which is passed as an argument to be executed at some point in the future. From webhook-mailer at python.org Tue Oct 11 23:56:59 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Wed, 12 Oct 2022 03:56:59 -0000 Subject: [Python-checkins] Formatting fixes in contextlib docs (#98111) Message-ID: https://github.com/python/cpython/commit/3b33c2010aa00ef5877bc35b02ae658e3c9f27af commit: 3b33c2010aa00ef5877bc35b02ae658e3c9f27af branch: main author: Stanley <46876382+slateny at users.noreply.github.com> committer: JelleZijlstra date: 2022-10-11T20:56:32-07:00 summary: Formatting fixes in contextlib docs (#98111) files: M Doc/library/contextlib.rst diff --git a/Doc/library/contextlib.rst b/Doc/library/contextlib.rst index 2d28fb35a9e3..1b55868c3aa6 100644 --- a/Doc/library/contextlib.rst +++ b/Doc/library/contextlib.rst @@ -66,6 +66,8 @@ Functions and classes provided: # Code to release resource, e.g.: release_resource(resource) + The function can then be used like this:: + >>> with managed_resource(timeout=3600) as resource: ... # Resource is released at the end of this block, ... # even if code in the block raises an exception @@ -140,9 +142,9 @@ Functions and classes provided: finally: print(f'it took {time.monotonic() - now}s to run') - @timeit() - async def main(): - # ... async code ... + @timeit() + async def main(): + # ... async code ... When used as a decorator, a new generator instance is implicitly created on each function call. This allows the otherwise "one-shot" context managers @@ -249,15 +251,15 @@ Functions and classes provided: :ref:`asynchronous context managers `:: async def send_http(session=None): - if not session: - # If no http session, create it with aiohttp - cm = aiohttp.ClientSession() - else: - # Caller is responsible for closing the session - cm = nullcontext(session) + if not session: + # If no http session, create it with aiohttp + cm = aiohttp.ClientSession() + else: + # Caller is responsible for closing the session + cm = nullcontext(session) - async with cm as session: - # Send http requests with session + async with cm as session: + # Send http requests with session .. versionadded:: 3.7 @@ -396,6 +398,8 @@ Functions and classes provided: print('Finishing') return False + The class can then be used like this:: + >>> @mycontext() ... def function(): ... print('The bit in the middle') @@ -466,6 +470,8 @@ Functions and classes provided: print('Finishing') return False + The class can then be used like this:: + >>> @mycontext() ... async def function(): ... print('The bit in the middle') From webhook-mailer at python.org Wed Oct 12 00:05:18 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 12 Oct 2022 04:05:18 -0000 Subject: [Python-checkins] Formatting fixes in contextlib docs (GH-98111) Message-ID: https://github.com/python/cpython/commit/59ddbc4ab6fbdc646d0f23c2f3a80fd2e71df0d8 commit: 59ddbc4ab6fbdc646d0f23c2f3a80fd2e71df0d8 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-11T21:05:12-07:00 summary: Formatting fixes in contextlib docs (GH-98111) (cherry picked from commit 3b33c2010aa00ef5877bc35b02ae658e3c9f27af) Co-authored-by: Stanley <46876382+slateny at users.noreply.github.com> files: M Doc/library/contextlib.rst diff --git a/Doc/library/contextlib.rst b/Doc/library/contextlib.rst index 2d28fb35a9e3..1b55868c3aa6 100644 --- a/Doc/library/contextlib.rst +++ b/Doc/library/contextlib.rst @@ -66,6 +66,8 @@ Functions and classes provided: # Code to release resource, e.g.: release_resource(resource) + The function can then be used like this:: + >>> with managed_resource(timeout=3600) as resource: ... # Resource is released at the end of this block, ... # even if code in the block raises an exception @@ -140,9 +142,9 @@ Functions and classes provided: finally: print(f'it took {time.monotonic() - now}s to run') - @timeit() - async def main(): - # ... async code ... + @timeit() + async def main(): + # ... async code ... When used as a decorator, a new generator instance is implicitly created on each function call. This allows the otherwise "one-shot" context managers @@ -249,15 +251,15 @@ Functions and classes provided: :ref:`asynchronous context managers `:: async def send_http(session=None): - if not session: - # If no http session, create it with aiohttp - cm = aiohttp.ClientSession() - else: - # Caller is responsible for closing the session - cm = nullcontext(session) + if not session: + # If no http session, create it with aiohttp + cm = aiohttp.ClientSession() + else: + # Caller is responsible for closing the session + cm = nullcontext(session) - async with cm as session: - # Send http requests with session + async with cm as session: + # Send http requests with session .. versionadded:: 3.7 @@ -396,6 +398,8 @@ Functions and classes provided: print('Finishing') return False + The class can then be used like this:: + >>> @mycontext() ... def function(): ... print('The bit in the middle') @@ -466,6 +470,8 @@ Functions and classes provided: print('Finishing') return False + The class can then be used like this:: + >>> @mycontext() ... async def function(): ... print('The bit in the middle') From webhook-mailer at python.org Wed Oct 12 00:06:45 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 12 Oct 2022 04:06:45 -0000 Subject: [Python-checkins] Formatting fixes in contextlib docs (GH-98111) Message-ID: https://github.com/python/cpython/commit/f6abb332a2cc9bf1027bf90637b98c606dc63b4a commit: f6abb332a2cc9bf1027bf90637b98c606dc63b4a branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-11T21:06:40-07:00 summary: Formatting fixes in contextlib docs (GH-98111) (cherry picked from commit 3b33c2010aa00ef5877bc35b02ae658e3c9f27af) Co-authored-by: Stanley <46876382+slateny at users.noreply.github.com> files: M Doc/library/contextlib.rst diff --git a/Doc/library/contextlib.rst b/Doc/library/contextlib.rst index 7c0b83140796..c65670713e0d 100644 --- a/Doc/library/contextlib.rst +++ b/Doc/library/contextlib.rst @@ -66,6 +66,8 @@ Functions and classes provided: # Code to release resource, e.g.: release_resource(resource) + The function can then be used like this:: + >>> with managed_resource(timeout=3600) as resource: ... # Resource is released at the end of this block, ... # even if code in the block raises an exception @@ -140,9 +142,9 @@ Functions and classes provided: finally: print(f'it took {time.monotonic() - now}s to run') - @timeit() - async def main(): - # ... async code ... + @timeit() + async def main(): + # ... async code ... When used as a decorator, a new generator instance is implicitly created on each function call. This allows the otherwise "one-shot" context managers @@ -249,15 +251,15 @@ Functions and classes provided: :ref:`asynchronous context managers `:: async def send_http(session=None): - if not session: - # If no http session, create it with aiohttp - cm = aiohttp.ClientSession() - else: - # Caller is responsible for closing the session - cm = nullcontext(session) + if not session: + # If no http session, create it with aiohttp + cm = aiohttp.ClientSession() + else: + # Caller is responsible for closing the session + cm = nullcontext(session) - async with cm as session: - # Send http requests with session + async with cm as session: + # Send http requests with session .. versionadded:: 3.7 @@ -379,6 +381,8 @@ Functions and classes provided: print('Finishing') return False + The class can then be used like this:: + >>> @mycontext() ... def function(): ... print('The bit in the middle') @@ -449,6 +453,8 @@ Functions and classes provided: print('Finishing') return False + The class can then be used like this:: + >>> @mycontext() ... async def function(): ... print('The bit in the middle') From webhook-mailer at python.org Wed Oct 12 00:43:07 2022 From: webhook-mailer at python.org (gvanrossum) Date: Wed, 12 Oct 2022 04:43:07 -0000 Subject: [Python-checkins] gh-65046: Link to logging cookbook from asyncio docs (#98207) Message-ID: https://github.com/python/cpython/commit/c39a0c335486fa8eac0f3030930f9e8769118a4f commit: c39a0c335486fa8eac0f3030930f9e8769118a4f branch: main author: Shantanu <12621235+hauntsaninja at users.noreply.github.com> committer: gvanrossum date: 2022-10-11T21:42:57-07:00 summary: gh-65046: Link to logging cookbook from asyncio docs (#98207) files: M Doc/howto/logging-cookbook.rst M Doc/library/asyncio-dev.rst diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst index 913502eba764..99e886c61b4c 100644 --- a/Doc/howto/logging-cookbook.rst +++ b/Doc/howto/logging-cookbook.rst @@ -332,6 +332,8 @@ configuration:: print('complete') +.. _blocking-handlers: + Dealing with handlers that block -------------------------------- diff --git a/Doc/library/asyncio-dev.rst b/Doc/library/asyncio-dev.rst index 14f2c3533c97..921a394a59fe 100644 --- a/Doc/library/asyncio-dev.rst +++ b/Doc/library/asyncio-dev.rst @@ -149,7 +149,8 @@ adjusted:: Network logging can block the event loop. It is recommended to use -a separate thread for handling logs or use non-blocking IO. +a separate thread for handling logs or use non-blocking IO. For example, +see :ref:`blocking-handlers`. .. _asyncio-coroutine-not-scheduled: From webhook-mailer at python.org Wed Oct 12 00:50:21 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 12 Oct 2022 04:50:21 -0000 Subject: [Python-checkins] gh-65046: Link to logging cookbook from asyncio docs (GH-98207) Message-ID: https://github.com/python/cpython/commit/bd7311095962a4dd91d4014d6c7601c663cb6415 commit: bd7311095962a4dd91d4014d6c7601c663cb6415 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-11T21:50:15-07:00 summary: gh-65046: Link to logging cookbook from asyncio docs (GH-98207) (cherry picked from commit c39a0c335486fa8eac0f3030930f9e8769118a4f) Co-authored-by: Shantanu <12621235+hauntsaninja at users.noreply.github.com> files: M Doc/howto/logging-cookbook.rst M Doc/library/asyncio-dev.rst diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst index 5b079744df12..43f967c77351 100644 --- a/Doc/howto/logging-cookbook.rst +++ b/Doc/howto/logging-cookbook.rst @@ -332,6 +332,8 @@ configuration:: print('complete') +.. _blocking-handlers: + Dealing with handlers that block -------------------------------- diff --git a/Doc/library/asyncio-dev.rst b/Doc/library/asyncio-dev.rst index 7ed597a50570..0816492a0a4a 100644 --- a/Doc/library/asyncio-dev.rst +++ b/Doc/library/asyncio-dev.rst @@ -149,7 +149,8 @@ adjusted:: Network logging can block the event loop. It is recommended to use -a separate thread for handling logs or use non-blocking IO. +a separate thread for handling logs or use non-blocking IO. For example, +see :ref:`blocking-handlers`. .. _asyncio-coroutine-not-scheduled: From webhook-mailer at python.org Wed Oct 12 00:51:18 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 12 Oct 2022 04:51:18 -0000 Subject: [Python-checkins] gh-65046: Link to logging cookbook from asyncio docs (GH-98207) Message-ID: https://github.com/python/cpython/commit/316590116a33978f029666c461970f51f6c36344 commit: 316590116a33978f029666c461970f51f6c36344 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-11T21:51:13-07:00 summary: gh-65046: Link to logging cookbook from asyncio docs (GH-98207) (cherry picked from commit c39a0c335486fa8eac0f3030930f9e8769118a4f) Co-authored-by: Shantanu <12621235+hauntsaninja at users.noreply.github.com> files: M Doc/howto/logging-cookbook.rst M Doc/library/asyncio-dev.rst diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst index ff7ba0789608..d43ffb24085d 100644 --- a/Doc/howto/logging-cookbook.rst +++ b/Doc/howto/logging-cookbook.rst @@ -332,6 +332,8 @@ configuration:: print('complete') +.. _blocking-handlers: + Dealing with handlers that block -------------------------------- diff --git a/Doc/library/asyncio-dev.rst b/Doc/library/asyncio-dev.rst index 14f2c3533c97..921a394a59fe 100644 --- a/Doc/library/asyncio-dev.rst +++ b/Doc/library/asyncio-dev.rst @@ -149,7 +149,8 @@ adjusted:: Network logging can block the event loop. It is recommended to use -a separate thread for handling logs or use non-blocking IO. +a separate thread for handling logs or use non-blocking IO. For example, +see :ref:`blocking-handlers`. .. _asyncio-coroutine-not-scheduled: From webhook-mailer at python.org Wed Oct 12 04:09:31 2022 From: webhook-mailer at python.org (vstinner) Date: Wed, 12 Oct 2022 08:09:31 -0000 Subject: [Python-checkins] gh-97669: Create Tools/patchcheck/ directory (#98186) Message-ID: https://github.com/python/cpython/commit/0895c2a066c64c84cab0821886dfa66efc1bdc2f commit: 0895c2a066c64c84cab0821886dfa66efc1bdc2f branch: main author: Victor Stinner committer: vstinner date: 2022-10-12T10:09:21+02:00 summary: gh-97669: Create Tools/patchcheck/ directory (#98186) Move patchcheck.py, reindent.py and untabify.py scripts to a new Tools/patchcheck/ directory. files: A Tools/patchcheck/patchcheck.py A Tools/patchcheck/reindent.py A Tools/patchcheck/untabify.py D Tools/scripts/patchcheck.py D Tools/scripts/reindent.py D Tools/scripts/untabify.py M .azure-pipelines/posix-steps.yml M Lib/test/test_tools/test_reindent.py M Makefile.pre.in M Tools/scripts/README diff --git a/.azure-pipelines/posix-steps.yml b/.azure-pipelines/posix-steps.yml index 29b43e093447..9d7c5e1279f4 100644 --- a/.azure-pipelines/posix-steps.yml +++ b/.azure-pipelines/posix-steps.yml @@ -68,7 +68,7 @@ steps: - ${{ if eq(parameters.patchcheck, 'true') }}: - script: | git fetch origin - ./python Tools/scripts/patchcheck.py --ci true + ./python Tools/patchcheck/patchcheck.py --ci true displayName: 'Run patchcheck.py' condition: and(succeeded(), eq(variables['Build.Reason'], 'PullRequest')) diff --git a/Lib/test/test_tools/test_reindent.py b/Lib/test/test_tools/test_reindent.py index 34df0c5d5119..3b0c793a38e4 100644 --- a/Lib/test/test_tools/test_reindent.py +++ b/Lib/test/test_tools/test_reindent.py @@ -9,12 +9,12 @@ from test.support.script_helper import assert_python_ok from test.support import findfile -from test.test_tools import scriptsdir, skip_if_missing +from test.test_tools import toolsdir, skip_if_missing skip_if_missing() class ReindentTests(unittest.TestCase): - script = os.path.join(scriptsdir, 'reindent.py') + script = os.path.join(toolsdir, 'patchcheck', 'reindent.py') def test_noargs(self): assert_python_ok(self.script) diff --git a/Makefile.pre.in b/Makefile.pre.in index 4602db69d15a..7e2567173bc2 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -2386,7 +2386,7 @@ Python/dtoa.o: Python/dtoa.c # Run reindent on the library reindent: - ./$(BUILDPYTHON) $(srcdir)/Tools/scripts/reindent.py -r $(srcdir)/Lib + ./$(BUILDPYTHON) $(srcdir)/Tools/patchcheck/reindent.py -r $(srcdir)/Lib # Rerun configure with the same options as it was run last time, # provided the config.status script exists @@ -2546,7 +2546,7 @@ funny: # Perform some verification checks on any modified files. patchcheck: all - $(RUNSHARED) ./$(BUILDPYTHON) $(srcdir)/Tools/scripts/patchcheck.py + $(RUNSHARED) ./$(BUILDPYTHON) $(srcdir)/Tools/patchcheck/patchcheck.py check-limited-abi: all $(RUNSHARED) ./$(BUILDPYTHON) $(srcdir)/Tools/scripts/stable_abi.py --all $(srcdir)/Misc/stable_abi.toml diff --git a/Tools/scripts/patchcheck.py b/Tools/patchcheck/patchcheck.py similarity index 100% rename from Tools/scripts/patchcheck.py rename to Tools/patchcheck/patchcheck.py diff --git a/Tools/scripts/reindent.py b/Tools/patchcheck/reindent.py similarity index 100% rename from Tools/scripts/reindent.py rename to Tools/patchcheck/reindent.py diff --git a/Tools/scripts/untabify.py b/Tools/patchcheck/untabify.py similarity index 100% rename from Tools/scripts/untabify.py rename to Tools/patchcheck/untabify.py diff --git a/Tools/scripts/README b/Tools/scripts/README index 9943d4c42fc4..b95226815959 100644 --- a/Tools/scripts/README +++ b/Tools/scripts/README @@ -5,9 +5,6 @@ useful while building, extending or managing Python. combinerefs.py A helper for analyzing PYTHONDUMPREFS output idle3 Main program to start IDLE parse_html5_entities.py Utility for parsing HTML5 entity definitions -patchcheck.py Perform common checks and cleanup before committing pydoc3 Python documentation browser -reindent.py Change .py files to use 4-space indents run_tests.py Run the test suite with more sensible default options stable_abi.py Stable ABI checks and file generators. -untabify.py Replace tabs with spaces in argument files From webhook-mailer at python.org Wed Oct 12 11:26:31 2022 From: webhook-mailer at python.org (vstinner) Date: Wed, 12 Oct 2022 15:26:31 -0000 Subject: [Python-checkins] gh-97669: Fix test_tools reference leak (#98216) Message-ID: https://github.com/python/cpython/commit/a8c8526fd8ce2f3f50837bbbb820741e54b58512 commit: a8c8526fd8ce2f3f50837bbbb820741e54b58512 branch: main author: Victor Stinner committer: vstinner date: 2022-10-12T17:26:21+02:00 summary: gh-97669: Fix test_tools reference leak (#98216) test_tools.test_sundry() now uses an unittest mock to prevent the logging module to register a real "atfork" function which kept the logging module dictionary alive. So the logging module can be properly unloaded. Previously, the logging module was loaded before test_sundry(), but it's no longer the case since recent test_tools sub-tests removals. files: M Lib/test/support/import_helper.py M Lib/test/test_importlib/test_threaded_import.py M Lib/test/test_tools/test_sundry.py diff --git a/Lib/test/support/import_helper.py b/Lib/test/support/import_helper.py index 5201dc84cf6d..63a8a7952db7 100644 --- a/Lib/test/support/import_helper.py +++ b/Lib/test/support/import_helper.py @@ -246,3 +246,11 @@ def modules_cleanup(oldmodules): # do currently). Implicitly imported *real* modules should be left alone # (see issue 10556). sys.modules.update(oldmodules) + + +def mock_register_at_fork(func): + # bpo-30599: Mock os.register_at_fork() when importing the random module, + # since this function doesn't allow to unregister callbacks and would leak + # memory. + from unittest import mock + return mock.patch('os.register_at_fork', create=True)(func) diff --git a/Lib/test/test_importlib/test_threaded_import.py b/Lib/test/test_importlib/test_threaded_import.py index 9aeeb5e686e9..85c3032aed53 100644 --- a/Lib/test/test_importlib/test_threaded_import.py +++ b/Lib/test/test_importlib/test_threaded_import.py @@ -15,7 +15,7 @@ import unittest from unittest import mock from test.support import verbose -from test.support.import_helper import forget +from test.support.import_helper import forget, mock_register_at_fork from test.support.os_helper import (TESTFN, unlink, rmtree) from test.support import script_helper, threading_helper @@ -41,12 +41,6 @@ def task(N, done, done_tasks, errors): if finished: done.set() -def mock_register_at_fork(func): - # bpo-30599: Mock os.register_at_fork() when importing the random module, - # since this function doesn't allow to unregister callbacks and would leak - # memory. - return mock.patch('os.register_at_fork', create=True)(func) - # Create a circular import structure: A -> C -> B -> D -> A # NOTE: `time` is already loaded and therefore doesn't threaten to deadlock. diff --git a/Lib/test/test_tools/test_sundry.py b/Lib/test/test_tools/test_sundry.py index 04e38acdb348..81f06763980a 100644 --- a/Lib/test/test_tools/test_sundry.py +++ b/Lib/test/test_tools/test_sundry.py @@ -27,7 +27,11 @@ class TestSundryScripts(unittest.TestCase): skiplist = denylist + allowlist + other - def test_sundry(self): + # import logging registers "atfork" functions which keep indirectly the + # logging module dictionary alive. Mock the function to be able to unload + # cleanly the logging module. + @import_helper.mock_register_at_fork + def test_sundry(self, mock_os): old_modules = import_helper.modules_setup() try: for fn in os.listdir(scriptsdir): From webhook-mailer at python.org Wed Oct 12 11:27:08 2022 From: webhook-mailer at python.org (vstinner) Date: Wed, 12 Oct 2022 15:27:08 -0000 Subject: [Python-checkins] signalmodule.c uses _PyErr_WriteUnraisableMsg() (#98217) Message-ID: https://github.com/python/cpython/commit/342b1151ae7e6ae849c1ed7c8a2cbfdb4edcf51c commit: 342b1151ae7e6ae849c1ed7c8a2cbfdb4edcf51c branch: main author: Victor Stinner committer: vstinner date: 2022-10-12T17:26:58+02:00 summary: signalmodule.c uses _PyErr_WriteUnraisableMsg() (#98217) Signal wakeup fd errors are now logged with _PyErr_WriteUnraisableMsg(), rather than PySys_WriteStderr() and PyErr_WriteUnraisable(), to pass the error message to sys.unraisablehook. By default, it's still written into stderr (unless sys.unraisablehook is overriden). files: M Modules/signalmodule.c diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c index b85d6d19e8cd..bdd3f4b2204e 100644 --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -272,9 +272,8 @@ report_wakeup_write_error(void *data) errno = (int) (intptr_t) data; PyErr_Fetch(&exc, &val, &tb); PyErr_SetFromErrno(PyExc_OSError); - PySys_WriteStderr("Exception ignored when trying to write to the " - "signal wakeup fd:\n"); - PyErr_WriteUnraisable(NULL); + _PyErr_WriteUnraisableMsg("when trying to write to the signal wakeup fd", + NULL); PyErr_Restore(exc, val, tb); errno = save_errno; return 0; @@ -284,15 +283,15 @@ report_wakeup_write_error(void *data) static int report_wakeup_send_error(void* data) { + int send_errno = (int) (intptr_t) data; + PyObject *exc, *val, *tb; PyErr_Fetch(&exc, &val, &tb); /* PyErr_SetExcFromWindowsErr() invokes FormatMessage() which recognizes the error codes used by both GetLastError() and WSAGetLastError */ - PyErr_SetExcFromWindowsErr(PyExc_OSError, (int) (intptr_t) data); - PySys_WriteStderr("Exception ignored when trying to send to the " - "signal wakeup fd:\n"); - PyErr_WriteUnraisable(NULL); + PyErr_SetExcFromWindowsErr(PyExc_OSError, send_errno); + _PyErr_WriteUnraisableMsg("when trying to send to the signal wakeup fd", NULL); PyErr_Restore(exc, val, tb); return 0; } From webhook-mailer at python.org Wed Oct 12 11:53:55 2022 From: webhook-mailer at python.org (vstinner) Date: Wed, 12 Oct 2022 15:53:55 -0000 Subject: [Python-checkins] gh-97669: Remove Tools/scripts/startuptime.py (#98214) Message-ID: https://github.com/python/cpython/commit/d09d2c7c916eb4007f57f2a39c1198004e916b51 commit: d09d2c7c916eb4007f57f2a39c1198004e916b51 branch: main author: Victor Stinner committer: vstinner date: 2022-10-12T17:53:46+02:00 summary: gh-97669: Remove Tools/scripts/startuptime.py (#98214) The "pyperf command" tool be used instead. Example: $ python3 -m pyperf command -- python3 -c pass ..................... command: Mean +- std dev: 17.8 ms +- 0.4 ms pyperf also computes the standard deviation which gives an idea of the benchmark looks reliable or not. files: D Tools/scripts/startuptime.py diff --git a/Tools/scripts/startuptime.py b/Tools/scripts/startuptime.py deleted file mode 100644 index 1bb5b208f66e..000000000000 --- a/Tools/scripts/startuptime.py +++ /dev/null @@ -1,22 +0,0 @@ -# Quick script to time startup for various binaries - -import subprocess -import sys -import time - -NREPS = 100 - - -def main(): - binaries = sys.argv[1:] - for bin in binaries: - t0 = time.time() - for _ in range(NREPS): - result = subprocess.run([bin, "-c", "pass"]) - result.check_returncode() - t1 = time.time() - print(f"{(t1-t0)/NREPS:6.3f} {bin}") - - -if __name__ == "__main__": - main() From webhook-mailer at python.org Wed Oct 12 12:01:01 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Wed, 12 Oct 2022 16:01:01 -0000 Subject: [Python-checkins] tutorial: remove "with single quotes" (#98204) Message-ID: https://github.com/python/cpython/commit/5f8ca1b7969f34ee09adb7b28337ebd920e6215a commit: 5f8ca1b7969f34ee09adb7b28337ebd920e6215a branch: main author: Jelle Zijlstra committer: JelleZijlstra date: 2022-10-12T09:00:51-07:00 summary: tutorial: remove "with single quotes" (#98204) Closes #91856. On Windows double quotes are sometimes better, on Unix usually single quotes. It's not our place to explain that, so just don't. files: M Doc/tutorial/interpreter.rst diff --git a/Doc/tutorial/interpreter.rst b/Doc/tutorial/interpreter.rst index 9bee046809eb..b71c61089e6d 100644 --- a/Doc/tutorial/interpreter.rst +++ b/Doc/tutorial/interpreter.rst @@ -52,7 +52,7 @@ A second way of starting the interpreter is ``python -c command [arg] ...``, which executes the statement(s) in *command*, analogous to the shell's :option:`-c` option. Since Python statements often contain spaces or other characters that are special to the shell, it is usually advised to quote -*command* in its entirety with single quotes. +*command* in its entirety. Some Python modules are also useful as scripts. These can be invoked using ``python -m module [arg] ...``, which executes the source file for *module* as From webhook-mailer at python.org Wed Oct 12 12:04:49 2022 From: webhook-mailer at python.org (ezio-melotti) Date: Wed, 12 Oct 2022 16:04:49 -0000 Subject: [Python-checkins] gh-96265: Formatting changes for faq/general (#98129) Message-ID: https://github.com/python/cpython/commit/e9569ec43e2376aa77240cd630db4be07e8720f3 commit: e9569ec43e2376aa77240cd630db4be07e8720f3 branch: main author: Stanley <46876382+slateny at users.noreply.github.com> committer: ezio-melotti date: 2022-10-12T18:04:41+02:00 summary: gh-96265: Formatting changes for faq/general (#98129) * Some formatting changes for general faq * Use list for Python versioning Co-authored-by: Ezio Melotti * New line for list, list for a/b/rc * Line wrap for 80 chars * More line wrap * Remove PythonWin mention. Co-authored-by: C.A.M. Gerlach Co-authored-by: Ezio Melotti Co-authored-by: C.A.M. Gerlach files: M Doc/faq/general.rst diff --git a/Doc/faq/general.rst b/Doc/faq/general.rst index 81842fce4303..489bca76432d 100644 --- a/Doc/faq/general.rst +++ b/Doc/faq/general.rst @@ -125,11 +125,15 @@ find packages of interest to you. How does the Python version numbering scheme work? -------------------------------------------------- -Python versions are numbered A.B.C or A.B. A is the major version number -- it -is only incremented for really major changes in the language. B is the minor -version number, incremented for less earth-shattering changes. C is the -micro-level -- it is incremented for each bugfix release. See :pep:`6` for more -information about bugfix releases. +Python versions are numbered "A.B.C" or "A.B": + +* *A* is the major version number -- it is only incremented for really major + changes in the language. +* *B* is the minor version number -- it is incremented for less earth-shattering + changes. +* *C* is the micro version number -- it is incremented for each bugfix release. + +See :pep:`6` for more information about bugfix releases. Not all releases are bugfix releases. In the run-up to a new major release, a series of development releases are made, denoted as alpha, beta, or release @@ -139,12 +143,14 @@ Betas are more stable, preserving existing interfaces but possibly adding new modules, and release candidates are frozen, making no changes except as needed to fix critical bugs. -Alpha, beta and release candidate versions have an additional suffix. The -suffix for an alpha version is "aN" for some small number N, the suffix for a -beta version is "bN" for some small number N, and the suffix for a release -candidate version is "rcN" for some small number N. In other words, all versions -labeled 2.0aN precede the versions labeled 2.0bN, which precede versions labeled -2.0rcN, and *those* precede 2.0. +Alpha, beta and release candidate versions have an additional suffix: + +* The suffix for an alpha version is "aN" for some small number *N*. +* The suffix for a beta version is "bN" for some small number *N*. +* The suffix for a release candidate version is "rcN" for some small number *N*. + +In other words, all versions labeled *2.0aN* precede the versions labeled +*2.0bN*, which precede versions labeled *2.0rcN*, and *those* precede 2.0. You may also find version numbers with a "+" suffix, e.g. "2.2+". These are unreleased versions, built directly from the CPython development repository. In @@ -429,7 +435,7 @@ With the interpreter, documentation is never far from the student as they are programming. There are also good IDEs for Python. IDLE is a cross-platform IDE for Python -that is written in Python using Tkinter. PythonWin is a Windows-specific IDE. +that is written in Python using Tkinter. Emacs users will be happy to know that there is a very good Python mode for Emacs. All of these programming environments provide syntax highlighting, auto-indenting, and access to the interactive interpreter while coding. Consult From webhook-mailer at python.org Wed Oct 12 12:07:55 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 12 Oct 2022 16:07:55 -0000 Subject: [Python-checkins] tutorial: remove "with single quotes" (GH-98204) Message-ID: https://github.com/python/cpython/commit/2ed28a69b5a1976ceca6cd84c3c6053eb2738238 commit: 2ed28a69b5a1976ceca6cd84c3c6053eb2738238 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-12T09:07:49-07:00 summary: tutorial: remove "with single quotes" (GH-98204) Closes GH-91856. On Windows double quotes are sometimes better, on Unix usually single quotes. It's not our place to explain that, so just don't. (cherry picked from commit 5f8ca1b7969f34ee09adb7b28337ebd920e6215a) Co-authored-by: Jelle Zijlstra files: M Doc/tutorial/interpreter.rst diff --git a/Doc/tutorial/interpreter.rst b/Doc/tutorial/interpreter.rst index d2733a9968fb..e804a9d056bc 100644 --- a/Doc/tutorial/interpreter.rst +++ b/Doc/tutorial/interpreter.rst @@ -52,7 +52,7 @@ A second way of starting the interpreter is ``python -c command [arg] ...``, which executes the statement(s) in *command*, analogous to the shell's :option:`-c` option. Since Python statements often contain spaces or other characters that are special to the shell, it is usually advised to quote -*command* in its entirety with single quotes. +*command* in its entirety. Some Python modules are also useful as scripts. These can be invoked using ``python -m module [arg] ...``, which executes the source file for *module* as From webhook-mailer at python.org Wed Oct 12 12:09:01 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 12 Oct 2022 16:09:01 -0000 Subject: [Python-checkins] tutorial: remove "with single quotes" (GH-98204) Message-ID: https://github.com/python/cpython/commit/b2f037cce728117f134bba3a96a5d928fb73ae43 commit: b2f037cce728117f134bba3a96a5d928fb73ae43 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-12T09:08:56-07:00 summary: tutorial: remove "with single quotes" (GH-98204) Closes GH-91856. On Windows double quotes are sometimes better, on Unix usually single quotes. It's not our place to explain that, so just don't. (cherry picked from commit 5f8ca1b7969f34ee09adb7b28337ebd920e6215a) Co-authored-by: Jelle Zijlstra files: M Doc/tutorial/interpreter.rst diff --git a/Doc/tutorial/interpreter.rst b/Doc/tutorial/interpreter.rst index d7f300d93b02..08851cb8fda0 100644 --- a/Doc/tutorial/interpreter.rst +++ b/Doc/tutorial/interpreter.rst @@ -52,7 +52,7 @@ A second way of starting the interpreter is ``python -c command [arg] ...``, which executes the statement(s) in *command*, analogous to the shell's :option:`-c` option. Since Python statements often contain spaces or other characters that are special to the shell, it is usually advised to quote -*command* in its entirety with single quotes. +*command* in its entirety. Some Python modules are also useful as scripts. These can be invoked using ``python -m module [arg] ...``, which executes the source file for *module* as From webhook-mailer at python.org Wed Oct 12 12:12:19 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 12 Oct 2022 16:12:19 -0000 Subject: [Python-checkins] gh-96265: Formatting changes for faq/general (GH-98129) Message-ID: https://github.com/python/cpython/commit/258c440b479323998f633adbf4a1afb678c7787a commit: 258c440b479323998f633adbf4a1afb678c7787a branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-12T09:12:14-07:00 summary: gh-96265: Formatting changes for faq/general (GH-98129) * Some formatting changes for general faq * Use list for Python versioning Co-authored-by: Ezio Melotti * New line for list, list for a/b/rc * Line wrap for 80 chars * More line wrap * Remove PythonWin mention. Co-authored-by: C.A.M. Gerlach Co-authored-by: Ezio Melotti Co-authored-by: C.A.M. Gerlach (cherry picked from commit e9569ec43e2376aa77240cd630db4be07e8720f3) Co-authored-by: Stanley <46876382+slateny at users.noreply.github.com> files: M Doc/faq/general.rst diff --git a/Doc/faq/general.rst b/Doc/faq/general.rst index 7f64d8478951..16f726c593cd 100644 --- a/Doc/faq/general.rst +++ b/Doc/faq/general.rst @@ -125,11 +125,15 @@ find packages of interest to you. How does the Python version numbering scheme work? -------------------------------------------------- -Python versions are numbered A.B.C or A.B. A is the major version number -- it -is only incremented for really major changes in the language. B is the minor -version number, incremented for less earth-shattering changes. C is the -micro-level -- it is incremented for each bugfix release. See :pep:`6` for more -information about bugfix releases. +Python versions are numbered "A.B.C" or "A.B": + +* *A* is the major version number -- it is only incremented for really major + changes in the language. +* *B* is the minor version number -- it is incremented for less earth-shattering + changes. +* *C* is the micro version number -- it is incremented for each bugfix release. + +See :pep:`6` for more information about bugfix releases. Not all releases are bugfix releases. In the run-up to a new major release, a series of development releases are made, denoted as alpha, beta, or release @@ -139,12 +143,14 @@ Betas are more stable, preserving existing interfaces but possibly adding new modules, and release candidates are frozen, making no changes except as needed to fix critical bugs. -Alpha, beta and release candidate versions have an additional suffix. The -suffix for an alpha version is "aN" for some small number N, the suffix for a -beta version is "bN" for some small number N, and the suffix for a release -candidate version is "rcN" for some small number N. In other words, all versions -labeled 2.0aN precede the versions labeled 2.0bN, which precede versions labeled -2.0rcN, and *those* precede 2.0. +Alpha, beta and release candidate versions have an additional suffix: + +* The suffix for an alpha version is "aN" for some small number *N*. +* The suffix for a beta version is "bN" for some small number *N*. +* The suffix for a release candidate version is "rcN" for some small number *N*. + +In other words, all versions labeled *2.0aN* precede the versions labeled +*2.0bN*, which precede versions labeled *2.0rcN*, and *those* precede 2.0. You may also find version numbers with a "+" suffix, e.g. "2.2+". These are unreleased versions, built directly from the CPython development repository. In @@ -435,7 +441,7 @@ With the interpreter, documentation is never far from the student as they are programming. There are also good IDEs for Python. IDLE is a cross-platform IDE for Python -that is written in Python using Tkinter. PythonWin is a Windows-specific IDE. +that is written in Python using Tkinter. Emacs users will be happy to know that there is a very good Python mode for Emacs. All of these programming environments provide syntax highlighting, auto-indenting, and access to the interactive interpreter while coding. Consult From webhook-mailer at python.org Wed Oct 12 12:13:30 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 12 Oct 2022 16:13:30 -0000 Subject: [Python-checkins] gh-96265: Formatting changes for faq/general (GH-98129) Message-ID: https://github.com/python/cpython/commit/450306ed6770d7ffd16cb9128e471677dda9b3d1 commit: 450306ed6770d7ffd16cb9128e471677dda9b3d1 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-12T09:13:24-07:00 summary: gh-96265: Formatting changes for faq/general (GH-98129) * Some formatting changes for general faq * Use list for Python versioning Co-authored-by: Ezio Melotti * New line for list, list for a/b/rc * Line wrap for 80 chars * More line wrap * Remove PythonWin mention. Co-authored-by: C.A.M. Gerlach Co-authored-by: Ezio Melotti Co-authored-by: C.A.M. Gerlach (cherry picked from commit e9569ec43e2376aa77240cd630db4be07e8720f3) Co-authored-by: Stanley <46876382+slateny at users.noreply.github.com> files: M Doc/faq/general.rst diff --git a/Doc/faq/general.rst b/Doc/faq/general.rst index 81842fce4303..489bca76432d 100644 --- a/Doc/faq/general.rst +++ b/Doc/faq/general.rst @@ -125,11 +125,15 @@ find packages of interest to you. How does the Python version numbering scheme work? -------------------------------------------------- -Python versions are numbered A.B.C or A.B. A is the major version number -- it -is only incremented for really major changes in the language. B is the minor -version number, incremented for less earth-shattering changes. C is the -micro-level -- it is incremented for each bugfix release. See :pep:`6` for more -information about bugfix releases. +Python versions are numbered "A.B.C" or "A.B": + +* *A* is the major version number -- it is only incremented for really major + changes in the language. +* *B* is the minor version number -- it is incremented for less earth-shattering + changes. +* *C* is the micro version number -- it is incremented for each bugfix release. + +See :pep:`6` for more information about bugfix releases. Not all releases are bugfix releases. In the run-up to a new major release, a series of development releases are made, denoted as alpha, beta, or release @@ -139,12 +143,14 @@ Betas are more stable, preserving existing interfaces but possibly adding new modules, and release candidates are frozen, making no changes except as needed to fix critical bugs. -Alpha, beta and release candidate versions have an additional suffix. The -suffix for an alpha version is "aN" for some small number N, the suffix for a -beta version is "bN" for some small number N, and the suffix for a release -candidate version is "rcN" for some small number N. In other words, all versions -labeled 2.0aN precede the versions labeled 2.0bN, which precede versions labeled -2.0rcN, and *those* precede 2.0. +Alpha, beta and release candidate versions have an additional suffix: + +* The suffix for an alpha version is "aN" for some small number *N*. +* The suffix for a beta version is "bN" for some small number *N*. +* The suffix for a release candidate version is "rcN" for some small number *N*. + +In other words, all versions labeled *2.0aN* precede the versions labeled +*2.0bN*, which precede versions labeled *2.0rcN*, and *those* precede 2.0. You may also find version numbers with a "+" suffix, e.g. "2.2+". These are unreleased versions, built directly from the CPython development repository. In @@ -429,7 +435,7 @@ With the interpreter, documentation is never far from the student as they are programming. There are also good IDEs for Python. IDLE is a cross-platform IDE for Python -that is written in Python using Tkinter. PythonWin is a Windows-specific IDE. +that is written in Python using Tkinter. Emacs users will be happy to know that there is a very good Python mode for Emacs. All of these programming environments provide syntax highlighting, auto-indenting, and access to the interactive interpreter while coding. Consult From webhook-mailer at python.org Wed Oct 12 12:28:03 2022 From: webhook-mailer at python.org (vstinner) Date: Wed, 12 Oct 2022 16:28:03 -0000 Subject: [Python-checkins] gh-97982: Factorize PyUnicode_Count() and unicode_count() code (#98025) Message-ID: https://github.com/python/cpython/commit/ccab67ba7901a3012ad66f0ffafac4ea925a1ff0 commit: ccab67ba7901a3012ad66f0ffafac4ea925a1ff0 branch: main author: Nikita Sobolev committer: vstinner date: 2022-10-12T18:27:53+02:00 summary: gh-97982: Factorize PyUnicode_Count() and unicode_count() code (#98025) Add unicode_count_impl() to factorize PyUnicode_Count() and unicode_count() code. files: M Lib/test/test_unicode.py M Objects/unicodeobject.c diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py index 5b816574f2c3..15244cb949e3 100644 --- a/Lib/test/test_unicode.py +++ b/Lib/test/test_unicode.py @@ -241,6 +241,10 @@ def test_count(self): self.checkequal(0, 'a' * 10, 'count', 'a\u0102') self.checkequal(0, 'a' * 10, 'count', 'a\U00100304') self.checkequal(0, '\u0102' * 10, 'count', '\u0102\U00100304') + # test subclass + class MyStr(str): + pass + self.checkequal(3, MyStr('aaa'), 'count', 'a') def test_find(self): string_tests.CommonTest.test_find(self) @@ -3002,6 +3006,12 @@ def test_count(self): self.assertEqual(unicode_count(uni, ch, 0, len(uni)), 1) self.assertEqual(unicode_count(st, ch, 0, len(st)), 0) + # subclasses should still work + class MyStr(str): + pass + + self.assertEqual(unicode_count(MyStr('aab'), 'a', 0, 3), 2) + # Test PyUnicode_FindChar() @support.cpython_only @unittest.skipIf(_testcapi is None, 'need _testcapi module') diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 51e660afba08..5b737f1b596e 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -8964,21 +8964,20 @@ _PyUnicode_InsertThousandsGrouping( return count; } - -Py_ssize_t -PyUnicode_Count(PyObject *str, - PyObject *substr, - Py_ssize_t start, - Py_ssize_t end) +static Py_ssize_t +unicode_count_impl(PyObject *str, + PyObject *substr, + Py_ssize_t start, + Py_ssize_t end) { + assert(PyUnicode_Check(str)); + assert(PyUnicode_Check(substr)); + Py_ssize_t result; int kind1, kind2; const void *buf1 = NULL, *buf2 = NULL; Py_ssize_t len1, len2; - if (ensure_unicode(str) < 0 || ensure_unicode(substr) < 0) - return -1; - kind1 = PyUnicode_KIND(str); kind2 = PyUnicode_KIND(substr); if (kind1 < kind2) @@ -8998,6 +8997,7 @@ PyUnicode_Count(PyObject *str, goto onError; } + // We don't reuse `anylib_count` here because of the explicit casts. switch (kind1) { case PyUnicode_1BYTE_KIND: result = ucs1lib_count( @@ -9033,6 +9033,18 @@ PyUnicode_Count(PyObject *str, return -1; } +Py_ssize_t +PyUnicode_Count(PyObject *str, + PyObject *substr, + Py_ssize_t start, + Py_ssize_t end) +{ + if (ensure_unicode(str) < 0 || ensure_unicode(substr) < 0) + return -1; + + return unicode_count_impl(str, substr, start, end); +} + Py_ssize_t PyUnicode_Find(PyObject *str, PyObject *substr, @@ -10848,62 +10860,16 @@ unicode_count(PyObject *self, PyObject *args) PyObject *substring = NULL; /* initialize to fix a compiler warning */ Py_ssize_t start = 0; Py_ssize_t end = PY_SSIZE_T_MAX; - PyObject *result; - int kind1, kind2; - const void *buf1, *buf2; - Py_ssize_t len1, len2, iresult; + Py_ssize_t result; if (!parse_args_finds_unicode("count", args, &substring, &start, &end)) return NULL; - kind1 = PyUnicode_KIND(self); - kind2 = PyUnicode_KIND(substring); - if (kind1 < kind2) - return PyLong_FromLong(0); - - len1 = PyUnicode_GET_LENGTH(self); - len2 = PyUnicode_GET_LENGTH(substring); - ADJUST_INDICES(start, end, len1); - if (end - start < len2) - return PyLong_FromLong(0); - - buf1 = PyUnicode_DATA(self); - buf2 = PyUnicode_DATA(substring); - if (kind2 != kind1) { - buf2 = unicode_askind(kind2, buf2, len2, kind1); - if (!buf2) - return NULL; - } - switch (kind1) { - case PyUnicode_1BYTE_KIND: - iresult = ucs1lib_count( - ((const Py_UCS1*)buf1) + start, end - start, - buf2, len2, PY_SSIZE_T_MAX - ); - break; - case PyUnicode_2BYTE_KIND: - iresult = ucs2lib_count( - ((const Py_UCS2*)buf1) + start, end - start, - buf2, len2, PY_SSIZE_T_MAX - ); - break; - case PyUnicode_4BYTE_KIND: - iresult = ucs4lib_count( - ((const Py_UCS4*)buf1) + start, end - start, - buf2, len2, PY_SSIZE_T_MAX - ); - break; - default: - Py_UNREACHABLE(); - } - - result = PyLong_FromSsize_t(iresult); - - assert((kind2 == kind1) == (buf2 == PyUnicode_DATA(substring))); - if (kind2 != kind1) - PyMem_Free((void *)buf2); + result = unicode_count_impl(self, substring, start, end); + if (result == -1) + return NULL; - return result; + return PyLong_FromSsize_t(result); } /*[clinic input] From webhook-mailer at python.org Wed Oct 12 15:26:33 2022 From: webhook-mailer at python.org (JulienPalard) Date: Wed, 12 Oct 2022 19:26:33 -0000 Subject: [Python-checkins] [3.10] gh-86404: Doc CI: Disable suspicious checks. (GH-26575) (GH-98221) Message-ID: https://github.com/python/cpython/commit/a0c11529f32cae213795f3e160808cccd2752e38 commit: a0c11529f32cae213795f3e160808cccd2752e38 branch: 3.10 author: Julien Palard committer: JulienPalard date: 2022-10-12T21:26:27+02:00 summary: [3.10] gh-86404: Doc CI: Disable suspicious checks. (GH-26575) (GH-98221) gh-86404: Doc CI: Disable suspicious checks. files: M .github/workflows/doc.yml M .travis.yml diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index 3bc280be95f3..0de062fdc0fa 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -43,8 +43,6 @@ jobs: cache-dependency-path: 'Doc/requirements.txt' - name: 'Install build dependencies' run: make -C Doc/ venv - - name: 'Check documentation' - run: make -C Doc/ suspicious - name: 'Build HTML documentation' run: make -C Doc/ SPHINXOPTS="-q" SPHINXERRORHANDLING="-W --keep-going" html - name: 'Upload' diff --git a/.travis.yml b/.travis.yml index ee6cabe5ae0d..af64022be3dd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -54,7 +54,7 @@ matrix: - cd Doc - make venv PYTHON=python script: - - make check html suspicious SPHINXOPTS="-q -W -j4" + - make check html SPHINXOPTS="-q -W -j4" - name: "Documentation tests" os: linux language: c From webhook-mailer at python.org Wed Oct 12 15:40:59 2022 From: webhook-mailer at python.org (JulienPalard) Date: Wed, 12 Oct 2022 19:40:59 -0000 Subject: [Python-checkins] Mark all targets in `Doc/Makefile` as `PHONY` (GH-98189) Message-ID: https://github.com/python/cpython/commit/4414586172a7b22ce5b7508c68401e6dc2ac49cc commit: 4414586172a7b22ce5b7508c68401e6dc2ac49cc branch: main author: Nikita Sobolev committer: JulienPalard date: 2022-10-12T21:40:47+02:00 summary: Mark all targets in `Doc/Makefile` as `PHONY` (GH-98189) files: M Doc/Makefile diff --git a/Doc/Makefile b/Doc/Makefile index f52087409a04..b09a9d754fb5 100644 --- a/Doc/Makefile +++ b/Doc/Makefile @@ -21,9 +21,9 @@ PAPEROPT_letter = -D latex_elements.papersize=letterpaper ALLSPHINXOPTS = -b $(BUILDER) -d build/doctrees $(PAPEROPT_$(PAPER)) -j auto \ $(SPHINXOPTS) $(SPHINXERRORHANDLING) . build/$(BUILDER) $(SOURCES) -.PHONY: help build html htmlhelp latex text texinfo changes linkcheck \ - coverage doctest pydoc-topics htmlview clean dist check serve \ - autobuild-dev autobuild-stable venv +.PHONY: help build html htmlhelp latex text texinfo epub changes linkcheck \ + coverage doctest pydoc-topics htmlview clean clean-venv venv dist check serve \ + autobuild-dev autobuild-dev-html autobuild-stable autobuild-stable-html help: @echo "Please use \`make ' where is one of" From webhook-mailer at python.org Wed Oct 12 19:04:53 2022 From: webhook-mailer at python.org (brandtbucher) Date: Wed, 12 Oct 2022 23:04:53 -0000 Subject: [Python-checkins] [3.11] GH-93354: Fix PRECALL's adaptive backoff (GH-98011) Message-ID: https://github.com/python/cpython/commit/0a67f82eb1daf0afaebc68f31ac7e4609f314353 commit: 0a67f82eb1daf0afaebc68f31ac7e4609f314353 branch: 3.11 author: Brandt Bucher committer: brandtbucher date: 2022-10-12T16:04:47-07:00 summary: [3.11] GH-93354: Fix PRECALL's adaptive backoff (GH-98011) files: A Misc/NEWS.d/next/Core and Builtins/2022-10-06-05-41-01.gh-issue-93354.6BpHl2.rst M Python/ceval.c diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-06-05-41-01.gh-issue-93354.6BpHl2.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-06-05-41-01.gh-issue-93354.6BpHl2.rst new file mode 100644 index 000000000000..4efc10da293a --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-06-05-41-01.gh-issue-93354.6BpHl2.rst @@ -0,0 +1,2 @@ +Fix an issue that could delay the specialization of :opcode:`PRECALL` +instructions. diff --git a/Python/ceval.c b/Python/ceval.c index c5283ace43cf..c0d9c68de04b 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -4793,7 +4793,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int TARGET(PRECALL_ADAPTIVE) { _PyPrecallCache *cache = (_PyPrecallCache *)next_instr; - if (cache->counter == 0) { + if (ADAPTIVE_COUNTER_IS_ZERO(cache)) { next_instr--; int is_meth = is_method(stack_pointer, oparg); int nargs = oparg + is_meth; @@ -4807,7 +4807,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int } else { STAT_INC(PRECALL, deferred); - cache->counter--; + DECREMENT_ADAPTIVE_COUNTER(cache); JUMP_TO_INSTRUCTION(PRECALL); } } From webhook-mailer at python.org Thu Oct 13 07:35:40 2022 From: webhook-mailer at python.org (ambv) Date: Thu, 13 Oct 2022 11:35:40 -0000 Subject: [Python-checkins] gh-98178: syslog() is not thread-safe on macOS (#98213) Message-ID: https://github.com/python/cpython/commit/d4b91663857e85eab1f309cacec4d27b5f6657ec commit: d4b91663857e85eab1f309cacec4d27b5f6657ec branch: main author: Victor Stinner committer: ambv date: 2022-10-13T13:34:55+02:00 summary: gh-98178: syslog() is not thread-safe on macOS (#98213) On macOS, fix a crash in syslog.syslog() in multi-threaded applications. On macOS, the libc syslog() function is not thread-safe, so syslog.syslog() no longer releases the GIL to call it. files: A Misc/NEWS.d/next/Library/2022-10-12-10-00-40.gh-issue-98178.hspH51.rst M Modules/syslogmodule.c diff --git a/Misc/NEWS.d/next/Library/2022-10-12-10-00-40.gh-issue-98178.hspH51.rst b/Misc/NEWS.d/next/Library/2022-10-12-10-00-40.gh-issue-98178.hspH51.rst new file mode 100644 index 000000000000..833a6e6bb3f7 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-12-10-00-40.gh-issue-98178.hspH51.rst @@ -0,0 +1,4 @@ +On macOS, fix a crash in :func:`syslog.syslog` in multi-threaded applications. +On macOS, the libc ``syslog()`` function is not thread-safe, so +:func:`syslog.syslog` no longer releases the GIL to call it. Patch by Victor +Stinner. diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index b6296ed0a69a..5137d01c6887 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -207,9 +207,14 @@ syslog_syslog_impl(PyObject *module, int group_left_1, int priority, */ PyObject *ident = S_ident_o; Py_XINCREF(ident); +#ifdef __APPLE__ + // gh-98178: On macOS, libc syslog() is not thread-safe + syslog(priority, "%s", message); +#else Py_BEGIN_ALLOW_THREADS; syslog(priority, "%s", message); Py_END_ALLOW_THREADS; +#endif Py_XDECREF(ident); Py_RETURN_NONE; } From webhook-mailer at python.org Thu Oct 13 07:59:51 2022 From: webhook-mailer at python.org (miss-islington) Date: Thu, 13 Oct 2022 11:59:51 -0000 Subject: [Python-checkins] gh-98178: syslog() is not thread-safe on macOS (GH-98213) Message-ID: https://github.com/python/cpython/commit/c7761bbc3297539480d1e2799f7f67f0437c24b1 commit: c7761bbc3297539480d1e2799f7f67f0437c24b1 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-13T04:59:23-07:00 summary: gh-98178: syslog() is not thread-safe on macOS (GH-98213) On macOS, fix a crash in syslog.syslog() in multi-threaded applications. On macOS, the libc syslog() function is not thread-safe, so syslog.syslog() no longer releases the GIL to call it. (cherry picked from commit d4b91663857e85eab1f309cacec4d27b5f6657ec) Co-authored-by: Victor Stinner files: A Misc/NEWS.d/next/Library/2022-10-12-10-00-40.gh-issue-98178.hspH51.rst M Modules/syslogmodule.c diff --git a/Misc/NEWS.d/next/Library/2022-10-12-10-00-40.gh-issue-98178.hspH51.rst b/Misc/NEWS.d/next/Library/2022-10-12-10-00-40.gh-issue-98178.hspH51.rst new file mode 100644 index 000000000000..833a6e6bb3f7 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-12-10-00-40.gh-issue-98178.hspH51.rst @@ -0,0 +1,4 @@ +On macOS, fix a crash in :func:`syslog.syslog` in multi-threaded applications. +On macOS, the libc ``syslog()`` function is not thread-safe, so +:func:`syslog.syslog` no longer releases the GIL to call it. Patch by Victor +Stinner. diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index 1593eea94a62..8416b6344ce4 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -207,9 +207,14 @@ syslog_syslog(PyObject * self, PyObject * args) */ PyObject *ident = S_ident_o; Py_XINCREF(ident); +#ifdef __APPLE__ + // gh-98178: On macOS, libc syslog() is not thread-safe + syslog(priority, "%s", message); +#else Py_BEGIN_ALLOW_THREADS; syslog(priority, "%s", message); Py_END_ALLOW_THREADS; +#endif Py_XDECREF(ident); Py_RETURN_NONE; } From webhook-mailer at python.org Thu Oct 13 08:05:24 2022 From: webhook-mailer at python.org (miss-islington) Date: Thu, 13 Oct 2022 12:05:24 -0000 Subject: [Python-checkins] gh-98178: syslog() is not thread-safe on macOS (GH-98213) Message-ID: https://github.com/python/cpython/commit/c7662420d62e04eefd99d7cdbcc74f72e68f3a6a commit: c7662420d62e04eefd99d7cdbcc74f72e68f3a6a branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-13T05:05:18-07:00 summary: gh-98178: syslog() is not thread-safe on macOS (GH-98213) On macOS, fix a crash in syslog.syslog() in multi-threaded applications. On macOS, the libc syslog() function is not thread-safe, so syslog.syslog() no longer releases the GIL to call it. (cherry picked from commit d4b91663857e85eab1f309cacec4d27b5f6657ec) Co-authored-by: Victor Stinner files: A Misc/NEWS.d/next/Library/2022-10-12-10-00-40.gh-issue-98178.hspH51.rst M Modules/syslogmodule.c diff --git a/Misc/NEWS.d/next/Library/2022-10-12-10-00-40.gh-issue-98178.hspH51.rst b/Misc/NEWS.d/next/Library/2022-10-12-10-00-40.gh-issue-98178.hspH51.rst new file mode 100644 index 000000000000..833a6e6bb3f7 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-12-10-00-40.gh-issue-98178.hspH51.rst @@ -0,0 +1,4 @@ +On macOS, fix a crash in :func:`syslog.syslog` in multi-threaded applications. +On macOS, the libc ``syslog()`` function is not thread-safe, so +:func:`syslog.syslog` no longer releases the GIL to call it. Patch by Victor +Stinner. diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index bfa2ca2b653b..8adbe2142d26 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -207,9 +207,14 @@ syslog_syslog(PyObject * self, PyObject * args) */ PyObject *ident = S_ident_o; Py_XINCREF(ident); +#ifdef __APPLE__ + // gh-98178: On macOS, libc syslog() is not thread-safe + syslog(priority, "%s", message); +#else Py_BEGIN_ALLOW_THREADS; syslog(priority, "%s", message); Py_END_ALLOW_THREADS; +#endif Py_XDECREF(ident); Py_RETURN_NONE; } From webhook-mailer at python.org Thu Oct 13 12:11:49 2022 From: webhook-mailer at python.org (gvanrossum) Date: Thu, 13 Oct 2022 16:11:49 -0000 Subject: [Python-checkins] bpo-46364: Use sockets for stdin of asyncio only on AIX (#30596) Message-ID: https://github.com/python/cpython/commit/c9ed0327a9c741a1808926b409df29467baf303a commit: c9ed0327a9c741a1808926b409df29467baf303a branch: main author: Christoph Hamsen <37963496+xopham at users.noreply.github.com> committer: gvanrossum date: 2022-10-13T09:11:15-07:00 summary: bpo-46364: Use sockets for stdin of asyncio only on AIX (#30596) Signed-off-by: Christoph Hamsen Co-authored-by: July Tikhonov files: A Misc/NEWS.d/next/Library/2022-01-14-10-49-20.bpo-46364.SzhlU9.rst M Lib/asyncio/unix_events.py M Lib/test/test_asyncio/test_subprocess.py diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py index bdffc032e318..9f9b03e0cb21 100644 --- a/Lib/asyncio/unix_events.py +++ b/Lib/asyncio/unix_events.py @@ -800,12 +800,11 @@ class _UnixSubprocessTransport(base_subprocess.BaseSubprocessTransport): def _start(self, args, shell, stdin, stdout, stderr, bufsize, **kwargs): stdin_w = None - if stdin == subprocess.PIPE: - # Use a socket pair for stdin, since not all platforms + if stdin == subprocess.PIPE and sys.platform.startswith('aix'): + # Use a socket pair for stdin on AIX, since it does not # support selecting read events on the write end of a # socket (which we use in order to detect closing of the - # other end). Notably this is needed on AIX, and works - # just fine on other platforms. + # other end). stdin, stdin_w = socket.socketpair() try: self._proc = subprocess.Popen( diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py index 915ad5587f0a..64df1b17189b 100644 --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -427,6 +427,26 @@ async def empty_error(): self.assertEqual(output, None) self.assertEqual(exitcode, 0) + @unittest.skipIf(sys.platform != 'linux', "Don't have /dev/stdin") + def test_devstdin_input(self): + + async def devstdin_input(message): + code = 'file = open("/dev/stdin"); data = file.read(); print(len(data))' + proc = await asyncio.create_subprocess_exec( + sys.executable, '-c', code, + stdin=asyncio.subprocess.PIPE, + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE, + close_fds=False, + ) + stdout, stderr = await proc.communicate(message) + exitcode = await proc.wait() + return (stdout, exitcode) + + output, exitcode = self.loop.run_until_complete(devstdin_input(b'abc')) + self.assertEqual(output.rstrip(), b'3') + self.assertEqual(exitcode, 0) + def test_cancel_process_wait(self): # Issue #23140: cancel Process.wait() diff --git a/Misc/NEWS.d/next/Library/2022-01-14-10-49-20.bpo-46364.SzhlU9.rst b/Misc/NEWS.d/next/Library/2022-01-14-10-49-20.bpo-46364.SzhlU9.rst new file mode 100644 index 000000000000..d547ffc6f97e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-01-14-10-49-20.bpo-46364.SzhlU9.rst @@ -0,0 +1 @@ +Restrict use of sockets instead of pipes for stdin of subprocesses created by :mod:`asyncio` to AIX platform only. From webhook-mailer at python.org Thu Oct 13 13:27:42 2022 From: webhook-mailer at python.org (miss-islington) Date: Thu, 13 Oct 2022 17:27:42 -0000 Subject: [Python-checkins] bpo-46364: Use sockets for stdin of asyncio only on AIX (GH-30596) Message-ID: https://github.com/python/cpython/commit/595ef03c7ceb25e63878e2a9231e1b54f9f0d125 commit: 595ef03c7ceb25e63878e2a9231e1b54f9f0d125 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-13T10:27:31-07:00 summary: bpo-46364: Use sockets for stdin of asyncio only on AIX (GH-30596) Signed-off-by: Christoph Hamsen Co-authored-by: July Tikhonov (cherry picked from commit c9ed0327a9c741a1808926b409df29467baf303a) Co-authored-by: Christoph Hamsen <37963496+xopham at users.noreply.github.com> files: A Misc/NEWS.d/next/Library/2022-01-14-10-49-20.bpo-46364.SzhlU9.rst M Lib/asyncio/unix_events.py M Lib/test/test_asyncio/test_subprocess.py diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py index 96e6d73a7597..0495f332f312 100644 --- a/Lib/asyncio/unix_events.py +++ b/Lib/asyncio/unix_events.py @@ -800,12 +800,11 @@ class _UnixSubprocessTransport(base_subprocess.BaseSubprocessTransport): def _start(self, args, shell, stdin, stdout, stderr, bufsize, **kwargs): stdin_w = None - if stdin == subprocess.PIPE: - # Use a socket pair for stdin, since not all platforms + if stdin == subprocess.PIPE and sys.platform.startswith('aix'): + # Use a socket pair for stdin on AIX, since it does not # support selecting read events on the write end of a # socket (which we use in order to detect closing of the - # other end). Notably this is needed on AIX, and works - # just fine on other platforms. + # other end). stdin, stdin_w = socket.socketpair() try: self._proc = subprocess.Popen( diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py index 9bc60b9dc2ae..7b7df4005631 100644 --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -427,6 +427,26 @@ async def empty_error(): self.assertEqual(output, None) self.assertEqual(exitcode, 0) + @unittest.skipIf(sys.platform != 'linux', "Don't have /dev/stdin") + def test_devstdin_input(self): + + async def devstdin_input(message): + code = 'file = open("/dev/stdin"); data = file.read(); print(len(data))' + proc = await asyncio.create_subprocess_exec( + sys.executable, '-c', code, + stdin=asyncio.subprocess.PIPE, + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE, + close_fds=False, + ) + stdout, stderr = await proc.communicate(message) + exitcode = await proc.wait() + return (stdout, exitcode) + + output, exitcode = self.loop.run_until_complete(devstdin_input(b'abc')) + self.assertEqual(output.rstrip(), b'3') + self.assertEqual(exitcode, 0) + def test_cancel_process_wait(self): # Issue #23140: cancel Process.wait() diff --git a/Misc/NEWS.d/next/Library/2022-01-14-10-49-20.bpo-46364.SzhlU9.rst b/Misc/NEWS.d/next/Library/2022-01-14-10-49-20.bpo-46364.SzhlU9.rst new file mode 100644 index 000000000000..d547ffc6f97e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-01-14-10-49-20.bpo-46364.SzhlU9.rst @@ -0,0 +1 @@ +Restrict use of sockets instead of pipes for stdin of subprocesses created by :mod:`asyncio` to AIX platform only. From webhook-mailer at python.org Thu Oct 13 13:27:42 2022 From: webhook-mailer at python.org (miss-islington) Date: Thu, 13 Oct 2022 17:27:42 -0000 Subject: [Python-checkins] bpo-46364: Use sockets for stdin of asyncio only on AIX (GH-30596) Message-ID: https://github.com/python/cpython/commit/fa9f65ef581c543583244b23e2ce9bb57feb68a2 commit: fa9f65ef581c543583244b23e2ce9bb57feb68a2 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-13T10:27:14-07:00 summary: bpo-46364: Use sockets for stdin of asyncio only on AIX (GH-30596) Signed-off-by: Christoph Hamsen Co-authored-by: July Tikhonov (cherry picked from commit c9ed0327a9c741a1808926b409df29467baf303a) Co-authored-by: Christoph Hamsen <37963496+xopham at users.noreply.github.com> files: A Misc/NEWS.d/next/Library/2022-01-14-10-49-20.bpo-46364.SzhlU9.rst M Lib/asyncio/unix_events.py M Lib/test/test_asyncio/test_subprocess.py diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py index 39b5e8382e16..faaca305c98d 100644 --- a/Lib/asyncio/unix_events.py +++ b/Lib/asyncio/unix_events.py @@ -789,12 +789,11 @@ class _UnixSubprocessTransport(base_subprocess.BaseSubprocessTransport): def _start(self, args, shell, stdin, stdout, stderr, bufsize, **kwargs): stdin_w = None - if stdin == subprocess.PIPE: - # Use a socket pair for stdin, since not all platforms + if stdin == subprocess.PIPE and sys.platform.startswith('aix'): + # Use a socket pair for stdin on AIX, since it does not # support selecting read events on the write end of a # socket (which we use in order to detect closing of the - # other end). Notably this is needed on AIX, and works - # just fine on other platforms. + # other end). stdin, stdin_w = socket.socketpair() try: self._proc = subprocess.Popen( diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py index 14fa6dd76f9c..7cd80fd68e3b 100644 --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -401,6 +401,26 @@ async def empty_error(): self.assertEqual(output, None) self.assertEqual(exitcode, 0) + @unittest.skipIf(sys.platform != 'linux', "Don't have /dev/stdin") + def test_devstdin_input(self): + + async def devstdin_input(message): + code = 'file = open("/dev/stdin"); data = file.read(); print(len(data))' + proc = await asyncio.create_subprocess_exec( + sys.executable, '-c', code, + stdin=asyncio.subprocess.PIPE, + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE, + close_fds=False, + ) + stdout, stderr = await proc.communicate(message) + exitcode = await proc.wait() + return (stdout, exitcode) + + output, exitcode = self.loop.run_until_complete(devstdin_input(b'abc')) + self.assertEqual(output.rstrip(), b'3') + self.assertEqual(exitcode, 0) + def test_cancel_process_wait(self): # Issue #23140: cancel Process.wait() diff --git a/Misc/NEWS.d/next/Library/2022-01-14-10-49-20.bpo-46364.SzhlU9.rst b/Misc/NEWS.d/next/Library/2022-01-14-10-49-20.bpo-46364.SzhlU9.rst new file mode 100644 index 000000000000..d547ffc6f97e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-01-14-10-49-20.bpo-46364.SzhlU9.rst @@ -0,0 +1 @@ +Restrict use of sockets instead of pipes for stdin of subprocesses created by :mod:`asyncio` to AIX platform only. From webhook-mailer at python.org Thu Oct 13 14:05:57 2022 From: webhook-mailer at python.org (gvanrossum) Date: Thu, 13 Oct 2022 18:05:57 -0000 Subject: [Python-checkins] Bpo-41246: IOCP Proactor avoid callback code duplication (#21399) Message-ID: https://github.com/python/cpython/commit/b863b9cd4b8681cf5fff5f121837a1039045783f commit: b863b9cd4b8681cf5fff5f121837a1039045783f branch: main author: Tony Solomonik committer: gvanrossum date: 2022-10-13T11:05:16-07:00 summary: Bpo-41246: IOCP Proactor avoid callback code duplication (#21399) Use the same callback function for overlapped operations recv, recv_into, recvfrom, sendto, send, and sendfile inside IocpProactor. files: A Misc/NEWS.d/next/Library/2020-07-08-20-32-13.bpo-41246.2trYf3.rst M Lib/asyncio/windows_events.py diff --git a/Lib/asyncio/windows_events.py b/Lib/asyncio/windows_events.py index 90b259cbafea..acc97daafecc 100644 --- a/Lib/asyncio/windows_events.py +++ b/Lib/asyncio/windows_events.py @@ -446,6 +446,17 @@ def _result(self, value): fut.set_result(value) return fut + @staticmethod + def finish_socket_func(trans, key, ov): + try: + return ov.getresult() + except OSError as exc: + if exc.winerror in (_overlapped.ERROR_NETNAME_DELETED, + _overlapped.ERROR_OPERATION_ABORTED): + raise ConnectionResetError(*exc.args) + else: + raise + def recv(self, conn, nbytes, flags=0): self._register_with_iocp(conn) ov = _overlapped.Overlapped(NULL) @@ -457,17 +468,7 @@ def recv(self, conn, nbytes, flags=0): except BrokenPipeError: return self._result(b'') - def finish_recv(trans, key, ov): - try: - return ov.getresult() - except OSError as exc: - if exc.winerror in (_overlapped.ERROR_NETNAME_DELETED, - _overlapped.ERROR_OPERATION_ABORTED): - raise ConnectionResetError(*exc.args) - else: - raise - - return self._register(ov, conn, finish_recv) + return self._register(ov, conn, self.finish_socket_func) def recv_into(self, conn, buf, flags=0): self._register_with_iocp(conn) @@ -480,17 +481,7 @@ def recv_into(self, conn, buf, flags=0): except BrokenPipeError: return self._result(0) - def finish_recv(trans, key, ov): - try: - return ov.getresult() - except OSError as exc: - if exc.winerror in (_overlapped.ERROR_NETNAME_DELETED, - _overlapped.ERROR_OPERATION_ABORTED): - raise ConnectionResetError(*exc.args) - else: - raise - - return self._register(ov, conn, finish_recv) + return self._register(ov, conn, self.finish_socket_func) def recvfrom(self, conn, nbytes, flags=0): self._register_with_iocp(conn) @@ -500,17 +491,7 @@ def recvfrom(self, conn, nbytes, flags=0): except BrokenPipeError: return self._result((b'', None)) - def finish_recv(trans, key, ov): - try: - return ov.getresult() - except OSError as exc: - if exc.winerror in (_overlapped.ERROR_NETNAME_DELETED, - _overlapped.ERROR_OPERATION_ABORTED): - raise ConnectionResetError(*exc.args) - else: - raise - - return self._register(ov, conn, finish_recv) + return self._register(ov, conn, self.finish_socket_func) def recvfrom_into(self, conn, buf, flags=0): self._register_with_iocp(conn) @@ -538,17 +519,7 @@ def sendto(self, conn, buf, flags=0, addr=None): ov.WSASendTo(conn.fileno(), buf, flags, addr) - def finish_send(trans, key, ov): - try: - return ov.getresult() - except OSError as exc: - if exc.winerror in (_overlapped.ERROR_NETNAME_DELETED, - _overlapped.ERROR_OPERATION_ABORTED): - raise ConnectionResetError(*exc.args) - else: - raise - - return self._register(ov, conn, finish_send) + return self._register(ov, conn, self.finish_socket_func) def send(self, conn, buf, flags=0): self._register_with_iocp(conn) @@ -558,17 +529,7 @@ def send(self, conn, buf, flags=0): else: ov.WriteFile(conn.fileno(), buf) - def finish_send(trans, key, ov): - try: - return ov.getresult() - except OSError as exc: - if exc.winerror in (_overlapped.ERROR_NETNAME_DELETED, - _overlapped.ERROR_OPERATION_ABORTED): - raise ConnectionResetError(*exc.args) - else: - raise - - return self._register(ov, conn, finish_send) + return self._register(ov, conn, self.finish_socket_func) def accept(self, listener): self._register_with_iocp(listener) @@ -639,16 +600,7 @@ def sendfile(self, sock, file, offset, count): offset_low, offset_high, count, 0, 0) - def finish_sendfile(trans, key, ov): - try: - return ov.getresult() - except OSError as exc: - if exc.winerror in (_overlapped.ERROR_NETNAME_DELETED, - _overlapped.ERROR_OPERATION_ABORTED): - raise ConnectionResetError(*exc.args) - else: - raise - return self._register(ov, sock, finish_sendfile) + return self._register(ov, sock, self.finish_socket_func) def accept_pipe(self, pipe): self._register_with_iocp(pipe) diff --git a/Misc/NEWS.d/next/Library/2020-07-08-20-32-13.bpo-41246.2trYf3.rst b/Misc/NEWS.d/next/Library/2020-07-08-20-32-13.bpo-41246.2trYf3.rst new file mode 100644 index 000000000000..17b884e777e9 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-07-08-20-32-13.bpo-41246.2trYf3.rst @@ -0,0 +1,3 @@ +Give the same callback function for when the overlapped operation is done to +the functions ``recv``, ``recv_into``, ``recvfrom``, ``sendto``, ``send`` +and ``sendfile`` inside ``IocpProactor``. From webhook-mailer at python.org Fri Oct 14 11:59:28 2022 From: webhook-mailer at python.org (zooba) Date: Fri, 14 Oct 2022 15:59:28 -0000 Subject: [Python-checkins] gh-98251: Allow venv to pass along PYTHON* variables to pip and ensurepip when they do not impact path resolution (GH-98259) Message-ID: https://github.com/python/cpython/commit/2fe44f728afa2dd506c304641f0481d6813d1dbd commit: 2fe44f728afa2dd506c304641f0481d6813d1dbd branch: main author: Steve Dower committer: zooba date: 2022-10-14T16:58:54+01:00 summary: gh-98251: Allow venv to pass along PYTHON* variables to pip and ensurepip when they do not impact path resolution (GH-98259) files: A Misc/NEWS.d/next/Library/2022-10-14-11-46-31.gh-issue-98251.Uxc9al.rst M Lib/test/test_venv.py M Lib/venv/__init__.py diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py index 4359a4e3ebe8..b355b0050cd5 100644 --- a/Lib/test/test_venv.py +++ b/Lib/test/test_venv.py @@ -216,7 +216,7 @@ def test_upgrade_dependencies(self): if sys.platform == 'win32': expect_exe = os.path.normcase(os.path.realpath(expect_exe)) - def pip_cmd_checker(cmd): + def pip_cmd_checker(cmd, **kwargs): cmd[0] = os.path.normcase(cmd[0]) self.assertEqual( cmd, @@ -232,7 +232,7 @@ def pip_cmd_checker(cmd): ) fake_context = builder.ensure_directories(fake_env_dir) - with patch('venv.subprocess.check_call', pip_cmd_checker): + with patch('venv.subprocess.check_output', pip_cmd_checker): builder.upgrade_dependencies(fake_context) @requireVenvCreate @@ -659,8 +659,8 @@ def nicer_error(self): try: yield except subprocess.CalledProcessError as exc: - out = exc.output.decode(errors="replace") - err = exc.stderr.decode(errors="replace") + out = (exc.output or b'').decode(errors="replace") + err = (exc.stderr or b'').decode(errors="replace") self.fail( f"{exc}\n\n" f"**Subprocess Output**\n{out}\n\n" diff --git a/Lib/venv/__init__.py b/Lib/venv/__init__.py index 034e3d420177..5e695c75ff49 100644 --- a/Lib/venv/__init__.py +++ b/Lib/venv/__init__.py @@ -339,14 +339,25 @@ def setup_python(self, context): shutil.copyfile(src, dst) break + def _call_new_python(self, context, *py_args, **kwargs): + """Executes the newly created Python using safe-ish options""" + # gh-98251: We do not want to just use '-I' because that masks + # legitimate user preferences (such as not writing bytecode). All we + # really need is to ensure that the path variables do not overrule + # normal venv handling. + args = [context.env_exec_cmd, *py_args] + kwargs['env'] = env = os.environ.copy() + env['VIRTUAL_ENV'] = context.env_dir + env.pop('PYTHONHOME', None) + env.pop('PYTHONPATH', None) + kwargs['cwd'] = context.env_dir + kwargs['executable'] = context.env_exec_cmd + subprocess.check_output(args, **kwargs) + def _setup_pip(self, context): """Installs or upgrades pip in a virtual environment""" - # We run ensurepip in isolated mode to avoid side effects from - # environment vars, the current directory and anything else - # intended for the global Python environment - cmd = [context.env_exec_cmd, '-Im', 'ensurepip', '--upgrade', - '--default-pip'] - subprocess.check_output(cmd, stderr=subprocess.STDOUT) + self._call_new_python(context, '-m', 'ensurepip', '--upgrade', + '--default-pip', stderr=subprocess.STDOUT) def setup_scripts(self, context): """ @@ -445,9 +456,8 @@ def upgrade_dependencies(self, context): logger.debug( f'Upgrading {CORE_VENV_DEPS} packages in {context.bin_path}' ) - cmd = [context.env_exec_cmd, '-m', 'pip', 'install', '--upgrade'] - cmd.extend(CORE_VENV_DEPS) - subprocess.check_call(cmd) + self._call_new_python(context, '-m', 'pip', 'install', '--upgrade', + *CORE_VENV_DEPS) def create(env_dir, system_site_packages=False, clear=False, diff --git a/Misc/NEWS.d/next/Library/2022-10-14-11-46-31.gh-issue-98251.Uxc9al.rst b/Misc/NEWS.d/next/Library/2022-10-14-11-46-31.gh-issue-98251.Uxc9al.rst new file mode 100644 index 000000000000..1a2b6a2537b9 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-14-11-46-31.gh-issue-98251.Uxc9al.rst @@ -0,0 +1,2 @@ +Allow :mod:`venv` to pass along :envvar:`PYTHON*` variables to ``ensurepip`` and ``pip`` when +they do not impact path resolution From webhook-mailer at python.org Fri Oct 14 12:22:27 2022 From: webhook-mailer at python.org (miss-islington) Date: Fri, 14 Oct 2022 16:22:27 -0000 Subject: [Python-checkins] gh-98251: Allow venv to pass along PYTHON* variables to pip and ensurepip when they do not impact path resolution (GH-98259) Message-ID: https://github.com/python/cpython/commit/c9da063e32725a66495e4047b8a5ed13e72d9e8e commit: c9da063e32725a66495e4047b8a5ed13e72d9e8e branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-14T09:22:19-07:00 summary: gh-98251: Allow venv to pass along PYTHON* variables to pip and ensurepip when they do not impact path resolution (GH-98259) (cherry picked from commit 2fe44f728afa2dd506c304641f0481d6813d1dbd) Co-authored-by: Steve Dower files: A Misc/NEWS.d/next/Library/2022-10-14-11-46-31.gh-issue-98251.Uxc9al.rst M Lib/test/test_venv.py M Lib/venv/__init__.py diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py index eca35ec4bfd1..fea986b9d868 100644 --- a/Lib/test/test_venv.py +++ b/Lib/test/test_venv.py @@ -159,7 +159,7 @@ def test_upgrade_dependencies(self): if sys.platform == 'win32': expect_exe = os.path.normcase(os.path.realpath(expect_exe)) - def pip_cmd_checker(cmd): + def pip_cmd_checker(cmd, **kwargs): cmd[0] = os.path.normcase(cmd[0]) self.assertEqual( cmd, @@ -175,7 +175,7 @@ def pip_cmd_checker(cmd): ) fake_context = builder.ensure_directories(fake_env_dir) - with patch('venv.subprocess.check_call', pip_cmd_checker): + with patch('venv.subprocess.check_output', pip_cmd_checker): builder.upgrade_dependencies(fake_context) @requireVenvCreate @@ -547,8 +547,8 @@ def nicer_error(self): try: yield except subprocess.CalledProcessError as exc: - out = exc.output.decode(errors="replace") - err = exc.stderr.decode(errors="replace") + out = (exc.output or b'').decode(errors="replace") + err = (exc.stderr or b'').decode(errors="replace") self.fail( f"{exc}\n\n" f"**Subprocess Output**\n{out}\n\n" diff --git a/Lib/venv/__init__.py b/Lib/venv/__init__.py index 885200851535..69155e5cc2ff 100644 --- a/Lib/venv/__init__.py +++ b/Lib/venv/__init__.py @@ -308,14 +308,25 @@ def setup_python(self, context): shutil.copyfile(src, dst) break + def _call_new_python(self, context, *py_args, **kwargs): + """Executes the newly created Python using safe-ish options""" + # gh-98251: We do not want to just use '-I' because that masks + # legitimate user preferences (such as not writing bytecode). All we + # really need is to ensure that the path variables do not overrule + # normal venv handling. + args = [context.env_exec_cmd, *py_args] + kwargs['env'] = env = os.environ.copy() + env['VIRTUAL_ENV'] = context.env_dir + env.pop('PYTHONHOME', None) + env.pop('PYTHONPATH', None) + kwargs['cwd'] = context.env_dir + kwargs['executable'] = context.env_exec_cmd + subprocess.check_output(args, **kwargs) + def _setup_pip(self, context): """Installs or upgrades pip in a virtual environment""" - # We run ensurepip in isolated mode to avoid side effects from - # environment vars, the current directory and anything else - # intended for the global Python environment - cmd = [context.env_exec_cmd, '-Im', 'ensurepip', '--upgrade', - '--default-pip'] - subprocess.check_output(cmd, stderr=subprocess.STDOUT) + self._call_new_python(context, '-m', 'ensurepip', '--upgrade', + '--default-pip', stderr=subprocess.STDOUT) def setup_scripts(self, context): """ @@ -414,9 +425,8 @@ def upgrade_dependencies(self, context): logger.debug( f'Upgrading {CORE_VENV_DEPS} packages in {context.bin_path}' ) - cmd = [context.env_exec_cmd, '-m', 'pip', 'install', '--upgrade'] - cmd.extend(CORE_VENV_DEPS) - subprocess.check_call(cmd) + self._call_new_python(context, '-m', 'pip', 'install', '--upgrade', + *CORE_VENV_DEPS) def create(env_dir, system_site_packages=False, clear=False, diff --git a/Misc/NEWS.d/next/Library/2022-10-14-11-46-31.gh-issue-98251.Uxc9al.rst b/Misc/NEWS.d/next/Library/2022-10-14-11-46-31.gh-issue-98251.Uxc9al.rst new file mode 100644 index 000000000000..1a2b6a2537b9 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-14-11-46-31.gh-issue-98251.Uxc9al.rst @@ -0,0 +1,2 @@ +Allow :mod:`venv` to pass along :envvar:`PYTHON*` variables to ``ensurepip`` and ``pip`` when +they do not impact path resolution From webhook-mailer at python.org Fri Oct 14 12:24:29 2022 From: webhook-mailer at python.org (miss-islington) Date: Fri, 14 Oct 2022 16:24:29 -0000 Subject: [Python-checkins] gh-98251: Allow venv to pass along PYTHON* variables to pip and ensurepip when they do not impact path resolution (GH-98259) Message-ID: https://github.com/python/cpython/commit/22ad9e5f3e267c48c238df9f83af224871926df6 commit: 22ad9e5f3e267c48c238df9f83af224871926df6 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-14T09:24:23-07:00 summary: gh-98251: Allow venv to pass along PYTHON* variables to pip and ensurepip when they do not impact path resolution (GH-98259) (cherry picked from commit 2fe44f728afa2dd506c304641f0481d6813d1dbd) Co-authored-by: Steve Dower files: A Misc/NEWS.d/next/Library/2022-10-14-11-46-31.gh-issue-98251.Uxc9al.rst M Lib/test/test_venv.py M Lib/venv/__init__.py diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py index 74039f59f797..b0a86ee4abc5 100644 --- a/Lib/test/test_venv.py +++ b/Lib/test/test_venv.py @@ -216,7 +216,7 @@ def test_upgrade_dependencies(self): if sys.platform == 'win32': expect_exe = os.path.normcase(os.path.realpath(expect_exe)) - def pip_cmd_checker(cmd): + def pip_cmd_checker(cmd, **kwargs): cmd[0] = os.path.normcase(cmd[0]) self.assertEqual( cmd, @@ -232,7 +232,7 @@ def pip_cmd_checker(cmd): ) fake_context = builder.ensure_directories(fake_env_dir) - with patch('venv.subprocess.check_call', pip_cmd_checker): + with patch('venv.subprocess.check_output', pip_cmd_checker): builder.upgrade_dependencies(fake_context) @requireVenvCreate @@ -659,8 +659,8 @@ def nicer_error(self): try: yield except subprocess.CalledProcessError as exc: - out = exc.output.decode(errors="replace") - err = exc.stderr.decode(errors="replace") + out = (exc.output or b'').decode(errors="replace") + err = (exc.stderr or b'').decode(errors="replace") self.fail( f"{exc}\n\n" f"**Subprocess Output**\n{out}\n\n" diff --git a/Lib/venv/__init__.py b/Lib/venv/__init__.py index f5570e8fcd7c..fbb002ff2778 100644 --- a/Lib/venv/__init__.py +++ b/Lib/venv/__init__.py @@ -338,14 +338,25 @@ def setup_python(self, context): shutil.copyfile(src, dst) break + def _call_new_python(self, context, *py_args, **kwargs): + """Executes the newly created Python using safe-ish options""" + # gh-98251: We do not want to just use '-I' because that masks + # legitimate user preferences (such as not writing bytecode). All we + # really need is to ensure that the path variables do not overrule + # normal venv handling. + args = [context.env_exec_cmd, *py_args] + kwargs['env'] = env = os.environ.copy() + env['VIRTUAL_ENV'] = context.env_dir + env.pop('PYTHONHOME', None) + env.pop('PYTHONPATH', None) + kwargs['cwd'] = context.env_dir + kwargs['executable'] = context.env_exec_cmd + subprocess.check_output(args, **kwargs) + def _setup_pip(self, context): """Installs or upgrades pip in a virtual environment""" - # We run ensurepip in isolated mode to avoid side effects from - # environment vars, the current directory and anything else - # intended for the global Python environment - cmd = [context.env_exec_cmd, '-Im', 'ensurepip', '--upgrade', - '--default-pip'] - subprocess.check_output(cmd, stderr=subprocess.STDOUT) + self._call_new_python(context, '-m', 'ensurepip', '--upgrade', + '--default-pip', stderr=subprocess.STDOUT) def setup_scripts(self, context): """ @@ -444,9 +455,8 @@ def upgrade_dependencies(self, context): logger.debug( f'Upgrading {CORE_VENV_DEPS} packages in {context.bin_path}' ) - cmd = [context.env_exec_cmd, '-m', 'pip', 'install', '--upgrade'] - cmd.extend(CORE_VENV_DEPS) - subprocess.check_call(cmd) + self._call_new_python(context, '-m', 'pip', 'install', '--upgrade', + *CORE_VENV_DEPS) def create(env_dir, system_site_packages=False, clear=False, diff --git a/Misc/NEWS.d/next/Library/2022-10-14-11-46-31.gh-issue-98251.Uxc9al.rst b/Misc/NEWS.d/next/Library/2022-10-14-11-46-31.gh-issue-98251.Uxc9al.rst new file mode 100644 index 000000000000..1a2b6a2537b9 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-14-11-46-31.gh-issue-98251.Uxc9al.rst @@ -0,0 +1,2 @@ +Allow :mod:`venv` to pass along :envvar:`PYTHON*` variables to ``ensurepip`` and ``pip`` when +they do not impact path resolution From webhook-mailer at python.org Sat Oct 15 06:20:19 2022 From: webhook-mailer at python.org (JulienPalard) Date: Sat, 15 Oct 2022 10:20:19 -0000 Subject: [Python-checkins] gh-91485: Doc: Using Python syntax to document builtin Python functions. (GH-96579) Message-ID: https://github.com/python/cpython/commit/3c4cbd177f36777a04e78eb07ce20367560a66d3 commit: 3c4cbd177f36777a04e78eb07ce20367560a66d3 branch: main author: Julien Palard committer: JulienPalard date: 2022-10-15T12:19:35+02:00 summary: gh-91485: Doc: Using Python syntax to document builtin Python functions. (GH-96579) files: M Doc/library/functions.rst diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 93c9f4ad2bc2..8108c98332e9 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -54,14 +54,14 @@ are always available. They are listed here in alphabetical order. .. |func-bytearray| replace:: ``bytearray()`` .. |func-bytes| replace:: ``bytes()`` -.. function:: abs(x) +.. function:: abs(x, /) Return the absolute value of a number. The argument may be an integer, a floating point number, or an object implementing :meth:`__abs__`. If the argument is a complex number, its magnitude is returned. -.. function:: aiter(async_iterable) +.. function:: aiter(async_iterable, /) Return an :term:`asynchronous iterator` for an :term:`asynchronous iterable`. Equivalent to calling ``x.__aiter__()``. @@ -70,7 +70,7 @@ are always available. They are listed here in alphabetical order. .. versionadded:: 3.10 -.. function:: all(iterable) +.. function:: all(iterable, /) Return ``True`` if all elements of the *iterable* are true (or if the iterable is empty). Equivalent to:: @@ -82,7 +82,8 @@ are always available. They are listed here in alphabetical order. return True -.. awaitablefunction:: anext(async_iterator[, default]) +.. awaitablefunction:: anext(async_iterator, /) + anext(async_iterator, default, /) When awaited, return the next item from the given :term:`asynchronous iterator`, or *default* if given and the iterator is exhausted. @@ -97,7 +98,7 @@ are always available. They are listed here in alphabetical order. .. versionadded:: 3.10 -.. function:: any(iterable) +.. function:: any(iterable, /) Return ``True`` if any element of the *iterable* is true. If the iterable is empty, return ``False``. Equivalent to:: @@ -109,7 +110,7 @@ are always available. They are listed here in alphabetical order. return False -.. function:: ascii(object) +.. function:: ascii(object, /) As :func:`repr`, return a string containing a printable representation of an object, but escape the non-ASCII characters in the string returned by @@ -117,7 +118,7 @@ are always available. They are listed here in alphabetical order. similar to that returned by :func:`repr` in Python 2. -.. function:: bin(x) +.. function:: bin(x, /) Convert an integer number to a binary string prefixed with "0b". The result is a valid Python expression. If *x* is not a Python :class:`int` object, it @@ -139,7 +140,7 @@ are always available. They are listed here in alphabetical order. See also :func:`format` for more information. -.. class:: bool([x]) +.. class:: bool(x=False, /) Return a Boolean value, i.e. one of ``True`` or ``False``. *x* is converted using the standard :ref:`truth testing procedure `. If *x* is false @@ -172,7 +173,9 @@ are always available. They are listed here in alphabetical order. .. versionadded:: 3.7 .. _func-bytearray: -.. class:: bytearray([source[, encoding[, errors]]]) +.. class:: bytearray(source=b'') + bytearray(source, encoding) + bytearray(source, encoding, errors) :noindex: Return a new array of bytes. The :class:`bytearray` class is a mutable @@ -202,7 +205,9 @@ are always available. They are listed here in alphabetical order. .. _func-bytes: -.. class:: bytes([source[, encoding[, errors]]]) +.. class:: bytes(source=b'') + bytes(source, encoding) + bytes(source, encoding, errors) :noindex: Return a new "bytes" object which is an immutable sequence of integers in @@ -217,7 +222,7 @@ are always available. They are listed here in alphabetical order. See also :ref:`binaryseq`, :ref:`typebytes`, and :ref:`bytes-methods`. -.. function:: callable(object) +.. function:: callable(object, /) Return :const:`True` if the *object* argument appears callable, :const:`False` if not. If this returns ``True``, it is still possible that a @@ -230,7 +235,7 @@ are always available. They are listed here in alphabetical order. in Python 3.2. -.. function:: chr(i) +.. function:: chr(i, /) Return the string representing a character whose Unicode code point is the integer *i*. For example, ``chr(97)`` returns the string ``'a'``, while @@ -358,7 +363,8 @@ are always available. They are listed here in alphabetical order. support for top-level ``await``, ``async for``, and ``async with``. -.. class:: complex([real[, imag]]) +.. class:: complex(real=0, imag=0) + complex(string, /) Return a complex number with the value *real* + *imag*\*1j or convert a string or number to a complex number. If the first parameter is a string, it will @@ -391,7 +397,7 @@ are always available. They are listed here in alphabetical order. :meth:`__float__` are not defined. -.. function:: delattr(object, name) +.. function:: delattr(object, name, /) This is a relative of :func:`setattr`. The arguments are an object and a string. The string must be the name of one of the object's attributes. The @@ -402,8 +408,8 @@ are always available. They are listed here in alphabetical order. .. _func-dict: .. class:: dict(**kwarg) - dict(mapping, **kwarg) - dict(iterable, **kwarg) + dict(mapping, /, **kwarg) + dict(iterable, /, **kwarg) :noindex: Create a new dictionary. The :class:`dict` object is the dictionary class. @@ -413,7 +419,8 @@ are always available. They are listed here in alphabetical order. :class:`tuple` classes, as well as the :mod:`collections` module. -.. function:: dir([object]) +.. function:: dir() + dir(object, /) Without arguments, return the list of names in the current local scope. With an argument, attempt to return a list of valid attributes for that object. @@ -469,7 +476,7 @@ are always available. They are listed here in alphabetical order. class. -.. function:: divmod(a, b) +.. function:: divmod(a, b, /) Take two (non-complex) numbers as arguments and return a pair of numbers consisting of their quotient and remainder when using integer division. With @@ -505,7 +512,7 @@ are always available. They are listed here in alphabetical order. .. _func-eval: -.. function:: eval(expression[, globals[, locals]]) +.. function:: eval(expression, /, globals=None, locals=None) The arguments are a string and optional globals and locals. If provided, *globals* must be a dictionary. If provided, *locals* can be any mapping @@ -556,7 +563,7 @@ are always available. They are listed here in alphabetical order. .. index:: builtin: exec -.. function:: exec(object[, globals[, locals]], *, closure=None) +.. function:: exec(object, globals=None, locals=None, /, *, closure=None) This function supports dynamic execution of Python code. *object* must be either a string or a code object. If it is a string, the string is parsed as @@ -612,7 +619,7 @@ are always available. They are listed here in alphabetical order. Added the *closure* parameter. -.. function:: filter(function, iterable) +.. function:: filter(function, iterable, /) Construct an iterator from those elements of *iterable* for which *function* returns true. *iterable* may be either a sequence, a container which @@ -629,7 +636,7 @@ are always available. They are listed here in alphabetical order. elements of *iterable* for which *function* returns false. -.. class:: float([x]) +.. class:: float(x=0.0, /) .. index:: single: NaN @@ -697,7 +704,7 @@ are always available. They are listed here in alphabetical order. single: __format__ single: string; format() (built-in function) -.. function:: format(value[, format_spec]) +.. function:: format(value, format_spec="", /) Convert a *value* to a "formatted" representation, as controlled by *format_spec*. The interpretation of *format_spec* will depend on the type @@ -720,7 +727,7 @@ are always available. They are listed here in alphabetical order. .. _func-frozenset: -.. class:: frozenset([iterable]) +.. class:: frozenset(iterable=set(), /) :noindex: Return a new :class:`frozenset` object, optionally with elements taken from @@ -732,7 +739,8 @@ are always available. They are listed here in alphabetical order. module. -.. function:: getattr(object, name[, default]) +.. function:: getattr(object, name, /) + getattr(object, name, default, /) Return the value of the named attribute of *object*. *name* must be a string. If the string is the name of one of the object's attributes, the result is the @@ -756,7 +764,7 @@ are always available. They are listed here in alphabetical order. regardless of where the function is called. -.. function:: hasattr(object, name) +.. function:: hasattr(object, name, /) The arguments are an object and a string. The result is ``True`` if the string is the name of one of the object's attributes, ``False`` if not. (This @@ -764,7 +772,7 @@ are always available. They are listed here in alphabetical order. raises an :exc:`AttributeError` or not.) -.. function:: hash(object) +.. function:: hash(object, /) Return the hash value of the object (if it has one). Hash values are integers. They are used to quickly compare dictionary keys during a @@ -777,7 +785,8 @@ are always available. They are listed here in alphabetical order. truncates the return value based on the bit width of the host machine. See :meth:`__hash__` for details. -.. function:: help([object]) +.. function:: help() + help(request) Invoke the built-in help system. (This function is intended for interactive use.) If no argument is given, the interactive help system starts on the @@ -798,7 +807,7 @@ are always available. They are listed here in alphabetical order. signatures for callables are now more comprehensive and consistent. -.. function:: hex(x) +.. function:: hex(x, /) Convert an integer number to a lowercase hexadecimal string prefixed with "0x". If *x* is not a Python :class:`int` object, it has to define an @@ -830,7 +839,7 @@ are always available. They are listed here in alphabetical order. :meth:`float.hex` method. -.. function:: id(object) +.. function:: id(object, /) Return the "identity" of an object. This is an integer which is guaranteed to be unique and constant for this object during its lifetime. @@ -842,7 +851,8 @@ are always available. They are listed here in alphabetical order. .. audit-event:: builtins.id id id -.. function:: input([prompt]) +.. function:: input() + input(prompt, /) If the *prompt* argument is present, it is written to standard output without a trailing newline. The function then reads a line from input, converts it @@ -868,8 +878,8 @@ are always available. They are listed here in alphabetical order. with the result after successfully reading input. -.. class:: int([x]) - int(x, base=10) +.. class:: int(x=0, /) + int(x, /, base=10) Return an integer object constructed from a number or string *x*, or return ``0`` if no arguments are given. If *x* defines :meth:`__int__`, @@ -920,7 +930,7 @@ are always available. They are listed here in alphabetical order. See the :ref:`integer string conversion length limitation ` documentation. -.. function:: isinstance(object, classinfo) +.. function:: isinstance(object, classinfo, /) Return ``True`` if the *object* argument is an instance of the *classinfo* argument, or of a (direct, indirect, or :term:`virtual `) of *classinfo*. A @@ -951,7 +961,8 @@ are always available. They are listed here in alphabetical order. *classinfo* can be a :ref:`types-union`. -.. function:: iter(object[, sentinel]) +.. function:: iter(object, /) + iter(object, sentinel, /) Return an :term:`iterator` object. The first argument is interpreted very differently depending on the presence of the second argument. Without a @@ -978,7 +989,7 @@ are always available. They are listed here in alphabetical order. process_block(block) -.. function:: len(s) +.. function:: len(s, /) Return the length (the number of items) of an object. The argument may be a sequence (such as a string, bytes, tuple, list, or range) or a collection @@ -991,7 +1002,8 @@ are always available. They are listed here in alphabetical order. .. _func-list: -.. class:: list([iterable]) +.. class:: list() + list(iterable, /) :noindex: Rather than being a function, :class:`list` is actually a mutable @@ -1009,18 +1021,19 @@ are always available. They are listed here in alphabetical order. The contents of this dictionary should not be modified; changes may not affect the values of local and free variables used by the interpreter. -.. function:: map(function, iterable, ...) +.. function:: map(function, iterable, /, *iterables) Return an iterator that applies *function* to every item of *iterable*, - yielding the results. If additional *iterable* arguments are passed, + yielding the results. If additional *iterables* arguments are passed, *function* must take that many arguments and is applied to the items from all iterables in parallel. With multiple iterables, the iterator stops when the shortest iterable is exhausted. For cases where the function inputs are already arranged into argument tuples, see :func:`itertools.starmap`\. -.. function:: max(iterable, *[, key, default]) - max(arg1, arg2, *args[, key]) +.. function:: max(iterable, /, *, key=None) + max(iterable, /, *, default, key=None) + max(arg1, arg2, /, *args, key=None) Return the largest item in an iterable or the largest of two or more arguments. @@ -1056,8 +1069,9 @@ are always available. They are listed here in alphabetical order. :ref:`typememoryview` for more information. -.. function:: min(iterable, *[, key, default]) - min(arg1, arg2, *args[, key]) +.. function:: min(iterable, /, *, key=None) + min(iterable, /, *, default, key=None) + min(arg1, arg2, /, *args, key=None) Return the smallest item in an iterable or the smallest of two or more arguments. @@ -1085,7 +1099,8 @@ are always available. They are listed here in alphabetical order. The *key* can be ``None``. -.. function:: next(iterator[, default]) +.. function:: next(iterator, /) + next(iterator, default, /) Retrieve the next item from the :term:`iterator` by calling its :meth:`~iterator.__next__` method. If *default* is given, it is returned @@ -1104,7 +1119,7 @@ are always available. They are listed here in alphabetical order. assign arbitrary attributes to an instance of the :class:`object` class. -.. function:: oct(x) +.. function:: oct(x, /) Convert an integer number to an octal string prefixed with "0o". The result is a valid Python expression. If *x* is not a Python :class:`int` object, it @@ -1356,7 +1371,7 @@ are always available. They are listed here in alphabetical order. .. versionchanged:: 3.11 The ``'U'`` mode has been removed. -.. function:: ord(c) +.. function:: ord(c, /) Given a string representing one Unicode character, return an integer representing the Unicode code point of that character. For example, @@ -1364,7 +1379,7 @@ are always available. They are listed here in alphabetical order. returns ``8364``. This is the inverse of :func:`chr`. -.. function:: pow(base, exp[, mod]) +.. function:: pow(base, exp, mod=None) Return *base* to the power *exp*; if *mod* is present, return *base* to the power *exp*, modulo *mod* (computed more efficiently than @@ -1507,15 +1522,15 @@ are always available. They are listed here in alphabetical order. .. _func-range: -.. class:: range(stop) - range(start, stop[, step]) +.. class:: range(stop, /) + range(start, stop, step=1, /) :noindex: Rather than being a function, :class:`range` is actually an immutable sequence type, as documented in :ref:`typesseq-range` and :ref:`typesseq`. -.. function:: repr(object) +.. function:: repr(object, /) Return a string containing a printable representation of an object. For many types, this function makes an attempt to return a string that would yield an @@ -1528,7 +1543,7 @@ are always available. They are listed here in alphabetical order. :exc:`RuntimeError`. -.. function:: reversed(seq) +.. function:: reversed(seq, /) Return a reverse :term:`iterator`. *seq* must be an object which has a :meth:`__reversed__` method or supports the sequence protocol (the @@ -1536,7 +1551,7 @@ are always available. They are listed here in alphabetical order. arguments starting at ``0``). -.. function:: round(number[, ndigits]) +.. function:: round(number, ndigits=None) Return *number* rounded to *ndigits* precision after the decimal point. If *ndigits* is omitted or is ``None``, it returns the @@ -1564,7 +1579,8 @@ are always available. They are listed here in alphabetical order. .. _func-set: -.. class:: set([iterable]) +.. class:: set() + set(iterable, /) :noindex: Return a new :class:`set` object, optionally with elements taken from @@ -1576,7 +1592,7 @@ are always available. They are listed here in alphabetical order. module. -.. function:: setattr(object, name, value) +.. function:: setattr(object, name, value, /) This is the counterpart of :func:`getattr`. The arguments are an object, a string, and an arbitrary value. The string may name an existing attribute or a @@ -1598,8 +1614,8 @@ are always available. They are listed here in alphabetical order. :func:`setattr`. -.. class:: slice(stop) - slice(start, stop[, step]) +.. class:: slice(stop, /) + slice(start, stop, step=1, /) Return a :term:`slice` object representing the set of indices specified by ``range(start, stop, step)``. The *start* and *step* arguments default to @@ -1716,21 +1732,22 @@ are always available. They are listed here in alphabetical order. .. versionchanged:: 3.8 The *start* parameter can be specified as a keyword argument. -.. class:: super([type[, object-or-type]]) +.. class:: super() + super(type, object_or_type=None, /) Return a proxy object that delegates method calls to a parent or sibling class of *type*. This is useful for accessing inherited methods that have been overridden in a class. - The *object-or-type* determines the :term:`method resolution order` + The *object_or_type* determines the :term:`method resolution order` to be searched. The search starts from the class right after the *type*. - For example, if :attr:`~class.__mro__` of *object-or-type* is + For example, if :attr:`~class.__mro__` of *object_or_type* is ``D -> B -> C -> A -> object`` and the value of *type* is ``B``, then :func:`super` searches ``C -> A -> object``. - The :attr:`~class.__mro__` attribute of the *object-or-type* lists the method + The :attr:`~class.__mro__` attribute of the *object_or_type* lists the method resolution search order used by both :func:`getattr` and :func:`super`. The attribute is dynamic and can change whenever the inheritance hierarchy is updated. @@ -1786,15 +1803,16 @@ are always available. They are listed here in alphabetical order. .. _func-tuple: -.. class:: tuple([iterable]) +.. class:: tuple() + tuple(iterable, /) :noindex: Rather than being a function, :class:`tuple` is actually an immutable sequence type, as documented in :ref:`typesseq-tuple` and :ref:`typesseq`. -.. class:: type(object) - type(name, bases, dict, **kwds) +.. class:: type(object, /) + type(name, bases, dict, /, **kwds) .. index:: object: type @@ -1834,7 +1852,8 @@ are always available. They are listed here in alphabetical order. Subclasses of :class:`type` which don't override ``type.__new__`` may no longer use the one-argument form to get the type of an object. -.. function:: vars([object]) +.. function:: vars() + vars(object, /) Return the :attr:`~object.__dict__` attribute for a module, class, instance, or any other object with a :attr:`~object.__dict__` attribute. From webhook-mailer at python.org Sat Oct 15 09:30:14 2022 From: webhook-mailer at python.org (nanjekyejoannah) Date: Sat, 15 Oct 2022 13:30:14 -0000 Subject: [Python-checkins] gh-85525: Indicate supported sound header formats (#21575) Message-ID: https://github.com/python/cpython/commit/05c042e70786bd2e3fcb274d185e1e0a54dab5a7 commit: 05c042e70786bd2e3fcb274d185e1e0a54dab5a7 branch: main author: Joannah Nanjekye <33177550+nanjekyejoannah at users.noreply.github.com> committer: nanjekyejoannah <33177550+nanjekyejoannah at users.noreply.github.com> date: 2022-10-15T09:30:05-04:00 summary: gh-85525: Indicate supported sound header formats (#21575) * Indicate supported sound header formats * modify file names Co-authored-by: Jelle Zijlstra files: M Doc/library/sndhdr.rst M Lib/sndhdr.py diff --git a/Doc/library/sndhdr.rst b/Doc/library/sndhdr.rst index e1dbe4a1a344..8c5c0bfc617b 100644 --- a/Doc/library/sndhdr.rst +++ b/Doc/library/sndhdr.rst @@ -54,3 +54,52 @@ be the sample size in bits or ``'A'`` for A-LAW or ``'U'`` for u-LAW. .. versionchanged:: 3.5 Result changed from a tuple to a namedtuple. +The following sound header types are recognized, as listed below with the return value +from :func:`whathdr`: and :func:`what`: + ++------------+------------------------------------+ +| Value | Sound header format | ++============+====================================+ +| ``'aifc'`` | Compressed Audio Interchange Files | ++------------+------------------------------------+ +| ``'aiff'`` | Audio Interchange Files | ++------------+------------------------------------+ +| ``'au'`` | Au Files | ++------------+------------------------------------+ +| ``'hcom'`` | HCOM Files | ++------------+------------------------------------+ ++------------+------------------------------------+ +| ``'sndt'`` | Sndtool Sound Files | ++------------+------------------------------------+ +| ``'voc'`` | Creative Labs Audio Files | ++------------+------------------------------------+ +| ``'wav'`` | Waveform Audio File Format Files | ++------------+------------------------------------+ +| ``'8svx'`` | 8-Bit Sampled Voice Files | ++------------+------------------------------------+ +| ``'sb'`` | Signed Byte Audio Data Files | ++------------+------------------------------------+ +| ``'ub'`` | UB Files | ++------------+------------------------------------+ +| ``'ul'`` | uLAW Audio Files | ++------------+------------------------------------+ + +.. data:: tests + + A list of functions performing the individual tests. Each function takes two + arguments: the byte-stream and an open file-like object. When :func:`what` is + called with a byte-stream, the file-like object will be ``None``. + + The test function should return a string describing the image type if the test + succeeded, or ``None`` if it failed. + +Example: + +.. code-block:: pycon + + >>> import sndhdr + >>> imghdr.what('bass.wav') + 'wav' + >>> imghdr.whathdr('bass.wav') + 'wav' + diff --git a/Lib/sndhdr.py b/Lib/sndhdr.py index 98a783448239..45def9ad16d3 100644 --- a/Lib/sndhdr.py +++ b/Lib/sndhdr.py @@ -77,6 +77,7 @@ def whathdr(filename): tests = [] def test_aifc(h, f): + """AIFC and AIFF files""" with warnings.catch_warnings(): warnings.simplefilter('ignore', category=DeprecationWarning) import aifc @@ -100,6 +101,7 @@ def test_aifc(h, f): def test_au(h, f): + """AU and SND files""" if h.startswith(b'.snd'): func = get_long_be elif h[:4] in (b'\0ds.', b'dns.'): @@ -133,6 +135,7 @@ def test_au(h, f): def test_hcom(h, f): + """HCOM file""" if h[65:69] != b'FSSD' or h[128:132] != b'HCOM': return None divisor = get_long_be(h[144:148]) @@ -146,6 +149,7 @@ def test_hcom(h, f): def test_voc(h, f): + """VOC file""" if not h.startswith(b'Creative Voice File\032'): return None sbseek = get_short_le(h[20:22]) @@ -160,6 +164,7 @@ def test_voc(h, f): def test_wav(h, f): + """WAV file""" import wave # 'RIFF' 'WAVE' 'fmt ' if not h.startswith(b'RIFF') or h[8:12] != b'WAVE' or h[12:16] != b'fmt ': @@ -176,6 +181,7 @@ def test_wav(h, f): def test_8svx(h, f): + """8SVX file""" if not h.startswith(b'FORM') or h[8:12] != b'8SVX': return None # Should decode it to get #channels -- assume always 1 @@ -185,6 +191,7 @@ def test_8svx(h, f): def test_sndt(h, f): + """SNDT file""" if h.startswith(b'SOUND'): nsamples = get_long_le(h[8:12]) rate = get_short_le(h[20:22]) @@ -194,6 +201,7 @@ def test_sndt(h, f): def test_sndr(h, f): + """SNDR file""" if h.startswith(b'\0\0'): rate = get_short_le(h[2:4]) if 4000 <= rate <= 25000: From webhook-mailer at python.org Sat Oct 15 09:31:14 2022 From: webhook-mailer at python.org (nanjekyejoannah) Date: Sat, 15 Oct 2022 13:31:14 -0000 Subject: [Python-checkins] gh-85455: Add missing doc strings and improve docs (#21573) Message-ID: https://github.com/python/cpython/commit/bf786e6901934a7c25cb0aa6b7d42a1677f02300 commit: bf786e6901934a7c25cb0aa6b7d42a1677f02300 branch: main author: Joannah Nanjekye <33177550+nanjekyejoannah at users.noreply.github.com> committer: nanjekyejoannah <33177550+nanjekyejoannah at users.noreply.github.com> date: 2022-10-15T09:31:06-04:00 summary: gh-85455: Add missing doc strings and improve docs (#21573) * Add missing doc strings and improve docs * Use imperative form * Modify docstring wording files: M Doc/library/imghdr.rst M Lib/imghdr.py diff --git a/Doc/library/imghdr.rst b/Doc/library/imghdr.rst index 318fe650776d..630fd7019f94 100644 --- a/Doc/library/imghdr.rst +++ b/Doc/library/imghdr.rst @@ -21,8 +21,8 @@ The :mod:`imghdr` module defines the following function: .. function:: what(file, h=None) - Tests the image data contained in the file named by *file*, and returns a - string describing the image type. If optional *h* is provided, the *file* + Test the image data contained in the file named *file* and return a + string describing the image type. If *h* is provided, the *file* argument is ignored and *h* is assumed to contain the byte stream to test. .. versionchanged:: 3.6 diff --git a/Lib/imghdr.py b/Lib/imghdr.py index 6a372e66c7f2..338688834707 100644 --- a/Lib/imghdr.py +++ b/Lib/imghdr.py @@ -14,6 +14,7 @@ #-------------------------# def what(file, h=None): + """Return the type of image contained in a file or byte stream.""" f = None try: if h is None: @@ -40,7 +41,7 @@ def what(file, h=None): tests = [] def test_jpeg(h, f): - """JPEG data with JFIF or Exif markers; and raw JPEG""" + """Test for JPEG data with JFIF or Exif markers; and raw JPEG.""" if h[6:10] in (b'JFIF', b'Exif'): return 'jpeg' elif h[:4] == b'\xff\xd8\xff\xdb': @@ -49,34 +50,35 @@ def test_jpeg(h, f): tests.append(test_jpeg) def test_png(h, f): + """Verify if the image is a PNG.""" if h.startswith(b'\211PNG\r\n\032\n'): return 'png' tests.append(test_png) def test_gif(h, f): - """GIF ('87 and '89 variants)""" + """Verify if the image is a GIF ('87 or '89 variants).""" if h[:6] in (b'GIF87a', b'GIF89a'): return 'gif' tests.append(test_gif) def test_tiff(h, f): - """TIFF (can be in Motorola or Intel byte order)""" + """Verify if the image is a TIFF (can be in Motorola or Intel byte order).""" if h[:2] in (b'MM', b'II'): return 'tiff' tests.append(test_tiff) def test_rgb(h, f): - """SGI image library""" + """test for the SGI image library.""" if h.startswith(b'\001\332'): return 'rgb' tests.append(test_rgb) def test_pbm(h, f): - """PBM (portable bitmap)""" + """Verify if the image is a PBM (portable bitmap).""" if len(h) >= 3 and \ h[0] == ord(b'P') and h[1] in b'14' and h[2] in b' \t\n\r': return 'pbm' @@ -84,7 +86,7 @@ def test_pbm(h, f): tests.append(test_pbm) def test_pgm(h, f): - """PGM (portable graymap)""" + """Verify if the image is a PGM (portable graymap).""" if len(h) >= 3 and \ h[0] == ord(b'P') and h[1] in b'25' and h[2] in b' \t\n\r': return 'pgm' @@ -92,7 +94,7 @@ def test_pgm(h, f): tests.append(test_pgm) def test_ppm(h, f): - """PPM (portable pixmap)""" + """Verify if the image is a PPM (portable pixmap).""" if len(h) >= 3 and \ h[0] == ord(b'P') and h[1] in b'36' and h[2] in b' \t\n\r': return 'ppm' @@ -100,32 +102,35 @@ def test_ppm(h, f): tests.append(test_ppm) def test_rast(h, f): - """Sun raster file""" + """test for the Sun raster file.""" if h.startswith(b'\x59\xA6\x6A\x95'): return 'rast' tests.append(test_rast) def test_xbm(h, f): - """X bitmap (X10 or X11)""" + """Verify if the image is a X bitmap (X10 or X11).""" if h.startswith(b'#define '): return 'xbm' tests.append(test_xbm) def test_bmp(h, f): + """Verify if the image is a BMP file.""" if h.startswith(b'BM'): return 'bmp' tests.append(test_bmp) def test_webp(h, f): + """Verify if the image is a WebP.""" if h.startswith(b'RIFF') and h[8:12] == b'WEBP': return 'webp' tests.append(test_webp) def test_exr(h, f): + """verify is the image ia a OpenEXR fileOpenEXR.""" if h.startswith(b'\x76\x2f\x31\x01'): return 'exr' From webhook-mailer at python.org Sat Oct 15 10:32:43 2022 From: webhook-mailer at python.org (miss-islington) Date: Sat, 15 Oct 2022 14:32:43 -0000 Subject: [Python-checkins] gh-91485: Doc: Using Python syntax to document builtin Python functions. (GH-96579) Message-ID: https://github.com/python/cpython/commit/42d536c1c7b9fcb2f85663a54f11f4a073211fef commit: 42d536c1c7b9fcb2f85663a54f11f4a073211fef branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-15T07:32:37-07:00 summary: gh-91485: Doc: Using Python syntax to document builtin Python functions. (GH-96579) (cherry picked from commit 3c4cbd177f36777a04e78eb07ce20367560a66d3) Co-authored-by: Julien Palard files: M Doc/library/functions.rst diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 93c9f4ad2bc2..8108c98332e9 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -54,14 +54,14 @@ are always available. They are listed here in alphabetical order. .. |func-bytearray| replace:: ``bytearray()`` .. |func-bytes| replace:: ``bytes()`` -.. function:: abs(x) +.. function:: abs(x, /) Return the absolute value of a number. The argument may be an integer, a floating point number, or an object implementing :meth:`__abs__`. If the argument is a complex number, its magnitude is returned. -.. function:: aiter(async_iterable) +.. function:: aiter(async_iterable, /) Return an :term:`asynchronous iterator` for an :term:`asynchronous iterable`. Equivalent to calling ``x.__aiter__()``. @@ -70,7 +70,7 @@ are always available. They are listed here in alphabetical order. .. versionadded:: 3.10 -.. function:: all(iterable) +.. function:: all(iterable, /) Return ``True`` if all elements of the *iterable* are true (or if the iterable is empty). Equivalent to:: @@ -82,7 +82,8 @@ are always available. They are listed here in alphabetical order. return True -.. awaitablefunction:: anext(async_iterator[, default]) +.. awaitablefunction:: anext(async_iterator, /) + anext(async_iterator, default, /) When awaited, return the next item from the given :term:`asynchronous iterator`, or *default* if given and the iterator is exhausted. @@ -97,7 +98,7 @@ are always available. They are listed here in alphabetical order. .. versionadded:: 3.10 -.. function:: any(iterable) +.. function:: any(iterable, /) Return ``True`` if any element of the *iterable* is true. If the iterable is empty, return ``False``. Equivalent to:: @@ -109,7 +110,7 @@ are always available. They are listed here in alphabetical order. return False -.. function:: ascii(object) +.. function:: ascii(object, /) As :func:`repr`, return a string containing a printable representation of an object, but escape the non-ASCII characters in the string returned by @@ -117,7 +118,7 @@ are always available. They are listed here in alphabetical order. similar to that returned by :func:`repr` in Python 2. -.. function:: bin(x) +.. function:: bin(x, /) Convert an integer number to a binary string prefixed with "0b". The result is a valid Python expression. If *x* is not a Python :class:`int` object, it @@ -139,7 +140,7 @@ are always available. They are listed here in alphabetical order. See also :func:`format` for more information. -.. class:: bool([x]) +.. class:: bool(x=False, /) Return a Boolean value, i.e. one of ``True`` or ``False``. *x* is converted using the standard :ref:`truth testing procedure `. If *x* is false @@ -172,7 +173,9 @@ are always available. They are listed here in alphabetical order. .. versionadded:: 3.7 .. _func-bytearray: -.. class:: bytearray([source[, encoding[, errors]]]) +.. class:: bytearray(source=b'') + bytearray(source, encoding) + bytearray(source, encoding, errors) :noindex: Return a new array of bytes. The :class:`bytearray` class is a mutable @@ -202,7 +205,9 @@ are always available. They are listed here in alphabetical order. .. _func-bytes: -.. class:: bytes([source[, encoding[, errors]]]) +.. class:: bytes(source=b'') + bytes(source, encoding) + bytes(source, encoding, errors) :noindex: Return a new "bytes" object which is an immutable sequence of integers in @@ -217,7 +222,7 @@ are always available. They are listed here in alphabetical order. See also :ref:`binaryseq`, :ref:`typebytes`, and :ref:`bytes-methods`. -.. function:: callable(object) +.. function:: callable(object, /) Return :const:`True` if the *object* argument appears callable, :const:`False` if not. If this returns ``True``, it is still possible that a @@ -230,7 +235,7 @@ are always available. They are listed here in alphabetical order. in Python 3.2. -.. function:: chr(i) +.. function:: chr(i, /) Return the string representing a character whose Unicode code point is the integer *i*. For example, ``chr(97)`` returns the string ``'a'``, while @@ -358,7 +363,8 @@ are always available. They are listed here in alphabetical order. support for top-level ``await``, ``async for``, and ``async with``. -.. class:: complex([real[, imag]]) +.. class:: complex(real=0, imag=0) + complex(string, /) Return a complex number with the value *real* + *imag*\*1j or convert a string or number to a complex number. If the first parameter is a string, it will @@ -391,7 +397,7 @@ are always available. They are listed here in alphabetical order. :meth:`__float__` are not defined. -.. function:: delattr(object, name) +.. function:: delattr(object, name, /) This is a relative of :func:`setattr`. The arguments are an object and a string. The string must be the name of one of the object's attributes. The @@ -402,8 +408,8 @@ are always available. They are listed here in alphabetical order. .. _func-dict: .. class:: dict(**kwarg) - dict(mapping, **kwarg) - dict(iterable, **kwarg) + dict(mapping, /, **kwarg) + dict(iterable, /, **kwarg) :noindex: Create a new dictionary. The :class:`dict` object is the dictionary class. @@ -413,7 +419,8 @@ are always available. They are listed here in alphabetical order. :class:`tuple` classes, as well as the :mod:`collections` module. -.. function:: dir([object]) +.. function:: dir() + dir(object, /) Without arguments, return the list of names in the current local scope. With an argument, attempt to return a list of valid attributes for that object. @@ -469,7 +476,7 @@ are always available. They are listed here in alphabetical order. class. -.. function:: divmod(a, b) +.. function:: divmod(a, b, /) Take two (non-complex) numbers as arguments and return a pair of numbers consisting of their quotient and remainder when using integer division. With @@ -505,7 +512,7 @@ are always available. They are listed here in alphabetical order. .. _func-eval: -.. function:: eval(expression[, globals[, locals]]) +.. function:: eval(expression, /, globals=None, locals=None) The arguments are a string and optional globals and locals. If provided, *globals* must be a dictionary. If provided, *locals* can be any mapping @@ -556,7 +563,7 @@ are always available. They are listed here in alphabetical order. .. index:: builtin: exec -.. function:: exec(object[, globals[, locals]], *, closure=None) +.. function:: exec(object, globals=None, locals=None, /, *, closure=None) This function supports dynamic execution of Python code. *object* must be either a string or a code object. If it is a string, the string is parsed as @@ -612,7 +619,7 @@ are always available. They are listed here in alphabetical order. Added the *closure* parameter. -.. function:: filter(function, iterable) +.. function:: filter(function, iterable, /) Construct an iterator from those elements of *iterable* for which *function* returns true. *iterable* may be either a sequence, a container which @@ -629,7 +636,7 @@ are always available. They are listed here in alphabetical order. elements of *iterable* for which *function* returns false. -.. class:: float([x]) +.. class:: float(x=0.0, /) .. index:: single: NaN @@ -697,7 +704,7 @@ are always available. They are listed here in alphabetical order. single: __format__ single: string; format() (built-in function) -.. function:: format(value[, format_spec]) +.. function:: format(value, format_spec="", /) Convert a *value* to a "formatted" representation, as controlled by *format_spec*. The interpretation of *format_spec* will depend on the type @@ -720,7 +727,7 @@ are always available. They are listed here in alphabetical order. .. _func-frozenset: -.. class:: frozenset([iterable]) +.. class:: frozenset(iterable=set(), /) :noindex: Return a new :class:`frozenset` object, optionally with elements taken from @@ -732,7 +739,8 @@ are always available. They are listed here in alphabetical order. module. -.. function:: getattr(object, name[, default]) +.. function:: getattr(object, name, /) + getattr(object, name, default, /) Return the value of the named attribute of *object*. *name* must be a string. If the string is the name of one of the object's attributes, the result is the @@ -756,7 +764,7 @@ are always available. They are listed here in alphabetical order. regardless of where the function is called. -.. function:: hasattr(object, name) +.. function:: hasattr(object, name, /) The arguments are an object and a string. The result is ``True`` if the string is the name of one of the object's attributes, ``False`` if not. (This @@ -764,7 +772,7 @@ are always available. They are listed here in alphabetical order. raises an :exc:`AttributeError` or not.) -.. function:: hash(object) +.. function:: hash(object, /) Return the hash value of the object (if it has one). Hash values are integers. They are used to quickly compare dictionary keys during a @@ -777,7 +785,8 @@ are always available. They are listed here in alphabetical order. truncates the return value based on the bit width of the host machine. See :meth:`__hash__` for details. -.. function:: help([object]) +.. function:: help() + help(request) Invoke the built-in help system. (This function is intended for interactive use.) If no argument is given, the interactive help system starts on the @@ -798,7 +807,7 @@ are always available. They are listed here in alphabetical order. signatures for callables are now more comprehensive and consistent. -.. function:: hex(x) +.. function:: hex(x, /) Convert an integer number to a lowercase hexadecimal string prefixed with "0x". If *x* is not a Python :class:`int` object, it has to define an @@ -830,7 +839,7 @@ are always available. They are listed here in alphabetical order. :meth:`float.hex` method. -.. function:: id(object) +.. function:: id(object, /) Return the "identity" of an object. This is an integer which is guaranteed to be unique and constant for this object during its lifetime. @@ -842,7 +851,8 @@ are always available. They are listed here in alphabetical order. .. audit-event:: builtins.id id id -.. function:: input([prompt]) +.. function:: input() + input(prompt, /) If the *prompt* argument is present, it is written to standard output without a trailing newline. The function then reads a line from input, converts it @@ -868,8 +878,8 @@ are always available. They are listed here in alphabetical order. with the result after successfully reading input. -.. class:: int([x]) - int(x, base=10) +.. class:: int(x=0, /) + int(x, /, base=10) Return an integer object constructed from a number or string *x*, or return ``0`` if no arguments are given. If *x* defines :meth:`__int__`, @@ -920,7 +930,7 @@ are always available. They are listed here in alphabetical order. See the :ref:`integer string conversion length limitation ` documentation. -.. function:: isinstance(object, classinfo) +.. function:: isinstance(object, classinfo, /) Return ``True`` if the *object* argument is an instance of the *classinfo* argument, or of a (direct, indirect, or :term:`virtual `) of *classinfo*. A @@ -951,7 +961,8 @@ are always available. They are listed here in alphabetical order. *classinfo* can be a :ref:`types-union`. -.. function:: iter(object[, sentinel]) +.. function:: iter(object, /) + iter(object, sentinel, /) Return an :term:`iterator` object. The first argument is interpreted very differently depending on the presence of the second argument. Without a @@ -978,7 +989,7 @@ are always available. They are listed here in alphabetical order. process_block(block) -.. function:: len(s) +.. function:: len(s, /) Return the length (the number of items) of an object. The argument may be a sequence (such as a string, bytes, tuple, list, or range) or a collection @@ -991,7 +1002,8 @@ are always available. They are listed here in alphabetical order. .. _func-list: -.. class:: list([iterable]) +.. class:: list() + list(iterable, /) :noindex: Rather than being a function, :class:`list` is actually a mutable @@ -1009,18 +1021,19 @@ are always available. They are listed here in alphabetical order. The contents of this dictionary should not be modified; changes may not affect the values of local and free variables used by the interpreter. -.. function:: map(function, iterable, ...) +.. function:: map(function, iterable, /, *iterables) Return an iterator that applies *function* to every item of *iterable*, - yielding the results. If additional *iterable* arguments are passed, + yielding the results. If additional *iterables* arguments are passed, *function* must take that many arguments and is applied to the items from all iterables in parallel. With multiple iterables, the iterator stops when the shortest iterable is exhausted. For cases where the function inputs are already arranged into argument tuples, see :func:`itertools.starmap`\. -.. function:: max(iterable, *[, key, default]) - max(arg1, arg2, *args[, key]) +.. function:: max(iterable, /, *, key=None) + max(iterable, /, *, default, key=None) + max(arg1, arg2, /, *args, key=None) Return the largest item in an iterable or the largest of two or more arguments. @@ -1056,8 +1069,9 @@ are always available. They are listed here in alphabetical order. :ref:`typememoryview` for more information. -.. function:: min(iterable, *[, key, default]) - min(arg1, arg2, *args[, key]) +.. function:: min(iterable, /, *, key=None) + min(iterable, /, *, default, key=None) + min(arg1, arg2, /, *args, key=None) Return the smallest item in an iterable or the smallest of two or more arguments. @@ -1085,7 +1099,8 @@ are always available. They are listed here in alphabetical order. The *key* can be ``None``. -.. function:: next(iterator[, default]) +.. function:: next(iterator, /) + next(iterator, default, /) Retrieve the next item from the :term:`iterator` by calling its :meth:`~iterator.__next__` method. If *default* is given, it is returned @@ -1104,7 +1119,7 @@ are always available. They are listed here in alphabetical order. assign arbitrary attributes to an instance of the :class:`object` class. -.. function:: oct(x) +.. function:: oct(x, /) Convert an integer number to an octal string prefixed with "0o". The result is a valid Python expression. If *x* is not a Python :class:`int` object, it @@ -1356,7 +1371,7 @@ are always available. They are listed here in alphabetical order. .. versionchanged:: 3.11 The ``'U'`` mode has been removed. -.. function:: ord(c) +.. function:: ord(c, /) Given a string representing one Unicode character, return an integer representing the Unicode code point of that character. For example, @@ -1364,7 +1379,7 @@ are always available. They are listed here in alphabetical order. returns ``8364``. This is the inverse of :func:`chr`. -.. function:: pow(base, exp[, mod]) +.. function:: pow(base, exp, mod=None) Return *base* to the power *exp*; if *mod* is present, return *base* to the power *exp*, modulo *mod* (computed more efficiently than @@ -1507,15 +1522,15 @@ are always available. They are listed here in alphabetical order. .. _func-range: -.. class:: range(stop) - range(start, stop[, step]) +.. class:: range(stop, /) + range(start, stop, step=1, /) :noindex: Rather than being a function, :class:`range` is actually an immutable sequence type, as documented in :ref:`typesseq-range` and :ref:`typesseq`. -.. function:: repr(object) +.. function:: repr(object, /) Return a string containing a printable representation of an object. For many types, this function makes an attempt to return a string that would yield an @@ -1528,7 +1543,7 @@ are always available. They are listed here in alphabetical order. :exc:`RuntimeError`. -.. function:: reversed(seq) +.. function:: reversed(seq, /) Return a reverse :term:`iterator`. *seq* must be an object which has a :meth:`__reversed__` method or supports the sequence protocol (the @@ -1536,7 +1551,7 @@ are always available. They are listed here in alphabetical order. arguments starting at ``0``). -.. function:: round(number[, ndigits]) +.. function:: round(number, ndigits=None) Return *number* rounded to *ndigits* precision after the decimal point. If *ndigits* is omitted or is ``None``, it returns the @@ -1564,7 +1579,8 @@ are always available. They are listed here in alphabetical order. .. _func-set: -.. class:: set([iterable]) +.. class:: set() + set(iterable, /) :noindex: Return a new :class:`set` object, optionally with elements taken from @@ -1576,7 +1592,7 @@ are always available. They are listed here in alphabetical order. module. -.. function:: setattr(object, name, value) +.. function:: setattr(object, name, value, /) This is the counterpart of :func:`getattr`. The arguments are an object, a string, and an arbitrary value. The string may name an existing attribute or a @@ -1598,8 +1614,8 @@ are always available. They are listed here in alphabetical order. :func:`setattr`. -.. class:: slice(stop) - slice(start, stop[, step]) +.. class:: slice(stop, /) + slice(start, stop, step=1, /) Return a :term:`slice` object representing the set of indices specified by ``range(start, stop, step)``. The *start* and *step* arguments default to @@ -1716,21 +1732,22 @@ are always available. They are listed here in alphabetical order. .. versionchanged:: 3.8 The *start* parameter can be specified as a keyword argument. -.. class:: super([type[, object-or-type]]) +.. class:: super() + super(type, object_or_type=None, /) Return a proxy object that delegates method calls to a parent or sibling class of *type*. This is useful for accessing inherited methods that have been overridden in a class. - The *object-or-type* determines the :term:`method resolution order` + The *object_or_type* determines the :term:`method resolution order` to be searched. The search starts from the class right after the *type*. - For example, if :attr:`~class.__mro__` of *object-or-type* is + For example, if :attr:`~class.__mro__` of *object_or_type* is ``D -> B -> C -> A -> object`` and the value of *type* is ``B``, then :func:`super` searches ``C -> A -> object``. - The :attr:`~class.__mro__` attribute of the *object-or-type* lists the method + The :attr:`~class.__mro__` attribute of the *object_or_type* lists the method resolution search order used by both :func:`getattr` and :func:`super`. The attribute is dynamic and can change whenever the inheritance hierarchy is updated. @@ -1786,15 +1803,16 @@ are always available. They are listed here in alphabetical order. .. _func-tuple: -.. class:: tuple([iterable]) +.. class:: tuple() + tuple(iterable, /) :noindex: Rather than being a function, :class:`tuple` is actually an immutable sequence type, as documented in :ref:`typesseq-tuple` and :ref:`typesseq`. -.. class:: type(object) - type(name, bases, dict, **kwds) +.. class:: type(object, /) + type(name, bases, dict, /, **kwds) .. index:: object: type @@ -1834,7 +1852,8 @@ are always available. They are listed here in alphabetical order. Subclasses of :class:`type` which don't override ``type.__new__`` may no longer use the one-argument form to get the type of an object. -.. function:: vars([object]) +.. function:: vars() + vars(object, /) Return the :attr:`~object.__dict__` attribute for a module, class, instance, or any other object with a :attr:`~object.__dict__` attribute. From webhook-mailer at python.org Sat Oct 15 10:56:27 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Sat, 15 Oct 2022 14:56:27 -0000 Subject: [Python-checkins] gh-96258: move Py_REFCNT and Py_SET_REFCNT to reference counting page (#96259) Message-ID: https://github.com/python/cpython/commit/4e2bd58af46fef2c913273acbf78a3b1ed934d1d commit: 4e2bd58af46fef2c913273acbf78a3b1ed934d1d branch: main author: QuakeIV committer: JelleZijlstra date: 2022-10-15T07:56:14-07:00 summary: gh-96258: move Py_REFCNT and Py_SET_REFCNT to reference counting page (#96259) files: M Doc/c-api/refcounting.rst M Doc/c-api/structures.rst diff --git a/Doc/c-api/refcounting.rst b/Doc/c-api/refcounting.rst index 1cff4e7215cf..cd1f2ef70768 100644 --- a/Doc/c-api/refcounting.rst +++ b/Doc/c-api/refcounting.rst @@ -11,6 +11,26 @@ The macros in this section are used for managing reference counts of Python objects. +.. c:function:: Py_ssize_t Py_REFCNT(PyObject *o) + + Get the reference count of the Python object *o*. + + Use the :c:func:`Py_SET_REFCNT()` function to set an object reference count. + + .. versionchanged:: 3.11 + The parameter type is no longer :c:expr:`const PyObject*`. + + .. versionchanged:: 3.10 + :c:func:`Py_REFCNT()` is changed to the inline static function. + + +.. c:function:: void Py_SET_REFCNT(PyObject *o, Py_ssize_t refcnt) + + Set the object *o* reference counter to *refcnt*. + + .. versionadded:: 3.9 + + .. c:function:: void Py_INCREF(PyObject *o) Increment the reference count for object *o*. diff --git a/Doc/c-api/structures.rst b/Doc/c-api/structures.rst index 76803a093353..ee757e3a186e 100644 --- a/Doc/c-api/structures.rst +++ b/Doc/c-api/structures.rst @@ -17,7 +17,8 @@ All Python objects ultimately share a small number of fields at the beginning of the object's representation in memory. These are represented by the :c:type:`PyObject` and :c:type:`PyVarObject` types, which are defined, in turn, by the expansions of some macros also used, whether directly or indirectly, in -the definition of all other Python objects. +the definition of all other Python objects. Additional macros can be found +under :ref:`reference counting `. .. c:type:: PyObject @@ -121,26 +122,6 @@ the definition of all other Python objects. .. versionadded:: 3.9 -.. c:function:: Py_ssize_t Py_REFCNT(PyObject *o) - - Get the reference count of the Python object *o*. - - Use the :c:func:`Py_SET_REFCNT()` function to set an object reference count. - - .. versionchanged:: 3.11 - The parameter type is no longer :c:expr:`const PyObject*`. - - .. versionchanged:: 3.10 - :c:func:`Py_REFCNT()` is changed to the inline static function. - - -.. c:function:: void Py_SET_REFCNT(PyObject *o, Py_ssize_t refcnt) - - Set the object *o* reference counter to *refcnt*. - - .. versionadded:: 3.9 - - .. c:function:: Py_ssize_t Py_SIZE(PyVarObject *o) Get the size of the Python object *o*. From webhook-mailer at python.org Sat Oct 15 10:57:14 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Sat, 15 Oct 2022 14:57:14 -0000 Subject: [Python-checkins] gh-95971: Turn @writes_bytecode_files to skip when not running (#95972) Message-ID: https://github.com/python/cpython/commit/07b5c4699e64eb30c3bdcb1275c167e675d37423 commit: 07b5c4699e64eb30c3bdcb1275c167e675d37423 branch: main author: Jeong YunWon <69878+youknowone at users.noreply.github.com> committer: JelleZijlstra date: 2022-10-15T07:57:06-07:00 summary: gh-95971: Turn @writes_bytecode_files to skip when not running (#95972) Co-authored-by: Jelle Zijlstra files: M Lib/test/test_importlib/util.py diff --git a/Lib/test/test_importlib/util.py b/Lib/test/test_importlib/util.py index c07ac2a64c28..0b6dcc5eaf03 100644 --- a/Lib/test/test_importlib/util.py +++ b/Lib/test/test_importlib/util.py @@ -298,7 +298,7 @@ def writes_bytecode_files(fxn): """Decorator to protect sys.dont_write_bytecode from mutation and to skip tests that require it to be set to False.""" if sys.dont_write_bytecode: - return lambda *args, **kwargs: None + return unittest.skip("relies on writing bytecode")(fxn) @functools.wraps(fxn) def wrapper(*args, **kwargs): original = sys.dont_write_bytecode From webhook-mailer at python.org Sat Oct 15 10:58:02 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Sat, 15 Oct 2022 14:58:02 -0000 Subject: [Python-checkins] gh-95731: Fix module docstring extraction in pygettext (#95732) Message-ID: https://github.com/python/cpython/commit/120b4ab2b68aebf96ce0de243eab89a25fc2d282 commit: 120b4ab2b68aebf96ce0de243eab89a25fc2d282 branch: main author: Jakub Kuczys committer: JelleZijlstra date: 2022-10-15T07:57:53-07:00 summary: gh-95731: Fix module docstring extraction in pygettext (#95732) files: A Misc/NEWS.d/next/Tools-Demos/2022-08-05-23-25-59.gh-issue-95731.N2KohU.rst M Lib/test/test_tools/test_i18n.py M Tools/i18n/pygettext.py diff --git a/Lib/test/test_tools/test_i18n.py b/Lib/test/test_tools/test_i18n.py index 7f18edaaa8ca..c083a04475e7 100644 --- a/Lib/test/test_tools/test_i18n.py +++ b/Lib/test/test_tools/test_i18n.py @@ -155,6 +155,26 @@ class C: ''')) self.assertFalse([msgid for msgid in msgids if 'doc' in msgid]) + def test_moduledocstring(self): + for doc in ('"""doc"""', "r'''doc'''", "R'doc'", 'u"doc"'): + with self.subTest(doc): + msgids = self.extract_docstrings_from_str(dedent('''\ + %s + ''' % doc)) + self.assertIn('doc', msgids) + + def test_moduledocstring_bytes(self): + msgids = self.extract_docstrings_from_str(dedent('''\ + b"""doc""" + ''')) + self.assertFalse([msgid for msgid in msgids if 'doc' in msgid]) + + def test_moduledocstring_fstring(self): + msgids = self.extract_docstrings_from_str(dedent('''\ + f"""doc""" + ''')) + self.assertFalse([msgid for msgid in msgids if 'doc' in msgid]) + def test_msgid(self): msgids = self.extract_docstrings_from_str( '''_("""doc""" r'str' u"ing")''') diff --git a/Misc/NEWS.d/next/Tools-Demos/2022-08-05-23-25-59.gh-issue-95731.N2KohU.rst b/Misc/NEWS.d/next/Tools-Demos/2022-08-05-23-25-59.gh-issue-95731.N2KohU.rst new file mode 100644 index 000000000000..6b214616c0a9 --- /dev/null +++ b/Misc/NEWS.d/next/Tools-Demos/2022-08-05-23-25-59.gh-issue-95731.N2KohU.rst @@ -0,0 +1 @@ +Fix handling of module docstrings in :file:`Tools/i18n/pygettext.py`. diff --git a/Tools/i18n/pygettext.py b/Tools/i18n/pygettext.py index 6f889adffe6c..7ada79105db1 100755 --- a/Tools/i18n/pygettext.py +++ b/Tools/i18n/pygettext.py @@ -335,9 +335,10 @@ def __waiting(self, ttype, tstring, lineno): if ttype == tokenize.STRING and is_literal_string(tstring): self.__addentry(safe_eval(tstring), lineno, isdocstring=1) self.__freshmodule = 0 - elif ttype not in (tokenize.COMMENT, tokenize.NL): - self.__freshmodule = 0 - return + return + if ttype in (tokenize.COMMENT, tokenize.NL, tokenize.ENCODING): + return + self.__freshmodule = 0 # class or func/method docstring? if ttype == tokenize.NAME and tstring in ('class', 'def'): self.__state = self.__suiteseen From webhook-mailer at python.org Sat Oct 15 11:09:33 2022 From: webhook-mailer at python.org (miss-islington) Date: Sat, 15 Oct 2022 15:09:33 -0000 Subject: [Python-checkins] gh-85525: Indicate supported sound header formats (GH-21575) Message-ID: https://github.com/python/cpython/commit/232a9889128fb681f9c2767e1b22cb99fbad3ad3 commit: 232a9889128fb681f9c2767e1b22cb99fbad3ad3 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-15T08:09:20-07:00 summary: gh-85525: Indicate supported sound header formats (GH-21575) * Indicate supported sound header formats * modify file names Co-authored-by: Jelle Zijlstra (cherry picked from commit 05c042e70786bd2e3fcb274d185e1e0a54dab5a7) Co-authored-by: Joannah Nanjekye <33177550+nanjekyejoannah at users.noreply.github.com> files: M Doc/library/sndhdr.rst M Lib/sndhdr.py diff --git a/Doc/library/sndhdr.rst b/Doc/library/sndhdr.rst index e1dbe4a1a344..8c5c0bfc617b 100644 --- a/Doc/library/sndhdr.rst +++ b/Doc/library/sndhdr.rst @@ -54,3 +54,52 @@ be the sample size in bits or ``'A'`` for A-LAW or ``'U'`` for u-LAW. .. versionchanged:: 3.5 Result changed from a tuple to a namedtuple. +The following sound header types are recognized, as listed below with the return value +from :func:`whathdr`: and :func:`what`: + ++------------+------------------------------------+ +| Value | Sound header format | ++============+====================================+ +| ``'aifc'`` | Compressed Audio Interchange Files | ++------------+------------------------------------+ +| ``'aiff'`` | Audio Interchange Files | ++------------+------------------------------------+ +| ``'au'`` | Au Files | ++------------+------------------------------------+ +| ``'hcom'`` | HCOM Files | ++------------+------------------------------------+ ++------------+------------------------------------+ +| ``'sndt'`` | Sndtool Sound Files | ++------------+------------------------------------+ +| ``'voc'`` | Creative Labs Audio Files | ++------------+------------------------------------+ +| ``'wav'`` | Waveform Audio File Format Files | ++------------+------------------------------------+ +| ``'8svx'`` | 8-Bit Sampled Voice Files | ++------------+------------------------------------+ +| ``'sb'`` | Signed Byte Audio Data Files | ++------------+------------------------------------+ +| ``'ub'`` | UB Files | ++------------+------------------------------------+ +| ``'ul'`` | uLAW Audio Files | ++------------+------------------------------------+ + +.. data:: tests + + A list of functions performing the individual tests. Each function takes two + arguments: the byte-stream and an open file-like object. When :func:`what` is + called with a byte-stream, the file-like object will be ``None``. + + The test function should return a string describing the image type if the test + succeeded, or ``None`` if it failed. + +Example: + +.. code-block:: pycon + + >>> import sndhdr + >>> imghdr.what('bass.wav') + 'wav' + >>> imghdr.whathdr('bass.wav') + 'wav' + diff --git a/Lib/sndhdr.py b/Lib/sndhdr.py index 98a783448239..45def9ad16d3 100644 --- a/Lib/sndhdr.py +++ b/Lib/sndhdr.py @@ -77,6 +77,7 @@ def whathdr(filename): tests = [] def test_aifc(h, f): + """AIFC and AIFF files""" with warnings.catch_warnings(): warnings.simplefilter('ignore', category=DeprecationWarning) import aifc @@ -100,6 +101,7 @@ def test_aifc(h, f): def test_au(h, f): + """AU and SND files""" if h.startswith(b'.snd'): func = get_long_be elif h[:4] in (b'\0ds.', b'dns.'): @@ -133,6 +135,7 @@ def test_au(h, f): def test_hcom(h, f): + """HCOM file""" if h[65:69] != b'FSSD' or h[128:132] != b'HCOM': return None divisor = get_long_be(h[144:148]) @@ -146,6 +149,7 @@ def test_hcom(h, f): def test_voc(h, f): + """VOC file""" if not h.startswith(b'Creative Voice File\032'): return None sbseek = get_short_le(h[20:22]) @@ -160,6 +164,7 @@ def test_voc(h, f): def test_wav(h, f): + """WAV file""" import wave # 'RIFF' 'WAVE' 'fmt ' if not h.startswith(b'RIFF') or h[8:12] != b'WAVE' or h[12:16] != b'fmt ': @@ -176,6 +181,7 @@ def test_wav(h, f): def test_8svx(h, f): + """8SVX file""" if not h.startswith(b'FORM') or h[8:12] != b'8SVX': return None # Should decode it to get #channels -- assume always 1 @@ -185,6 +191,7 @@ def test_8svx(h, f): def test_sndt(h, f): + """SNDT file""" if h.startswith(b'SOUND'): nsamples = get_long_le(h[8:12]) rate = get_short_le(h[20:22]) @@ -194,6 +201,7 @@ def test_sndt(h, f): def test_sndr(h, f): + """SNDR file""" if h.startswith(b'\0\0'): rate = get_short_le(h[2:4]) if 4000 <= rate <= 25000: From webhook-mailer at python.org Sat Oct 15 11:20:47 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Sat, 15 Oct 2022 15:20:47 -0000 Subject: [Python-checkins] gh-94808: Cover `PyEval_GetFuncName` (#98246) Message-ID: https://github.com/python/cpython/commit/f01b56c7bdec239abe0dae2706f8325f4336249c commit: f01b56c7bdec239abe0dae2706f8325f4336249c branch: main author: Nikita Sobolev committer: JelleZijlstra date: 2022-10-15T08:20:39-07:00 summary: gh-94808: Cover `PyEval_GetFuncName` (#98246) files: M Lib/test/test_capi.py M Modules/_testcapimodule.c diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py index 17425050ce00..ae434c05baf2 100644 --- a/Lib/test/test_capi.py +++ b/Lib/test/test_capi.py @@ -880,6 +880,21 @@ def __init__(self): _testcapi.clear_managed_dict(c) self.assertEqual(c.__dict__, {}) + def test_eval_get_func_name(self): + def function_example(): ... + + class A: + def method_example(self): ... + + self.assertEqual(_testcapi.eval_get_func_name(function_example), + "function_example") + self.assertEqual(_testcapi.eval_get_func_name(A.method_example), + "method_example") + self.assertEqual(_testcapi.eval_get_func_name(A().method_example), + "method_example") + self.assertEqual(_testcapi.eval_get_func_name(sum), "sum") # c function + self.assertEqual(_testcapi.eval_get_func_name(A), "type") + class TestPendingCalls(unittest.TestCase): diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 95c67fc95e89..76e619d11f98 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -5469,6 +5469,12 @@ frame_getlasti(PyObject *self, PyObject *frame) return PyLong_FromLong(lasti); } +static PyObject * +eval_get_func_name(PyObject *self, PyObject *func) +{ + return PyUnicode_FromString(PyEval_GetFuncName(func)); +} + static PyObject * get_feature_macros(PyObject *self, PyObject *Py_UNUSED(args)) { @@ -5925,6 +5931,7 @@ static PyMethodDef TestMethods[] = { {"frame_getgenerator", frame_getgenerator, METH_O, NULL}, {"frame_getbuiltins", frame_getbuiltins, METH_O, NULL}, {"frame_getlasti", frame_getlasti, METH_O, NULL}, + {"eval_get_func_name", eval_get_func_name, METH_O, NULL}, {"get_feature_macros", get_feature_macros, METH_NOARGS, NULL}, {"test_code_api", test_code_api, METH_NOARGS, NULL}, {"settrace_to_record", settrace_to_record, METH_O, NULL}, From webhook-mailer at python.org Sat Oct 15 11:22:44 2022 From: webhook-mailer at python.org (miss-islington) Date: Sat, 15 Oct 2022 15:22:44 -0000 Subject: [Python-checkins] gh-95971: Turn @writes_bytecode_files to skip when not running (GH-95972) Message-ID: https://github.com/python/cpython/commit/4e78d9482a661d700ce889e0f4197e30cf98f32b commit: 4e78d9482a661d700ce889e0f4197e30cf98f32b branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-15T08:22:38-07:00 summary: gh-95971: Turn @writes_bytecode_files to skip when not running (GH-95972) Co-authored-by: Jelle Zijlstra (cherry picked from commit 07b5c4699e64eb30c3bdcb1275c167e675d37423) Co-authored-by: Jeong YunWon <69878+youknowone at users.noreply.github.com> files: M Lib/test/test_importlib/util.py diff --git a/Lib/test/test_importlib/util.py b/Lib/test/test_importlib/util.py index c07ac2a64c28..0b6dcc5eaf03 100644 --- a/Lib/test/test_importlib/util.py +++ b/Lib/test/test_importlib/util.py @@ -298,7 +298,7 @@ def writes_bytecode_files(fxn): """Decorator to protect sys.dont_write_bytecode from mutation and to skip tests that require it to be set to False.""" if sys.dont_write_bytecode: - return lambda *args, **kwargs: None + return unittest.skip("relies on writing bytecode")(fxn) @functools.wraps(fxn) def wrapper(*args, **kwargs): original = sys.dont_write_bytecode From webhook-mailer at python.org Sat Oct 15 11:33:26 2022 From: webhook-mailer at python.org (miss-islington) Date: Sat, 15 Oct 2022 15:33:26 -0000 Subject: [Python-checkins] gh-95731: Fix module docstring extraction in pygettext (GH-95732) Message-ID: https://github.com/python/cpython/commit/84a26e114ed5ca080ffe2f84aa0b7c59848afed6 commit: 84a26e114ed5ca080ffe2f84aa0b7c59848afed6 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-15T08:33:19-07:00 summary: gh-95731: Fix module docstring extraction in pygettext (GH-95732) (cherry picked from commit 120b4ab2b68aebf96ce0de243eab89a25fc2d282) Co-authored-by: Jakub Kuczys files: A Misc/NEWS.d/next/Tools-Demos/2022-08-05-23-25-59.gh-issue-95731.N2KohU.rst M Lib/test/test_tools/test_i18n.py M Tools/i18n/pygettext.py diff --git a/Lib/test/test_tools/test_i18n.py b/Lib/test/test_tools/test_i18n.py index 12f778dbf840..985e2262c7c6 100644 --- a/Lib/test/test_tools/test_i18n.py +++ b/Lib/test/test_tools/test_i18n.py @@ -155,6 +155,26 @@ class C: ''')) self.assertFalse([msgid for msgid in msgids if 'doc' in msgid]) + def test_moduledocstring(self): + for doc in ('"""doc"""', "r'''doc'''", "R'doc'", 'u"doc"'): + with self.subTest(doc): + msgids = self.extract_docstrings_from_str(dedent('''\ + %s + ''' % doc)) + self.assertIn('doc', msgids) + + def test_moduledocstring_bytes(self): + msgids = self.extract_docstrings_from_str(dedent('''\ + b"""doc""" + ''')) + self.assertFalse([msgid for msgid in msgids if 'doc' in msgid]) + + def test_moduledocstring_fstring(self): + msgids = self.extract_docstrings_from_str(dedent('''\ + f"""doc""" + ''')) + self.assertFalse([msgid for msgid in msgids if 'doc' in msgid]) + def test_msgid(self): msgids = self.extract_docstrings_from_str( '''_("""doc""" r'str' u"ing")''') diff --git a/Misc/NEWS.d/next/Tools-Demos/2022-08-05-23-25-59.gh-issue-95731.N2KohU.rst b/Misc/NEWS.d/next/Tools-Demos/2022-08-05-23-25-59.gh-issue-95731.N2KohU.rst new file mode 100644 index 000000000000..6b214616c0a9 --- /dev/null +++ b/Misc/NEWS.d/next/Tools-Demos/2022-08-05-23-25-59.gh-issue-95731.N2KohU.rst @@ -0,0 +1 @@ +Fix handling of module docstrings in :file:`Tools/i18n/pygettext.py`. diff --git a/Tools/i18n/pygettext.py b/Tools/i18n/pygettext.py index 6f889adffe6c..7ada79105db1 100755 --- a/Tools/i18n/pygettext.py +++ b/Tools/i18n/pygettext.py @@ -335,9 +335,10 @@ def __waiting(self, ttype, tstring, lineno): if ttype == tokenize.STRING and is_literal_string(tstring): self.__addentry(safe_eval(tstring), lineno, isdocstring=1) self.__freshmodule = 0 - elif ttype not in (tokenize.COMMENT, tokenize.NL): - self.__freshmodule = 0 - return + return + if ttype in (tokenize.COMMENT, tokenize.NL, tokenize.ENCODING): + return + self.__freshmodule = 0 # class or func/method docstring? if ttype == tokenize.NAME and tstring in ('class', 'def'): self.__state = self.__suiteseen From webhook-mailer at python.org Sat Oct 15 11:40:49 2022 From: webhook-mailer at python.org (miss-islington) Date: Sat, 15 Oct 2022 15:40:49 -0000 Subject: [Python-checkins] gh-95971: Turn @writes_bytecode_files to skip when not running (GH-95972) Message-ID: https://github.com/python/cpython/commit/146232f8af1130578ebeccbe7899c69be7e0d03e commit: 146232f8af1130578ebeccbe7899c69be7e0d03e branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-15T08:40:43-07:00 summary: gh-95971: Turn @writes_bytecode_files to skip when not running (GH-95972) Co-authored-by: Jelle Zijlstra (cherry picked from commit 07b5c4699e64eb30c3bdcb1275c167e675d37423) Co-authored-by: Jeong YunWon <69878+youknowone at users.noreply.github.com> files: M Lib/test/test_importlib/util.py diff --git a/Lib/test/test_importlib/util.py b/Lib/test/test_importlib/util.py index ca0d8c9b6eb3..b14ecb51b255 100644 --- a/Lib/test/test_importlib/util.py +++ b/Lib/test/test_importlib/util.py @@ -307,7 +307,7 @@ def writes_bytecode_files(fxn): """Decorator to protect sys.dont_write_bytecode from mutation and to skip tests that require it to be set to False.""" if sys.dont_write_bytecode: - return lambda *args, **kwargs: None + return unittest.skip("relies on writing bytecode")(fxn) @functools.wraps(fxn) def wrapper(*args, **kwargs): original = sys.dont_write_bytecode From webhook-mailer at python.org Sat Oct 15 12:04:23 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Sat, 15 Oct 2022 16:04:23 -0000 Subject: [Python-checkins] gh-98227: executionmodel.rst: except* can also bind names (#98256) Message-ID: https://github.com/python/cpython/commit/146f168fbf5b239158922f4defd494088c381525 commit: 146f168fbf5b239158922f4defd494088c381525 branch: main author: BiscuitCandy <70342294+BiscuitCandy at users.noreply.github.com> committer: JelleZijlstra date: 2022-10-15T09:04:08-07:00 summary: gh-98227: executionmodel.rst: except* can also bind names (#98256) Co-authored-by: Jelle Zijlstra files: M Doc/reference/executionmodel.rst diff --git a/Doc/reference/executionmodel.rst b/Doc/reference/executionmodel.rst index d9183561820b..3f01180e13f7 100644 --- a/Doc/reference/executionmodel.rst +++ b/Doc/reference/executionmodel.rst @@ -67,7 +67,7 @@ The following constructs bind names: + :keyword:`for` loop header, + after :keyword:`!as` in a :keyword:`with` statement, :keyword:`except` - clause or in the as-pattern in structural pattern matching, + clause, :keyword:`except* ` clause, or in the as-pattern in structural pattern matching, + in a capture pattern in structural pattern matching * :keyword:`import` statements. From webhook-mailer at python.org Sat Oct 15 12:12:24 2022 From: webhook-mailer at python.org (miss-islington) Date: Sat, 15 Oct 2022 16:12:24 -0000 Subject: [Python-checkins] gh-98227: executionmodel.rst: except* can also bind names (GH-98256) Message-ID: https://github.com/python/cpython/commit/c0083e6470940f4c049b4b4f52cfeb2bb96ef3c3 commit: c0083e6470940f4c049b4b4f52cfeb2bb96ef3c3 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-15T09:12:18-07:00 summary: gh-98227: executionmodel.rst: except* can also bind names (GH-98256) Co-authored-by: Jelle Zijlstra (cherry picked from commit 146f168fbf5b239158922f4defd494088c381525) Co-authored-by: BiscuitCandy <70342294+BiscuitCandy at users.noreply.github.com> files: M Doc/reference/executionmodel.rst diff --git a/Doc/reference/executionmodel.rst b/Doc/reference/executionmodel.rst index d9183561820b..3f01180e13f7 100644 --- a/Doc/reference/executionmodel.rst +++ b/Doc/reference/executionmodel.rst @@ -67,7 +67,7 @@ The following constructs bind names: + :keyword:`for` loop header, + after :keyword:`!as` in a :keyword:`with` statement, :keyword:`except` - clause or in the as-pattern in structural pattern matching, + clause, :keyword:`except* ` clause, or in the as-pattern in structural pattern matching, + in a capture pattern in structural pattern matching * :keyword:`import` statements. From webhook-mailer at python.org Sat Oct 15 13:44:07 2022 From: webhook-mailer at python.org (rhettinger) Date: Sat, 15 Oct 2022 17:44:07 -0000 Subject: [Python-checkins] Faster sieve() recipe (#98287) Message-ID: https://github.com/python/cpython/commit/f4370318d67f1f2f686c1c3a4b217ccc461d31e5 commit: f4370318d67f1f2f686c1c3a4b217ccc461d31e5 branch: main author: Raymond Hettinger committer: rhettinger date: 2022-10-15T12:43:58-05:00 summary: Faster sieve() recipe (#98287) files: M Doc/library/itertools.rst diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 6571114ef311..056b0788a4d8 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -809,15 +809,25 @@ which incur interpreter overhead. for k in range(len(roots) + 1) ] + def iter_index(seq, value, start=0): + "Return indices where a value occurs in a sequence." + # iter_index('AABCADEAF', 'A') --> 0 1 4 7 + i = start - 1 + try: + while True: + yield (i := seq.index(value, i+1)) + except ValueError: + pass + def sieve(n): - "Primes less than n" - # sieve(30) --> 2 3 5 7 11 13 17 19 23 29 - data = bytearray([1]) * n - data[:2] = 0, 0 - limit = math.isqrt(n) + 1 - for p in compress(range(limit), data): - data[p+p : n : p] = bytearray(len(range(p+p, n, p))) - return compress(count(), data) + "Primes less than n" + # sieve(30) --> 2 3 5 7 11 13 17 19 23 29 + data = bytearray([1]) * n + data[:2] = 0, 0 + limit = math.isqrt(n) + 1 + for p in compress(range(limit), data): + data[p*p : n : p] = bytearray(len(range(p*p, n, p))) + return iter_index(data, 1) def flatten(list_of_lists): "Flatten one level of nesting" @@ -1170,6 +1180,15 @@ which incur interpreter overhead. >>> all(factored(x) == expanded(x) for x in range(-10, 11)) True + >>> list(iter_index('AABCADEAF', 'A')) + [0, 1, 4, 7] + >>> list(iter_index('AABCADEAF', 'B')) + [2] + >>> list(iter_index('AABCADEAF', 'X')) + [] + >>> list(iter_index('', 'X')) + [] + >>> list(sieve(30)) [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] >>> small_primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97] From webhook-mailer at python.org Sat Oct 15 13:52:51 2022 From: webhook-mailer at python.org (miss-islington) Date: Sat, 15 Oct 2022 17:52:51 -0000 Subject: [Python-checkins] Faster sieve() recipe (GH-98287) Message-ID: https://github.com/python/cpython/commit/42511fc72d7dd9f4c5a57a5d88ae20262be2faf7 commit: 42511fc72d7dd9f4c5a57a5d88ae20262be2faf7 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-15T10:52:45-07:00 summary: Faster sieve() recipe (GH-98287) (cherry picked from commit f4370318d67f1f2f686c1c3a4b217ccc461d31e5) Co-authored-by: Raymond Hettinger files: M Doc/library/itertools.rst diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 844972e5cd4f..004dd19a7f3a 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -809,15 +809,25 @@ which incur interpreter overhead. for k in range(len(roots) + 1) ] + def iter_index(seq, value, start=0): + "Return indices where a value occurs in a sequence." + # iter_index('AABCADEAF', 'A') --> 0 1 4 7 + i = start - 1 + try: + while True: + yield (i := seq.index(value, i+1)) + except ValueError: + pass + def sieve(n): - "Primes less than n" - # sieve(30) --> 2 3 5 7 11 13 17 19 23 29 - data = bytearray([1]) * n - data[:2] = 0, 0 - limit = math.isqrt(n) + 1 - for p in compress(range(limit), data): - data[p+p : n : p] = bytearray(len(range(p+p, n, p))) - return compress(count(), data) + "Primes less than n" + # sieve(30) --> 2 3 5 7 11 13 17 19 23 29 + data = bytearray([1]) * n + data[:2] = 0, 0 + limit = math.isqrt(n) + 1 + for p in compress(range(limit), data): + data[p*p : n : p] = bytearray(len(range(p*p, n, p))) + return iter_index(data, 1) def flatten(list_of_lists): "Flatten one level of nesting" @@ -1170,6 +1180,15 @@ which incur interpreter overhead. >>> all(factored(x) == expanded(x) for x in range(-10, 11)) True + >>> list(iter_index('AABCADEAF', 'A')) + [0, 1, 4, 7] + >>> list(iter_index('AABCADEAF', 'B')) + [2] + >>> list(iter_index('AABCADEAF', 'X')) + [] + >>> list(iter_index('', 'X')) + [] + >>> list(sieve(30)) [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] >>> small_primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97] From webhook-mailer at python.org Sat Oct 15 14:11:09 2022 From: webhook-mailer at python.org (rhettinger) Date: Sat, 15 Oct 2022 18:11:09 -0000 Subject: [Python-checkins] [3.11] Backport docstring improvement from 3.12 (#98288) Message-ID: https://github.com/python/cpython/commit/099620b0ce964ffe85fc52a7595ece13a55ca81c commit: 099620b0ce964ffe85fc52a7595ece13a55ca81c branch: 3.11 author: Raymond Hettinger committer: rhettinger date: 2022-10-15T13:11:04-05:00 summary: [3.11] Backport docstring improvement from 3.12 (#98288) Backport docstring improvement from 3.12 files: M Lib/random.py diff --git a/Lib/random.py b/Lib/random.py index 1f3530e880fc..f94616e048c5 100644 --- a/Lib/random.py +++ b/Lib/random.py @@ -282,10 +282,10 @@ def randbytes(self, n): ## -------------------- integer methods ------------------- def randrange(self, start, stop=None, step=_ONE): - """Choose a random item from range(start, stop[, step]). + """Choose a random item from range(stop) or range(start, stop[, step]). - This fixes the problem with randint() which includes the - endpoint; in Python this is usually not what you want. + Roughly equivalent to ``choice(range(start, stop, step))`` but + supports arbitrarily large ranges and is optimized for common cases. """ From webhook-mailer at python.org Sat Oct 15 14:40:55 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Sat, 15 Oct 2022 18:40:55 -0000 Subject: [Python-checkins] gh-94808: Cover `str.rsplit` for UCS1, UCS2 or UCS4 (#98228) Message-ID: https://github.com/python/cpython/commit/b7dd2cad186e44e2b481f4518be62f34c682ea59 commit: b7dd2cad186e44e2b481f4518be62f34c682ea59 branch: main author: Nikita Sobolev committer: JelleZijlstra date: 2022-10-15T11:40:22-07:00 summary: gh-94808: Cover `str.rsplit` for UCS1, UCS2 or UCS4 (#98228) files: M Lib/test/string_tests.py M Lib/test/test_unicode.py diff --git a/Lib/test/string_tests.py b/Lib/test/string_tests.py index e998146c190d..709cac7a27a4 100644 --- a/Lib/test/string_tests.py +++ b/Lib/test/string_tests.py @@ -505,6 +505,11 @@ def test_split(self): self.checkraises(ValueError, 'hello', 'split', '', 0) def test_rsplit(self): + # without arg + self.checkequal(['a', 'b', 'c', 'd'], 'a b c d', 'rsplit') + self.checkequal(['a', 'b', 'c', 'd'], 'a b c d', 'rsplit') + self.checkequal([], '', 'rsplit') + # by a char self.checkequal(['a', 'b', 'c', 'd'], 'a|b|c|d', 'rsplit', '|') self.checkequal(['a|b|c', 'd'], 'a|b|c|d', 'rsplit', '|', 1) @@ -558,6 +563,9 @@ def test_rsplit(self): # with keyword args self.checkequal(['a', 'b', 'c', 'd'], 'a|b|c|d', 'rsplit', sep='|') + self.checkequal(['a', 'b', 'c', 'd'], 'a b c d', 'rsplit', sep=None) + self.checkequal(['a b c', 'd'], + 'a b c d', 'rsplit', sep=None, maxsplit=1) self.checkequal(['a|b|c', 'd'], 'a|b|c|d', 'rsplit', '|', maxsplit=1) self.checkequal(['a|b|c', 'd'], diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py index 15244cb949e3..05e7e30d639a 100644 --- a/Lib/test/test_unicode.py +++ b/Lib/test/test_unicode.py @@ -445,10 +445,10 @@ def test_split(self): def test_rsplit(self): string_tests.CommonTest.test_rsplit(self) # test mixed kinds - for left, right in ('ba', '\u0101\u0100', '\U00010301\U00010300'): + for left, right in ('ba', '??', '\u0101\u0100', '\U00010301\U00010300'): left *= 9 right *= 9 - for delim in ('c', '\u0102', '\U00010302'): + for delim in ('c', '?', '\u0102', '\U00010302'): self.checkequal([left + right], left + right, 'rsplit', delim) self.checkequal([left, right], @@ -458,6 +458,10 @@ def test_rsplit(self): self.checkequal([left, right], left + delim * 2 + right, 'rsplit', delim *2) + # Check `None` as well: + self.checkequal([left + right], + left + right, 'rsplit', None) + def test_partition(self): string_tests.MixinStrUnicodeUserStringTest.test_partition(self) # test mixed kinds From webhook-mailer at python.org Sat Oct 15 14:48:54 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Sat, 15 Oct 2022 18:48:54 -0000 Subject: [Python-checkins] [3.11] gh-94808: Cover `PyEval_GetFuncName` (GH-98246). (#98283) Message-ID: https://github.com/python/cpython/commit/93d0d9cfdd74b7ff80a75ce8887adef600f21c69 commit: 93d0d9cfdd74b7ff80a75ce8887adef600f21c69 branch: 3.11 author: Jelle Zijlstra committer: JelleZijlstra date: 2022-10-15T11:48:48-07:00 summary: [3.11] gh-94808: Cover `PyEval_GetFuncName` (GH-98246). (#98283) (cherry picked from commit f01b56c7bdec239abe0dae2706f8325f4336249c) Co-authored-by: Nikita Sobolev files: M Lib/test/test_capi.py M Modules/_testcapimodule.c diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py index e157d9fdc850..6e56016a47cc 100644 --- a/Lib/test/test_capi.py +++ b/Lib/test/test_capi.py @@ -724,6 +724,21 @@ def test_export_symbols(self): with self.subTest(name=name): self.assertTrue(hasattr(ctypes.pythonapi, name)) + def test_eval_get_func_name(self): + def function_example(): ... + + class A: + def method_example(self): ... + + self.assertEqual(_testcapi.eval_get_func_name(function_example), + "function_example") + self.assertEqual(_testcapi.eval_get_func_name(A.method_example), + "method_example") + self.assertEqual(_testcapi.eval_get_func_name(A().method_example), + "method_example") + self.assertEqual(_testcapi.eval_get_func_name(sum), "sum") # c function + self.assertEqual(_testcapi.eval_get_func_name(A), "type") + class TestPendingCalls(unittest.TestCase): diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 43fec8138a0e..69703be186d1 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -5935,6 +5935,12 @@ frame_getlasti(PyObject *self, PyObject *frame) return PyLong_FromLong(lasti); } +static PyObject * +eval_get_func_name(PyObject *self, PyObject *func) +{ + return PyUnicode_FromString(PyEval_GetFuncName(func)); +} + static PyObject * get_feature_macros(PyObject *self, PyObject *Py_UNUSED(args)) { @@ -6372,6 +6378,7 @@ static PyMethodDef TestMethods[] = { {"frame_getgenerator", frame_getgenerator, METH_O, NULL}, {"frame_getbuiltins", frame_getbuiltins, METH_O, NULL}, {"frame_getlasti", frame_getlasti, METH_O, NULL}, + {"eval_get_func_name", eval_get_func_name, METH_O, NULL}, {"get_feature_macros", get_feature_macros, METH_NOARGS, NULL}, {"test_code_api", test_code_api, METH_NOARGS, NULL}, {"settrace_to_record", settrace_to_record, METH_O, NULL}, From webhook-mailer at python.org Sat Oct 15 15:03:33 2022 From: webhook-mailer at python.org (miss-islington) Date: Sat, 15 Oct 2022 19:03:33 -0000 Subject: [Python-checkins] Upgrade ccache-action to one using Node 16 (GH-98166) Message-ID: https://github.com/python/cpython/commit/91bcd2161f150548b247a3821af4eb18167c3fca commit: 91bcd2161f150548b247a3821af4eb18167c3fca branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-15T12:03:27-07:00 summary: Upgrade ccache-action to one using Node 16 (GH-98166) Github Actions has deprecated the use of Node 12, and will be turning it off by summer 2023. https://github.blog/changelog/2022-09-22-github-actions-all-actions-will-begin-running-on-node16-instead-of-node12/ (cherry picked from commit ad8e297b7297dfdc34fad53b589b31d0920150ab) Co-authored-by: Michael Droettboom files: M .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8a535831a605..cba0eac83ca8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -107,7 +107,7 @@ jobs: - name: Add ccache to PATH run: echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV - name: Configure ccache action - uses: hendrikmuhs/ccache-action at v1 + uses: hendrikmuhs/ccache-action at v1.2 - name: Check Autoconf version 2.69 and aclocal 1.16.3 run: | grep "Generated by GNU Autoconf 2.69" configure @@ -236,7 +236,7 @@ jobs: run: | echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV - name: Configure ccache action - uses: hendrikmuhs/ccache-action at v1 + uses: hendrikmuhs/ccache-action at v1.2 - name: Setup directory envs for out-of-tree builds run: | echo "CPYTHON_RO_SRCDIR=$(realpath -m ${GITHUB_WORKSPACE}/../cpython-ro-srcdir)" >> $GITHUB_ENV @@ -299,7 +299,7 @@ jobs: run: | echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV - name: Configure ccache action - uses: hendrikmuhs/ccache-action at v1 + uses: hendrikmuhs/ccache-action at v1.2 - name: Configure CPython run: ./configure --with-pydebug --with-openssl=$OPENSSL_DIR - name: Build CPython @@ -343,7 +343,7 @@ jobs: run: | echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV - name: Configure ccache action - uses: hendrikmuhs/ccache-action at v1 + uses: hendrikmuhs/ccache-action at v1.2 - name: Configure CPython run: ./configure --with-address-sanitizer --without-pymalloc - name: Build CPython From webhook-mailer at python.org Sat Oct 15 15:18:00 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Sat, 15 Oct 2022 19:18:00 -0000 Subject: [Python-checkins] docs(typing): harmonize "See PEP x for more details" (#97927) Message-ID: https://github.com/python/cpython/commit/02389658a4751a0166e2ed22be112b646378a01b commit: 02389658a4751a0166e2ed22be112b646378a01b branch: main author: Simon Legner committer: JelleZijlstra date: 2022-10-15T12:17:51-07:00 summary: docs(typing): harmonize "See PEP x for more details" (#97927) files: M Doc/library/typing.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index fee55becc7f5..dc5696aff69b 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -248,7 +248,7 @@ respectively. .. versionchanged:: 3.10 ``Callable`` now supports :class:`ParamSpec` and :data:`Concatenate`. - See :pep:`612` for more information. + See :pep:`612` for more details. .. seealso:: The documentation for :class:`ParamSpec` and :class:`Concatenate` provides @@ -723,7 +723,7 @@ These can be used as types in annotations and do not support ``[]``. of the ``cls`` parameter. - Annotating an :meth:`~object.__enter__` method which returns self. - For more information, see :pep:`673`. + See :pep:`673` for more details. .. versionadded:: 3.11 @@ -854,7 +854,7 @@ These can be used as types in annotations using ``[]``, each having a unique syn .. versionchanged:: 3.10 ``Callable`` now supports :class:`ParamSpec` and :data:`Concatenate`. - See :pep:`612` for more information. + See :pep:`612` for more details. .. seealso:: The documentation for :class:`ParamSpec` and :class:`Concatenate` provide @@ -1040,8 +1040,7 @@ These can be used as types in annotations using ``[]``, each having a unique syn Special typing constructs that mark individual keys of a :class:`TypedDict` as either required or non-required respectively. - For more information, see :class:`TypedDict` and - :pep:`655` ("Marking individual TypedDict items as required or potentially missing"). + See :class:`TypedDict` and :pep:`655` for more details. .. versionadded:: 3.11 @@ -1192,8 +1191,7 @@ These can be used as types in annotations using ``[]``, each having a unique syn is not a subtype of the former, since ``list`` is invariant. The responsibility of writing type-safe type guards is left to the user. - ``TypeGuard`` also works with type variables. For more information, see - :pep:`647` (User-Defined Type Guards). + ``TypeGuard`` also works with type variables. See :pep:`647` for more details. .. versionadded:: 3.10 @@ -1393,7 +1391,7 @@ These are not used in annotations. They are building blocks for creating generic to ``call_soon`` match the types of the (positional) arguments of ``callback``. - For more details on type variable tuples, see :pep:`646`. + See :pep:`646` for more details on type variable tuples. .. versionadded:: 3.11 @@ -1556,7 +1554,7 @@ These are not used in annotations. They are building blocks for creating generic func(C()) # Passes static type check - See :pep:`544` for details. Protocol classes decorated with + See :pep:`544` for more details. Protocol classes decorated with :func:`runtime_checkable` (described later) act as simple-minded runtime protocols that check only the presence of given attributes, ignoring their type signatures. @@ -2632,7 +2630,7 @@ Functions and decorators def process(response): - See :pep:`484` for details and comparison with other typing semantics. + See :pep:`484` for more details and comparison with other typing semantics. .. versionchanged:: 3.11 Overloaded functions can now be introspected at runtime using From webhook-mailer at python.org Sat Oct 15 15:26:04 2022 From: webhook-mailer at python.org (miss-islington) Date: Sat, 15 Oct 2022 19:26:04 -0000 Subject: [Python-checkins] docs(typing): harmonize "See PEP x for more details" (GH-97927) Message-ID: https://github.com/python/cpython/commit/d3b57dc7291dee8adf276dee59d7654cad7942b4 commit: d3b57dc7291dee8adf276dee59d7654cad7942b4 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-15T12:25:58-07:00 summary: docs(typing): harmonize "See PEP x for more details" (GH-97927) (cherry picked from commit 02389658a4751a0166e2ed22be112b646378a01b) Co-authored-by: Simon Legner files: M Doc/library/typing.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 070f3006e20c..04f63f6f54bc 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -248,7 +248,7 @@ respectively. .. versionchanged:: 3.10 ``Callable`` now supports :class:`ParamSpec` and :data:`Concatenate`. - See :pep:`612` for more information. + See :pep:`612` for more details. .. seealso:: The documentation for :class:`ParamSpec` and :class:`Concatenate` provides @@ -723,7 +723,7 @@ These can be used as types in annotations and do not support ``[]``. of the ``cls`` parameter. - Annotating an :meth:`~object.__enter__` method which returns self. - For more information, see :pep:`673`. + See :pep:`673` for more details. .. versionadded:: 3.11 @@ -854,7 +854,7 @@ These can be used as types in annotations using ``[]``, each having a unique syn .. versionchanged:: 3.10 ``Callable`` now supports :class:`ParamSpec` and :data:`Concatenate`. - See :pep:`612` for more information. + See :pep:`612` for more details. .. seealso:: The documentation for :class:`ParamSpec` and :class:`Concatenate` provide @@ -1040,8 +1040,7 @@ These can be used as types in annotations using ``[]``, each having a unique syn Special typing constructs that mark individual keys of a :class:`TypedDict` as either required or non-required respectively. - For more information, see :class:`TypedDict` and - :pep:`655` ("Marking individual TypedDict items as required or potentially missing"). + See :class:`TypedDict` and :pep:`655` for more details. .. versionadded:: 3.11 @@ -1192,8 +1191,7 @@ These can be used as types in annotations using ``[]``, each having a unique syn is not a subtype of the former, since ``list`` is invariant. The responsibility of writing type-safe type guards is left to the user. - ``TypeGuard`` also works with type variables. For more information, see - :pep:`647` (User-Defined Type Guards). + ``TypeGuard`` also works with type variables. See :pep:`647` for more details. .. versionadded:: 3.10 @@ -1393,7 +1391,7 @@ These are not used in annotations. They are building blocks for creating generic to ``call_soon`` match the types of the (positional) arguments of ``callback``. - For more details on type variable tuples, see :pep:`646`. + See :pep:`646` for more details on type variable tuples. .. versionadded:: 3.11 @@ -1556,7 +1554,7 @@ These are not used in annotations. They are building blocks for creating generic func(C()) # Passes static type check - See :pep:`544` for details. Protocol classes decorated with + See :pep:`544` for more details. Protocol classes decorated with :func:`runtime_checkable` (described later) act as simple-minded runtime protocols that check only the presence of given attributes, ignoring their type signatures. @@ -2626,7 +2624,7 @@ Functions and decorators def process(response): - See :pep:`484` for details and comparison with other typing semantics. + See :pep:`484` for more details and comparison with other typing semantics. .. versionchanged:: 3.11 Overloaded functions can now be introspected at runtime using From webhook-mailer at python.org Sat Oct 15 16:23:15 2022 From: webhook-mailer at python.org (vsajip) Date: Sat, 15 Oct 2022 20:23:15 -0000 Subject: [Python-checkins] [doc] Update logging cookbook with an example of custom handling of levels. (GH-98290) Message-ID: https://github.com/python/cpython/commit/11c25a402d77bda507f8012ee2c14c95c835cf15 commit: 11c25a402d77bda507f8012ee2c14c95c835cf15 branch: main author: Vinay Sajip committer: vsajip date: 2022-10-15T21:23:06+01:00 summary: [doc] Update logging cookbook with an example of custom handling of levels. (GH-98290) Co-authored-by: Jelle Zijlstra files: M Doc/howto/logging-cookbook.rst diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst index 99e886c61b4c..eac34aaab3aa 100644 --- a/Doc/howto/logging-cookbook.rst +++ b/Doc/howto/logging-cookbook.rst @@ -276,6 +276,211 @@ choose a different directory name for the log - just ensure that the directory e and that you have the permissions to create and update files in it. +.. _custom-level-handling: + +Custom handling of levels +------------------------- + +Sometimes, you might want to do something slightly different from the standard +handling of levels in handlers, where all levels above a threshold get +processed by a handler. To do this, you need to use filters. Let's look at a +scenario where you want to arrange things as follows: + +* Send messages of severity ``INFO`` and ``WARNING`` to ``sys.stdout`` +* Send messages of severity ``ERROR`` and above to ``sys.stderr`` +* Send messages of severity ``DEBUG`` and above to file ``app.log`` + +Suppose you configure logging with the following JSON: + +.. code-block:: json + + { + "version": 1, + "disable_existing_loggers": false, + "formatters": { + "simple": { + "format": "%(levelname)-8s - %(message)s" + } + }, + "handlers": { + "stdout": { + "class": "logging.StreamHandler", + "level": "INFO", + "formatter": "simple", + "stream": "ext://sys.stdout", + }, + "stderr": { + "class": "logging.StreamHandler", + "level": "ERROR", + "formatter": "simple", + "stream": "ext://sys.stderr" + }, + "file": { + "class": "logging.FileHandler", + "formatter": "simple", + "filename": "app.log", + "mode": "w" + } + }, + "root": { + "level": "DEBUG", + "handlers": [ + "stderr", + "stdout", + "file" + ] + } + } + +This configuration does *almost* what we want, except that ``sys.stdout`` would +show messages of severity ``ERROR`` and above as well as ``INFO`` and +``WARNING`` messages. To prevent this, we can set up a filter which excludes +those messages and add it to the relevant handler. This can be configured by +adding a ``filters`` section parallel to ``formatters`` and ``handlers``: + +.. code-block:: json + + "filters": { + "warnings_and_below": { + "()" : "__main__.filter_maker", + "level": "WARNING" + } + } + +and changing the section on the ``stdout`` handler to add it: + +.. code-block:: json + + "stdout": { + "class": "logging.StreamHandler", + "level": "INFO", + "formatter": "simple", + "stream": "ext://sys.stdout", + "filters": ["warnings_and_below"] + } + +A filter is just a function, so we can define the ``filter_maker`` (a factory +function) as follows: + +.. code-block:: python + + def filter_maker(level): + level = getattr(logging, level) + + def filter(record): + return record.levelno <= level + + return filter + +This converts the string argument passed in to a numeric level, and returns a +function which only returns ``True`` if the level of the passed in record is +at or below the specified level. Note that in this example I have defined the +``filter_maker`` in a test script ``main.py`` that I run from the command line, +so its module will be ``__main__`` - hence the ``__main__.filter_maker`` in the +filter configuration. You will need to change that if you define it in a +different module. + +With the filter added, we can run ``main.py``, which in full is: + +.. code-block:: python + + import json + import logging + import logging.config + + CONFIG = ''' + { + "version": 1, + "disable_existing_loggers": false, + "formatters": { + "simple": { + "format": "%(levelname)-8s - %(message)s" + } + }, + "filters": { + "warnings_and_below": { + "()" : "__main__.filter_maker", + "level": "WARNING" + } + }, + "handlers": { + "stdout": { + "class": "logging.StreamHandler", + "level": "INFO", + "formatter": "simple", + "stream": "ext://sys.stdout", + "filters": ["warnings_and_below"] + }, + "stderr": { + "class": "logging.StreamHandler", + "level": "ERROR", + "formatter": "simple", + "stream": "ext://sys.stderr" + }, + "file": { + "class": "logging.FileHandler", + "formatter": "simple", + "filename": "app.log", + "mode": "w" + } + }, + "root": { + "level": "DEBUG", + "handlers": [ + "stderr", + "stdout", + "file" + ] + } + } + ''' + + def filter_maker(level): + level = getattr(logging, level) + + def filter(record): + return record.levelno <= level + + return filter + + logging.config.dictConfig(json.loads(CONFIG)) + logging.debug('A DEBUG message') + logging.info('An INFO message') + logging.warning('A WARNING message') + logging.error('An ERROR message') + logging.critical('A CRITICAL message') + +And after running it like this: + +.. code-block:: shell + + python main.py 2>stderr.log >stdout.log + +We can see the results are as expected: + +.. code-block:: shell + + $ more *.log + :::::::::::::: + app.log + :::::::::::::: + DEBUG - A DEBUG message + INFO - An INFO message + WARNING - A WARNING message + ERROR - An ERROR message + CRITICAL - A CRITICAL message + :::::::::::::: + stderr.log + :::::::::::::: + ERROR - An ERROR message + CRITICAL - A CRITICAL message + :::::::::::::: + stdout.log + :::::::::::::: + INFO - An INFO message + WARNING - A WARNING message + + Configuration server example ---------------------------- @@ -3503,7 +3708,7 @@ instance). Then, you'd get this kind of result: WARNING:demo:Bar >>> -Of course, these above examples show output according to the format used by +Of course, the examples above show output according to the format used by :func:`~logging.basicConfig`, but you can use a different formatter when you configure logging. @@ -3517,7 +3722,6 @@ need to do or deal with, it is worth mentioning some usage patterns which are *unhelpful*, and which should therefore be avoided in most cases. The following sections are in no particular order. - Opening the same log file multiple times ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -3566,7 +3770,6 @@ that in other languages such as Java and C#, loggers are often static class attributes. However, this pattern doesn't make sense in Python, where the module (and not the class) is the unit of software decomposition. - Adding handlers other than :class:`NullHandler` to a logger in a library ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -3575,7 +3778,6 @@ responsibility of the application developer, not the library developer. If you are maintaining a library, ensure that you don't add handlers to any of your loggers other than a :class:`~logging.NullHandler` instance. - Creating a lot of loggers ^^^^^^^^^^^^^^^^^^^^^^^^^ From webhook-mailer at python.org Sat Oct 15 16:52:03 2022 From: webhook-mailer at python.org (vsajip) Date: Sat, 15 Oct 2022 20:52:03 -0000 Subject: [Python-checkins] =?utf-8?b?WzMuMTFdIFtkb2NdIFVwZGF0ZSBsb2dnaW5n?= =?utf-8?q?_cookbook_with_an_example_of_custom_handli=E2=80=A6_=28GH-98296?= =?utf-8?q?=29?= Message-ID: https://github.com/python/cpython/commit/79c0adeb1dd5a5af07398b5f4446fa2d86dddf1f commit: 79c0adeb1dd5a5af07398b5f4446fa2d86dddf1f branch: 3.11 author: Vinay Sajip committer: vsajip date: 2022-10-15T21:51:58+01:00 summary: [3.11] [doc] Update logging cookbook with an example of custom handli? (GH-98296) Co-authored-by: Jelle Zijlstra files: M Doc/howto/logging-cookbook.rst diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst index d43ffb24085d..acbc708e2f5c 100644 --- a/Doc/howto/logging-cookbook.rst +++ b/Doc/howto/logging-cookbook.rst @@ -276,6 +276,211 @@ choose a different directory name for the log - just ensure that the directory e and that you have the permissions to create and update files in it. +.. _custom-level-handling: + +Custom handling of levels +------------------------- + +Sometimes, you might want to do something slightly different from the standard +handling of levels in handlers, where all levels above a threshold get +processed by a handler. To do this, you need to use filters. Let's look at a +scenario where you want to arrange things as follows: + +* Send messages of severity ``INFO`` and ``WARNING`` to ``sys.stdout`` +* Send messages of severity ``ERROR`` and above to ``sys.stderr`` +* Send messages of severity ``DEBUG`` and above to file ``app.log`` + +Suppose you configure logging with the following JSON: + +.. code-block:: json + + { + "version": 1, + "disable_existing_loggers": false, + "formatters": { + "simple": { + "format": "%(levelname)-8s - %(message)s" + } + }, + "handlers": { + "stdout": { + "class": "logging.StreamHandler", + "level": "INFO", + "formatter": "simple", + "stream": "ext://sys.stdout", + }, + "stderr": { + "class": "logging.StreamHandler", + "level": "ERROR", + "formatter": "simple", + "stream": "ext://sys.stderr" + }, + "file": { + "class": "logging.FileHandler", + "formatter": "simple", + "filename": "app.log", + "mode": "w" + } + }, + "root": { + "level": "DEBUG", + "handlers": [ + "stderr", + "stdout", + "file" + ] + } + } + +This configuration does *almost* what we want, except that ``sys.stdout`` would +show messages of severity ``ERROR`` and above as well as ``INFO`` and +``WARNING`` messages. To prevent this, we can set up a filter which excludes +those messages and add it to the relevant handler. This can be configured by +adding a ``filters`` section parallel to ``formatters`` and ``handlers``: + +.. code-block:: json + + "filters": { + "warnings_and_below": { + "()" : "__main__.filter_maker", + "level": "WARNING" + } + } + +and changing the section on the ``stdout`` handler to add it: + +.. code-block:: json + + "stdout": { + "class": "logging.StreamHandler", + "level": "INFO", + "formatter": "simple", + "stream": "ext://sys.stdout", + "filters": ["warnings_and_below"] + } + +A filter is just a function, so we can define the ``filter_maker`` (a factory +function) as follows: + +.. code-block:: python + + def filter_maker(level): + level = getattr(logging, level) + + def filter(record): + return record.levelno <= level + + return filter + +This converts the string argument passed in to a numeric level, and returns a +function which only returns ``True`` if the level of the passed in record is +at or below the specified level. Note that in this example I have defined the +``filter_maker`` in a test script ``main.py`` that I run from the command line, +so its module will be ``__main__`` - hence the ``__main__.filter_maker`` in the +filter configuration. You will need to change that if you define it in a +different module. + +With the filter added, we can run ``main.py``, which in full is: + +.. code-block:: python + + import json + import logging + import logging.config + + CONFIG = ''' + { + "version": 1, + "disable_existing_loggers": false, + "formatters": { + "simple": { + "format": "%(levelname)-8s - %(message)s" + } + }, + "filters": { + "warnings_and_below": { + "()" : "__main__.filter_maker", + "level": "WARNING" + } + }, + "handlers": { + "stdout": { + "class": "logging.StreamHandler", + "level": "INFO", + "formatter": "simple", + "stream": "ext://sys.stdout", + "filters": ["warnings_and_below"] + }, + "stderr": { + "class": "logging.StreamHandler", + "level": "ERROR", + "formatter": "simple", + "stream": "ext://sys.stderr" + }, + "file": { + "class": "logging.FileHandler", + "formatter": "simple", + "filename": "app.log", + "mode": "w" + } + }, + "root": { + "level": "DEBUG", + "handlers": [ + "stderr", + "stdout", + "file" + ] + } + } + ''' + + def filter_maker(level): + level = getattr(logging, level) + + def filter(record): + return record.levelno <= level + + return filter + + logging.config.dictConfig(json.loads(CONFIG)) + logging.debug('A DEBUG message') + logging.info('An INFO message') + logging.warning('A WARNING message') + logging.error('An ERROR message') + logging.critical('A CRITICAL message') + +And after running it like this: + +.. code-block:: shell + + python main.py 2>stderr.log >stdout.log + +We can see the results are as expected: + +.. code-block:: shell + + $ more *.log + :::::::::::::: + app.log + :::::::::::::: + DEBUG - A DEBUG message + INFO - An INFO message + WARNING - A WARNING message + ERROR - An ERROR message + CRITICAL - A CRITICAL message + :::::::::::::: + stderr.log + :::::::::::::: + ERROR - An ERROR message + CRITICAL - A CRITICAL message + :::::::::::::: + stdout.log + :::::::::::::: + INFO - An INFO message + WARNING - A WARNING message + + Configuration server example ---------------------------- @@ -3503,7 +3708,7 @@ instance). Then, you'd get this kind of result: WARNING:demo:Bar >>> -Of course, these above examples show output according to the format used by +Of course, the examples above show output according to the format used by :func:`~logging.basicConfig`, but you can use a different formatter when you configure logging. @@ -3517,7 +3722,6 @@ need to do or deal with, it is worth mentioning some usage patterns which are *unhelpful*, and which should therefore be avoided in most cases. The following sections are in no particular order. - Opening the same log file multiple times ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -3566,7 +3770,6 @@ that in other languages such as Java and C#, loggers are often static class attributes. However, this pattern doesn't make sense in Python, where the module (and not the class) is the unit of software decomposition. - Adding handlers other than :class:`NullHandler` to a logger in a library ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -3575,7 +3778,6 @@ responsibility of the application developer, not the library developer. If you are maintaining a library, ensure that you don't add handlers to any of your loggers other than a :class:`~logging.NullHandler` instance. - Creating a lot of loggers ^^^^^^^^^^^^^^^^^^^^^^^^^ From webhook-mailer at python.org Sat Oct 15 16:59:18 2022 From: webhook-mailer at python.org (vsajip) Date: Sat, 15 Oct 2022 20:59:18 -0000 Subject: [Python-checkins] =?utf-8?b?WzMuMTBdIFtkb2NdIFVwZGF0ZSBsb2dnaW5n?= =?utf-8?q?_cookbook_with_an_example_of_custom_handli=E2=80=A6_=28GH-98299?= =?utf-8?q?=29?= Message-ID: https://github.com/python/cpython/commit/7b604d83d226d8d7abc29b3a4fdd50e3bd100877 commit: 7b604d83d226d8d7abc29b3a4fdd50e3bd100877 branch: 3.10 author: Vinay Sajip committer: vsajip date: 2022-10-15T21:59:13+01:00 summary: [3.10] [doc] Update logging cookbook with an example of custom handli? (GH-98299) Co-authored-by: Jelle Zijlstra files: M Doc/howto/logging-cookbook.rst diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst index 43f967c77351..d9a19420db7b 100644 --- a/Doc/howto/logging-cookbook.rst +++ b/Doc/howto/logging-cookbook.rst @@ -276,6 +276,211 @@ choose a different directory name for the log - just ensure that the directory e and that you have the permissions to create and update files in it. +.. _custom-level-handling: + +Custom handling of levels +------------------------- + +Sometimes, you might want to do something slightly different from the standard +handling of levels in handlers, where all levels above a threshold get +processed by a handler. To do this, you need to use filters. Let's look at a +scenario where you want to arrange things as follows: + +* Send messages of severity ``INFO`` and ``WARNING`` to ``sys.stdout`` +* Send messages of severity ``ERROR`` and above to ``sys.stderr`` +* Send messages of severity ``DEBUG`` and above to file ``app.log`` + +Suppose you configure logging with the following JSON: + +.. code-block:: json + + { + "version": 1, + "disable_existing_loggers": false, + "formatters": { + "simple": { + "format": "%(levelname)-8s - %(message)s" + } + }, + "handlers": { + "stdout": { + "class": "logging.StreamHandler", + "level": "INFO", + "formatter": "simple", + "stream": "ext://sys.stdout", + }, + "stderr": { + "class": "logging.StreamHandler", + "level": "ERROR", + "formatter": "simple", + "stream": "ext://sys.stderr" + }, + "file": { + "class": "logging.FileHandler", + "formatter": "simple", + "filename": "app.log", + "mode": "w" + } + }, + "root": { + "level": "DEBUG", + "handlers": [ + "stderr", + "stdout", + "file" + ] + } + } + +This configuration does *almost* what we want, except that ``sys.stdout`` would +show messages of severity ``ERROR`` and above as well as ``INFO`` and +``WARNING`` messages. To prevent this, we can set up a filter which excludes +those messages and add it to the relevant handler. This can be configured by +adding a ``filters`` section parallel to ``formatters`` and ``handlers``: + +.. code-block:: json + + "filters": { + "warnings_and_below": { + "()" : "__main__.filter_maker", + "level": "WARNING" + } + } + +and changing the section on the ``stdout`` handler to add it: + +.. code-block:: json + + "stdout": { + "class": "logging.StreamHandler", + "level": "INFO", + "formatter": "simple", + "stream": "ext://sys.stdout", + "filters": ["warnings_and_below"] + } + +A filter is just a function, so we can define the ``filter_maker`` (a factory +function) as follows: + +.. code-block:: python + + def filter_maker(level): + level = getattr(logging, level) + + def filter(record): + return record.levelno <= level + + return filter + +This converts the string argument passed in to a numeric level, and returns a +function which only returns ``True`` if the level of the passed in record is +at or below the specified level. Note that in this example I have defined the +``filter_maker`` in a test script ``main.py`` that I run from the command line, +so its module will be ``__main__`` - hence the ``__main__.filter_maker`` in the +filter configuration. You will need to change that if you define it in a +different module. + +With the filter added, we can run ``main.py``, which in full is: + +.. code-block:: python + + import json + import logging + import logging.config + + CONFIG = ''' + { + "version": 1, + "disable_existing_loggers": false, + "formatters": { + "simple": { + "format": "%(levelname)-8s - %(message)s" + } + }, + "filters": { + "warnings_and_below": { + "()" : "__main__.filter_maker", + "level": "WARNING" + } + }, + "handlers": { + "stdout": { + "class": "logging.StreamHandler", + "level": "INFO", + "formatter": "simple", + "stream": "ext://sys.stdout", + "filters": ["warnings_and_below"] + }, + "stderr": { + "class": "logging.StreamHandler", + "level": "ERROR", + "formatter": "simple", + "stream": "ext://sys.stderr" + }, + "file": { + "class": "logging.FileHandler", + "formatter": "simple", + "filename": "app.log", + "mode": "w" + } + }, + "root": { + "level": "DEBUG", + "handlers": [ + "stderr", + "stdout", + "file" + ] + } + } + ''' + + def filter_maker(level): + level = getattr(logging, level) + + def filter(record): + return record.levelno <= level + + return filter + + logging.config.dictConfig(json.loads(CONFIG)) + logging.debug('A DEBUG message') + logging.info('An INFO message') + logging.warning('A WARNING message') + logging.error('An ERROR message') + logging.critical('A CRITICAL message') + +And after running it like this: + +.. code-block:: shell + + python main.py 2>stderr.log >stdout.log + +We can see the results are as expected: + +.. code-block:: shell + + $ more *.log + :::::::::::::: + app.log + :::::::::::::: + DEBUG - A DEBUG message + INFO - An INFO message + WARNING - A WARNING message + ERROR - An ERROR message + CRITICAL - A CRITICAL message + :::::::::::::: + stderr.log + :::::::::::::: + ERROR - An ERROR message + CRITICAL - A CRITICAL message + :::::::::::::: + stdout.log + :::::::::::::: + INFO - An INFO message + WARNING - A WARNING message + + Configuration server example ---------------------------- @@ -564,7 +769,7 @@ To run a logging listener in production, you may need to use a process-managemen such as `Supervisor `_. `Here `_ is a Gist which provides the bare-bones files to run the above functionality using Supervisor: you -will need to change the `/path/to/` parts in the Gist to reflect the actual paths you +will need to change the ``/path/to/`` parts in the Gist to reflect the actual paths you want to use. @@ -2776,7 +2981,7 @@ Formatting times using UTC (GMT) via configuration -------------------------------------------------- Sometimes you want to format times using UTC, which can be done using a class -such as `UTCFormatter`, shown below:: +such as ``UTCFormatter``, shown below:: import logging import time @@ -3430,6 +3635,82 @@ the above handler, you'd pass structured data using something like this:: i = 1 logger.debug('Message %d', i, extra=extra) +How to treat a logger like an output stream +------------------------------------------- + +Sometimes, you need to interface to a third-party API which expects a file-like +object to write to, but you want to direct the API's output to a logger. You +can do this using a class which wraps a logger with a file-like API. +Here's a short script illustrating such a class: + +.. code-block:: python + + import logging + + class LoggerWriter: + def __init__(self, logger, level): + self.logger = logger + self.level = level + + def write(self, message): + if message != '\n': # avoid printing bare newlines, if you like + self.logger.log(self.level, message) + + def flush(self): + # doesn't actually do anything, but might be expected of a file-like + # object - so optional depending on your situation + pass + + def close(self): + # doesn't actually do anything, but might be expected of a file-like + # object - so optional depending on your situation. You might want + # to set a flag so that later calls to write raise an exception + pass + + def main(): + logging.basicConfig(level=logging.DEBUG) + logger = logging.getLogger('demo') + info_fp = LoggerWriter(logger, logging.INFO) + debug_fp = LoggerWriter(logger, logging.DEBUG) + print('An INFO message', file=info_fp) + print('A DEBUG message', file=debug_fp) + + if __name__ == "__main__": + main() + +When this script is run, it prints + +.. code-block:: text + + INFO:demo:An INFO message + DEBUG:demo:A DEBUG message + +You could also use ``LoggerWriter`` to redirect ``sys.stdout`` and +``sys.stderr`` by doing something like this: + +.. code-block:: python + + import sys + + sys.stdout = LoggerWriter(logger, logging.INFO) + sys.stderr = LoggerWriter(logger, logging.WARNING) + +You should do this *after* configuring logging for your needs. In the above +example, the :func:`~logging.basicConfig` call does this (using the +``sys.stderr`` value *before* it is overwritten by a ``LoggerWriter`` +instance). Then, you'd get this kind of result: + +.. code-block:: pycon + + >>> print('Foo') + INFO:demo:Foo + >>> print('Bar', file=sys.stderr) + WARNING:demo:Bar + >>> + +Of course, these above examples show output according to the format used by +:func:`~logging.basicConfig`, but you can use a different formatter when you +configure logging. .. patterns-to-avoid: From webhook-mailer at python.org Sat Oct 15 17:05:37 2022 From: webhook-mailer at python.org (rhettinger) Date: Sat, 15 Oct 2022 21:05:37 -0000 Subject: [Python-checkins] Improve speed. Reduce auxiliary memory to 16.6% of the main array. (GH-98294) Message-ID: https://github.com/python/cpython/commit/3a639bbeace73d54f7e5431d3224c8c8223d81ae commit: 3a639bbeace73d54f7e5431d3224c8c8223d81ae branch: main author: Raymond Hettinger committer: rhettinger date: 2022-10-15T16:05:28-05:00 summary: Improve speed. Reduce auxiliary memory to 16.6% of the main array. (GH-98294) files: M Doc/library/itertools.rst diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 056b0788a4d8..88e1e5aa6ef7 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -822,12 +822,13 @@ which incur interpreter overhead. def sieve(n): "Primes less than n" # sieve(30) --> 2 3 5 7 11 13 17 19 23 29 - data = bytearray([1]) * n - data[:2] = 0, 0 + data = bytearray((0, 1)) * (n // 2) + data[:3] = 0, 0, 0 limit = math.isqrt(n) + 1 for p in compress(range(limit), data): - data[p*p : n : p] = bytearray(len(range(p*p, n, p))) - return iter_index(data, 1) + data[p*p : n : p+p] = bytes(len(range(p*p, n, p+p))) + data[2] = 1 + return iter_index(data, 1) if n > 2 else iter([]) def flatten(list_of_lists): "Flatten one level of nesting" From webhook-mailer at python.org Sat Oct 15 17:24:11 2022 From: webhook-mailer at python.org (rhettinger) Date: Sat, 15 Oct 2022 21:24:11 -0000 Subject: [Python-checkins] [3.11] Improve speed. Reduce auxiliary memory to 16.6% of the main array. (GH-98294) (GH-98303) Message-ID: https://github.com/python/cpython/commit/a2ae35dfa4605f3f6a1777ce136b3872dcb97a8e commit: a2ae35dfa4605f3f6a1777ce136b3872dcb97a8e branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: rhettinger date: 2022-10-15T16:24:05-05:00 summary: [3.11] Improve speed. Reduce auxiliary memory to 16.6% of the main array. (GH-98294) (GH-98303) files: M Doc/library/itertools.rst diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 004dd19a7f3a..49fb8407890c 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -822,12 +822,13 @@ which incur interpreter overhead. def sieve(n): "Primes less than n" # sieve(30) --> 2 3 5 7 11 13 17 19 23 29 - data = bytearray([1]) * n - data[:2] = 0, 0 + data = bytearray((0, 1)) * (n // 2) + data[:3] = 0, 0, 0 limit = math.isqrt(n) + 1 for p in compress(range(limit), data): - data[p*p : n : p] = bytearray(len(range(p*p, n, p))) - return iter_index(data, 1) + data[p*p : n : p+p] = bytes(len(range(p*p, n, p+p))) + data[2] = 1 + return iter_index(data, 1) if n > 2 else iter([]) def flatten(list_of_lists): "Flatten one level of nesting" From webhook-mailer at python.org Sat Oct 15 18:13:56 2022 From: webhook-mailer at python.org (pablogsal) Date: Sat, 15 Oct 2022 22:13:56 -0000 Subject: [Python-checkins] gh-98254: Include stdlib module names in error messages for NameErrors (#98255) Message-ID: https://github.com/python/cpython/commit/bb56dead336357153a0c3b8cc9d9d6856d2c5a03 commit: bb56dead336357153a0c3b8cc9d9d6856d2c5a03 branch: main author: Pablo Galindo Salgado committer: pablogsal date: 2022-10-15T23:13:33+01:00 summary: gh-98254: Include stdlib module names in error messages for NameErrors (#98255) files: A Misc/NEWS.d/next/Core and Builtins/2022-10-13-23-23-01.gh-issue-98254.bC8IKt.rst M Lib/idlelib/idle_test/test_run.py M Lib/test/test_traceback.py M Lib/traceback.py M Python/pythonrun.c M Python/suggestions.c diff --git a/Lib/idlelib/idle_test/test_run.py b/Lib/idlelib/idle_test/test_run.py index ec4637c5ca61..a38e43dcb9d1 100644 --- a/Lib/idlelib/idle_test/test_run.py +++ b/Lib/idlelib/idle_test/test_run.py @@ -39,7 +39,8 @@ def __eq__(self, other): data = (('1/0', ZeroDivisionError, "division by zero\n"), ('abc', NameError, "name 'abc' is not defined. " - "Did you mean: 'abs'?\n"), + "Did you mean: 'abs'? " + "Or did you forget to import 'abc'?\n"), ('int.reel', AttributeError, "type object 'int' has no attribute 'reel'. " "Did you mean: 'real'?\n"), diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 4864b5c10b01..2d17e0600650 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -3185,6 +3185,21 @@ def func(): actual = self.get_suggestion(func) self.assertNotIn("something", actual) + def test_name_error_for_stdlib_modules(self): + def func(): + stream = io.StringIO() + + actual = self.get_suggestion(func) + self.assertIn("forget to import 'io'", actual) + + def test_name_error_for_private_stdlib_modules(self): + def func(): + stream = _io.StringIO() + + actual = self.get_suggestion(func) + self.assertIn("forget to import '_io'", actual) + + class PurePythonSuggestionFormattingTests( PurePythonExceptionFormattingMixin, diff --git a/Lib/traceback.py b/Lib/traceback.py index c46ddaf51a00..bb7856a5142e 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -712,6 +712,13 @@ def __init__(self, exc_type, exc_value, exc_traceback, *, limit=None, suggestion = _compute_suggestion_error(exc_value, exc_traceback) if suggestion: self._str += f". Did you mean: '{suggestion}'?" + if issubclass(exc_type, NameError): + wrong_name = getattr(exc_value, "name", None) + if wrong_name is not None and wrong_name in sys.stdlib_module_names: + if suggestion: + self._str += f" Or did you forget to import '{wrong_name}'" + else: + self._str += f". Did you forget to import '{wrong_name}'" if lookup_lines: self._load_lines() self.__suppress_context__ = \ diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-13-23-23-01.gh-issue-98254.bC8IKt.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-13-23-23-01.gh-issue-98254.bC8IKt.rst new file mode 100644 index 000000000000..af5d93ff24e9 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-13-23-23-01.gh-issue-98254.bC8IKt.rst @@ -0,0 +1,3 @@ +Modules from the standard library are now potentially suggested as part of the +error messages displayed by the interpreter when an :exc:`NameError` is raised +to the top level. Patch by Pablo Galindo diff --git a/Python/pythonrun.c b/Python/pythonrun.c index acb1330b85fb..a0005b32fcf1 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -1107,16 +1107,9 @@ print_exception_suggestions(struct exception_print_context *ctx, PyObject *f = ctx->file; PyObject *suggestions = _Py_Offer_Suggestions(value); if (suggestions) { - // Add a trailer ". Did you mean: (...)?" - if (PyFile_WriteString(". Did you mean: '", f) < 0) { - goto error; - } if (PyFile_WriteObject(suggestions, f, Py_PRINT_RAW) < 0) { goto error; } - if (PyFile_WriteString("'?", f) < 0) { - goto error; - } Py_DECREF(suggestions); } else if (PyErr_Occurred()) { diff --git a/Python/suggestions.c b/Python/suggestions.c index c336ec8ffffc..89b86f78bc7a 100644 --- a/Python/suggestions.c +++ b/Python/suggestions.c @@ -3,6 +3,7 @@ #include "pycore_pyerrors.h" #include "pycore_code.h" // _PyCode_GetVarnames() +#include "stdlib_module_names.h" // _Py_stdlib_module_names #define MAX_CANDIDATE_ITEMS 750 #define MAX_STRING_SIZE 40 @@ -175,7 +176,7 @@ calculate_suggestions(PyObject *dir, } static PyObject * -offer_suggestions_for_attribute_error(PyAttributeErrorObject *exc) +get_suggestions_for_attribute_error(PyAttributeErrorObject *exc) { PyObject *name = exc->name; // borrowed reference PyObject *obj = exc->obj; // borrowed reference @@ -195,35 +196,25 @@ offer_suggestions_for_attribute_error(PyAttributeErrorObject *exc) return suggestions; } - static PyObject * -offer_suggestions_for_name_error(PyNameErrorObject *exc) +offer_suggestions_for_attribute_error(PyAttributeErrorObject *exc) { - PyObject *name = exc->name; // borrowed reference - PyTracebackObject *traceback = (PyTracebackObject *) exc->traceback; // borrowed reference - // Abort if we don't have a variable name or we have an invalid one - // or if we don't have a traceback to work with - if (name == NULL || !PyUnicode_CheckExact(name) || - traceback == NULL || !Py_IS_TYPE(traceback, &PyTraceBack_Type) - ) { + PyObject* suggestion = get_suggestions_for_attribute_error(exc); + if (suggestion == NULL) { return NULL; } + // Add a trailer ". Did you mean: (...)?" + PyObject* result = PyUnicode_FromFormat(". Did you mean: %R?", suggestion); + Py_DECREF(suggestion); + return result; +} - // Move to the traceback of the exception - while (1) { - PyTracebackObject *next = traceback->tb_next; - if (next == NULL || !Py_IS_TYPE(next, &PyTraceBack_Type)) { - break; - } - else { - traceback = next; - } - } - - PyFrameObject *frame = traceback->tb_frame; - assert(frame != NULL); +static PyObject * +get_suggestions_for_name_error(PyObject* name, PyFrameObject* frame) +{ PyCodeObject *code = PyFrame_GetCode(frame); assert(code != NULL && code->co_localsplusnames != NULL); + PyObject *varnames = _PyCode_GetVarnames(code); if (varnames == NULL) { return NULL; @@ -261,6 +252,66 @@ offer_suggestions_for_name_error(PyNameErrorObject *exc) return suggestions; } +static bool +is_name_stdlib_module(PyObject* name) +{ + const char* the_name = PyUnicode_AsUTF8(name); + Py_ssize_t len = Py_ARRAY_LENGTH(_Py_stdlib_module_names); + for (Py_ssize_t i = 0; i < len; i++) { + if (strcmp(the_name, _Py_stdlib_module_names[i]) == 0) { + return 1; + } + } + return 0; +} + +static PyObject * +offer_suggestions_for_name_error(PyNameErrorObject *exc) +{ + PyObject *name = exc->name; // borrowed reference + PyTracebackObject *traceback = (PyTracebackObject *) exc->traceback; // borrowed reference + // Abort if we don't have a variable name or we have an invalid one + // or if we don't have a traceback to work with + if (name == NULL || !PyUnicode_CheckExact(name) || + traceback == NULL || !Py_IS_TYPE(traceback, &PyTraceBack_Type) + ) { + return NULL; + } + + // Move to the traceback of the exception + while (1) { + PyTracebackObject *next = traceback->tb_next; + if (next == NULL || !Py_IS_TYPE(next, &PyTraceBack_Type)) { + break; + } + else { + traceback = next; + } + } + + PyFrameObject *frame = traceback->tb_frame; + assert(frame != NULL); + + PyObject* suggestion = get_suggestions_for_name_error(name, frame); + bool is_stdlib_module = is_name_stdlib_module(name); + + if (suggestion == NULL && !is_stdlib_module) { + return NULL; + } + + // Add a trailer ". Did you mean: (...)?" + PyObject* result = NULL; + if (!is_stdlib_module) { + result = PyUnicode_FromFormat(". Did you mean: %R?", suggestion); + } else if (suggestion == NULL) { + result = PyUnicode_FromFormat(". Did you forget to import %R?", name); + } else { + result = PyUnicode_FromFormat(". Did you mean: %R? Or did you forget to import %R?", suggestion, name); + } + Py_XDECREF(suggestion); + return result; +} + // Offer suggestions for a given exception. Returns a python string object containing the // suggestions. This function returns NULL if no suggestion was found or if an exception happened, // users must call PyErr_Occurred() to disambiguate. From webhook-mailer at python.org Sat Oct 15 19:09:57 2022 From: webhook-mailer at python.org (gvanrossum) Date: Sat, 15 Oct 2022 23:09:57 -0000 Subject: [Python-checkins] GH-94597: Deprecate child watcher getters and setters (#98215) Message-ID: https://github.com/python/cpython/commit/660f10248ba321e7783c07f3801991275e2aee1e commit: 660f10248ba321e7783c07f3801991275e2aee1e branch: main author: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> committer: gvanrossum date: 2022-10-15T16:09:30-07:00 summary: GH-94597: Deprecate child watcher getters and setters (#98215) This is the next step for deprecating child watchers. Until we've removed the API completely we have to use it, so this PR is mostly suppressing a lot of warnings when using the API internally. Once the child watcher API is totally removed, the two child watcher implementations we actually use and need (Pidfd and Thread) will be turned into internal helpers. files: A Misc/NEWS.d/next/Library/2022-10-12-11-20-54.gh-issue-94597.GYJZlb.rst M Doc/library/asyncio-policy.rst M Doc/whatsnew/3.12.rst M Lib/asyncio/unix_events.py M Lib/test/test_asyncio/test_events.py M Lib/test/test_asyncio/test_streams.py M Lib/test/test_asyncio/test_subprocess.py M Lib/test/test_asyncio/test_unix_events.py M Lib/test/test_asyncio/utils.py diff --git a/Doc/library/asyncio-policy.rst b/Doc/library/asyncio-policy.rst index bfc3e3090fdc..052378ef3274 100644 --- a/Doc/library/asyncio-policy.rst +++ b/Doc/library/asyncio-policy.rst @@ -88,12 +88,16 @@ The abstract event loop policy base class is defined as follows: This function is Unix specific. + .. deprecated:: 3.12 + .. method:: set_child_watcher(watcher) Set the current child process watcher to *watcher*. This function is Unix specific. + .. deprecated:: 3.12 + .. _asyncio-policy-builtin: @@ -158,12 +162,16 @@ implementation used by the asyncio event loop: Return the current child watcher for the current policy. + .. deprecated:: 3.12 + .. function:: set_child_watcher(watcher) Set the current child watcher to *watcher* for the current policy. *watcher* must implement methods defined in the :class:`AbstractChildWatcher` base class. + .. deprecated:: 3.12 + .. note:: Third-party event loops implementations might not support custom child watchers. For such event loops, using @@ -245,6 +253,8 @@ implementation used by the asyncio event loop: .. versionadded:: 3.8 + .. deprecated:: 3.12 + .. class:: SafeChildWatcher This implementation uses active event loop from the main thread to handle @@ -257,6 +267,8 @@ implementation used by the asyncio event loop: This solution is as safe as :class:`MultiLoopChildWatcher` and has the same *O(N)* complexity but requires a running event loop in the main thread to work. + .. deprecated:: 3.12 + .. class:: FastChildWatcher This implementation reaps every terminated processes by calling @@ -269,6 +281,8 @@ implementation used by the asyncio event loop: This solution requires a running event loop in the main thread to work, as :class:`SafeChildWatcher`. + .. deprecated:: 3.12 + .. class:: PidfdChildWatcher This implementation polls process file descriptors (pidfds) to await child diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index ebc490691e30..ecc74e9beba2 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -126,6 +126,12 @@ asyncio if supported and :class:`~asyncio.ThreadedChildWatcher` otherwise). (Contributed by Kumar Aditya in :gh:`94597`.) +* :func:`asyncio.set_child_watcher`, :func:`asyncio.get_child_watcher`, + :meth:`asyncio.AbstractEventLoopPolicy.set_child_watcher` and + :meth:`asyncio.AbstractEventLoopPolicy.get_child_watcher` are deprecated + and will be removed in Python 3.14. + (Contributed by Kumar Aditya in :gh:`94597`.) + pathlib ------- diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py index 9f9b03e0cb21..ea7010ee1073 100644 --- a/Lib/asyncio/unix_events.py +++ b/Lib/asyncio/unix_events.py @@ -195,30 +195,32 @@ def _make_write_pipe_transport(self, pipe, protocol, waiter=None, async def _make_subprocess_transport(self, protocol, args, shell, stdin, stdout, stderr, bufsize, extra=None, **kwargs): - with events.get_child_watcher() as watcher: - if not watcher.is_active(): - # Check early. - # Raising exception before process creation - # prevents subprocess execution if the watcher - # is not ready to handle it. - raise RuntimeError("asyncio.get_child_watcher() is not activated, " - "subprocess support is not installed.") - waiter = self.create_future() - transp = _UnixSubprocessTransport(self, protocol, args, shell, - stdin, stdout, stderr, bufsize, - waiter=waiter, extra=extra, - **kwargs) - - watcher.add_child_handler(transp.get_pid(), - self._child_watcher_callback, transp) - try: - await waiter - except (SystemExit, KeyboardInterrupt): - raise - except BaseException: - transp.close() - await transp._wait() - raise + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + with events.get_child_watcher() as watcher: + if not watcher.is_active(): + # Check early. + # Raising exception before process creation + # prevents subprocess execution if the watcher + # is not ready to handle it. + raise RuntimeError("asyncio.get_child_watcher() is not activated, " + "subprocess support is not installed.") + waiter = self.create_future() + transp = _UnixSubprocessTransport(self, protocol, args, shell, + stdin, stdout, stderr, bufsize, + waiter=waiter, extra=extra, + **kwargs) + + watcher.add_child_handler(transp.get_pid(), + self._child_watcher_callback, transp) + try: + await waiter + except (SystemExit, KeyboardInterrupt): + raise + except BaseException: + transp.close() + await transp._wait() + raise return transp @@ -1469,6 +1471,9 @@ def get_child_watcher(self): if self._watcher is None: self._init_watcher() + warnings._deprecated("get_child_watcher", + "{name!r} is deprecated as of Python 3.12 and will be " + "removed in Python {remove}.", remove=(3, 14)) return self._watcher def set_child_watcher(self, watcher): @@ -1480,6 +1485,9 @@ def set_child_watcher(self, watcher): self._watcher.close() self._watcher = watcher + warnings._deprecated("set_child_watcher", + "{name!r} is deprecated as of Python 3.12 and will be " + "removed in Python {remove}.", remove=(3, 14)) SelectorEventLoop = _UnixSelectorEventLoop diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py index 98b55dec37f4..cabe75f56d9f 100644 --- a/Lib/test/test_asyncio/test_events.py +++ b/Lib/test/test_asyncio/test_events.py @@ -2058,11 +2058,13 @@ def setUp(self): with warnings.catch_warnings(): warnings.simplefilter('ignore', DeprecationWarning) watcher = asyncio.SafeChildWatcher() - watcher.attach_loop(self.loop) - asyncio.set_child_watcher(watcher) + watcher.attach_loop(self.loop) + asyncio.set_child_watcher(watcher) def tearDown(self): - asyncio.set_child_watcher(None) + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + asyncio.set_child_watcher(None) super().tearDown() @@ -2657,13 +2659,15 @@ def setUp(self): with warnings.catch_warnings(): warnings.simplefilter('ignore', DeprecationWarning) watcher = asyncio.SafeChildWatcher() - watcher.attach_loop(self.loop) - asyncio.set_child_watcher(watcher) + watcher.attach_loop(self.loop) + asyncio.set_child_watcher(watcher) def tearDown(self): try: if sys.platform != 'win32': - asyncio.set_child_watcher(None) + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + asyncio.set_child_watcher(None) super().tearDown() finally: diff --git a/Lib/test/test_asyncio/test_streams.py b/Lib/test/test_asyncio/test_streams.py index 8fb9313e09dd..01d5407a497a 100644 --- a/Lib/test/test_asyncio/test_streams.py +++ b/Lib/test/test_asyncio/test_streams.py @@ -797,7 +797,9 @@ def test_read_all_from_pipe_reader(self): watcher = asyncio.SafeChildWatcher() watcher.attach_loop(self.loop) try: - asyncio.set_child_watcher(watcher) + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + asyncio.set_child_watcher(watcher) create = asyncio.create_subprocess_exec( *args, pass_fds={wfd}, @@ -805,7 +807,9 @@ def test_read_all_from_pipe_reader(self): proc = self.loop.run_until_complete(create) self.loop.run_until_complete(proc.wait()) finally: - asyncio.set_child_watcher(None) + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + asyncio.set_child_watcher(None) os.close(wfd) data = self.loop.run_until_complete(reader.read(-1)) diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py index 64df1b17189b..8e5511559061 100644 --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -582,7 +582,9 @@ async def kill_running(): # manually to avoid a warning when the watcher is detached. if (sys.platform != 'win32' and isinstance(self, SubprocessFastWatcherTests)): - asyncio.get_child_watcher()._callbacks.clear() + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + asyncio.get_child_watcher()._callbacks.clear() async def _test_popen_error(self, stdin): if sys.platform == 'win32': @@ -696,13 +698,17 @@ def setUp(self): watcher = self._get_watcher() watcher.attach_loop(self.loop) - policy.set_child_watcher(watcher) + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + policy.set_child_watcher(watcher) def tearDown(self): super().tearDown() policy = asyncio.get_event_loop_policy() - watcher = policy.get_child_watcher() - policy.set_child_watcher(None) + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + watcher = policy.get_child_watcher() + policy.set_child_watcher(None) watcher.attach_loop(None) watcher.close() @@ -752,7 +758,9 @@ def test_create_subprocess_fails_with_inactive_watcher(self): ) async def execute(): - asyncio.set_child_watcher(watcher) + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + asyncio.set_child_watcher(watcher) with self.assertRaises(RuntimeError): await subprocess.create_subprocess_exec( @@ -761,7 +769,9 @@ async def execute(): watcher.add_child_handler.assert_not_called() with asyncio.Runner(loop_factory=asyncio.new_event_loop) as runner: - self.assertIsNone(runner.run(execute())) + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + self.assertIsNone(runner.run(execute())) self.assertListEqual(watcher.mock_calls, [ mock.call.__enter__(), mock.call.__enter__().is_active(), @@ -788,15 +798,16 @@ async def main(): with self.assertRaises(RuntimeError): asyncio.get_event_loop_policy().get_event_loop() return await asyncio.to_thread(asyncio.run, in_thread()) - - asyncio.set_child_watcher(asyncio.PidfdChildWatcher()) + with self.assertWarns(DeprecationWarning): + asyncio.set_child_watcher(asyncio.PidfdChildWatcher()) try: with asyncio.Runner(loop_factory=asyncio.new_event_loop) as runner: returncode, stdout = runner.run(main()) self.assertEqual(returncode, 0) self.assertEqual(stdout, b'some data') finally: - asyncio.set_child_watcher(None) + with self.assertWarns(DeprecationWarning): + asyncio.set_child_watcher(None) else: # Windows class SubprocessProactorTests(SubprocessMixin, test_utils.TestCase): diff --git a/Lib/test/test_asyncio/test_unix_events.py b/Lib/test/test_asyncio/test_unix_events.py index 025da0f20ed4..d806ed497aaa 100644 --- a/Lib/test/test_asyncio/test_unix_events.py +++ b/Lib/test/test_asyncio/test_unix_events.py @@ -1709,33 +1709,36 @@ def test_get_default_child_watcher(self): self.assertIsNone(policy._watcher) unix_events.can_use_pidfd = mock.Mock() unix_events.can_use_pidfd.return_value = False - watcher = policy.get_child_watcher() + with self.assertWarns(DeprecationWarning): + watcher = policy.get_child_watcher() self.assertIsInstance(watcher, asyncio.ThreadedChildWatcher) self.assertIs(policy._watcher, watcher) - - self.assertIs(watcher, policy.get_child_watcher()) + with self.assertWarns(DeprecationWarning): + self.assertIs(watcher, policy.get_child_watcher()) policy = self.create_policy() self.assertIsNone(policy._watcher) unix_events.can_use_pidfd = mock.Mock() unix_events.can_use_pidfd.return_value = True - watcher = policy.get_child_watcher() + with self.assertWarns(DeprecationWarning): + watcher = policy.get_child_watcher() self.assertIsInstance(watcher, asyncio.PidfdChildWatcher) self.assertIs(policy._watcher, watcher) - - self.assertIs(watcher, policy.get_child_watcher()) + with self.assertWarns(DeprecationWarning): + self.assertIs(watcher, policy.get_child_watcher()) def test_get_child_watcher_after_set(self): policy = self.create_policy() with warnings.catch_warnings(): warnings.simplefilter("ignore", DeprecationWarning) watcher = asyncio.FastChildWatcher() + policy.set_child_watcher(watcher) - policy.set_child_watcher(watcher) self.assertIs(policy._watcher, watcher) - self.assertIs(watcher, policy.get_child_watcher()) + with self.assertWarns(DeprecationWarning): + self.assertIs(watcher, policy.get_child_watcher()) def test_get_child_watcher_thread(self): @@ -1769,7 +1772,7 @@ def test_child_watcher_replace_mainloop_existing(self): with warnings.catch_warnings(): warnings.simplefilter("ignore", DeprecationWarning) watcher = asyncio.SafeChildWatcher() - policy.set_child_watcher(watcher) + policy.set_child_watcher(watcher) watcher.attach_loop(loop) self.assertIs(watcher._loop, loop) diff --git a/Lib/test/test_asyncio/utils.py b/Lib/test/test_asyncio/utils.py index 96be5a1c3bcf..5b9c86eb9859 100644 --- a/Lib/test/test_asyncio/utils.py +++ b/Lib/test/test_asyncio/utils.py @@ -14,7 +14,7 @@ import threading import unittest import weakref - +import warnings from unittest import mock from http.server import HTTPServer @@ -544,7 +544,9 @@ def close_loop(loop): policy = support.maybe_get_event_loop_policy() if policy is not None: try: - watcher = policy.get_child_watcher() + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + watcher = policy.get_child_watcher() except NotImplementedError: # watcher is not implemented by EventLoopPolicy, e.g. Windows pass diff --git a/Misc/NEWS.d/next/Library/2022-10-12-11-20-54.gh-issue-94597.GYJZlb.rst b/Misc/NEWS.d/next/Library/2022-10-12-11-20-54.gh-issue-94597.GYJZlb.rst new file mode 100644 index 000000000000..5ea1358b7d8a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-12-11-20-54.gh-issue-94597.GYJZlb.rst @@ -0,0 +1 @@ +Deprecated :meth:`asyncio.AbstractEventLoopPolicy.get_child_watcher` and :meth:`asyncio.AbstractEventLoopPolicy.set_child_watcher` methods to be removed in Python 3.14. Patch by Kumar Aditya. From webhook-mailer at python.org Sun Oct 16 00:08:52 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Sun, 16 Oct 2022 04:08:52 -0000 Subject: [Python-checkins] [3.10] docs(typing): harmonize "See PEP x for more details" (GH-97927). (#98293) Message-ID: https://github.com/python/cpython/commit/8a1f1cbe1a8c766071afa72225f1d722464997f3 commit: 8a1f1cbe1a8c766071afa72225f1d722464997f3 branch: 3.10 author: Jelle Zijlstra committer: JelleZijlstra date: 2022-10-15T21:08:46-07:00 summary: [3.10] docs(typing): harmonize "See PEP x for more details" (GH-97927). (#98293) (cherry picked from commit 02389658a4751a0166e2ed22be112b646378a01b) Co-authored-by: Simon Legner files: M Doc/library/typing.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index c1cf899203c8..cfe484b8e469 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -234,7 +234,7 @@ respectively. .. versionchanged:: 3.10 ``Callable`` now supports :class:`ParamSpec` and :data:`Concatenate`. - See :pep:`612` for more information. + See :pep:`612` for more details. .. seealso:: The documentation for :class:`ParamSpec` and :class:`Concatenate` provides @@ -725,7 +725,7 @@ These can be used as types in annotations using ``[]``, each having a unique syn .. versionchanged:: 3.10 ``Callable`` now supports :class:`ParamSpec` and :data:`Concatenate`. - See :pep:`612` for more information. + See :pep:`612` for more details. .. seealso:: The documentation for :class:`ParamSpec` and :class:`Concatenate` provide @@ -1050,8 +1050,7 @@ These can be used as types in annotations using ``[]``, each having a unique syn is not a subtype of the former, since ``List`` is invariant. The responsibility of writing type-safe type guards is left to the user. - ``TypeGuard`` also works with type variables. For more information, see - :pep:`647` (User-Defined Type Guards). + ``TypeGuard`` also works with type variables. See :pep:`647` for more details. .. versionadded:: 3.10 @@ -1323,7 +1322,7 @@ These are not used in annotations. They are building blocks for creating generic func(C()) # Passes static type check - See :pep:`544` for details. Protocol classes decorated with + See :pep:`544` for more details. Protocol classes decorated with :func:`runtime_checkable` (described later) act as simple-minded runtime protocols that check only the presence of given attributes, ignoring their type signatures. @@ -2127,7 +2126,7 @@ Functions and decorators def process(response): - See :pep:`484` for details and comparison with other typing semantics. + See :pep:`484` for more details and comparison with other typing semantics. .. decorator:: final From webhook-mailer at python.org Sun Oct 16 00:15:23 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Sun, 16 Oct 2022 04:15:23 -0000 Subject: [Python-checkins] [3.11] gh-95731: Fix module docstring extraction in pygettext (GH-95732) (#98281) Message-ID: https://github.com/python/cpython/commit/b5874fae0a618e4b0815a54242b0703bd92482be commit: b5874fae0a618e4b0815a54242b0703bd92482be branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: JelleZijlstra date: 2022-10-15T21:15:17-07:00 summary: [3.11] gh-95731: Fix module docstring extraction in pygettext (GH-95732) (#98281) gh-95731: Fix module docstring extraction in pygettext (GH-95732) (cherry picked from commit 120b4ab2b68aebf96ce0de243eab89a25fc2d282) Co-authored-by: Jakub Kuczys files: A Misc/NEWS.d/next/Tools-Demos/2022-08-05-23-25-59.gh-issue-95731.N2KohU.rst M Lib/test/test_tools/test_i18n.py M Tools/i18n/pygettext.py diff --git a/Lib/test/test_tools/test_i18n.py b/Lib/test/test_tools/test_i18n.py index 7f18edaaa8ca..c083a04475e7 100644 --- a/Lib/test/test_tools/test_i18n.py +++ b/Lib/test/test_tools/test_i18n.py @@ -155,6 +155,26 @@ class C: ''')) self.assertFalse([msgid for msgid in msgids if 'doc' in msgid]) + def test_moduledocstring(self): + for doc in ('"""doc"""', "r'''doc'''", "R'doc'", 'u"doc"'): + with self.subTest(doc): + msgids = self.extract_docstrings_from_str(dedent('''\ + %s + ''' % doc)) + self.assertIn('doc', msgids) + + def test_moduledocstring_bytes(self): + msgids = self.extract_docstrings_from_str(dedent('''\ + b"""doc""" + ''')) + self.assertFalse([msgid for msgid in msgids if 'doc' in msgid]) + + def test_moduledocstring_fstring(self): + msgids = self.extract_docstrings_from_str(dedent('''\ + f"""doc""" + ''')) + self.assertFalse([msgid for msgid in msgids if 'doc' in msgid]) + def test_msgid(self): msgids = self.extract_docstrings_from_str( '''_("""doc""" r'str' u"ing")''') diff --git a/Misc/NEWS.d/next/Tools-Demos/2022-08-05-23-25-59.gh-issue-95731.N2KohU.rst b/Misc/NEWS.d/next/Tools-Demos/2022-08-05-23-25-59.gh-issue-95731.N2KohU.rst new file mode 100644 index 000000000000..6b214616c0a9 --- /dev/null +++ b/Misc/NEWS.d/next/Tools-Demos/2022-08-05-23-25-59.gh-issue-95731.N2KohU.rst @@ -0,0 +1 @@ +Fix handling of module docstrings in :file:`Tools/i18n/pygettext.py`. diff --git a/Tools/i18n/pygettext.py b/Tools/i18n/pygettext.py index 6f889adffe6c..7ada79105db1 100755 --- a/Tools/i18n/pygettext.py +++ b/Tools/i18n/pygettext.py @@ -335,9 +335,10 @@ def __waiting(self, ttype, tstring, lineno): if ttype == tokenize.STRING and is_literal_string(tstring): self.__addentry(safe_eval(tstring), lineno, isdocstring=1) self.__freshmodule = 0 - elif ttype not in (tokenize.COMMENT, tokenize.NL): - self.__freshmodule = 0 - return + return + if ttype in (tokenize.COMMENT, tokenize.NL, tokenize.ENCODING): + return + self.__freshmodule = 0 # class or func/method docstring? if ttype == tokenize.NAME and tstring in ('class', 'def'): self.__state = self.__suiteseen From webhook-mailer at python.org Sun Oct 16 00:19:08 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Sun, 16 Oct 2022 04:19:08 -0000 Subject: [Python-checkins] gh-94808: Cover `PyFunction_GetCode`, `PyFunction_GetGlobals`, `PyFunction_GetModule` (#98158) Message-ID: https://github.com/python/cpython/commit/7b48d02933639c91ebd957b2326d8c352d8eddec commit: 7b48d02933639c91ebd957b2326d8c352d8eddec branch: main author: Nikita Sobolev committer: JelleZijlstra date: 2022-10-15T21:18:59-07:00 summary: gh-94808: Cover `PyFunction_GetCode`, `PyFunction_GetGlobals`, `PyFunction_GetModule` (#98158) files: M Lib/test/test_capi.py M Modules/_testcapimodule.c diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py index ae434c05baf2..a2183cfb0fdf 100644 --- a/Lib/test/test_capi.py +++ b/Lib/test/test_capi.py @@ -895,6 +895,41 @@ def method_example(self): ... self.assertEqual(_testcapi.eval_get_func_name(sum), "sum") # c function self.assertEqual(_testcapi.eval_get_func_name(A), "type") + def test_function_get_code(self): + import types + + def some(): + pass + + code = _testcapi.function_get_code(some) + self.assertIsInstance(code, types.CodeType) + self.assertEqual(code, some.__code__) + + with self.assertRaises(SystemError): + _testcapi.function_get_code(None) # not a function + + def test_function_get_globals(self): + def some(): + pass + + globals_ = _testcapi.function_get_globals(some) + self.assertIsInstance(globals_, dict) + self.assertEqual(globals_, some.__globals__) + + with self.assertRaises(SystemError): + _testcapi.function_get_globals(None) # not a function + + def test_function_get_module(self): + def some(): + pass + + module = _testcapi.function_get_module(some) + self.assertIsInstance(module, str) + self.assertEqual(module, some.__module__) + + with self.assertRaises(SystemError): + _testcapi.function_get_module(None) # not a function + class TestPendingCalls(unittest.TestCase): diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 76e619d11f98..624e878b20d8 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -5658,6 +5658,42 @@ test_macros(PyObject *self, PyObject *Py_UNUSED(args)) Py_RETURN_NONE; } +static PyObject * +function_get_code(PyObject *self, PyObject *func) +{ + PyObject *code = PyFunction_GetCode(func); + if (code != NULL) { + Py_INCREF(code); + return code; + } else { + return NULL; + } +} + +static PyObject * +function_get_globals(PyObject *self, PyObject *func) +{ + PyObject *globals = PyFunction_GetGlobals(func); + if (globals != NULL) { + Py_INCREF(globals); + return globals; + } else { + return NULL; + } +} + +static PyObject * +function_get_module(PyObject *self, PyObject *func) +{ + PyObject *module = PyFunction_GetModule(func); + if (module != NULL) { + Py_INCREF(module); + return module; + } else { + return NULL; + } +} + static PyObject *test_buildvalue_issue38913(PyObject *, PyObject *); static PyObject *getargs_s_hash_int(PyObject *, PyObject *, PyObject*); @@ -5942,6 +5978,9 @@ static PyMethodDef TestMethods[] = { {"watch_dict", watch_dict, METH_VARARGS, NULL}, {"unwatch_dict", unwatch_dict, METH_VARARGS, NULL}, {"get_dict_watcher_events", get_dict_watcher_events, METH_NOARGS, NULL}, + {"function_get_code", function_get_code, METH_O, NULL}, + {"function_get_globals", function_get_globals, METH_O, NULL}, + {"function_get_module", function_get_module, METH_O, NULL}, {NULL, NULL} /* sentinel */ }; From webhook-mailer at python.org Sun Oct 16 04:16:28 2022 From: webhook-mailer at python.org (vsajip) Date: Sun, 16 Oct 2022 08:16:28 -0000 Subject: [Python-checkins] gh-98307: Add docstring and documentation for SysLogHandler.createSocket (GH-98319) Message-ID: https://github.com/python/cpython/commit/f6b1e4048dc353aecfbfbae07de8212900632098 commit: f6b1e4048dc353aecfbfbae07de8212900632098 branch: main author: Vinay Sajip committer: vsajip date: 2022-10-16T09:15:46+01:00 summary: gh-98307: Add docstring and documentation for SysLogHandler.createSocket (GH-98319) Co-authored-by: C.A.M. Gerlach files: A Misc/NEWS.d/next/Library/2022-10-16-06-18-59.gh-issue-98307.b2_CDu.rst M Doc/library/logging.handlers.rst M Lib/logging/handlers.py diff --git a/Doc/library/logging.handlers.rst b/Doc/library/logging.handlers.rst index f3b26e726aaf..d4429d3d0a4f 100644 --- a/Doc/library/logging.handlers.rst +++ b/Doc/library/logging.handlers.rst @@ -650,6 +650,17 @@ supports sending logging messages to a remote or local Unix syslog. Closes the socket to the remote host. + .. method:: createSocket() + + Tries to create a socket and, if it's not a datagram socket, connect it + to the other end. This method is called during handler initialization, + but it's not regarded as an error if the other end isn't listening at + this point - the method will be called again when emitting an event, if + but it's not regarded as an error if the other end isn't listening yet + --- the method will be called again when emitting an event, + if there is no socket at that point. + + .. versionadded:: 3.11 .. method:: emit(record) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py index b4c5c1304b97..9847104446ea 100644 --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -891,6 +891,13 @@ def _connect_unixsocket(self, address): raise def createSocket(self): + """ + Try to create a socket and, if it's not a datagram socket, connect it + to the other end. This method is called during handler initialization, + but it's not regarded as an error if the other end isn't listening yet + --- the method will be called again when emitting an event, + if there is no socket at that point. + """ address = self.address socktype = self.socktype @@ -898,7 +905,7 @@ def createSocket(self): self.unixsocket = True # Syslog server may be unavailable during handler initialisation. # C's openlog() function also ignores connection errors. - # Moreover, we ignore these errors while logging, so it not worse + # Moreover, we ignore these errors while logging, so it's not worse # to ignore it also here. try: self._connect_unixsocket(address) diff --git a/Misc/NEWS.d/next/Library/2022-10-16-06-18-59.gh-issue-98307.b2_CDu.rst b/Misc/NEWS.d/next/Library/2022-10-16-06-18-59.gh-issue-98307.b2_CDu.rst new file mode 100644 index 000000000000..3fe41d53c980 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-16-06-18-59.gh-issue-98307.b2_CDu.rst @@ -0,0 +1,2 @@ +A :meth:`~logging.handlers.SysLogHandler.createSocket` method was added to +:class:`~logging.handlers.SysLogHandler`. From webhook-mailer at python.org Sun Oct 16 10:23:20 2022 From: webhook-mailer at python.org (terryjreedy) Date: Sun, 16 Oct 2022 14:23:20 -0000 Subject: [Python-checkins] gh-97527: IDLE - fix buggy macosx patch (#98313) Message-ID: https://github.com/python/cpython/commit/35fa5d5e7f2b0971b39b2659dc70cb77e34a7dd6 commit: 35fa5d5e7f2b0971b39b2659dc70cb77e34a7dd6 branch: main author: Terry Jan Reedy committer: terryjreedy date: 2022-10-16T10:23:11-04:00 summary: gh-97527: IDLE - fix buggy macosx patch (#98313) #97530 fixed IDLE tests possibly crashing on a Mac without a GUI. But it resulted in IDLE not starting in 3.10.8, 3.12.0a1, and Microsoft Python 3.10.2288.0 when test/* is not installed. After this patch, test.* is only imported when testing on Mac. files: A Misc/NEWS.d/next/IDLE/2022-10-15-21-20-40.gh-issue-97527.otAHJM.rst M Lib/idlelib/NEWS.txt M Lib/idlelib/macosx.py diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt index 7fa7facf8cf7..e64e96f75e6c 100644 --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -4,6 +4,11 @@ Released on 2022-10-03 ========================= +gh-97527: Fix a bug in the previous bugfix that caused IDLE to not +start when run with 3.10.8, 3.12.0a1, and at least Microsoft Python +3.10.2288.0 installed without the Lib/test package. 3.11.0 was never +affected. + gh-65802: Document handling of extensions in Save As dialogs. gh-95191: Include prompts when saving Shell (interactive input/output). diff --git a/Lib/idlelib/macosx.py b/Lib/idlelib/macosx.py index 12399f152aea..89b645702d33 100644 --- a/Lib/idlelib/macosx.py +++ b/Lib/idlelib/macosx.py @@ -4,7 +4,6 @@ from os.path import expanduser import plistlib from sys import platform # Used in _init_tk_type, changed by test. -from test.support import requires, ResourceDenied import tkinter @@ -16,27 +15,38 @@ def _init_tk_type(): """ Initialize _tk_type for isXyzTk functions. + + This function is only called once, when _tk_type is still None. """ global _tk_type if platform == 'darwin': - try: - requires('gui') - except ResourceDenied: # Possible when testing. - _tk_type = "cocoa" # Newest and most common. - else: - root = tkinter.Tk() - ws = root.tk.call('tk', 'windowingsystem') - if 'x11' in ws: - _tk_type = "xquartz" - elif 'aqua' not in ws: - _tk_type = "other" - elif 'AppKit' in root.tk.call('winfo', 'server', '.'): + + # When running IDLE, GUI is present, test/* may not be. + # When running tests, test/* is present, GUI may not be. + # If not, guess most common. Does not matter for testing. + from idlelib.__init__ import testing + if testing: + from test.support import requires, ResourceDenied + try: + requires('gui') + except ResourceDenied: _tk_type = "cocoa" - else: - _tk_type = "carbon" - root.destroy() + return + + root = tkinter.Tk() + ws = root.tk.call('tk', 'windowingsystem') + if 'x11' in ws: + _tk_type = "xquartz" + elif 'aqua' not in ws: + _tk_type = "other" + elif 'AppKit' in root.tk.call('winfo', 'server', '.'): + _tk_type = "cocoa" + else: + _tk_type = "carbon" + root.destroy() else: _tk_type = "other" + return def isAquaTk(): """ diff --git a/Misc/NEWS.d/next/IDLE/2022-10-15-21-20-40.gh-issue-97527.otAHJM.rst b/Misc/NEWS.d/next/IDLE/2022-10-15-21-20-40.gh-issue-97527.otAHJM.rst new file mode 100644 index 000000000000..e7fda8974194 --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2022-10-15-21-20-40.gh-issue-97527.otAHJM.rst @@ -0,0 +1,3 @@ +Fix a bug in the previous bugfix that caused IDLE to not start when run with +3.10.8, 3.12.0a1, and at least Microsoft Python 3.10.2288.0 installed +without the Lib/test package. 3.11.0 was never affected. From webhook-mailer at python.org Sun Oct 16 11:33:39 2022 From: webhook-mailer at python.org (miss-islington) Date: Sun, 16 Oct 2022 15:33:39 -0000 Subject: [Python-checkins] gh-97527: IDLE - fix buggy macosx patch (GH-98313) Message-ID: https://github.com/python/cpython/commit/928b5f1bdeb4f9ab243ccfdf0aa0ca52839974f9 commit: 928b5f1bdeb4f9ab243ccfdf0aa0ca52839974f9 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-16T08:33:33-07:00 summary: gh-97527: IDLE - fix buggy macosx patch (GH-98313) GH-97530 fixed IDLE tests possibly crashing on a Mac without a GUI. But it resulted in IDLE not starting in 3.10.8, 3.12.0a1, and Microsoft Python 3.10.2288.0 when test/* is not installed. After this patch, test.* is only imported when testing on Mac. (cherry picked from commit 35fa5d5e7f2b0971b39b2659dc70cb77e34a7dd6) Co-authored-by: Terry Jan Reedy files: A Misc/NEWS.d/next/IDLE/2022-10-15-21-20-40.gh-issue-97527.otAHJM.rst M Lib/idlelib/NEWS.txt M Lib/idlelib/macosx.py diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt index 277fd9429a4c..521b1f12f933 100644 --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -4,6 +4,11 @@ Released 2023-04-03? ========================= +gh-97527: Fix a bug in the previous bugfix that caused IDLE to not +start when run with 3.10.8, 3.12.0a1, and at least Microsoft Python +3.10.2288.0 installed without the Lib/test package. 3.11.0 was never +affected. + gh-65802: Document handling of extensions in Save As dialogs. gh-95191: Include prompts when saving Shell (interactive input/output). diff --git a/Lib/idlelib/macosx.py b/Lib/idlelib/macosx.py index 1085d689f6ff..f53bd58970e6 100644 --- a/Lib/idlelib/macosx.py +++ b/Lib/idlelib/macosx.py @@ -4,7 +4,6 @@ from os.path import expanduser import plistlib from sys import platform # Used in _init_tk_type, changed by test. -from test.support import requires, ResourceDenied import tkinter @@ -16,27 +15,38 @@ def _init_tk_type(): """ Initialize _tk_type for isXyzTk functions. + + This function is only called once, when _tk_type is still None. """ global _tk_type if platform == 'darwin': - try: - requires('gui') - except ResourceDenied: # Possible when testing. - _tk_type = "cocoa" # Newest and most common. - else: - root = tkinter.Tk() - ws = root.tk.call('tk', 'windowingsystem') - if 'x11' in ws: - _tk_type = "xquartz" - elif 'aqua' not in ws: - _tk_type = "other" - elif 'AppKit' in root.tk.call('winfo', 'server', '.'): + + # When running IDLE, GUI is present, test/* may not be. + # When running tests, test/* is present, GUI may not be. + # If not, guess most common. Does not matter for testing. + from idlelib.__init__ import testing + if testing: + from test.support import requires, ResourceDenied + try: + requires('gui') + except ResourceDenied: _tk_type = "cocoa" - else: - _tk_type = "carbon" - root.destroy() + return + + root = tkinter.Tk() + ws = root.tk.call('tk', 'windowingsystem') + if 'x11' in ws: + _tk_type = "xquartz" + elif 'aqua' not in ws: + _tk_type = "other" + elif 'AppKit' in root.tk.call('winfo', 'server', '.'): + _tk_type = "cocoa" + else: + _tk_type = "carbon" + root.destroy() else: _tk_type = "other" + return def isAquaTk(): """ diff --git a/Misc/NEWS.d/next/IDLE/2022-10-15-21-20-40.gh-issue-97527.otAHJM.rst b/Misc/NEWS.d/next/IDLE/2022-10-15-21-20-40.gh-issue-97527.otAHJM.rst new file mode 100644 index 000000000000..e7fda8974194 --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2022-10-15-21-20-40.gh-issue-97527.otAHJM.rst @@ -0,0 +1,3 @@ +Fix a bug in the previous bugfix that caused IDLE to not start when run with +3.10.8, 3.12.0a1, and at least Microsoft Python 3.10.2288.0 installed +without the Lib/test package. 3.11.0 was never affected. From webhook-mailer at python.org Sun Oct 16 12:00:52 2022 From: webhook-mailer at python.org (miss-islington) Date: Sun, 16 Oct 2022 16:00:52 -0000 Subject: [Python-checkins] gh-97527: IDLE - fix buggy macosx patch (GH-98313) Message-ID: https://github.com/python/cpython/commit/21fbf1631d37fd5f769fde5795c62e1f1e90842a commit: 21fbf1631d37fd5f769fde5795c62e1f1e90842a branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-16T09:00:47-07:00 summary: gh-97527: IDLE - fix buggy macosx patch (GH-98313) GH-97530 fixed IDLE tests possibly crashing on a Mac without a GUI. But it resulted in IDLE not starting in 3.10.8, 3.12.0a1, and Microsoft Python 3.10.2288.0 when test/* is not installed. After this patch, test.* is only imported when testing on Mac. (cherry picked from commit 35fa5d5e7f2b0971b39b2659dc70cb77e34a7dd6) Co-authored-by: Terry Jan Reedy files: A Misc/NEWS.d/next/IDLE/2022-10-15-21-20-40.gh-issue-97527.otAHJM.rst M Lib/idlelib/NEWS.txt M Lib/idlelib/macosx.py diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt index 7fa7facf8cf7..e64e96f75e6c 100644 --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -4,6 +4,11 @@ Released on 2022-10-03 ========================= +gh-97527: Fix a bug in the previous bugfix that caused IDLE to not +start when run with 3.10.8, 3.12.0a1, and at least Microsoft Python +3.10.2288.0 installed without the Lib/test package. 3.11.0 was never +affected. + gh-65802: Document handling of extensions in Save As dialogs. gh-95191: Include prompts when saving Shell (interactive input/output). diff --git a/Lib/idlelib/macosx.py b/Lib/idlelib/macosx.py index 12399f152aea..89b645702d33 100644 --- a/Lib/idlelib/macosx.py +++ b/Lib/idlelib/macosx.py @@ -4,7 +4,6 @@ from os.path import expanduser import plistlib from sys import platform # Used in _init_tk_type, changed by test. -from test.support import requires, ResourceDenied import tkinter @@ -16,27 +15,38 @@ def _init_tk_type(): """ Initialize _tk_type for isXyzTk functions. + + This function is only called once, when _tk_type is still None. """ global _tk_type if platform == 'darwin': - try: - requires('gui') - except ResourceDenied: # Possible when testing. - _tk_type = "cocoa" # Newest and most common. - else: - root = tkinter.Tk() - ws = root.tk.call('tk', 'windowingsystem') - if 'x11' in ws: - _tk_type = "xquartz" - elif 'aqua' not in ws: - _tk_type = "other" - elif 'AppKit' in root.tk.call('winfo', 'server', '.'): + + # When running IDLE, GUI is present, test/* may not be. + # When running tests, test/* is present, GUI may not be. + # If not, guess most common. Does not matter for testing. + from idlelib.__init__ import testing + if testing: + from test.support import requires, ResourceDenied + try: + requires('gui') + except ResourceDenied: _tk_type = "cocoa" - else: - _tk_type = "carbon" - root.destroy() + return + + root = tkinter.Tk() + ws = root.tk.call('tk', 'windowingsystem') + if 'x11' in ws: + _tk_type = "xquartz" + elif 'aqua' not in ws: + _tk_type = "other" + elif 'AppKit' in root.tk.call('winfo', 'server', '.'): + _tk_type = "cocoa" + else: + _tk_type = "carbon" + root.destroy() else: _tk_type = "other" + return def isAquaTk(): """ diff --git a/Misc/NEWS.d/next/IDLE/2022-10-15-21-20-40.gh-issue-97527.otAHJM.rst b/Misc/NEWS.d/next/IDLE/2022-10-15-21-20-40.gh-issue-97527.otAHJM.rst new file mode 100644 index 000000000000..e7fda8974194 --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2022-10-15-21-20-40.gh-issue-97527.otAHJM.rst @@ -0,0 +1,3 @@ +Fix a bug in the previous bugfix that caused IDLE to not start when run with +3.10.8, 3.12.0a1, and at least Microsoft Python 3.10.2288.0 installed +without the Lib/test package. 3.11.0 was never affected. From webhook-mailer at python.org Sun Oct 16 13:05:03 2022 From: webhook-mailer at python.org (gvanrossum) Date: Sun, 16 Oct 2022 17:05:03 -0000 Subject: [Python-checkins] gh-85299: Add note warning about entry point guard for asyncio example (#93457) Message-ID: https://github.com/python/cpython/commit/79fd6ccdbe00ec95e4d33fc24fe76076282a334e commit: 79fd6ccdbe00ec95e4d33fc24fe76076282a334e branch: main author: Stanley <46876382+slateny at users.noreply.github.com> committer: gvanrossum date: 2022-10-16T10:04:43-07:00 summary: gh-85299: Add note warning about entry point guard for asyncio example (#93457) files: M Doc/library/asyncio-eventloop.rst M Doc/library/multiprocessing.rst diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index 2f306b7edb8f..4f12074dd700 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -1253,7 +1253,13 @@ Executing code in thread or process pools pool, cpu_bound) print('custom process pool', result) - asyncio.run(main()) + if __name__ == '__main__': + asyncio.run(main()) + + Note that the entry point guard (``if __name__ == '__main__'``) + is required for option 3 due to the peculiarities of :mod:`multiprocessing`, + which is used by :class:`~concurrent.futures.ProcessPoolExecutor`. + See :ref:`Safe importing of main module `. This method returns a :class:`asyncio.Future` object. diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst index dab115acdc20..551608478067 100644 --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -2954,6 +2954,8 @@ Global variables However, global variables which are just module level constants cause no problems. +.. _multiprocessing-safe-main-import: + Safe importing of main module Make sure that the main module can be safely imported by a new Python From webhook-mailer at python.org Sun Oct 16 13:13:33 2022 From: webhook-mailer at python.org (miss-islington) Date: Sun, 16 Oct 2022 17:13:33 -0000 Subject: [Python-checkins] gh-85299: Add note warning about entry point guard for asyncio example (GH-93457) Message-ID: https://github.com/python/cpython/commit/26307384ffd14d9086ff7aad36ab1fdc408fe6ab commit: 26307384ffd14d9086ff7aad36ab1fdc408fe6ab branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-16T10:13:28-07:00 summary: gh-85299: Add note warning about entry point guard for asyncio example (GH-93457) (cherry picked from commit 79fd6ccdbe00ec95e4d33fc24fe76076282a334e) Co-authored-by: Stanley <46876382+slateny at users.noreply.github.com> files: M Doc/library/asyncio-eventloop.rst M Doc/library/multiprocessing.rst diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index 343672d350ab..0565f902b7bc 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -1140,7 +1140,13 @@ Executing code in thread or process pools pool, cpu_bound) print('custom process pool', result) - asyncio.run(main()) + if __name__ == '__main__': + asyncio.run(main()) + + Note that the entry point guard (``if __name__ == '__main__'``) + is required for option 3 due to the peculiarities of :mod:`multiprocessing`, + which is used by :class:`~concurrent.futures.ProcessPoolExecutor`. + See :ref:`Safe importing of main module `. This method returns a :class:`asyncio.Future` object. diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst index 95e74b9b93d6..f59a61faaa5d 100644 --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -2920,6 +2920,8 @@ Global variables However, global variables which are just module level constants cause no problems. +.. _multiprocessing-safe-main-import: + Safe importing of main module Make sure that the main module can be safely imported by a new Python From webhook-mailer at python.org Sun Oct 16 13:16:53 2022 From: webhook-mailer at python.org (miss-islington) Date: Sun, 16 Oct 2022 17:16:53 -0000 Subject: [Python-checkins] gh-85299: Add note warning about entry point guard for asyncio example (GH-93457) Message-ID: https://github.com/python/cpython/commit/e26c526fd4f483fdaa821850392149d40d41d9ea commit: e26c526fd4f483fdaa821850392149d40d41d9ea branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-16T10:16:48-07:00 summary: gh-85299: Add note warning about entry point guard for asyncio example (GH-93457) (cherry picked from commit 79fd6ccdbe00ec95e4d33fc24fe76076282a334e) Co-authored-by: Stanley <46876382+slateny at users.noreply.github.com> files: M Doc/library/asyncio-eventloop.rst M Doc/library/multiprocessing.rst diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index 8125612de58a..93bca96fff6f 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -1232,7 +1232,13 @@ Executing code in thread or process pools pool, cpu_bound) print('custom process pool', result) - asyncio.run(main()) + if __name__ == '__main__': + asyncio.run(main()) + + Note that the entry point guard (``if __name__ == '__main__'``) + is required for option 3 due to the peculiarities of :mod:`multiprocessing`, + which is used by :class:`~concurrent.futures.ProcessPoolExecutor`. + See :ref:`Safe importing of main module `. This method returns a :class:`asyncio.Future` object. diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst index dab115acdc20..551608478067 100644 --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -2954,6 +2954,8 @@ Global variables However, global variables which are just module level constants cause no problems. +.. _multiprocessing-safe-main-import: + Safe importing of main module Make sure that the main module can be safely imported by a new Python From webhook-mailer at python.org Sun Oct 16 13:43:39 2022 From: webhook-mailer at python.org (nanjekyejoannah) Date: Sun, 16 Oct 2022 17:43:39 -0000 Subject: [Python-checkins] gh-85525: Remove extra row in doc (#98337) Message-ID: https://github.com/python/cpython/commit/5c9302d03a57759225dab9e2d7bdd38e79009441 commit: 5c9302d03a57759225dab9e2d7bdd38e79009441 branch: main author: Joannah Nanjekye <33177550+nanjekyejoannah at users.noreply.github.com> committer: nanjekyejoannah <33177550+nanjekyejoannah at users.noreply.github.com> date: 2022-10-16T13:43:31-04:00 summary: gh-85525: Remove extra row in doc (#98337) * remove extra row * ?? Added by blurb_it. Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> files: A Misc/NEWS.d/next/Documentation/2022-10-16-17-34-45.gh-issue-85525.DvkD0v.rst M Doc/library/sndhdr.rst diff --git a/Doc/library/sndhdr.rst b/Doc/library/sndhdr.rst index 8c5c0bfc617b..fa9323e18dc3 100644 --- a/Doc/library/sndhdr.rst +++ b/Doc/library/sndhdr.rst @@ -68,7 +68,6 @@ from :func:`whathdr`: and :func:`what`: +------------+------------------------------------+ | ``'hcom'`` | HCOM Files | +------------+------------------------------------+ -+------------+------------------------------------+ | ``'sndt'`` | Sndtool Sound Files | +------------+------------------------------------+ | ``'voc'`` | Creative Labs Audio Files | diff --git a/Misc/NEWS.d/next/Documentation/2022-10-16-17-34-45.gh-issue-85525.DvkD0v.rst b/Misc/NEWS.d/next/Documentation/2022-10-16-17-34-45.gh-issue-85525.DvkD0v.rst new file mode 100644 index 000000000000..292e16998acd --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2022-10-16-17-34-45.gh-issue-85525.DvkD0v.rst @@ -0,0 +1 @@ +Remove extra row From webhook-mailer at python.org Sun Oct 16 13:46:04 2022 From: webhook-mailer at python.org (vsajip) Date: Sun, 16 Oct 2022 17:46:04 -0000 Subject: [Python-checkins] =?utf-8?q?=5B3=2E11=5D_gh-98307=3A_Add_docstri?= =?utf-8?q?ng_and_documentation_for_SysLogHandler=2Ecr=E2=80=A6_=28GH-9832?= =?utf-8?q?5=29?= Message-ID: https://github.com/python/cpython/commit/f64e26c04e30a159901a68a5c7d3040944bc5f03 commit: f64e26c04e30a159901a68a5c7d3040944bc5f03 branch: 3.11 author: Vinay Sajip committer: vsajip date: 2022-10-16T18:45:59+01:00 summary: [3.11] gh-98307: Add docstring and documentation for SysLogHandler.cr? (GH-98325) Co-authored-by: C.A.M. Gerlach files: A Misc/NEWS.d/next/Library/2022-10-16-06-18-59.gh-issue-98307.b2_CDu.rst M Doc/library/logging.handlers.rst M Lib/logging/handlers.py diff --git a/Doc/library/logging.handlers.rst b/Doc/library/logging.handlers.rst index 8ab76ab93b60..b64552982787 100644 --- a/Doc/library/logging.handlers.rst +++ b/Doc/library/logging.handlers.rst @@ -650,6 +650,17 @@ supports sending logging messages to a remote or local Unix syslog. Closes the socket to the remote host. + .. method:: createSocket() + + Tries to create a socket and, if it's not a datagram socket, connect it + to the other end. This method is called during handler initialization, + but it's not regarded as an error if the other end isn't listening at + this point - the method will be called again when emitting an event, if + but it's not regarded as an error if the other end isn't listening yet + --- the method will be called again when emitting an event, + if there is no socket at that point. + + .. versionadded:: 3.11 .. method:: emit(record) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py index c6853e0513e0..f5a9760fd496 100644 --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -891,6 +891,13 @@ def _connect_unixsocket(self, address): raise def createSocket(self): + """ + Try to create a socket and, if it's not a datagram socket, connect it + to the other end. This method is called during handler initialization, + but it's not regarded as an error if the other end isn't listening yet + --- the method will be called again when emitting an event, + if there is no socket at that point. + """ address = self.address socktype = self.socktype @@ -898,7 +905,7 @@ def createSocket(self): self.unixsocket = True # Syslog server may be unavailable during handler initialisation. # C's openlog() function also ignores connection errors. - # Moreover, we ignore these errors while logging, so it not worse + # Moreover, we ignore these errors while logging, so it's not worse # to ignore it also here. try: self._connect_unixsocket(address) diff --git a/Misc/NEWS.d/next/Library/2022-10-16-06-18-59.gh-issue-98307.b2_CDu.rst b/Misc/NEWS.d/next/Library/2022-10-16-06-18-59.gh-issue-98307.b2_CDu.rst new file mode 100644 index 000000000000..3fe41d53c980 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-16-06-18-59.gh-issue-98307.b2_CDu.rst @@ -0,0 +1,2 @@ +A :meth:`~logging.handlers.SysLogHandler.createSocket` method was added to +:class:`~logging.handlers.SysLogHandler`. From webhook-mailer at python.org Sun Oct 16 15:00:48 2022 From: webhook-mailer at python.org (jaraco) Date: Sun, 16 Oct 2022 19:00:48 -0000 Subject: [Python-checkins] gh-97930: Merge with importlib_resources 5.9 (GH-97929) Message-ID: https://github.com/python/cpython/commit/cea910ebf14d1bd9d8bc0c8a5046e69ae8f5be17 commit: cea910ebf14d1bd9d8bc0c8a5046e69ae8f5be17 branch: main author: Jason R. Coombs committer: jaraco date: 2022-10-16T15:00:39-04:00 summary: gh-97930: Merge with importlib_resources 5.9 (GH-97929) * Merge with importlib_resources 5.9 * Update changelog files: A Misc/NEWS.d/next/Library/2022-10-05-16-10-24.gh-issue-97930.NPSrzE.rst M Lib/importlib/resources/_common.py M Lib/importlib/resources/abc.py M Lib/importlib/resources/readers.py M Lib/importlib/resources/simple.py M Lib/test/test_importlib/resources/test_reader.py M Lib/test/test_importlib/resources/test_resource.py diff --git a/Lib/importlib/resources/_common.py b/Lib/importlib/resources/_common.py index ca1fa8ab2fe6..8c0be7ee547e 100644 --- a/Lib/importlib/resources/_common.py +++ b/Lib/importlib/resources/_common.py @@ -67,10 +67,14 @@ def from_package(package): @contextlib.contextmanager -def _tempfile(reader, suffix='', - # gh-93353: Keep a reference to call os.remove() in late Python - # finalization. - *, _os_remove=os.remove): +def _tempfile( + reader, + suffix='', + # gh-93353: Keep a reference to call os.remove() in late Python + # finalization. + *, + _os_remove=os.remove, +): # Not using tempfile.NamedTemporaryFile as it leads to deeper 'try' # blocks due to the need to close the temporary file to work on Windows # properly. @@ -89,13 +93,30 @@ def _tempfile(reader, suffix='', pass +def _temp_file(path): + return _tempfile(path.read_bytes, suffix=path.name) + + +def _is_present_dir(path: Traversable) -> bool: + """ + Some Traversables implement ``is_dir()`` to raise an + exception (i.e. ``FileNotFoundError``) when the + directory doesn't exist. This function wraps that call + to always return a boolean and only return True + if there's a dir and it exists. + """ + with contextlib.suppress(FileNotFoundError): + return path.is_dir() + return False + + @functools.singledispatch def as_file(path): """ Given a Traversable object, return that object as a path on the local file system in a context manager. """ - return _tempfile(path.read_bytes, suffix=path.name) + return _temp_dir(path) if _is_present_dir(path) else _temp_file(path) @as_file.register(pathlib.Path) @@ -105,3 +126,34 @@ def _(path): Degenerate behavior for pathlib.Path objects. """ yield path + + + at contextlib.contextmanager +def _temp_path(dir: tempfile.TemporaryDirectory): + """ + Wrap tempfile.TemporyDirectory to return a pathlib object. + """ + with dir as result: + yield pathlib.Path(result) + + + at contextlib.contextmanager +def _temp_dir(path): + """ + Given a traversable dir, recursively replicate the whole tree + to the file system in a context manager. + """ + assert path.is_dir() + with _temp_path(tempfile.TemporaryDirectory()) as temp_dir: + yield _write_contents(temp_dir, path) + + +def _write_contents(target, source): + child = target.joinpath(source.name) + if source.is_dir(): + child.mkdir() + for item in source.iterdir(): + _write_contents(child, item) + else: + child.open('wb').write(source.read_bytes()) + return child diff --git a/Lib/importlib/resources/abc.py b/Lib/importlib/resources/abc.py index 0b7bfdc41582..67c78c078567 100644 --- a/Lib/importlib/resources/abc.py +++ b/Lib/importlib/resources/abc.py @@ -1,6 +1,8 @@ import abc import io +import itertools import os +import pathlib from typing import Any, BinaryIO, Iterable, Iterator, NoReturn, Text, Optional from typing import runtime_checkable, Protocol from typing import Union @@ -53,6 +55,10 @@ def contents(self) -> Iterable[str]: raise FileNotFoundError +class TraversalError(Exception): + pass + + @runtime_checkable class Traversable(Protocol): """ @@ -95,7 +101,6 @@ def is_file(self) -> bool: Return True if self is a file """ - @abc.abstractmethod def joinpath(self, *descendants: StrPath) -> "Traversable": """ Return Traversable resolved with any descendants applied. @@ -104,6 +109,22 @@ def joinpath(self, *descendants: StrPath) -> "Traversable": and each may contain multiple levels separated by ``posixpath.sep`` (``/``). """ + if not descendants: + return self + names = itertools.chain.from_iterable( + path.parts for path in map(pathlib.PurePosixPath, descendants) + ) + target = next(names) + matches = ( + traversable for traversable in self.iterdir() if traversable.name == target + ) + try: + match = next(matches) + except StopIteration: + raise TraversalError( + "Target not found during traversal.", target, list(names) + ) + return match.joinpath(*names) def __truediv__(self, child: StrPath) -> "Traversable": """ diff --git a/Lib/importlib/resources/readers.py b/Lib/importlib/resources/readers.py index b470a2062b2b..80cb320dd8bd 100644 --- a/Lib/importlib/resources/readers.py +++ b/Lib/importlib/resources/readers.py @@ -82,15 +82,13 @@ def is_dir(self): def is_file(self): return False - def joinpath(self, child): - # first try to find child in current paths - for file in self.iterdir(): - if file.name == child: - return file - # if it does not exist, construct it with the first path - return self._paths[0] / child - - __truediv__ = joinpath + def joinpath(self, *descendants): + try: + return super().joinpath(*descendants) + except abc.TraversalError: + # One of the paths did not resolve (a directory does not exist). + # Just return something that will not exist. + return self._paths[0].joinpath(*descendants) def open(self, *args, **kwargs): raise FileNotFoundError(f'{self} is not a file') diff --git a/Lib/importlib/resources/simple.py b/Lib/importlib/resources/simple.py index d0fbf237762c..b85e4694aced 100644 --- a/Lib/importlib/resources/simple.py +++ b/Lib/importlib/resources/simple.py @@ -99,20 +99,6 @@ def iterdir(self): def open(self, *args, **kwargs): raise IsADirectoryError() - @staticmethod - def _flatten(compound_names): - for name in compound_names: - yield from name.split('/') - - def joinpath(self, *descendants): - if not descendants: - return self - names = self._flatten(descendants) - target = next(names) - return next( - traversable for traversable in self.iterdir() if traversable.name == target - ).joinpath(*names) - class TraversableReader(TraversableResources, SimpleReader): """ diff --git a/Lib/test/test_importlib/resources/test_reader.py b/Lib/test/test_importlib/resources/test_reader.py index 9d20c976b825..4fd9e6bbe428 100644 --- a/Lib/test/test_importlib/resources/test_reader.py +++ b/Lib/test/test_importlib/resources/test_reader.py @@ -75,6 +75,11 @@ def test_join_path(self): str(path.joinpath('imaginary'))[len(prefix) + 1 :], os.path.join('namespacedata01', 'imaginary'), ) + self.assertEqual(path.joinpath(), path) + + def test_join_path_compound(self): + path = MultiplexedPath(self.folder) + assert not path.joinpath('imaginary/foo.py').exists() def test_repr(self): self.assertEqual( diff --git a/Lib/test/test_importlib/resources/test_resource.py b/Lib/test/test_importlib/resources/test_resource.py index 1d6df0cc8431..f7e3abbdc805 100644 --- a/Lib/test/test_importlib/resources/test_resource.py +++ b/Lib/test/test_importlib/resources/test_resource.py @@ -111,6 +111,14 @@ def test_submodule_contents_by_name(self): {'__init__.py', 'binary.file'}, ) + def test_as_file_directory(self): + with resources.as_file(resources.files('ziptestdata')) as data: + assert data.name == 'ziptestdata' + assert data.is_dir() + assert data.joinpath('subdirectory').is_dir() + assert len(list(data.iterdir())) + assert not data.parent.exists() + class ResourceFromZipsTest02(util.ZipSetupBase, unittest.TestCase): ZIP_MODULE = zipdata02 # type: ignore diff --git a/Misc/NEWS.d/next/Library/2022-10-05-16-10-24.gh-issue-97930.NPSrzE.rst b/Misc/NEWS.d/next/Library/2022-10-05-16-10-24.gh-issue-97930.NPSrzE.rst new file mode 100644 index 000000000000..860f6adeb201 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-05-16-10-24.gh-issue-97930.NPSrzE.rst @@ -0,0 +1,3 @@ +Apply changes from importlib_resources 5.8 and 5.9: ``Traversable.joinpath`` +provides a concrete implementation. ``as_file`` now supports directories of +resources. From webhook-mailer at python.org Sun Oct 16 15:34:33 2022 From: webhook-mailer at python.org (rhettinger) Date: Sun, 16 Oct 2022 19:34:33 -0000 Subject: [Python-checkins] GH-91415: Mention alphabetical sort ordering in the Sorting HOWTO (GH-98336) Message-ID: https://github.com/python/cpython/commit/ae192178679c532e2c1b2d3b8c0928b77e0fe90e commit: ae192178679c532e2c1b2d3b8c0928b77e0fe90e branch: main author: Raymond Hettinger committer: rhettinger date: 2022-10-16T14:34:25-05:00 summary: GH-91415: Mention alphabetical sort ordering in the Sorting HOWTO (GH-98336) files: M Doc/howto/sorting.rst diff --git a/Doc/howto/sorting.rst b/Doc/howto/sorting.rst index 53cbe01e9214..588e895b04bd 100644 --- a/Doc/howto/sorting.rst +++ b/Doc/howto/sorting.rst @@ -186,8 +186,8 @@ The `Timsort `_ algorithm used in Python does multiple sorts efficiently because it can take advantage of any ordering already present in a dataset. -The Old Way Using Decorate-Sort-Undecorate -========================================== +Decorate-Sort-Undecorate +======================== This idiom is called Decorate-Sort-Undecorate after its three steps: @@ -226,90 +226,36 @@ after Randal L. Schwartz, who popularized it among Perl programmers. Now that Python sorting provides key-functions, this technique is not often needed. +Comparison Functions +==================== -The Old Way Using the *cmp* Parameter -===================================== - -Many constructs given in this HOWTO assume Python 2.4 or later. Before that, -there was no :func:`sorted` builtin and :meth:`list.sort` took no keyword -arguments. Instead, all of the Py2.x versions supported a *cmp* parameter to -handle user specified comparison functions. - -In Py3.0, the *cmp* parameter was removed entirely (as part of a larger effort to -simplify and unify the language, eliminating the conflict between rich -comparisons and the :meth:`__cmp__` magic method). - -In Py2.x, sort allowed an optional function which can be called for doing the -comparisons. That function should take two arguments to be compared and then -return a negative value for less-than, return zero if they are equal, or return -a positive value for greater-than. For example, we can do: - -.. doctest:: - - >>> def numeric_compare(x, y): - ... return x - y - >>> sorted([5, 2, 4, 1, 3], cmp=numeric_compare) # doctest: +SKIP - [1, 2, 3, 4, 5] - -Or you can reverse the order of comparison with: - -.. doctest:: - - >>> def reverse_numeric(x, y): - ... return y - x - >>> sorted([5, 2, 4, 1, 3], cmp=reverse_numeric) # doctest: +SKIP - [5, 4, 3, 2, 1] - -When porting code from Python 2.x to 3.x, the situation can arise when you have -the user supplying a comparison function and you need to convert that to a key -function. The following wrapper makes that easy to do: - -.. testcode:: - - def cmp_to_key(mycmp): - 'Convert a cmp= function into a key= function' - class K: - def __init__(self, obj, *args): - self.obj = obj - def __lt__(self, other): - return mycmp(self.obj, other.obj) < 0 - def __gt__(self, other): - return mycmp(self.obj, other.obj) > 0 - def __eq__(self, other): - return mycmp(self.obj, other.obj) == 0 - def __le__(self, other): - return mycmp(self.obj, other.obj) <= 0 - def __ge__(self, other): - return mycmp(self.obj, other.obj) >= 0 - def __ne__(self, other): - return mycmp(self.obj, other.obj) != 0 - return K - -.. doctest:: - :hide: +Unlike key functions that return an absolute value for sorting, a comparison +function computes the relative ordering for two inputs. - >>> sorted([5, 2, 4, 1, 3], key=cmp_to_key(reverse_numeric)) - [5, 4, 3, 2, 1] +For example, a `balance scale +`_ +compares two samples giving a relative ordering: lighter, equal, or heavier. +Likewise, a comparison function such as ``cmp(a, b)`` will return a negative +value for less-than, zero if the inputs are equal, or a positive value for +greater-than. -To convert to a key function, just wrap the old comparison function: - -.. testsetup:: - - from functools import cmp_to_key - -.. doctest:: +It is common to encounter comparison functions when translating algorithms from +other languages. Also, some libraries provide comparison functions as part of +their API. For example, :func:`locale.strcoll` is a comparison function. - >>> sorted([5, 2, 4, 1, 3], key=cmp_to_key(reverse_numeric)) - [5, 4, 3, 2, 1] +To accommodate those situations, Python provides +:class:`functools.cmp_to_key` to wrap the comparison function +to make it usable as a key function:: -In Python 3.2, the :func:`functools.cmp_to_key` function was added to the -:mod:`functools` module in the standard library. + sorted(words, key=cmp_to_key(strcoll) Odds and Ends ============= * For locale aware sorting, use :func:`locale.strxfrm` for a key function or - :func:`locale.strcoll` for a comparison function. + :func:`locale.strcoll` for a comparison function. This is necessary + because "alphabetical" sort orderings can vary across cultures even + if the underlying alphabet is the same. * The *reverse* parameter still maintains sort stability (so that records with equal keys retain the original order). Interestingly, that effect can be From webhook-mailer at python.org Sun Oct 16 15:41:46 2022 From: webhook-mailer at python.org (miss-islington) Date: Sun, 16 Oct 2022 19:41:46 -0000 Subject: [Python-checkins] GH-91415: Mention alphabetical sort ordering in the Sorting HOWTO (GH-98336) Message-ID: https://github.com/python/cpython/commit/211b8193cac5d996406f7140e4162f1383154c89 commit: 211b8193cac5d996406f7140e4162f1383154c89 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-16T12:41:41-07:00 summary: GH-91415: Mention alphabetical sort ordering in the Sorting HOWTO (GH-98336) (cherry picked from commit ae192178679c532e2c1b2d3b8c0928b77e0fe90e) Co-authored-by: Raymond Hettinger files: M Doc/howto/sorting.rst diff --git a/Doc/howto/sorting.rst b/Doc/howto/sorting.rst index 53cbe01e9214..588e895b04bd 100644 --- a/Doc/howto/sorting.rst +++ b/Doc/howto/sorting.rst @@ -186,8 +186,8 @@ The `Timsort `_ algorithm used in Python does multiple sorts efficiently because it can take advantage of any ordering already present in a dataset. -The Old Way Using Decorate-Sort-Undecorate -========================================== +Decorate-Sort-Undecorate +======================== This idiom is called Decorate-Sort-Undecorate after its three steps: @@ -226,90 +226,36 @@ after Randal L. Schwartz, who popularized it among Perl programmers. Now that Python sorting provides key-functions, this technique is not often needed. +Comparison Functions +==================== -The Old Way Using the *cmp* Parameter -===================================== - -Many constructs given in this HOWTO assume Python 2.4 or later. Before that, -there was no :func:`sorted` builtin and :meth:`list.sort` took no keyword -arguments. Instead, all of the Py2.x versions supported a *cmp* parameter to -handle user specified comparison functions. - -In Py3.0, the *cmp* parameter was removed entirely (as part of a larger effort to -simplify and unify the language, eliminating the conflict between rich -comparisons and the :meth:`__cmp__` magic method). - -In Py2.x, sort allowed an optional function which can be called for doing the -comparisons. That function should take two arguments to be compared and then -return a negative value for less-than, return zero if they are equal, or return -a positive value for greater-than. For example, we can do: - -.. doctest:: - - >>> def numeric_compare(x, y): - ... return x - y - >>> sorted([5, 2, 4, 1, 3], cmp=numeric_compare) # doctest: +SKIP - [1, 2, 3, 4, 5] - -Or you can reverse the order of comparison with: - -.. doctest:: - - >>> def reverse_numeric(x, y): - ... return y - x - >>> sorted([5, 2, 4, 1, 3], cmp=reverse_numeric) # doctest: +SKIP - [5, 4, 3, 2, 1] - -When porting code from Python 2.x to 3.x, the situation can arise when you have -the user supplying a comparison function and you need to convert that to a key -function. The following wrapper makes that easy to do: - -.. testcode:: - - def cmp_to_key(mycmp): - 'Convert a cmp= function into a key= function' - class K: - def __init__(self, obj, *args): - self.obj = obj - def __lt__(self, other): - return mycmp(self.obj, other.obj) < 0 - def __gt__(self, other): - return mycmp(self.obj, other.obj) > 0 - def __eq__(self, other): - return mycmp(self.obj, other.obj) == 0 - def __le__(self, other): - return mycmp(self.obj, other.obj) <= 0 - def __ge__(self, other): - return mycmp(self.obj, other.obj) >= 0 - def __ne__(self, other): - return mycmp(self.obj, other.obj) != 0 - return K - -.. doctest:: - :hide: +Unlike key functions that return an absolute value for sorting, a comparison +function computes the relative ordering for two inputs. - >>> sorted([5, 2, 4, 1, 3], key=cmp_to_key(reverse_numeric)) - [5, 4, 3, 2, 1] +For example, a `balance scale +`_ +compares two samples giving a relative ordering: lighter, equal, or heavier. +Likewise, a comparison function such as ``cmp(a, b)`` will return a negative +value for less-than, zero if the inputs are equal, or a positive value for +greater-than. -To convert to a key function, just wrap the old comparison function: - -.. testsetup:: - - from functools import cmp_to_key - -.. doctest:: +It is common to encounter comparison functions when translating algorithms from +other languages. Also, some libraries provide comparison functions as part of +their API. For example, :func:`locale.strcoll` is a comparison function. - >>> sorted([5, 2, 4, 1, 3], key=cmp_to_key(reverse_numeric)) - [5, 4, 3, 2, 1] +To accommodate those situations, Python provides +:class:`functools.cmp_to_key` to wrap the comparison function +to make it usable as a key function:: -In Python 3.2, the :func:`functools.cmp_to_key` function was added to the -:mod:`functools` module in the standard library. + sorted(words, key=cmp_to_key(strcoll) Odds and Ends ============= * For locale aware sorting, use :func:`locale.strxfrm` for a key function or - :func:`locale.strcoll` for a comparison function. + :func:`locale.strcoll` for a comparison function. This is necessary + because "alphabetical" sort orderings can vary across cultures even + if the underlying alphabet is the same. * The *reverse* parameter still maintains sort stability (so that records with equal keys retain the original order). Interestingly, that effect can be From webhook-mailer at python.org Sun Oct 16 21:43:32 2022 From: webhook-mailer at python.org (gpshead) Date: Mon, 17 Oct 2022 01:43:32 -0000 Subject: [Python-checkins] gh-95913: Forward-port int/str security change to 3.11 What's New in main (#98344) Message-ID: https://github.com/python/cpython/commit/bb38b39b339191c5fc001c8fbfbc3037c13bc7bb commit: bb38b39b339191c5fc001c8fbfbc3037c13bc7bb branch: main author: C.A.M. Gerlach committer: gpshead date: 2022-10-16T18:43:13-07:00 summary: gh-95913: Forward-port int/str security change to 3.11 What's New in main (#98344) Add int/str security change from issue gh-95778 PRs gh-96499 / gh-95800 Co-authored-by: Gregory P. Smith [Google] files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 56a35f4e4802..73e23a1a9e7f 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -530,6 +530,17 @@ Other CPython Implementation Changes and with the new :option:`--help-all`. (Contributed by ?ric Araujo in :issue:`46142`.) +* Converting between :class:`int` and :class:`str` in bases other than 2 + (binary), 4, 8 (octal), 16 (hexadecimal), or 32 such as base 10 (decimal) + now raises a :exc:`ValueError` if the number of digits in string form is + above a limit to avoid potential denial of service attacks due to the + algorithmic complexity. This is a mitigation for `CVE-2020-10735 + `_. + This limit can be configured or disabled by environment variable, command + line flag, or :mod:`sys` APIs. See the :ref:`integer string conversion + length limitation ` documentation. The default limit + is 4300 digits in string form. + .. _whatsnew311-new-modules: From webhook-mailer at python.org Sun Oct 16 22:11:14 2022 From: webhook-mailer at python.org (gpshead) Date: Mon, 17 Oct 2022 02:11:14 -0000 Subject: [Python-checkins] gh-95534: Improve gzip reading speed by 10% (#97664) Message-ID: https://github.com/python/cpython/commit/eae7dad40255bad42e4abce53ff8143dcbc66af5 commit: eae7dad40255bad42e4abce53ff8143dcbc66af5 branch: main author: Ruben Vorderman committer: gpshead date: 2022-10-16T19:10:58-07:00 summary: gh-95534: Improve gzip reading speed by 10% (#97664) Change summary: + There is now a `gzip.READ_BUFFER_SIZE` constant that is 128KB. Other programs that read in 128KB chunks: pigz and cat. So this seems best practice among good programs. Also it is faster than 8 kb chunks. + a zlib._ZlibDecompressor was added. This is the _bz2.BZ2Decompressor ported to zlib. Since the zlib.Decompress object is better for in-memory decompression, the _ZlibDecompressor is hidden. It only makes sense in file decompression, and that is already implemented now in the gzip library. No need to bother the users with this. + The ZlibDecompressor uses the older Cpython arrange_output_buffer functions, as those are faster and more appropriate for the use case. + GzipFile.read has been optimized. There is no longer a `unconsumed_tail` member to write back to padded file. This is instead handled by the ZlibDecompressor itself, which has an internal buffer. `_add_read_data` has been inlined, as it was just two calls. EDIT: While I am adding improvements anyway, I figured I could add another one-liner optimization now to the python -m gzip application. That read chunks in io.DEFAULT_BUFFER_SIZE previously, but has been updated now to use READ_BUFFER_SIZE chunks. files: A Misc/NEWS.d/next/Library/2022-09-30-09-22-37.gh-issue-95534.ndEfPj.rst M Lib/gzip.py M Lib/test/test_zlib.py M Modules/clinic/zlibmodule.c.h M Modules/zlibmodule.c diff --git a/Lib/gzip.py b/Lib/gzip.py index 8edcda4493c8..75c6ddc3f2cf 100644 --- a/Lib/gzip.py +++ b/Lib/gzip.py @@ -21,6 +21,8 @@ _COMPRESS_LEVEL_TRADEOFF = 6 _COMPRESS_LEVEL_BEST = 9 +READ_BUFFER_SIZE = 128 * 1024 + def open(filename, mode="rb", compresslevel=_COMPRESS_LEVEL_BEST, encoding=None, errors=None, newline=None): @@ -446,7 +448,7 @@ def _read_gzip_header(fp): class _GzipReader(_compression.DecompressReader): def __init__(self, fp): - super().__init__(_PaddedFile(fp), zlib.decompressobj, + super().__init__(_PaddedFile(fp), zlib._ZlibDecompressor, wbits=-zlib.MAX_WBITS) # Set flag indicating start of a new member self._new_member = True @@ -494,12 +496,13 @@ def read(self, size=-1): self._new_member = False # Read a chunk of data from the file - buf = self._fp.read(io.DEFAULT_BUFFER_SIZE) + if self._decompressor.needs_input: + buf = self._fp.read(READ_BUFFER_SIZE) + uncompress = self._decompressor.decompress(buf, size) + else: + uncompress = self._decompressor.decompress(b"", size) - uncompress = self._decompressor.decompress(buf, size) - if self._decompressor.unconsumed_tail != b"": - self._fp.prepend(self._decompressor.unconsumed_tail) - elif self._decompressor.unused_data != b"": + if self._decompressor.unused_data != b"": # Prepend the already read bytes to the fileobj so they can # be seen by _read_eof() and _read_gzip_header() self._fp.prepend(self._decompressor.unused_data) @@ -510,14 +513,11 @@ def read(self, size=-1): raise EOFError("Compressed file ended before the " "end-of-stream marker was reached") - self._add_read_data( uncompress ) + self._crc = zlib.crc32(uncompress, self._crc) + self._stream_size += len(uncompress) self._pos += len(uncompress) return uncompress - def _add_read_data(self, data): - self._crc = zlib.crc32(data, self._crc) - self._stream_size = self._stream_size + len(data) - def _read_eof(self): # We've read to the end of the file # We check that the computed CRC and size of the @@ -647,7 +647,7 @@ def main(): f = builtins.open(arg, "rb") g = open(arg + ".gz", "wb") while True: - chunk = f.read(io.DEFAULT_BUFFER_SIZE) + chunk = f.read(READ_BUFFER_SIZE) if not chunk: break g.write(chunk) diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py index f20aad051da9..ae54f6c46891 100644 --- a/Lib/test/test_zlib.py +++ b/Lib/test/test_zlib.py @@ -944,6 +944,173 @@ def choose_lines(source, number, seed=None, generator=random): """ +class ZlibDecompressorTest(): + # Test adopted from test_bz2.py + TEXT = HAMLET_SCENE + DATA = zlib.compress(HAMLET_SCENE) + BAD_DATA = b"Not a valid deflate block" + def test_Constructor(self): + self.assertRaises(TypeError, zlib._ZlibDecompressor, 42) + + def testDecompress(self): + zlibd = zlib._ZlibDecompressor() + self.assertRaises(TypeError, zlibd.decompress) + text = zlibd.decompress(self.DATA) + self.assertEqual(text, self.TEXT) + + def testDecompressChunks10(self): + zlibd = zlib._ZlibDecompressor() + text = b'' + n = 0 + while True: + str = self.DATA[n*10:(n+1)*10] + if not str: + break + text += zlibd.decompress(str) + n += 1 + self.assertEqual(text, self.TEXT) + + def testDecompressUnusedData(self): + zlibd = zlib._ZlibDecompressor() + unused_data = b"this is unused data" + text = zlibd.decompress(self.DATA+unused_data) + self.assertEqual(text, self.TEXT) + self.assertEqual(zlibd.unused_data, unused_data) + + def testEOFError(self): + zlibd = zlib._ZlibDecompressor() + text = zlibd.decompress(self.DATA) + self.assertRaises(EOFError, zlibd.decompress, b"anything") + self.assertRaises(EOFError, zlibd.decompress, b"") + + @support.skip_if_pgo_task + @bigmemtest(size=_4G + 100, memuse=3.3) + def testDecompress4G(self, size): + # "Test zlib._ZlibDecompressor.decompress() with >4GiB input" + blocksize = 10 * 1024 * 1024 + block = random.randbytes(blocksize) + try: + data = block * (size // blocksize + 1) + compressed = zlib.compress(data) + zlibd = zlib._ZlibDecompressor() + decompressed = zlibd.decompress(compressed) + self.assertTrue(decompressed == data) + finally: + data = None + compressed = None + decompressed = None + + def testPickle(self): + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.assertRaises(TypeError): + pickle.dumps(zlib._ZlibDecompressor(), proto) + + def testDecompressorChunksMaxsize(self): + zlibd = zlib._ZlibDecompressor() + max_length = 100 + out = [] + + # Feed some input + len_ = len(self.BIG_DATA) - 64 + out.append(zlibd.decompress(self.BIG_DATA[:len_], + max_length=max_length)) + self.assertFalse(zlibd.needs_input) + self.assertEqual(len(out[-1]), max_length) + + # Retrieve more data without providing more input + out.append(zlibd.decompress(b'', max_length=max_length)) + self.assertFalse(zlibd.needs_input) + self.assertEqual(len(out[-1]), max_length) + + # Retrieve more data while providing more input + out.append(zlibd.decompress(self.BIG_DATA[len_:], + max_length=max_length)) + self.assertLessEqual(len(out[-1]), max_length) + + # Retrieve remaining uncompressed data + while not zlibd.eof: + out.append(zlibd.decompress(b'', max_length=max_length)) + self.assertLessEqual(len(out[-1]), max_length) + + out = b"".join(out) + self.assertEqual(out, self.BIG_TEXT) + self.assertEqual(zlibd.unused_data, b"") + + def test_decompressor_inputbuf_1(self): + # Test reusing input buffer after moving existing + # contents to beginning + zlibd = zlib._ZlibDecompressor() + out = [] + + # Create input buffer and fill it + self.assertEqual(zlibd.decompress(self.DATA[:100], + max_length=0), b'') + + # Retrieve some results, freeing capacity at beginning + # of input buffer + out.append(zlibd.decompress(b'', 2)) + + # Add more data that fits into input buffer after + # moving existing data to beginning + out.append(zlibd.decompress(self.DATA[100:105], 15)) + + # Decompress rest of data + out.append(zlibd.decompress(self.DATA[105:])) + self.assertEqual(b''.join(out), self.TEXT) + + def test_decompressor_inputbuf_2(self): + # Test reusing input buffer by appending data at the + # end right away + zlibd = zlib._ZlibDecompressor() + out = [] + + # Create input buffer and empty it + self.assertEqual(zlibd.decompress(self.DATA[:200], + max_length=0), b'') + out.append(zlibd.decompress(b'')) + + # Fill buffer with new data + out.append(zlibd.decompress(self.DATA[200:280], 2)) + + # Append some more data, not enough to require resize + out.append(zlibd.decompress(self.DATA[280:300], 2)) + + # Decompress rest of data + out.append(zlibd.decompress(self.DATA[300:])) + self.assertEqual(b''.join(out), self.TEXT) + + def test_decompressor_inputbuf_3(self): + # Test reusing input buffer after extending it + + zlibd = zlib._ZlibDecompressor() + out = [] + + # Create almost full input buffer + out.append(zlibd.decompress(self.DATA[:200], 5)) + + # Add even more data to it, requiring resize + out.append(zlibd.decompress(self.DATA[200:300], 5)) + + # Decompress rest of data + out.append(zlibd.decompress(self.DATA[300:])) + self.assertEqual(b''.join(out), self.TEXT) + + def test_failure(self): + zlibd = zlib._ZlibDecompressor() + self.assertRaises(Exception, zlibd.decompress, self.BAD_DATA * 30) + # Previously, a second call could crash due to internal inconsistency + self.assertRaises(Exception, zlibd.decompress, self.BAD_DATA * 30) + + @support.refcount_test + def test_refleaks_in___init__(self): + gettotalrefcount = support.get_attribute(sys, 'gettotalrefcount') + zlibd = zlib._ZlibDecompressor() + refs_before = gettotalrefcount() + for i in range(100): + zlibd.__init__() + self.assertAlmostEqual(gettotalrefcount() - refs_before, 0, delta=10) + + class CustomInt: def __index__(self): return 100 diff --git a/Misc/NEWS.d/next/Library/2022-09-30-09-22-37.gh-issue-95534.ndEfPj.rst b/Misc/NEWS.d/next/Library/2022-09-30-09-22-37.gh-issue-95534.ndEfPj.rst new file mode 100644 index 000000000000..131d4ed69991 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-09-30-09-22-37.gh-issue-95534.ndEfPj.rst @@ -0,0 +1 @@ +:meth:`gzip.GzipFile.read` reads 10% faster. diff --git a/Modules/clinic/zlibmodule.c.h b/Modules/clinic/zlibmodule.c.h index a04b954a57f3..65412b2435ad 100644 --- a/Modules/clinic/zlibmodule.c.h +++ b/Modules/clinic/zlibmodule.c.h @@ -897,6 +897,104 @@ zlib_Decompress_flush(compobject *self, PyTypeObject *cls, PyObject *const *args return return_value; } +PyDoc_STRVAR(zlib_ZlibDecompressor_decompress__doc__, +"decompress($self, /, data, max_length=-1)\n" +"--\n" +"\n" +"Decompress *data*, returning uncompressed data as bytes.\n" +"\n" +"If *max_length* is nonnegative, returns at most *max_length* bytes of\n" +"decompressed data. If this limit is reached and further output can be\n" +"produced, *self.needs_input* will be set to ``False``. In this case, the next\n" +"call to *decompress()* may provide *data* as b\'\' to obtain more of the output.\n" +"\n" +"If all of the input data was decompressed and returned (either because this\n" +"was less than *max_length* bytes, or because *max_length* was negative),\n" +"*self.needs_input* will be set to True.\n" +"\n" +"Attempting to decompress data after the end of stream is reached raises an\n" +"EOFError. Any data found after the end of the stream is ignored and saved in\n" +"the unused_data attribute."); + +#define ZLIB_ZLIBDECOMPRESSOR_DECOMPRESS_METHODDEF \ + {"decompress", _PyCFunction_CAST(zlib_ZlibDecompressor_decompress), METH_FASTCALL|METH_KEYWORDS, zlib_ZlibDecompressor_decompress__doc__}, + +static PyObject * +zlib_ZlibDecompressor_decompress_impl(ZlibDecompressor *self, + Py_buffer *data, Py_ssize_t max_length); + +static PyObject * +zlib_ZlibDecompressor_decompress(ZlibDecompressor *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(data), &_Py_ID(max_length), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"data", "max_length", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "decompress", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; + Py_buffer data = {NULL, NULL}; + Py_ssize_t max_length = -1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 2, 0, argsbuf); + if (!args) { + goto exit; + } + if (PyObject_GetBuffer(args[0], &data, PyBUF_SIMPLE) != 0) { + goto exit; + } + if (!PyBuffer_IsContiguous(&data, 'C')) { + _PyArg_BadArgument("decompress", "argument 'data'", "contiguous buffer", args[0]); + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + { + Py_ssize_t ival = -1; + PyObject *iobj = _PyNumber_Index(args[1]); + if (iobj != NULL) { + ival = PyLong_AsSsize_t(iobj); + Py_DECREF(iobj); + } + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + max_length = ival; + } +skip_optional_pos: + return_value = zlib_ZlibDecompressor_decompress_impl(self, &data, max_length); + +exit: + /* Cleanup for data */ + if (data.obj) { + PyBuffer_Release(&data); + } + + return return_value; +} + PyDoc_STRVAR(zlib_adler32__doc__, "adler32($module, data, value=1, /)\n" "--\n" @@ -1031,4 +1129,4 @@ zlib_crc32(PyObject *module, PyObject *const *args, Py_ssize_t nargs) #ifndef ZLIB_DECOMPRESS___DEEPCOPY___METHODDEF #define ZLIB_DECOMPRESS___DEEPCOPY___METHODDEF #endif /* !defined(ZLIB_DECOMPRESS___DEEPCOPY___METHODDEF) */ -/*[clinic end generated code: output=9e5f9911d0c273e1 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=57ff7b511ab23132 input=a9049054013a1b77]*/ diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c index 2fc39a3bd562..88d2dd556353 100644 --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -8,6 +8,11 @@ #include "Python.h" #include "structmember.h" // PyMemberDef #include "zlib.h" +#include "stdbool.h" + +#if defined(ZLIB_VERNUM) && ZLIB_VERNUM < 0x1221 +#error "At least zlib version 1.2.2.1 is required" +#endif // Blocks output buffer wrappers #include "pycore_blocks_output_buffer.h" @@ -171,9 +176,6 @@ OutputBuffer_WindowOnError(_BlocksOutputBuffer *buffer, _Uint32Window *window) } } while (0) #define LEAVE_ZLIB(obj) PyThread_release_lock((obj)->lock); -#if defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1221 -# define AT_LEAST_ZLIB_1_2_2_1 -#endif /* The following parameters are copied from zutil.h, version 0.95 */ #define DEFLATED 8 @@ -185,12 +187,14 @@ OutputBuffer_WindowOnError(_BlocksOutputBuffer *buffer, _Uint32Window *window) /* Initial buffer size. */ #define DEF_BUF_SIZE (16*1024) +#define DEF_MAX_INITIAL_BUF_SIZE (16 * 1024 * 1024) static PyModuleDef zlibmodule; typedef struct { PyTypeObject *Comptype; PyTypeObject *Decomptype; + PyTypeObject *ZlibDecompressorType; PyObject *ZlibError; } zlibstate; @@ -209,7 +213,7 @@ typedef struct PyObject *unused_data; PyObject *unconsumed_tail; char eof; - int is_initialised; + bool is_initialised; PyObject *zdict; PyThread_type_lock lock; } compobject; @@ -320,7 +324,7 @@ static PyObject * zlib_compress_impl(PyObject *module, Py_buffer *data, int level, int wbits) /*[clinic end generated code: output=46bd152fadd66df2 input=c4d06ee5782a7e3f]*/ { - PyObject *RetVal; + PyObject *return_value; int flush; z_stream zst; _BlocksOutputBuffer buffer = {.list = NULL}; @@ -387,11 +391,11 @@ zlib_compress_impl(PyObject *module, Py_buffer *data, int level, int wbits) err = deflateEnd(&zst); if (err == Z_OK) { - RetVal = OutputBuffer_Finish(&buffer, zst.avail_out); - if (RetVal == NULL) { + return_value = OutputBuffer_Finish(&buffer, zst.avail_out); + if (return_value == NULL) { goto error; } - return RetVal; + return return_value; } else zlib_error(state, zst, err, "while finishing compression"); @@ -419,7 +423,7 @@ zlib_decompress_impl(PyObject *module, Py_buffer *data, int wbits, Py_ssize_t bufsize) /*[clinic end generated code: output=77c7e35111dc8c42 input=a9ac17beff1f893f]*/ { - PyObject *RetVal; + PyObject *return_value; Byte *ibuf; Py_ssize_t ibuflen; int err, flush; @@ -514,9 +518,9 @@ zlib_decompress_impl(PyObject *module, Py_buffer *data, int wbits, goto error; } - RetVal = OutputBuffer_WindowFinish(&buffer, &window, zst.avail_out); - if (RetVal != NULL) { - return RetVal; + return_value = OutputBuffer_WindowFinish(&buffer, &window, zst.avail_out); + if (return_value != NULL) { + return return_value; } error: @@ -675,18 +679,10 @@ zlib_decompressobj_impl(PyObject *module, int wbits, PyObject *zdict) case Z_OK: self->is_initialised = 1; if (self->zdict != NULL && wbits < 0) { -#ifdef AT_LEAST_ZLIB_1_2_2_1 if (set_inflate_zdict(state, self) < 0) { Py_DECREF(self); return NULL; } -#else - PyErr_Format(state->ZlibError, - "zlib version %s does not allow raw inflate with dictionary", - ZLIB_VERSION); - Py_DECREF(self); - return NULL; -#endif } return (PyObject *)self; case Z_STREAM_ERROR: @@ -753,7 +749,7 @@ zlib_Compress_compress_impl(compobject *self, PyTypeObject *cls, Py_buffer *data) /*[clinic end generated code: output=6731b3f0ff357ca6 input=04d00f65ab01d260]*/ { - PyObject *RetVal; + PyObject *return_value; int err; _BlocksOutputBuffer buffer = {.list = NULL}; zlibstate *state = PyType_GetModuleState(cls); @@ -791,17 +787,17 @@ zlib_Compress_compress_impl(compobject *self, PyTypeObject *cls, } while (ibuflen != 0); - RetVal = OutputBuffer_Finish(&buffer, self->zst.avail_out); - if (RetVal != NULL) { + return_value = OutputBuffer_Finish(&buffer, self->zst.avail_out); + if (return_value != NULL) { goto success; } error: OutputBuffer_OnError(&buffer); - RetVal = NULL; + return_value = NULL; success: LEAVE_ZLIB(self); - return RetVal; + return return_value; } /* Helper for objdecompress() and flush(). Saves any unconsumed input data in @@ -875,7 +871,7 @@ zlib_Decompress_decompress_impl(compobject *self, PyTypeObject *cls, { int err = Z_OK; Py_ssize_t ibuflen; - PyObject *RetVal; + PyObject *return_value; _BlocksOutputBuffer buffer = {.list = NULL}; PyObject *module = PyType_GetModule(cls); @@ -953,17 +949,17 @@ zlib_Decompress_decompress_impl(compobject *self, PyTypeObject *cls, goto abort; } - RetVal = OutputBuffer_Finish(&buffer, self->zst.avail_out); - if (RetVal != NULL) { + return_value = OutputBuffer_Finish(&buffer, self->zst.avail_out); + if (return_value != NULL) { goto success; } abort: OutputBuffer_OnError(&buffer); - RetVal = NULL; + return_value = NULL; success: LEAVE_ZLIB(self); - return RetVal; + return return_value; } /*[clinic input] @@ -985,7 +981,7 @@ zlib_Compress_flush_impl(compobject *self, PyTypeObject *cls, int mode) /*[clinic end generated code: output=c7efd13efd62add2 input=286146e29442eb6c]*/ { int err; - PyObject *RetVal; + PyObject *return_value; _BlocksOutputBuffer buffer = {.list = NULL}; zlibstate *state = PyType_GetModuleState(cls); @@ -1042,17 +1038,17 @@ zlib_Compress_flush_impl(compobject *self, PyTypeObject *cls, int mode) goto error; } - RetVal = OutputBuffer_Finish(&buffer, self->zst.avail_out); - if (RetVal != NULL) { + return_value = OutputBuffer_Finish(&buffer, self->zst.avail_out); + if (return_value != NULL) { goto success; } error: OutputBuffer_OnError(&buffer); - RetVal = NULL; + return_value = NULL; success: LEAVE_ZLIB(self); - return RetVal; + return return_value; } #ifdef HAVE_ZLIB_COPY @@ -1071,14 +1067,14 @@ zlib_Compress_copy_impl(compobject *self, PyTypeObject *cls) { zlibstate *state = PyType_GetModuleState(cls); - compobject *retval = newcompobject(state->Comptype); - if (!retval) return NULL; + compobject *return_value = newcompobject(state->Comptype); + if (!return_value) return NULL; /* Copy the zstream state * We use ENTER_ZLIB / LEAVE_ZLIB to make this thread-safe */ ENTER_ZLIB(self); - int err = deflateCopy(&retval->zst, &self->zst); + int err = deflateCopy(&return_value->zst, &self->zst); switch (err) { case Z_OK: break; @@ -1094,22 +1090,22 @@ zlib_Compress_copy_impl(compobject *self, PyTypeObject *cls) goto error; } Py_INCREF(self->unused_data); - Py_XSETREF(retval->unused_data, self->unused_data); + Py_XSETREF(return_value->unused_data, self->unused_data); Py_INCREF(self->unconsumed_tail); - Py_XSETREF(retval->unconsumed_tail, self->unconsumed_tail); + Py_XSETREF(return_value->unconsumed_tail, self->unconsumed_tail); Py_XINCREF(self->zdict); - Py_XSETREF(retval->zdict, self->zdict); - retval->eof = self->eof; + Py_XSETREF(return_value->zdict, self->zdict); + return_value->eof = self->eof; /* Mark it as being initialized */ - retval->is_initialised = 1; + return_value->is_initialised = 1; LEAVE_ZLIB(self); - return (PyObject *)retval; + return (PyObject *)return_value; error: LEAVE_ZLIB(self); - Py_XDECREF(retval); + Py_XDECREF(return_value); return NULL; } @@ -1158,14 +1154,14 @@ zlib_Decompress_copy_impl(compobject *self, PyTypeObject *cls) { zlibstate *state = PyType_GetModuleState(cls); - compobject *retval = newcompobject(state->Decomptype); - if (!retval) return NULL; + compobject *return_value = newcompobject(state->Decomptype); + if (!return_value) return NULL; /* Copy the zstream state * We use ENTER_ZLIB / LEAVE_ZLIB to make this thread-safe */ ENTER_ZLIB(self); - int err = inflateCopy(&retval->zst, &self->zst); + int err = inflateCopy(&return_value->zst, &self->zst); switch (err) { case Z_OK: break; @@ -1182,22 +1178,22 @@ zlib_Decompress_copy_impl(compobject *self, PyTypeObject *cls) } Py_INCREF(self->unused_data); - Py_XSETREF(retval->unused_data, self->unused_data); + Py_XSETREF(return_value->unused_data, self->unused_data); Py_INCREF(self->unconsumed_tail); - Py_XSETREF(retval->unconsumed_tail, self->unconsumed_tail); + Py_XSETREF(return_value->unconsumed_tail, self->unconsumed_tail); Py_XINCREF(self->zdict); - Py_XSETREF(retval->zdict, self->zdict); - retval->eof = self->eof; + Py_XSETREF(return_value->zdict, self->zdict); + return_value->eof = self->eof; /* Mark it as being initialized */ - retval->is_initialised = 1; + return_value->is_initialised = 1; LEAVE_ZLIB(self); - return (PyObject *)retval; + return (PyObject *)return_value; error: LEAVE_ZLIB(self); - Py_XDECREF(retval); + Py_XDECREF(return_value); return NULL; } @@ -1252,7 +1248,7 @@ zlib_Decompress_flush_impl(compobject *self, PyTypeObject *cls, { int err, flush; Py_buffer data; - PyObject *RetVal; + PyObject *return_value; Py_ssize_t ibuflen; _BlocksOutputBuffer buffer = {.list = NULL}; _Uint32Window window; // output buffer's UINT32_MAX sliding window @@ -1306,13 +1302,6 @@ zlib_Decompress_flush_impl(compobject *self, PyTypeObject *cls, case Z_STREAM_END: break; default: - if (err == Z_NEED_DICT && self->zdict != NULL) { - if (set_inflate_zdict(state, self) < 0) { - goto abort; - } - else - break; - } goto save; } @@ -1336,18 +1325,475 @@ zlib_Decompress_flush_impl(compobject *self, PyTypeObject *cls, } } - RetVal = OutputBuffer_WindowFinish(&buffer, &window, self->zst.avail_out); - if (RetVal != NULL) { + return_value = OutputBuffer_WindowFinish(&buffer, &window, self->zst.avail_out); + if (return_value != NULL) { goto success; } abort: OutputBuffer_WindowOnError(&buffer, &window); - RetVal = NULL; + return_value = NULL; success: PyBuffer_Release(&data); LEAVE_ZLIB(self); - return RetVal; + return return_value; +} + + +typedef struct { + PyObject_HEAD + z_stream zst; + PyObject *zdict; + PyThread_type_lock lock; + PyObject *unused_data; + uint8_t *input_buffer; + Py_ssize_t input_buffer_size; + /* zst>avail_in is only 32 bit, so we store the true length + separately. Conversion and looping is encapsulated in + decompress_buf() */ + Py_ssize_t avail_in_real; + bool is_initialised; + char eof; /* T_BOOL expects a char */ + char needs_input; +} ZlibDecompressor; + +/*[clinic input] +class zlib.ZlibDecompressor "ZlibDecompressor *" "&ZlibDecompressorType" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=0658178ab94645df]*/ + +static void +ZlibDecompressor_dealloc(ZlibDecompressor *self) +{ + PyObject *type = (PyObject *)Py_TYPE(self); + PyThread_free_lock(self->lock); + if (self->is_initialised) { + inflateEnd(&self->zst); + } + PyMem_Free(self->input_buffer); + Py_CLEAR(self->unused_data); + Py_CLEAR(self->zdict); + PyObject_Free(self); + Py_DECREF(type); +} + +static int +set_inflate_zdict_ZlibDecompressor(zlibstate *state, ZlibDecompressor *self) +{ + Py_buffer zdict_buf; + if (PyObject_GetBuffer(self->zdict, &zdict_buf, PyBUF_SIMPLE) == -1) { + return -1; + } + if ((size_t)zdict_buf.len > UINT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "zdict length does not fit in an unsigned int"); + PyBuffer_Release(&zdict_buf); + return -1; + } + int err; + err = inflateSetDictionary(&self->zst, + zdict_buf.buf, (unsigned int)zdict_buf.len); + PyBuffer_Release(&zdict_buf); + if (err != Z_OK) { + zlib_error(state, self->zst, err, "while setting zdict"); + return -1; + } + return 0; +} + +static Py_ssize_t +arrange_output_buffer_with_maximum(uint32_t *avail_out, + uint8_t **next_out, + PyObject **buffer, + Py_ssize_t length, + Py_ssize_t max_length) +{ + Py_ssize_t occupied; + + if (*buffer == NULL) { + if (!(*buffer = PyBytes_FromStringAndSize(NULL, length))) + return -1; + occupied = 0; + } + else { + occupied = *next_out - (uint8_t *)PyBytes_AS_STRING(*buffer); + + if (length == occupied) { + Py_ssize_t new_length; + assert(length <= max_length); + /* can not scale the buffer over max_length */ + if (length == max_length) + return -2; + if (length <= (max_length >> 1)) + new_length = length << 1; + else + new_length = max_length; + if (_PyBytes_Resize(buffer, new_length) < 0) + return -1; + length = new_length; + } + } + + *avail_out = (uint32_t)Py_MIN((size_t)(length - occupied), UINT32_MAX); + *next_out = (uint8_t *)PyBytes_AS_STRING(*buffer) + occupied; + + return length; +} + +static inline Py_ssize_t +arrange_output_buffer(uint32_t *avail_out, + uint8_t **next_out, + PyObject **buffer, + Py_ssize_t length) +{ + Py_ssize_t ret; + + ret = arrange_output_buffer_with_maximum(avail_out, next_out, buffer, + length, + PY_SSIZE_T_MAX); + if (ret == -2) + PyErr_NoMemory(); + return ret; +} + +/* Decompress data of length self->avail_in_real in self->state.next_in. The + output buffer is allocated dynamically and returned. If the max_length is + of sufficiently low size, max_length is allocated immediately. At most + max_length bytes are returned, so some of the input may not be consumed. + self->state.next_in and self->avail_in_real are updated to reflect the + consumed input. */ +static PyObject* +decompress_buf(ZlibDecompressor *self, Py_ssize_t max_length) +{ + /* data_size is strictly positive, but because we repeatedly have to + compare against max_length and PyBytes_GET_SIZE we declare it as + signed */ + PyObject *return_value = NULL; + Py_ssize_t hard_limit; + Py_ssize_t obuflen; + zlibstate *state = PyType_GetModuleState(Py_TYPE(self)); + + int err = Z_OK; + + /* When sys.maxsize is passed as default use DEF_BUF_SIZE as start buffer. + In this particular case the data may not necessarily be very big, so + it is better to grow dynamically.*/ + if ((max_length < 0) || max_length == PY_SSIZE_T_MAX) { + hard_limit = PY_SSIZE_T_MAX; + obuflen = DEF_BUF_SIZE; + } else { + /* Assume that decompressor is used in file decompression with a fixed + block size of max_length. In that case we will reach max_length almost + always (except at the end of the file). So it makes sense to allocate + max_length. */ + hard_limit = max_length; + obuflen = max_length; + if (obuflen > DEF_MAX_INITIAL_BUF_SIZE){ + // Safeguard against memory overflow. + obuflen = DEF_MAX_INITIAL_BUF_SIZE; + } + } + + do { + arrange_input_buffer(&(self->zst), &(self->avail_in_real)); + + do { + obuflen = arrange_output_buffer_with_maximum(&(self->zst.avail_out), + &(self->zst.next_out), + &return_value, + obuflen, + hard_limit); + if (obuflen == -1){ + PyErr_SetString(PyExc_MemoryError, + "Insufficient memory for buffer allocation"); + goto error; + } + else if (obuflen == -2) { + break; + } + Py_BEGIN_ALLOW_THREADS + err = inflate(&self->zst, Z_SYNC_FLUSH); + Py_END_ALLOW_THREADS + switch (err) { + case Z_OK: /* fall through */ + case Z_BUF_ERROR: /* fall through */ + case Z_STREAM_END: + break; + default: + if (err == Z_NEED_DICT) { + goto error; + } + else { + break; + } + } + } while (self->zst.avail_out == 0); + } while(err != Z_STREAM_END && self->avail_in_real != 0); + + if (err == Z_STREAM_END) { + self->eof = 1; + self->is_initialised = 0; + /* Unlike the Decompress object we call inflateEnd here as there are no + backwards compatibility issues */ + err = inflateEnd(&self->zst); + if (err != Z_OK) { + zlib_error(state, self->zst, err, "while finishing decompression"); + goto error; + } + } else if (err != Z_OK && err != Z_BUF_ERROR) { + zlib_error(state, self->zst, err, "while decompressing data"); + } + + self->avail_in_real += self->zst.avail_in; + + if (_PyBytes_Resize(&return_value, self->zst.next_out - + (uint8_t *)PyBytes_AS_STRING(return_value)) != 0) { + goto error; + } + + goto success; +error: + Py_CLEAR(return_value); +success: + return return_value; +} + + +static PyObject * +decompress(ZlibDecompressor *self, uint8_t *data, + size_t len, Py_ssize_t max_length) +{ + bool input_buffer_in_use; + PyObject *result; + + /* Prepend unconsumed input if necessary */ + if (self->zst.next_in != NULL) { + size_t avail_now, avail_total; + + /* Number of bytes we can append to input buffer */ + avail_now = (self->input_buffer + self->input_buffer_size) + - (self->zst.next_in + self->avail_in_real); + + /* Number of bytes we can append if we move existing + contents to beginning of buffer (overwriting + consumed input) */ + avail_total = self->input_buffer_size - self->avail_in_real; + + if (avail_total < len) { + size_t offset = self->zst.next_in - self->input_buffer; + uint8_t *tmp; + size_t new_size = self->input_buffer_size + len - avail_now; + + /* Assign to temporary variable first, so we don't + lose address of allocated buffer if realloc fails */ + tmp = PyMem_Realloc(self->input_buffer, new_size); + if (tmp == NULL) { + PyErr_SetNone(PyExc_MemoryError); + return NULL; + } + self->input_buffer = tmp; + self->input_buffer_size = new_size; + + self->zst.next_in = self->input_buffer + offset; + } + else if (avail_now < len) { + memmove(self->input_buffer, self->zst.next_in, + self->avail_in_real); + self->zst.next_in = self->input_buffer; + } + memcpy((void*)(self->zst.next_in + self->avail_in_real), data, len); + self->avail_in_real += len; + input_buffer_in_use = 1; + } + else { + self->zst.next_in = data; + self->avail_in_real = len; + input_buffer_in_use = 0; + } + + result = decompress_buf(self, max_length); + if(result == NULL) { + self->zst.next_in = NULL; + return NULL; + } + + if (self->eof) { + self->needs_input = 0; + + if (self->avail_in_real > 0) { + PyObject *unused_data = PyBytes_FromStringAndSize( + (char *)self->zst.next_in, self->avail_in_real); + if (unused_data == NULL) { + goto error; + } + Py_XSETREF(self->unused_data, unused_data); + } + } + else if (self->avail_in_real == 0) { + self->zst.next_in = NULL; + self->needs_input = 1; + } + else { + self->needs_input = 0; + + /* If we did not use the input buffer, we now have + to copy the tail from the caller's buffer into the + input buffer */ + if (!input_buffer_in_use) { + + /* Discard buffer if it's too small + (resizing it may needlessly copy the current contents) */ + if (self->input_buffer != NULL && + self->input_buffer_size < self->avail_in_real) { + PyMem_Free(self->input_buffer); + self->input_buffer = NULL; + } + + /* Allocate if necessary */ + if (self->input_buffer == NULL) { + self->input_buffer = PyMem_Malloc(self->avail_in_real); + if (self->input_buffer == NULL) { + PyErr_SetNone(PyExc_MemoryError); + goto error; + } + self->input_buffer_size = self->avail_in_real; + } + + /* Copy tail */ + memcpy(self->input_buffer, self->zst.next_in, self->avail_in_real); + self->zst.next_in = self->input_buffer; + } + } + return result; + +error: + Py_XDECREF(result); + return NULL; +} + +/*[clinic input] +zlib.ZlibDecompressor.decompress + + data: Py_buffer + max_length: Py_ssize_t=-1 + +Decompress *data*, returning uncompressed data as bytes. + +If *max_length* is nonnegative, returns at most *max_length* bytes of +decompressed data. If this limit is reached and further output can be +produced, *self.needs_input* will be set to ``False``. In this case, the next +call to *decompress()* may provide *data* as b'' to obtain more of the output. + +If all of the input data was decompressed and returned (either because this +was less than *max_length* bytes, or because *max_length* was negative), +*self.needs_input* will be set to True. + +Attempting to decompress data after the end of stream is reached raises an +EOFError. Any data found after the end of the stream is ignored and saved in +the unused_data attribute. +[clinic start generated code]*/ + +static PyObject * +zlib_ZlibDecompressor_decompress_impl(ZlibDecompressor *self, + Py_buffer *data, Py_ssize_t max_length) +/*[clinic end generated code: output=990d32787b775f85 input=0b29d99715250b96]*/ + +{ + PyObject *result = NULL; + + ENTER_ZLIB(self); + if (self->eof) { + PyErr_SetString(PyExc_EOFError, "End of stream already reached"); + } + else { + result = decompress(self, data->buf, data->len, max_length); + } + LEAVE_ZLIB(self); + return result; +} + +PyDoc_STRVAR(ZlibDecompressor__new____doc__, +"_ZlibDecompressor(wbits=15, zdict=b\'\')\n" +"--\n" +"\n" +"Create a decompressor object for decompressing data incrementally.\n" +"\n" +" wbits = 15\n" +" zdict\n" +" The predefined compression dictionary. This is a sequence of bytes\n" +" (such as a bytes object) containing subsequences that are expected\n" +" to occur frequently in the data that is to be compressed. Those\n" +" subsequences that are expected to be most common should come at the\n" +" end of the dictionary. This must be the same dictionary as used by the\n" +" compressor that produced the input data.\n" +"\n"); + +static PyObject * +ZlibDecompressor__new__(PyTypeObject *cls, + PyObject *args, + PyObject *kwargs) +{ + static char *keywords[] = {"wbits", "zdict", NULL}; + static char *format = "|iO:_ZlibDecompressor"; + int wbits = MAX_WBITS; + PyObject *zdict = NULL; + zlibstate *state = PyType_GetModuleState(cls); + + if (!PyArg_ParseTupleAndKeywords( + args, kwargs, format, keywords, &wbits, &zdict)) { + return NULL; + } + ZlibDecompressor *self = PyObject_New(ZlibDecompressor, cls); + self->eof = 0; + self->needs_input = 1; + self->avail_in_real = 0; + self->input_buffer = NULL; + self->input_buffer_size = 0; + if (zdict != NULL) { + Py_INCREF(zdict); + } + self->zdict = zdict; + self->zst.opaque = NULL; + self->zst.zalloc = PyZlib_Malloc; + self->zst.zfree = PyZlib_Free; + self->zst.next_in = NULL; + self->zst.avail_in = 0; + self->unused_data = PyBytes_FromStringAndSize(NULL, 0); + if (self->unused_data == NULL) { + Py_CLEAR(self); + return NULL; + } + self->lock = PyThread_allocate_lock(); + if (self->lock == NULL) { + Py_DECREF(self); + PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock"); + return NULL; + } + int err = inflateInit2(&(self->zst), wbits); + switch (err) { + case Z_OK: + self->is_initialised = 1; + if (self->zdict != NULL && wbits < 0) { + if (set_inflate_zdict_ZlibDecompressor(state, self) < 0) { + Py_DECREF(self); + return NULL; + } + } + return (PyObject *)self; + case Z_STREAM_ERROR: + Py_DECREF(self); + PyErr_SetString(PyExc_ValueError, "Invalid initialization option"); + return NULL; + case Z_MEM_ERROR: + Py_DECREF(self); + PyErr_SetString(PyExc_MemoryError, + "Can't allocate memory for decompression object"); + return NULL; + default: + zlib_error(state, self->zst, err, "while creating decompression object"); + Py_DECREF(self); + return NULL; + } } #include "clinic/zlibmodule.c.h" @@ -1372,6 +1818,11 @@ static PyMethodDef Decomp_methods[] = {NULL, NULL} }; +static PyMethodDef ZlibDecompressor_methods[] = { + ZLIB_ZLIBDECOMPRESSOR_DECOMPRESS_METHODDEF + {NULL} +}; + #define COMP_OFF(x) offsetof(compobject, x) static PyMemberDef Decomp_members[] = { {"unused_data", T_OBJECT, COMP_OFF(unused_data), READONLY}, @@ -1380,6 +1831,26 @@ static PyMemberDef Decomp_members[] = { {NULL}, }; +PyDoc_STRVAR(ZlibDecompressor_eof__doc__, +"True if the end-of-stream marker has been reached."); + +PyDoc_STRVAR(ZlibDecompressor_unused_data__doc__, +"Data found after the end of the compressed stream."); + +PyDoc_STRVAR(ZlibDecompressor_needs_input_doc, +"True if more input is needed before more decompressed data can be produced."); + +static PyMemberDef ZlibDecompressor_members[] = { + {"eof", T_BOOL, offsetof(ZlibDecompressor, eof), + READONLY, ZlibDecompressor_eof__doc__}, + {"unused_data", T_OBJECT_EX, offsetof(ZlibDecompressor, unused_data), + READONLY, ZlibDecompressor_unused_data__doc__}, + {"needs_input", T_BOOL, offsetof(ZlibDecompressor, needs_input), READONLY, + ZlibDecompressor_needs_input_doc}, + {NULL}, +}; + + /*[clinic input] zlib.adler32 @@ -1497,6 +1968,25 @@ static PyType_Spec Decomptype_spec = { .slots = Decomptype_slots, }; +static PyType_Slot ZlibDecompressor_type_slots[] = { + {Py_tp_dealloc, ZlibDecompressor_dealloc}, + {Py_tp_members, ZlibDecompressor_members}, + {Py_tp_new, ZlibDecompressor__new__}, + {Py_tp_doc, (char *)ZlibDecompressor__new____doc__}, + {Py_tp_methods, ZlibDecompressor_methods}, + {0, 0}, +}; + +static PyType_Spec ZlibDecompressor_type_spec = { + .name = "zlib._ZlibDecompressor", + .basicsize = sizeof(ZlibDecompressor), + // Calling PyType_GetModuleState() on a subclass is not safe. + // ZlibDecompressor_type_spec does not have Py_TPFLAGS_BASETYPE flag + // which prevents to create a subclass. + // So calling PyType_GetModuleState() in this file is always safe. + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE), + .slots = ZlibDecompressor_type_slots, +}; PyDoc_STRVAR(zlib_module_documentation, "The functions in this module allow compression and decompression using the\n" "zlib library, which is based on GNU zip.\n" @@ -1518,6 +2008,7 @@ zlib_clear(PyObject *mod) zlibstate *state = get_zlib_state(mod); Py_CLEAR(state->Comptype); Py_CLEAR(state->Decomptype); + Py_CLEAR(state->ZlibDecompressorType); Py_CLEAR(state->ZlibError); return 0; } @@ -1528,6 +2019,7 @@ zlib_traverse(PyObject *mod, visitproc visit, void *arg) zlibstate *state = get_zlib_state(mod); Py_VISIT(state->Comptype); Py_VISIT(state->Decomptype); + Py_VISIT(state->ZlibDecompressorType); Py_VISIT(state->ZlibError); return 0; } @@ -1555,6 +2047,12 @@ zlib_exec(PyObject *mod) return -1; } + state->ZlibDecompressorType = (PyTypeObject *)PyType_FromModuleAndSpec( + mod, &ZlibDecompressor_type_spec, NULL); + if (state->ZlibDecompressorType == NULL) { + return -1; + } + state->ZlibError = PyErr_NewException("zlib.error", NULL, NULL); if (state->ZlibError == NULL) { return -1; @@ -1565,6 +2063,12 @@ zlib_exec(PyObject *mod) Py_DECREF(state->ZlibError); return -1; } + Py_INCREF(state->ZlibDecompressorType); + if (PyModule_AddObject(mod, "_ZlibDecompressor", + (PyObject *)state->ZlibDecompressorType) < 0) { + Py_DECREF(state->ZlibDecompressorType); + return -1; + } #define ZLIB_ADD_INT_MACRO(c) \ do { \ From webhook-mailer at python.org Mon Oct 17 06:01:15 2022 From: webhook-mailer at python.org (vstinner) Date: Mon, 17 Oct 2022 10:01:15 -0000 Subject: [Python-checkins] gh-97669: Create Tools/build/ directory (#97963) Message-ID: https://github.com/python/cpython/commit/1863302d61a7a5dd8b8d345a00f0ee242c7c10bf commit: 1863302d61a7a5dd8b8d345a00f0ee242c7c10bf branch: main author: Victor Stinner committer: vstinner date: 2022-10-17T12:01:00+02:00 summary: gh-97669: Create Tools/build/ directory (#97963) Create Tools/build/ directory. Move the following scripts from Tools/scripts/ to Tools/build/: * check_extension_modules.py * deepfreeze.py * freeze_modules.py * generate_global_objects.py * generate_levenshtein_examples.py * generate_opcode_h.py * generate_re_casefix.py * generate_sre_constants.py * generate_stdlib_module_names.py * generate_token.py * parse_html5_entities.py * smelly.py * stable_abi.py * umarshal.py * update_file.py * verify_ensurepip_wheels.py Update references to these scripts. files: A Tools/build/check_extension_modules.py A Tools/build/deepfreeze.py A Tools/build/freeze_modules.py A Tools/build/generate_global_objects.py A Tools/build/generate_levenshtein_examples.py A Tools/build/generate_opcode_h.py A Tools/build/generate_re_casefix.py A Tools/build/generate_sre_constants.py A Tools/build/generate_stdlib_module_names.py A Tools/build/generate_token.py A Tools/build/parse_html5_entities.py A Tools/build/smelly.py A Tools/build/stable_abi.py A Tools/build/umarshal.py A Tools/build/update_file.py A Tools/build/verify_ensurepip_wheels.py D Tools/scripts/check_extension_modules.py D Tools/scripts/deepfreeze.py D Tools/scripts/freeze_modules.py D Tools/scripts/generate_global_objects.py D Tools/scripts/generate_levenshtein_examples.py D Tools/scripts/generate_opcode_h.py D Tools/scripts/generate_re_casefix.py D Tools/scripts/generate_sre_constants.py D Tools/scripts/generate_stdlib_module_names.py D Tools/scripts/generate_token.py D Tools/scripts/parse_html5_entities.py D Tools/scripts/smelly.py D Tools/scripts/stable_abi.py D Tools/scripts/umarshal.py D Tools/scripts/update_file.py D Tools/scripts/verify_ensurepip_wheels.py M .github/CODEOWNERS M .github/workflows/verify-ensurepip-wheels.yml M .gitignore M Doc/library/token-list.inc M Include/internal/pycore_global_strings.h M Include/internal/pycore_opcode.h M Include/internal/pycore_runtime_init_generated.h M Include/internal/pycore_token.h M Include/opcode.h M Lib/html/entities.py M Lib/token.py M Makefile.pre.in M Misc/stable_abi.toml M Modules/_sre/sre_constants.h M Modules/_sre/sre_targets.h M PC/python3dll.c M PCbuild/_freeze_module.vcxproj M PCbuild/regen.targets M Parser/token.c M Programs/_bootstrap_python.c M Programs/_freeze_module.c M Python/deepfreeze/README.txt M Python/frozen.c M Python/frozen_modules/README.txt M Python/stdlib_module_names.h diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 585589d6ce3b..2fd933a22f3c 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -55,7 +55,7 @@ Python/traceback.c @iritkatriel /Lib/html/ @ezio-melotti /Lib/_markupbase.py @ezio-melotti /Lib/test/test_html*.py @ezio-melotti -/Tools/scripts/*html5* @ezio-melotti +/Tools/build/parse_html5_entities.py @ezio-melotti # Import (including importlib). # Ignoring importlib.h so as to not get flagged on diff --git a/.github/workflows/verify-ensurepip-wheels.yml b/.github/workflows/verify-ensurepip-wheels.yml index 9f4754f912b0..969515ed287b 100644 --- a/.github/workflows/verify-ensurepip-wheels.yml +++ b/.github/workflows/verify-ensurepip-wheels.yml @@ -6,12 +6,12 @@ on: paths: - 'Lib/ensurepip/_bundled/**' - '.github/workflows/verify-ensurepip-wheels.yml' - - 'Tools/scripts/verify_ensurepip_wheels.py' + - 'Tools/build/verify_ensurepip_wheels.py' pull_request: paths: - 'Lib/ensurepip/_bundled/**' - '.github/workflows/verify-ensurepip-wheels.yml' - - 'Tools/scripts/verify_ensurepip_wheels.py' + - 'Tools/build/verify_ensurepip_wheels.py' permissions: contents: read @@ -29,4 +29,4 @@ jobs: with: python-version: '3' - name: Compare checksums of bundled pip and setuptools to ones published on PyPI - run: ./Tools/scripts/verify_ensurepip_wheels.py + run: ./Tools/build/verify_ensurepip_wheels.py diff --git a/.gitignore b/.gitignore index 924c136ba9aa..6934faa91e98 100644 --- a/.gitignore +++ b/.gitignore @@ -143,7 +143,7 @@ Tools/ssl/win32 Tools/freeze/test/outdir # The frozen modules are always generated by the build so we don't -# keep them in the repo. Also see Tools/scripts/freeze_modules.py. +# keep them in the repo. Also see Tools/build/freeze_modules.py. Python/frozen_modules/*.h # The manifest can be generated at any time with "make regen-frozen". Python/frozen_modules/MANIFEST diff --git a/Doc/library/token-list.inc b/Doc/library/token-list.inc index 1a99f0518d1b..2739d5bfc1df 100644 --- a/Doc/library/token-list.inc +++ b/Doc/library/token-list.inc @@ -1,4 +1,4 @@ -.. Auto-generated by Tools/scripts/generate_token.py +.. Auto-generated by Tools/build/generate_token.py .. data:: ENDMARKER .. data:: NAME diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index f646979910c8..811cfc147fcf 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -8,7 +8,7 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif -// The data structure & init here are inspired by Tools/scripts/deepfreeze.py. +// The data structure & init here are inspired by Tools/build/deepfreeze.py. // All field names generated by ASCII_STR() have a common prefix, // to help avoid collisions with keywords, etc. @@ -25,7 +25,7 @@ extern "C" { // XXX Order by frequency of use? -/* The following is auto-generated by Tools/scripts/generate_global_objects.py. */ +/* The following is auto-generated by Tools/build/generate_global_objects.py. */ struct _Py_global_strings { struct { STRUCT_FOR_STR(anon_dictcomp, "") diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index 15925511cc1f..c8ef5dd73525 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -1,4 +1,4 @@ -// Auto-generated by Tools/scripts/generate_opcode_h.py from Lib/opcode.py +// Auto-generated by Tools/build/generate_opcode_h.py from Lib/opcode.py #ifndef Py_INTERNAL_OPCODE_H #define Py_INTERNAL_OPCODE_H diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index bd1fedebd65c..8ce95884ccdd 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -8,7 +8,7 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif -/* The following is auto-generated by Tools/scripts/generate_global_objects.py. */ +/* The following is auto-generated by Tools/build/generate_global_objects.py. */ #define _Py_global_objects_INIT { \ .singletons = { \ .small_ints = { \ diff --git a/Include/internal/pycore_token.h b/Include/internal/pycore_token.h index f9b8240e2168..95459ab9f7d0 100644 --- a/Include/internal/pycore_token.h +++ b/Include/internal/pycore_token.h @@ -1,4 +1,4 @@ -/* Auto-generated by Tools/scripts/generate_token.py */ +/* Auto-generated by Tools/build/generate_token.py */ /* Token types */ #ifndef Py_INTERNAL_TOKEN_H diff --git a/Include/opcode.h b/Include/opcode.h index 42825df6217b..0871eb1bfe0a 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -1,4 +1,4 @@ -// Auto-generated by Tools/scripts/generate_opcode_h.py from Lib/opcode.py +// Auto-generated by Tools/build/generate_opcode_h.py from Lib/opcode.py #ifndef Py_OPCODE_H #define Py_OPCODE_H diff --git a/Lib/html/entities.py b/Lib/html/entities.py index cc59bc314499..eb6dc1219058 100644 --- a/Lib/html/entities.py +++ b/Lib/html/entities.py @@ -261,7 +261,7 @@ # HTML5 named character references -# Generated by 'Tools/scripts/parse_html5_entities.py' +# Generated by Tools/build/parse_html5_entities.py # from https://html.spec.whatwg.org/entities.json and # https://html.spec.whatwg.org/multipage/named-characters.html. # Map HTML5 named character references to the equivalent Unicode character(s). diff --git a/Lib/token.py b/Lib/token.py index 9d0c0bf0fb03..95b107c6643b 100644 --- a/Lib/token.py +++ b/Lib/token.py @@ -1,5 +1,5 @@ """Token constants.""" -# Auto-generated by Tools/scripts/generate_token.py +# Auto-generated by Tools/build/generate_token.py __all__ = ['tok_name', 'ISTERMINAL', 'ISNONTERMINAL', 'ISEOF'] diff --git a/Makefile.pre.in b/Makefile.pre.in index 7e2567173bc2..5b4bf15eb8aa 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -285,7 +285,7 @@ BUILDPYTHON= python$(BUILDEXE) HOSTRUNNER= @HOSTRUNNER@ PYTHON_FOR_REGEN?=@PYTHON_FOR_REGEN@ -UPDATE_FILE=$(PYTHON_FOR_REGEN) $(srcdir)/Tools/scripts/update_file.py +UPDATE_FILE=$(PYTHON_FOR_REGEN) $(srcdir)/Tools/build/update_file.py PYTHON_FOR_BUILD=@PYTHON_FOR_BUILD@ # Single-platform builds depend on $(BUILDPYTHON). Cross builds use an # external "build Python" and have an empty PYTHON_FOR_BUILD_DEPS. @@ -705,7 +705,7 @@ coverage-report: regen-token regen-frozen .PHONY=clinic clinic: check-clean-src $(srcdir)/Modules/_blake2/blake2s_impl.c $(PYTHON_FOR_REGEN) $(srcdir)/Tools/clinic/clinic.py --make --srcdir $(srcdir) - $(PYTHON_FOR_REGEN) $(srcdir)/Tools/scripts/generate_global_objects.py + $(PYTHON_FOR_REGEN) $(srcdir)/Tools/build/generate_global_objects.py # Build the interpreter $(BUILDPYTHON): Programs/python.o $(LINK_PYTHON_DEPS) @@ -907,7 +907,7 @@ sharedmods: $(SHAREDMODS) pybuilddir.txt # dependency on BUILDPYTHON ensures that the target is run last checksharedmods: sharedmods $(PYTHON_FOR_BUILD_DEPS) $(BUILDPYTHON) - @$(RUNSHARED) $(PYTHON_FOR_BUILD) $(srcdir)/Tools/scripts/check_extension_modules.py + @$(RUNSHARED) $(PYTHON_FOR_BUILD) $(srcdir)/Tools/build/check_extension_modules.py rundsymutil: sharedmods $(PYTHON_FOR_BUILD_DEPS) $(BUILDPYTHON) @if [ ! -z $(DSYMUTIL) ] ; then \ @@ -961,13 +961,13 @@ regen-test-frozenmain: $(BUILDPYTHON) .PHONY: regen-test-levenshtein regen-test-levenshtein: # Regenerate Lib/test/levenshtein_examples.json - $(PYTHON_FOR_REGEN) $(srcdir)/Tools/scripts/generate_levenshtein_examples.py Lib/test/levenshtein_examples.json + $(PYTHON_FOR_REGEN) $(srcdir)/Tools/build/generate_levenshtein_examples.py Lib/test/levenshtein_examples.json .PHONY: regen-re regen-re: $(BUILDPYTHON) # Regenerate Lib/re/_casefix.py - # using Tools/scripts/generate_re_casefix.py - $(RUNSHARED) ./$(BUILDPYTHON) $(srcdir)/Tools/scripts/generate_re_casefix.py $(srcdir)/Lib/re/_casefix.py + # using Tools/build/generate_re_casefix.py + $(RUNSHARED) ./$(BUILDPYTHON) $(srcdir)/Tools/build/generate_re_casefix.py $(srcdir)/Lib/re/_casefix.py Programs/_testembed: Programs/_testembed.o $(LINK_PYTHON_DEPS) $(LINKCC) $(PY_CORE_LDFLAGS) $(LINKFORSHARED) -o $@ Programs/_testembed.o $(LINK_PYTHON_OBJS) $(LIBS) $(MODLIBS) $(SYSLIBS) @@ -1013,7 +1013,7 @@ _bootstrap_python: $(LIBRARY_OBJS_OMIT_FROZEN) Programs/_bootstrap_python.o Modu # 2) deepfreeze modules with external build Python. # -# FROZEN_FILES_* are auto-generated by Tools/scripts/freeze_modules.py. +# FROZEN_FILES_* are auto-generated by Tools/build/freeze_modules.py. FROZEN_FILES_IN = \ Lib/importlib/_bootstrap.py \ Lib/importlib/_bootstrap_external.py \ @@ -1149,11 +1149,11 @@ Python/frozen_modules/frozen_only.h: Tools/freeze/flag.py $(FREEZE_MODULE_DEPS) # END: freezing modules -Tools/scripts/freeze_modules.py: $(FREEZE_MODULE) +Tools/build/freeze_modules.py: $(FREEZE_MODULE) .PHONY: regen-frozen -regen-frozen: Tools/scripts/freeze_modules.py $(FROZEN_FILES_IN) - $(PYTHON_FOR_REGEN) $(srcdir)/Tools/scripts/freeze_modules.py +regen-frozen: Tools/build/freeze_modules.py $(FROZEN_FILES_IN) + $(PYTHON_FOR_REGEN) $(srcdir)/Tools/build/freeze_modules.py @echo "The Makefile was updated, you may need to re-run make." ############################################################################ @@ -1162,11 +1162,11 @@ regen-frozen: Tools/scripts/freeze_modules.py $(FROZEN_FILES_IN) .PHONY: regen-deepfreeze regen-deepfreeze: $(DEEPFREEZE_OBJS) -DEEPFREEZE_DEPS=$(srcdir)/Tools/scripts/deepfreeze.py $(FREEZE_MODULE_DEPS) $(FROZEN_FILES_OUT) +DEEPFREEZE_DEPS=$(srcdir)/Tools/build/deepfreeze.py $(FREEZE_MODULE_DEPS) $(FROZEN_FILES_OUT) # BEGIN: deepfreeze modules Python/deepfreeze/deepfreeze.c: $(DEEPFREEZE_DEPS) - $(PYTHON_FOR_FREEZE) $(srcdir)/Tools/scripts/deepfreeze.py \ + $(PYTHON_FOR_FREEZE) $(srcdir)/Tools/build/deepfreeze.py \ Python/frozen_modules/importlib._bootstrap.h:importlib._bootstrap \ Python/frozen_modules/importlib._bootstrap_external.h:importlib._bootstrap_external \ Python/frozen_modules/zipimport.h:zipimport \ @@ -1203,8 +1203,8 @@ regen-importlib: regen-frozen # Global objects .PHONY: regen-global-objects -regen-global-objects: $(srcdir)/Tools/scripts/generate_global_objects.py - $(PYTHON_FOR_REGEN) $(srcdir)/Tools/scripts/generate_global_objects.py +regen-global-objects: $(srcdir)/Tools/build/generate_global_objects.py + $(PYTHON_FOR_REGEN) $(srcdir)/Tools/build/generate_global_objects.py @echo "Note: Global objects can be added or removed by other tools (e.g. deepfreeze), " @echo " so be sure to re-run regen-global-objects after those tools." @@ -1220,7 +1220,7 @@ check-abidump: all abidiff $(srcdir)/Doc/data/python$(LDVERSION).abi "libpython$(LDVERSION).so" --drop-private-types --no-architecture --no-added-syms regen-limited-abi: all - $(RUNSHARED) ./$(BUILDPYTHON) $(srcdir)/Tools/scripts/stable_abi.py --generate-all $(srcdir)/Misc/stable_abi.toml + $(RUNSHARED) ./$(BUILDPYTHON) $(srcdir)/Tools/build/stable_abi.py --generate-all $(srcdir)/Misc/stable_abi.toml ############################################################################ # Regenerate all generated files @@ -1331,8 +1331,8 @@ regen-ast: .PHONY: regen-opcode regen-opcode: # Regenerate Include/opcode.h from Lib/opcode.py - # using Tools/scripts/generate_opcode_h.py - $(PYTHON_FOR_REGEN) $(srcdir)/Tools/scripts/generate_opcode_h.py \ + # using Tools/build/generate_opcode_h.py + $(PYTHON_FOR_REGEN) $(srcdir)/Tools/build/generate_opcode_h.py \ $(srcdir)/Lib/opcode.py \ $(srcdir)/Include/opcode.h.new \ $(srcdir)/Include/internal/pycore_opcode.h.new @@ -1342,23 +1342,23 @@ regen-opcode: .PHONY: regen-token regen-token: # Regenerate Doc/library/token-list.inc from Grammar/Tokens - # using Tools/scripts/generate_token.py - $(PYTHON_FOR_REGEN) $(srcdir)/Tools/scripts/generate_token.py rst \ + # using Tools/build/generate_token.py + $(PYTHON_FOR_REGEN) $(srcdir)/Tools/build/generate_token.py rst \ $(srcdir)/Grammar/Tokens \ $(srcdir)/Doc/library/token-list.inc # Regenerate Include/internal/pycore_token.h from Grammar/Tokens - # using Tools/scripts/generate_token.py - $(PYTHON_FOR_REGEN) $(srcdir)/Tools/scripts/generate_token.py h \ + # using Tools/build/generate_token.py + $(PYTHON_FOR_REGEN) $(srcdir)/Tools/build/generate_token.py h \ $(srcdir)/Grammar/Tokens \ $(srcdir)/Include/internal/pycore_token.h # Regenerate Parser/token.c from Grammar/Tokens - # using Tools/scripts/generate_token.py - $(PYTHON_FOR_REGEN) $(srcdir)/Tools/scripts/generate_token.py c \ + # using Tools/build/generate_token.py + $(PYTHON_FOR_REGEN) $(srcdir)/Tools/build/generate_token.py c \ $(srcdir)/Grammar/Tokens \ $(srcdir)/Parser/token.c # Regenerate Lib/token.py from Grammar/Tokens - # using Tools/scripts/generate_token.py - $(PYTHON_FOR_REGEN) $(srcdir)/Tools/scripts/generate_token.py py \ + # using Tools/build/generate_token.py + $(PYTHON_FOR_REGEN) $(srcdir)/Tools/build/generate_token.py py \ $(srcdir)/Grammar/Tokens \ $(srcdir)/Lib/token.py @@ -1375,16 +1375,16 @@ regen-keyword: .PHONY: regen-stdlib-module-names regen-stdlib-module-names: all Programs/_testembed # Regenerate Python/stdlib_module_names.h - # using Tools/scripts/generate_stdlib_module_names.py + # using Tools/build/generate_stdlib_module_names.py $(RUNSHARED) ./$(BUILDPYTHON) \ - $(srcdir)/Tools/scripts/generate_stdlib_module_names.py \ + $(srcdir)/Tools/build/generate_stdlib_module_names.py \ > $(srcdir)/Python/stdlib_module_names.h.new $(UPDATE_FILE) $(srcdir)/Python/stdlib_module_names.h $(srcdir)/Python/stdlib_module_names.h.new regen-sre: # Regenerate Modules/_sre/sre_constants.h and Modules/_sre/sre_targets.h - # from Lib/re/_constants.py using Tools/scripts/generate_sre_constants.py - $(PYTHON_FOR_REGEN) $(srcdir)/Tools/scripts/generate_sre_constants.py \ + # from Lib/re/_constants.py using Tools/build/generate_sre_constants.py + $(PYTHON_FOR_REGEN) $(srcdir)/Tools/build/generate_sre_constants.py \ $(srcdir)/Lib/re/_constants.py \ $(srcdir)/Modules/_sre/sre_constants.h \ $(srcdir)/Modules/_sre/sre_targets.h @@ -2511,7 +2511,7 @@ distclean: clobber docclean # Check that all symbols exported by libpython start with "Py" or "_Py" smelly: all - $(RUNSHARED) ./$(BUILDPYTHON) $(srcdir)/Tools/scripts/smelly.py + $(RUNSHARED) ./$(BUILDPYTHON) $(srcdir)/Tools/build/smelly.py # Find files with funny names funny: @@ -2549,7 +2549,7 @@ patchcheck: all $(RUNSHARED) ./$(BUILDPYTHON) $(srcdir)/Tools/patchcheck/patchcheck.py check-limited-abi: all - $(RUNSHARED) ./$(BUILDPYTHON) $(srcdir)/Tools/scripts/stable_abi.py --all $(srcdir)/Misc/stable_abi.toml + $(RUNSHARED) ./$(BUILDPYTHON) $(srcdir)/Tools/build/stable_abi.py --all $(srcdir)/Misc/stable_abi.toml .PHONY: update-config update-config: diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml index a8920d999e81..e78646fdea59 100644 --- a/Misc/stable_abi.toml +++ b/Misc/stable_abi.toml @@ -2,7 +2,7 @@ # Please append new items at the end. # The syntax of this file is not fixed. -# It is designed to be read only by Tools/stable_abi.py, which can change +# It is designed to be read only by Tools/build/stable_abi.py, which can change # without notice. # For the history of the stable ABI prior to this file, diff --git a/Modules/_sre/sre_constants.h b/Modules/_sre/sre_constants.h index c63351473686..f030815c6c00 100644 --- a/Modules/_sre/sre_constants.h +++ b/Modules/_sre/sre_constants.h @@ -3,7 +3,7 @@ * * regular expression matching engine * - * Auto-generated by Tools/scripts/generate_sre_constants.py from + * Auto-generated by Tools/build/generate_sre_constants.py from * Lib/re/_constants.py. * * Copyright (c) 1997-2001 by Secret Labs AB. All rights reserved. diff --git a/Modules/_sre/sre_targets.h b/Modules/_sre/sre_targets.h index 25b6edd436bb..62761a0000d8 100644 --- a/Modules/_sre/sre_targets.h +++ b/Modules/_sre/sre_targets.h @@ -3,7 +3,7 @@ * * regular expression matching engine * - * Auto-generated by Tools/scripts/generate_sre_constants.py from + * Auto-generated by Tools/build/generate_sre_constants.py from * Lib/re/_constants.py. * * Copyright (c) 1997-2001 by Secret Labs AB. All rights reserved. diff --git a/PC/python3dll.c b/PC/python3dll.c index 89bbd05932b8..c1b88c66903b 100755 --- a/PC/python3dll.c +++ b/PC/python3dll.c @@ -1,7 +1,7 @@ /* Re-export stable Python ABI */ -/* Generated by Tools/scripts/stable_abi.py */ +/* Generated by Tools/build/stable_abi.py */ #ifdef _M_IX86 #define DECORATE "_" diff --git a/PCbuild/_freeze_module.vcxproj b/PCbuild/_freeze_module.vcxproj index 39939a7ba983..49e5cc89a261 100644 --- a/PCbuild/_freeze_module.vcxproj +++ b/PCbuild/_freeze_module.vcxproj @@ -395,7 +395,7 @@ DependsOnTargets="FindPythonForBuild" Condition="$(Configuration) != 'PGUpdate'"> - -C - <_OpcodeSources Include="$(PySourcePath)Tools\scripts\generate_opcode_h.py;$(PySourcePath)Lib\opcode.py" /> + <_OpcodeSources Include="$(PySourcePath)Tools\build\generate_opcode_h.py;$(PySourcePath)Lib\opcode.py" /> <_OpcodeOutputs Include="$(PySourcePath)Include\opcode.h;$(PySourcePath)Include\internal\pycore_opcode.h;$(PySourcePath)Python\opcode_targets.h" /> <_TokenSources Include="$(PySourcePath)Grammar\Tokens" /> <_TokenOutputs Include="$(PySourcePath)Doc\library\token-list.inc"> @@ -59,7 +59,7 @@ Inputs="@(_OpcodeSources)" Outputs="@(_OpcodeOutputs)" DependsOnTargets="FindPythonForBuild"> - @@ -69,7 +69,7 @@ Inputs="@(_TokenSources)" Outputs="@(_TokenOutputs)" DependsOnTargets="FindPythonForBuild"> - @@ -85,7 +85,7 @@ - diff --git a/Parser/token.c b/Parser/token.c index fa03fbc450b2..6299ad2f5631 100644 --- a/Parser/token.c +++ b/Parser/token.c @@ -1,4 +1,4 @@ -/* Auto-generated by Tools/scripts/generate_token.py */ +/* Auto-generated by Tools/build/generate_token.py */ #include "Python.h" #include "pycore_token.h" diff --git a/Programs/_bootstrap_python.c b/Programs/_bootstrap_python.c index 6ecbf0c72b5f..bbac0c4e1a8a 100644 --- a/Programs/_bootstrap_python.c +++ b/Programs/_bootstrap_python.c @@ -2,7 +2,7 @@ /* Frozen modules bootstrap * * Limited and restricted Python interpreter to run - * "Tools/scripts/deepfreeze.py" on systems with no or older Python + * "Tools/build/deepfreeze.py" on systems with no or older Python * interpreter. */ diff --git a/Programs/_freeze_module.c b/Programs/_freeze_module.c index 3d27b79c237c..d6d737d48d60 100644 --- a/Programs/_freeze_module.c +++ b/Programs/_freeze_module.c @@ -2,7 +2,7 @@ modules into frozen modules (like Lib/importlib/_bootstrap.py into Python/importlib.h). - This is used directly by Tools/scripts/freeze_modules.py, and indirectly by "make regen-frozen". + This is used directly by Tools/build/freeze_modules.py, and indirectly by "make regen-frozen". See Python/frozen.c for more info. diff --git a/Python/deepfreeze/README.txt b/Python/deepfreeze/README.txt index da55d4e7c746..276ab51143ab 100644 --- a/Python/deepfreeze/README.txt +++ b/Python/deepfreeze/README.txt @@ -3,4 +3,4 @@ modules. Python/frozen.c depends on these files. None of these files are committed into the repo. -See Tools/scripts/freeze_modules.py for more info. +See Tools/build/freeze_modules.py for more info. diff --git a/Python/frozen.c b/Python/frozen.c index 8a2a7243537c..48b429519b66 100644 --- a/Python/frozen.c +++ b/Python/frozen.c @@ -8,7 +8,7 @@ * These files must be regenerated any time the corresponding .pyc * file would change (including with changes to the compiler, bytecode * format, marshal format). This can be done with "make regen-frozen". - * That make target just runs Tools/scripts/freeze_modules.py. + * That make target just runs Tools/build/freeze_modules.py. * * The freeze_modules.py script also determines which modules get * frozen. Update the list at the top of the script to add, remove, diff --git a/Python/frozen_modules/README.txt b/Python/frozen_modules/README.txt index 444167cc496a..795bb0efad34 100644 --- a/Python/frozen_modules/README.txt +++ b/Python/frozen_modules/README.txt @@ -4,4 +4,4 @@ modules. Python/frozen.c depends on these files. Note that, other than the required frozen modules, none of these files are committed into the repo. -See Tools/scripts/freeze_modules.py for more info. +See Tools/build/freeze_modules.py for more info. diff --git a/Python/stdlib_module_names.h b/Python/stdlib_module_names.h index b28156608d1b..12827e775754 100644 --- a/Python/stdlib_module_names.h +++ b/Python/stdlib_module_names.h @@ -1,4 +1,4 @@ -// Auto-generated by Tools/scripts/generate_stdlib_module_names.py. +// Auto-generated by Tools/build/generate_stdlib_module_names.py. // List used to create sys.stdlib_module_names. static const char* _Py_stdlib_module_names[] = { diff --git a/Tools/scripts/check_extension_modules.py b/Tools/build/check_extension_modules.py similarity index 100% rename from Tools/scripts/check_extension_modules.py rename to Tools/build/check_extension_modules.py diff --git a/Tools/scripts/deepfreeze.py b/Tools/build/deepfreeze.py similarity index 100% rename from Tools/scripts/deepfreeze.py rename to Tools/build/deepfreeze.py diff --git a/Tools/scripts/freeze_modules.py b/Tools/build/freeze_modules.py similarity index 99% rename from Tools/scripts/freeze_modules.py rename to Tools/build/freeze_modules.py index aa1e4fe2ea0f..810224b28f2f 100644 --- a/Tools/scripts/freeze_modules.py +++ b/Tools/build/freeze_modules.py @@ -581,7 +581,7 @@ def regen_makefile(modules): frozenfiles = [] rules = [''] deepfreezerules = ["Python/deepfreeze/deepfreeze.c: $(DEEPFREEZE_DEPS)", - "\t$(PYTHON_FOR_FREEZE) $(srcdir)/Tools/scripts/deepfreeze.py \\"] + "\t$(PYTHON_FOR_FREEZE) $(srcdir)/Tools/build/deepfreeze.py \\"] for src in _iter_sources(modules): frozen_header = relpath_for_posix_display(src.frozenfile, ROOT_DIR) frozenfiles.append(f'\t\t{frozen_header} \\') @@ -646,7 +646,7 @@ def regen_pcbuild(modules): projlines = [] filterlines = [] corelines = [] - deepfreezerules = ['\t https://github.com/python/cpython/commit/6da1a2e993c955aa69158871b8c8792cef3094c3 commit: 6da1a2e993c955aa69158871b8c8792cef3094c3 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2022-10-17T14:28:51+01:00 summary: gh-93691: Compiler's code-gen passes location around instead of holding it on the global compiler state (GH-98001) files: M Python/compile.c diff --git a/Python/compile.c b/Python/compile.c index 2da36d0f6316..5fbf6fe10d13 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -118,17 +118,17 @@ (c->c_flags->cf_flags & PyCF_ALLOW_TOP_LEVEL_AWAIT) \ && (c->u->u_ste->ste_type == ModuleBlock)) -struct location { +typedef struct location_ { int lineno; int end_lineno; int col_offset; int end_col_offset; -}; +} location; #define LOCATION(LNO, END_LNO, COL, END_COL) \ - ((const struct location){(LNO), (END_LNO), (COL), (END_COL)}) + ((const location){(LNO), (END_LNO), (COL), (END_COL)}) -static struct location NO_LOCATION = {-1, -1, -1, -1}; +static location NO_LOCATION = {-1, -1, -1, -1}; typedef struct jump_target_label_ { int id; @@ -153,7 +153,7 @@ static struct jump_target_label_ NO_LABEL = {-1}; struct instr { int i_opcode; int i_oparg; - struct location i_loc; + location i_loc; /* The following fields should not be set by the front-end: */ struct basicblock_ *i_target; /* target block (if jump instruction) */ struct basicblock_ *i_except; /* target block when exception is raised */ @@ -386,7 +386,6 @@ struct compiler_unit { struct fblockinfo u_fblock[CO_MAXBLOCKS]; int u_firstlineno; /* the first lineno of the block */ - struct location u_loc; /* line/column info of the current stmt */ }; /* This struct captures the global state of a compilation. @@ -418,7 +417,7 @@ struct compiler { }; #define CFG_BUILDER(c) (&((c)->u->u_cfg_builder)) -#define COMPILER_LOC(c) ((c)->u->u_loc) + typedef struct { // A list of strings corresponding to name captures. It is used to track: @@ -449,12 +448,12 @@ static int basicblock_next_instr(basicblock *); static basicblock *cfg_builder_new_block(cfg_builder *g); static int cfg_builder_maybe_start_new_block(cfg_builder *g); -static int cfg_builder_addop_i(cfg_builder *g, int opcode, Py_ssize_t oparg, struct location loc); +static int cfg_builder_addop_i(cfg_builder *g, int opcode, Py_ssize_t oparg, location loc); static void compiler_free(struct compiler *); -static int compiler_error(struct compiler *, const char *, ...); -static int compiler_warn(struct compiler *, const char *, ...); -static int compiler_nameop(struct compiler *, identifier, expr_context_ty); +static int compiler_error(struct compiler *, location loc, const char *, ...); +static int compiler_warn(struct compiler *, location loc, const char *, ...); +static int compiler_nameop(struct compiler *, location, identifier, expr_context_ty); static PyCodeObject *compiler_mod(struct compiler *, mod_ty); static int compiler_visit_stmt(struct compiler *, stmt_ty); @@ -472,31 +471,33 @@ static int compiler_with(struct compiler *, stmt_ty, int); static int compiler_async_with(struct compiler *, stmt_ty, int); static int compiler_async_for(struct compiler *, stmt_ty); static int compiler_call_simple_kw_helper(struct compiler *c, + location loc, asdl_keyword_seq *keywords, Py_ssize_t nkwelts); -static int compiler_call_helper(struct compiler *c, int n, - asdl_expr_seq *args, +static int compiler_call_helper(struct compiler *c, location loc, + int n, asdl_expr_seq *args, asdl_keyword_seq *keywords); static int compiler_try_except(struct compiler *, stmt_ty); static int compiler_try_star_except(struct compiler *, stmt_ty); static int compiler_set_qualname(struct compiler *); static int compiler_sync_comprehension_generator( - struct compiler *c, + struct compiler *c, location *ploc, asdl_comprehension_seq *generators, int gen_index, int depth, expr_ty elt, expr_ty val, int type); static int compiler_async_comprehension_generator( - struct compiler *c, + struct compiler *c, location *ploc, asdl_comprehension_seq *generators, int gen_index, int depth, expr_ty elt, expr_ty val, int type); -static int compiler_pattern(struct compiler *, pattern_ty, pattern_context *); +static int compiler_pattern(struct compiler *, location *, + pattern_ty, pattern_context *); static int compiler_match(struct compiler *, stmt_ty); -static int compiler_pattern_subpattern(struct compiler *, pattern_ty, - pattern_context *); +static int compiler_pattern_subpattern(struct compiler *, location *, + pattern_ty, pattern_context *); static void remove_redundant_nops(basicblock *bb); @@ -997,18 +998,15 @@ basicblock_next_instr(basicblock *b) - before the "except" and "finally" clauses */ -#define SET_LOC(c, x) \ - (c)->u->u_loc.lineno = (x)->lineno; \ - (c)->u->u_loc.end_lineno = (x)->end_lineno; \ - (c)->u->u_loc.col_offset = (x)->col_offset; \ - (c)->u->u_loc.end_col_offset = (x)->end_col_offset; +#define SET_LOC(c, x) // Artificial instructions -#define UNSET_LOC(c) \ - (c)->u->u_loc.lineno = -1; \ - (c)->u->u_loc.end_lineno = -1; \ - (c)->u->u_loc.col_offset = -1; \ - (c)->u->u_loc.end_col_offset = -1; +#define UNSET_LOC(c) + +#define LOC(x) LOCATION((x)->lineno, \ + (x)->end_lineno, \ + (x)->col_offset, \ + (x)->end_col_offset) /* Return the stack effect of opcode with argument oparg. @@ -1290,7 +1288,7 @@ PyCompile_OpcodeStackEffect(int opcode, int oparg) */ static int -basicblock_addop(basicblock *b, int opcode, int oparg, struct location loc) +basicblock_addop(basicblock *b, int opcode, int oparg, location loc) { assert(IS_WITHIN_OPCODE_RANGE(opcode)); assert(!IS_ASSEMBLER_OPCODE(opcode)); @@ -1336,7 +1334,7 @@ cfg_builder_maybe_start_new_block(cfg_builder *g) } static int -cfg_builder_addop(cfg_builder *g, int opcode, int oparg, struct location loc) +cfg_builder_addop(cfg_builder *g, int opcode, int oparg, location loc) { if (cfg_builder_maybe_start_new_block(g) != 0) { return -1; @@ -1345,7 +1343,7 @@ cfg_builder_addop(cfg_builder *g, int opcode, int oparg, struct location loc) } static int -cfg_builder_addop_noarg(cfg_builder *g, int opcode, struct location loc) +cfg_builder_addop_noarg(cfg_builder *g, int opcode, location loc) { assert(!HAS_ARG(opcode)); return cfg_builder_addop(g, opcode, 0, loc); @@ -1503,27 +1501,27 @@ compiler_add_const(struct compiler *c, PyObject *o) } static int -compiler_addop_load_const(struct compiler *c, PyObject *o) +compiler_addop_load_const(struct compiler *c, location loc, PyObject *o) { Py_ssize_t arg = compiler_add_const(c, o); if (arg < 0) return 0; - return cfg_builder_addop_i(CFG_BUILDER(c), LOAD_CONST, arg, COMPILER_LOC(c)); + return cfg_builder_addop_i(CFG_BUILDER(c), LOAD_CONST, arg, loc); } static int -compiler_addop_o(struct compiler *c, int opcode, PyObject *dict, - PyObject *o) +compiler_addop_o(struct compiler *c, location loc, + int opcode, PyObject *dict, PyObject *o) { Py_ssize_t arg = dict_add_o(dict, o); if (arg < 0) return 0; - return cfg_builder_addop_i(CFG_BUILDER(c), opcode, arg, COMPILER_LOC(c)); + return cfg_builder_addop_i(CFG_BUILDER(c), opcode, arg, loc); } static int -compiler_addop_name(struct compiler *c, int opcode, PyObject *dict, - PyObject *o) +compiler_addop_name(struct compiler *c, location loc, + int opcode, PyObject *dict, PyObject *o) { Py_ssize_t arg; @@ -1542,14 +1540,14 @@ compiler_addop_name(struct compiler *c, int opcode, PyObject *dict, arg <<= 1; arg |= 1; } - return cfg_builder_addop_i(CFG_BUILDER(c), opcode, arg, COMPILER_LOC(c)); + return cfg_builder_addop_i(CFG_BUILDER(c), opcode, arg, loc); } /* Add an opcode with an integer argument. Returns 0 on failure, 1 on success. */ static int -cfg_builder_addop_i(cfg_builder *g, int opcode, Py_ssize_t oparg, struct location loc) +cfg_builder_addop_i(cfg_builder *g, int opcode, Py_ssize_t oparg, location loc) { /* oparg value is unsigned, but a signed C int is usually used to store it in the C code (like Python/ceval.c). @@ -1564,7 +1562,8 @@ cfg_builder_addop_i(cfg_builder *g, int opcode, Py_ssize_t oparg, struct locatio } static int -cfg_builder_addop_j(cfg_builder *g, int opcode, jump_target_label target, struct location loc) +cfg_builder_addop_j(cfg_builder *g, location loc, + int opcode, jump_target_label target) { assert(IS_LABEL(target)); assert(IS_JUMP_OPCODE(opcode) || IS_BLOCK_PUSH_OPCODE(opcode)); @@ -1572,102 +1571,84 @@ cfg_builder_addop_j(cfg_builder *g, int opcode, jump_target_label target, struct } -#define ADDOP(C, OP) { \ - if (!cfg_builder_addop_noarg(CFG_BUILDER(C), (OP), COMPILER_LOC(C))) \ +#define ADDOP(C, LOC, OP) { \ + if (!cfg_builder_addop_noarg(CFG_BUILDER(C), (OP), (LOC))) \ return 0; \ } -#define ADDOP_NOLINE(C, OP) { \ - if (!cfg_builder_addop_noarg(CFG_BUILDER(C), (OP), NO_LOCATION)) \ - return 0; \ -} - -#define ADDOP_IN_SCOPE(C, OP) { \ - if (!cfg_builder_addop_noarg(CFG_BUILDER(C), (OP), COMPILER_LOC(C))) { \ +#define ADDOP_IN_SCOPE(C, LOC, OP) { \ + if (!cfg_builder_addop_noarg(CFG_BUILDER(C), (OP), (LOC))) { \ compiler_exit_scope(c); \ return 0; \ } \ } -#define ADDOP_LOAD_CONST(C, O) { \ - if (!compiler_addop_load_const((C), (O))) \ +#define ADDOP_LOAD_CONST(C, LOC, O) { \ + if (!compiler_addop_load_const((C), (LOC), (O))) \ return 0; \ } /* Same as ADDOP_LOAD_CONST, but steals a reference. */ -#define ADDOP_LOAD_CONST_NEW(C, O) { \ +#define ADDOP_LOAD_CONST_NEW(C, LOC, O) { \ PyObject *__new_const = (O); \ if (__new_const == NULL) { \ return 0; \ } \ - if (!compiler_addop_load_const((C), __new_const)) { \ + if (!compiler_addop_load_const((C), (LOC), __new_const)) { \ Py_DECREF(__new_const); \ return 0; \ } \ Py_DECREF(__new_const); \ } -#define ADDOP_N(C, OP, O, TYPE) { \ +#define ADDOP_N(C, LOC, OP, O, TYPE) { \ assert(!HAS_CONST(OP)); /* use ADDOP_LOAD_CONST_NEW */ \ - if (!compiler_addop_o((C), (OP), (C)->u->u_ ## TYPE, (O))) { \ + if (!compiler_addop_o((C), (LOC), (OP), (C)->u->u_ ## TYPE, (O))) { \ Py_DECREF((O)); \ return 0; \ } \ Py_DECREF((O)); \ } -#define ADDOP_NAME(C, OP, O, TYPE) { \ - if (!compiler_addop_name((C), (OP), (C)->u->u_ ## TYPE, (O))) \ +#define ADDOP_NAME(C, LOC, OP, O, TYPE) { \ + if (!compiler_addop_name((C), (LOC), (OP), (C)->u->u_ ## TYPE, (O))) \ return 0; \ } -#define ADDOP_I(C, OP, O) { \ - if (!cfg_builder_addop_i(CFG_BUILDER(C), (OP), (O), COMPILER_LOC(C))) \ +#define ADDOP_I(C, LOC, OP, O) { \ + if (!cfg_builder_addop_i(CFG_BUILDER(C), (OP), (O), (LOC))) \ return 0; \ } -#define ADDOP_I_NOLINE(C, OP, O) { \ - if (!cfg_builder_addop_i(CFG_BUILDER(C), (OP), (O), NO_LOCATION)) \ +#define ADDOP_JUMP(C, LOC, OP, O) { \ + if (!cfg_builder_addop_j(CFG_BUILDER(C), (LOC), (OP), (O))) \ return 0; \ } -#define ADDOP_JUMP(C, OP, O) { \ - if (!cfg_builder_addop_j(CFG_BUILDER(C), (OP), (O), COMPILER_LOC(C))) \ +#define ADDOP_COMPARE(C, LOC, CMP) { \ + if (!compiler_addcompare((C), (LOC), (cmpop_ty)(CMP))) \ return 0; \ } -/* Add a jump with no line number. - * Used for artificial jumps that have no corresponding - * token in the source code. */ -#define ADDOP_JUMP_NOLINE(C, OP, O) { \ - if (!cfg_builder_addop_j(CFG_BUILDER(C), (OP), (O), NO_LOCATION)) \ - return 0; \ -} +#define ADDOP_BINARY(C, LOC, BINOP) \ + RETURN_IF_FALSE(addop_binary((C), (LOC), (BINOP), false)) -#define ADDOP_COMPARE(C, CMP) { \ - if (!compiler_addcompare((C), (cmpop_ty)(CMP))) \ - return 0; \ -} +#define ADDOP_INPLACE(C, LOC, BINOP) \ + RETURN_IF_FALSE(addop_binary((C), (LOC), (BINOP), true)) + +#define ADD_YIELD_FROM(C, LOC, await) \ + RETURN_IF_FALSE(compiler_add_yield_from((C), (LOC), (await))) -#define ADDOP_BINARY(C, BINOP) \ - RETURN_IF_FALSE(addop_binary((C), (BINOP), false)) +#define POP_EXCEPT_AND_RERAISE(C, LOC) \ + RETURN_IF_FALSE(compiler_pop_except_and_reraise((C), (LOC))) -#define ADDOP_INPLACE(C, BINOP) \ - RETURN_IF_FALSE(addop_binary((C), (BINOP), true)) +#define ADDOP_YIELD(C, LOC) \ + RETURN_IF_FALSE(addop_yield((C), (LOC))) /* VISIT and VISIT_SEQ takes an ASDL type as their second argument. They use the ASDL name to synthesize the name of the C type and the visit function. */ -#define ADD_YIELD_FROM(C, await) \ - RETURN_IF_FALSE(compiler_add_yield_from((C), (await))) - -#define POP_EXCEPT_AND_RERAISE(C) \ - RETURN_IF_FALSE(compiler_pop_except_and_reraise((C))) - -#define ADDOP_YIELD(C) \ - RETURN_IF_FALSE(addop_yield(C)) - #define VISIT(C, TYPE, V) {\ if (!compiler_visit_ ## TYPE((C), (V))) \ return 0; \ @@ -1711,6 +1692,8 @@ static int compiler_enter_scope(struct compiler *c, identifier name, int scope_type, void *key, int lineno) { + location loc = LOCATION(lineno, lineno, 0, 0); + struct compiler_unit *u; u = (struct compiler_unit *)PyObject_Calloc(1, sizeof( @@ -1758,7 +1741,6 @@ compiler_enter_scope(struct compiler *c, identifier name, u->u_nfblocks = 0; u->u_firstlineno = lineno; - u->u_loc = LOCATION(lineno, lineno, 0, 0); u->u_consts = PyDict_New(); if (!u->u_consts) { compiler_unit_free(u); @@ -1794,16 +1776,16 @@ compiler_enter_scope(struct compiler *c, identifier name, } if (u->u_scope_type == COMPILER_SCOPE_MODULE) { - c->u->u_loc.lineno = 0; + loc.lineno = 0; } else { if (!compiler_set_qualname(c)) return 0; } - ADDOP_I(c, RESUME, 0); + ADDOP_I(c, loc, RESUME, 0); if (u->u_scope_type == COMPILER_SCOPE_MODULE) { - c->u->u_loc.lineno = -1; + loc.lineno = -1; } return 1; } @@ -1911,12 +1893,13 @@ find_ann(asdl_stmt_seq *stmts) */ static int -compiler_push_fblock(struct compiler *c, enum fblocktype t, jump_target_label block_label, +compiler_push_fblock(struct compiler *c, location loc, + enum fblocktype t, jump_target_label block_label, jump_target_label exit, void *datum) { struct fblockinfo *f; if (c->u->u_nfblocks >= CO_MAXBLOCKS) { - return compiler_error(c, "too many statically nested blocks"); + return compiler_error(c, loc, "too many statically nested blocks"); } f = &c->u->u_fblock[c->u->u_nfblocks++]; f->fb_type = t; @@ -1937,40 +1920,41 @@ compiler_pop_fblock(struct compiler *c, enum fblocktype t, jump_target_label blo } static int -compiler_call_exit_with_nones(struct compiler *c) { - ADDOP_LOAD_CONST(c, Py_None); - ADDOP_LOAD_CONST(c, Py_None); - ADDOP_LOAD_CONST(c, Py_None); - ADDOP_I(c, CALL, 2); +compiler_call_exit_with_nones(struct compiler *c, location loc) +{ + ADDOP_LOAD_CONST(c, loc, Py_None); + ADDOP_LOAD_CONST(c, loc, Py_None); + ADDOP_LOAD_CONST(c, loc, Py_None); + ADDOP_I(c, loc, CALL, 2); return 1; } static int -compiler_add_yield_from(struct compiler *c, int await) +compiler_add_yield_from(struct compiler *c, location loc, int await) { NEW_JUMP_TARGET_LABEL(c, send); NEW_JUMP_TARGET_LABEL(c, fail); NEW_JUMP_TARGET_LABEL(c, exit); USE_LABEL(c, send); - ADDOP_JUMP(c, SEND, exit); + ADDOP_JUMP(c, loc, SEND, exit); // Set up a virtual try/except to handle when StopIteration is raised during // a close or throw call. The only way YIELD_VALUE raises if they do! - ADDOP_JUMP(c, SETUP_FINALLY, fail); - ADDOP_I(c, YIELD_VALUE, 0); - ADDOP_NOLINE(c, POP_BLOCK); - ADDOP_I(c, RESUME, await ? 3 : 2); - ADDOP_JUMP(c, JUMP_NO_INTERRUPT, send); + ADDOP_JUMP(c, loc, SETUP_FINALLY, fail); + ADDOP_I(c, loc, YIELD_VALUE, 0); + ADDOP(c, NO_LOCATION, POP_BLOCK); + ADDOP_I(c, loc, RESUME, await ? 3 : 2); + ADDOP_JUMP(c, loc, JUMP_NO_INTERRUPT, send); USE_LABEL(c, fail); - ADDOP(c, CLEANUP_THROW); + ADDOP(c, loc, CLEANUP_THROW); USE_LABEL(c, exit); return 1; } static int -compiler_pop_except_and_reraise(struct compiler *c) +compiler_pop_except_and_reraise(struct compiler *c, location loc) { /* Stack contents * [exc_info, lasti, exc] COPY 3 @@ -1979,9 +1963,9 @@ compiler_pop_except_and_reraise(struct compiler *c) * (exception_unwind clears the stack) */ - ADDOP_I(c, COPY, 3); - ADDOP(c, POP_EXCEPT); - ADDOP_I(c, RERAISE, 1); + ADDOP_I(c, loc, COPY, 3); + ADDOP(c, loc, POP_EXCEPT); + ADDOP_I(c, loc, RERAISE, 1); return 1; } @@ -1991,8 +1975,8 @@ compiler_pop_except_and_reraise(struct compiler *c) * be popped. */ static int -compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info, - int preserve_tos) +compiler_unwind_fblock(struct compiler *c, location *ploc, + struct fblockinfo *info, int preserve_tos) { switch (info->fb_type) { case WHILE_LOOP: @@ -2004,20 +1988,20 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info, case FOR_LOOP: /* Pop the iterator */ if (preserve_tos) { - ADDOP_I(c, SWAP, 2); + ADDOP_I(c, *ploc, SWAP, 2); } - ADDOP(c, POP_TOP); + ADDOP(c, *ploc, POP_TOP); return 1; case TRY_EXCEPT: - ADDOP(c, POP_BLOCK); + ADDOP(c, *ploc, POP_BLOCK); return 1; case FINALLY_TRY: /* This POP_BLOCK gets the line number of the unwinding statement */ - ADDOP(c, POP_BLOCK); + ADDOP(c, *ploc, POP_BLOCK); if (preserve_tos) { - if (!compiler_push_fblock(c, POP_VALUE, NO_LABEL, NO_LABEL, NULL)) { + if (!compiler_push_fblock(c, *ploc, POP_VALUE, NO_LABEL, NO_LABEL, NULL)) { return 0; } } @@ -2030,78 +2014,84 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info, * statement causing the unwinding, so make the unwinding * instruction artificial */ UNSET_LOC(c); + *ploc = NO_LOCATION; return 1; case FINALLY_END: if (preserve_tos) { - ADDOP_I(c, SWAP, 2); + ADDOP_I(c, *ploc, SWAP, 2); } - ADDOP(c, POP_TOP); /* exc_value */ + ADDOP(c, *ploc, POP_TOP); /* exc_value */ if (preserve_tos) { - ADDOP_I(c, SWAP, 2); + ADDOP_I(c, *ploc, SWAP, 2); } - ADDOP(c, POP_BLOCK); - ADDOP(c, POP_EXCEPT); + ADDOP(c, *ploc, POP_BLOCK); + ADDOP(c, *ploc, POP_EXCEPT); return 1; case WITH: case ASYNC_WITH: SET_LOC(c, (stmt_ty)info->fb_datum); - ADDOP(c, POP_BLOCK); + *ploc = LOC((stmt_ty)info->fb_datum); + ADDOP(c, *ploc, POP_BLOCK); if (preserve_tos) { - ADDOP_I(c, SWAP, 2); + ADDOP_I(c, *ploc, SWAP, 2); } - if(!compiler_call_exit_with_nones(c)) { + if(!compiler_call_exit_with_nones(c, *ploc)) { return 0; } if (info->fb_type == ASYNC_WITH) { - ADDOP_I(c, GET_AWAITABLE, 2); - ADDOP_LOAD_CONST(c, Py_None); - ADD_YIELD_FROM(c, 1); + ADDOP_I(c, *ploc, GET_AWAITABLE, 2); + ADDOP_LOAD_CONST(c, *ploc, Py_None); + ADD_YIELD_FROM(c, *ploc, 1); } - ADDOP(c, POP_TOP); + ADDOP(c, *ploc, POP_TOP); /* The exit block should appear to execute after the * statement causing the unwinding, so make the unwinding * instruction artificial */ UNSET_LOC(c); + *ploc = NO_LOCATION; return 1; - case HANDLER_CLEANUP: + case HANDLER_CLEANUP: { if (info->fb_datum) { - ADDOP(c, POP_BLOCK); + ADDOP(c, *ploc, POP_BLOCK); } if (preserve_tos) { - ADDOP_I(c, SWAP, 2); + ADDOP_I(c, *ploc, SWAP, 2); } - ADDOP(c, POP_BLOCK); - ADDOP(c, POP_EXCEPT); + ADDOP(c, *ploc, POP_BLOCK); + ADDOP(c, *ploc, POP_EXCEPT); if (info->fb_datum) { - ADDOP_LOAD_CONST(c, Py_None); - compiler_nameop(c, info->fb_datum, Store); - compiler_nameop(c, info->fb_datum, Del); + ADDOP_LOAD_CONST(c, *ploc, Py_None); + compiler_nameop(c, *ploc, info->fb_datum, Store); + compiler_nameop(c, *ploc, info->fb_datum, Del); } return 1; - - case POP_VALUE: + } + case POP_VALUE: { if (preserve_tos) { - ADDOP_I(c, SWAP, 2); + ADDOP_I(c, *ploc, SWAP, 2); } - ADDOP(c, POP_TOP); + ADDOP(c, *ploc, POP_TOP); return 1; + } } Py_UNREACHABLE(); } /** Unwind block stack. If loop is not NULL, then stop when the first loop is encountered. */ static int -compiler_unwind_fblock_stack(struct compiler *c, int preserve_tos, struct fblockinfo **loop) { +compiler_unwind_fblock_stack(struct compiler *c, location *ploc, + int preserve_tos, struct fblockinfo **loop) +{ if (c->u->u_nfblocks == 0) { return 1; } struct fblockinfo *top = &c->u->u_fblock[c->u->u_nfblocks-1]; if (top->fb_type == EXCEPTION_GROUP_HANDLER) { return compiler_error( - c, "'break', 'continue' and 'return' cannot appear in an except* block"); + c, *ploc, "'break', 'continue' and 'return' cannot appear in an except* block"); } if (loop != NULL && (top->fb_type == WHILE_LOOP || top->fb_type == FOR_LOOP)) { *loop = top; @@ -2109,10 +2099,10 @@ compiler_unwind_fblock_stack(struct compiler *c, int preserve_tos, struct fblock } struct fblockinfo copy = *top; c->u->u_nfblocks--; - if (!compiler_unwind_fblock(c, ©, preserve_tos)) { + if (!compiler_unwind_fblock(c, ploc, ©, preserve_tos)) { return 0; } - if (!compiler_unwind_fblock_stack(c, preserve_tos, loop)) { + if (!compiler_unwind_fblock_stack(c, ploc, preserve_tos, loop)) { return 0; } c->u->u_fblock[c->u->u_nfblocks] = copy; @@ -2124,7 +2114,7 @@ compiler_unwind_fblock_stack(struct compiler *c, int preserve_tos, struct fblock and for annotations. */ static int -compiler_body(struct compiler *c, asdl_stmt_seq *stmts) +compiler_body(struct compiler *c, location loc, asdl_stmt_seq *stmts) { int i = 0; stmt_ty st; @@ -2137,10 +2127,11 @@ compiler_body(struct compiler *c, asdl_stmt_seq *stmts) if (c->u->u_scope_type == COMPILER_SCOPE_MODULE && asdl_seq_LEN(stmts)) { st = (stmt_ty)asdl_seq_GET(stmts, 0); SET_LOC(c, st); + loc = LOC(st); } /* Every annotated class and module should have __annotations__. */ if (find_ann(stmts)) { - ADDOP(c, SETUP_ANNOTATIONS); + ADDOP(c, loc, SETUP_ANNOTATIONS); } if (!asdl_seq_LEN(stmts)) return 1; @@ -2153,7 +2144,7 @@ compiler_body(struct compiler *c, asdl_stmt_seq *stmts) assert(st->kind == Expr_kind); VISIT(c, expr, st->v.Expr.value); UNSET_LOC(c); - if (!compiler_nameop(c, &_Py_ID(__doc__), Store)) + if (!compiler_nameop(c, NO_LOCATION, &_Py_ID(__doc__), Store)) return 0; } } @@ -2172,17 +2163,17 @@ compiler_mod(struct compiler *c, mod_ty mod) mod, 1)) { return NULL; } - c->u->u_loc.lineno = 1; + location loc = LOCATION(1, 1, 0, 0); switch (mod->kind) { case Module_kind: - if (!compiler_body(c, mod->v.Module.body)) { + if (!compiler_body(c, loc, mod->v.Module.body)) { compiler_exit_scope(c); return 0; } break; case Interactive_kind: if (find_ann(mod->v.Interactive.body)) { - ADDOP(c, SETUP_ANNOTATIONS); + ADDOP(c, loc, SETUP_ANNOTATIONS); } c->c_interactive = 1; VISIT_SEQ_IN_SCOPE(c, stmt, mod->v.Interactive.body); @@ -2239,8 +2230,8 @@ compiler_lookup_arg(PyObject *dict, PyObject *name) } static int -compiler_make_closure(struct compiler *c, PyCodeObject *co, Py_ssize_t flags, - PyObject *qualname) +compiler_make_closure(struct compiler *c, location loc, + PyCodeObject *co, Py_ssize_t flags, PyObject *qualname) { if (qualname == NULL) qualname = co->co_name; @@ -2286,13 +2277,13 @@ compiler_make_closure(struct compiler *c, PyCodeObject *co, Py_ssize_t flags, Py_DECREF(freevars); return 0; } - ADDOP_I(c, LOAD_CLOSURE, arg); + ADDOP_I(c, loc, LOAD_CLOSURE, arg); } flags |= 0x08; - ADDOP_I(c, BUILD_TUPLE, co->co_nfreevars); + ADDOP_I(c, loc, BUILD_TUPLE, co->co_nfreevars); } - ADDOP_LOAD_CONST(c, (PyObject*)co); - ADDOP_I(c, MAKE_FUNCTION, flags); + ADDOP_LOAD_CONST(c, loc, (PyObject*)co); + ADDOP_I(c, loc, MAKE_FUNCTION, flags); return 1; } @@ -2316,18 +2307,17 @@ compiler_apply_decorators(struct compiler *c, asdl_expr_seq* decos) if (!decos) return 1; - struct location old_loc = c->u->u_loc; for (Py_ssize_t i = asdl_seq_LEN(decos) - 1; i > -1; i--) { SET_LOC(c, (expr_ty)asdl_seq_GET(decos, i)); - ADDOP_I(c, CALL, 0); + location loc = LOC((expr_ty)asdl_seq_GET(decos, i)); + ADDOP_I(c, loc, CALL, 0); } - c->u->u_loc = old_loc; return 1; } static int -compiler_visit_kwonlydefaults(struct compiler *c, asdl_arg_seq *kwonlyargs, - asdl_expr_seq *kw_defaults) +compiler_visit_kwonlydefaults(struct compiler *c, location loc, + asdl_arg_seq *kwonlyargs, asdl_expr_seq *kw_defaults) { /* Push a dict of keyword-only default values. @@ -2368,8 +2358,8 @@ compiler_visit_kwonlydefaults(struct compiler *c, asdl_arg_seq *kwonlyargs, Py_ssize_t default_count = PyList_GET_SIZE(keys); PyObject *keys_tuple = PyList_AsTuple(keys); Py_DECREF(keys); - ADDOP_LOAD_CONST_NEW(c, keys_tuple); - ADDOP_I(c, BUILD_CONST_KEY_MAP, default_count); + ADDOP_LOAD_CONST_NEW(c, loc, keys_tuple); + ADDOP_I(c, loc, BUILD_CONST_KEY_MAP, default_count); assert(default_count > 0); return 1; } @@ -2385,23 +2375,23 @@ compiler_visit_kwonlydefaults(struct compiler *c, asdl_arg_seq *kwonlyargs, static int compiler_visit_annexpr(struct compiler *c, expr_ty annotation) { - ADDOP_LOAD_CONST_NEW(c, _PyAST_ExprAsUnicode(annotation)); + location loc = LOC(annotation); + ADDOP_LOAD_CONST_NEW(c, loc, _PyAST_ExprAsUnicode(annotation)); return 1; } static int compiler_visit_argannotation(struct compiler *c, identifier id, - expr_ty annotation, Py_ssize_t *annotations_len) + expr_ty annotation, Py_ssize_t *annotations_len, location loc) { if (!annotation) { return 1; } - PyObject *mangled = _Py_Mangle(c->u->u_private, id); if (!mangled) { return 0; } - ADDOP_LOAD_CONST(c, mangled); + ADDOP_LOAD_CONST(c, loc, mangled); Py_DECREF(mangled); if (c->c_future->ff_features & CO_FUTURE_ANNOTATIONS) { @@ -2414,7 +2404,7 @@ compiler_visit_argannotation(struct compiler *c, identifier id, // (Note that in theory we could end up here even for an argument // other than *args, but in practice the grammar doesn't allow it.) VISIT(c, expr, annotation->v.Starred.value); - ADDOP_I(c, UNPACK_SEQUENCE, (Py_ssize_t) 1); + ADDOP_I(c, loc, UNPACK_SEQUENCE, (Py_ssize_t) 1); } else { VISIT(c, expr, annotation); @@ -2426,7 +2416,7 @@ compiler_visit_argannotation(struct compiler *c, identifier id, static int compiler_visit_argannotations(struct compiler *c, asdl_arg_seq* args, - Py_ssize_t *annotations_len) + Py_ssize_t *annotations_len, location loc) { int i; for (i = 0; i < asdl_seq_LEN(args); i++) { @@ -2435,15 +2425,16 @@ compiler_visit_argannotations(struct compiler *c, asdl_arg_seq* args, c, arg->arg, arg->annotation, - annotations_len)) + annotations_len, + loc)) return 0; } return 1; } static int -compiler_visit_annotations(struct compiler *c, arguments_ty args, - expr_ty returns) +compiler_visit_annotations(struct compiler *c, location loc, + arguments_ty args, expr_ty returns) { /* Push arg annotation names and values. The expressions are evaluated out-of-order wrt the source code. @@ -2452,28 +2443,28 @@ compiler_visit_annotations(struct compiler *c, arguments_ty args, */ Py_ssize_t annotations_len = 0; - if (!compiler_visit_argannotations(c, args->args, &annotations_len)) + if (!compiler_visit_argannotations(c, args->args, &annotations_len, loc)) return 0; - if (!compiler_visit_argannotations(c, args->posonlyargs, &annotations_len)) + if (!compiler_visit_argannotations(c, args->posonlyargs, &annotations_len, loc)) return 0; if (args->vararg && args->vararg->annotation && !compiler_visit_argannotation(c, args->vararg->arg, - args->vararg->annotation, &annotations_len)) + args->vararg->annotation, &annotations_len, loc)) return 0; - if (!compiler_visit_argannotations(c, args->kwonlyargs, &annotations_len)) + if (!compiler_visit_argannotations(c, args->kwonlyargs, &annotations_len, loc)) return 0; if (args->kwarg && args->kwarg->annotation && !compiler_visit_argannotation(c, args->kwarg->arg, - args->kwarg->annotation, &annotations_len)) + args->kwarg->annotation, &annotations_len, loc)) return 0; if (!compiler_visit_argannotation(c, &_Py_ID(return), returns, - &annotations_len)) { + &annotations_len, loc)) { return 0; } if (annotations_len) { - ADDOP_I(c, BUILD_TUPLE, annotations_len); + ADDOP_I(c, loc, BUILD_TUPLE, annotations_len); return 1; } @@ -2481,24 +2472,27 @@ compiler_visit_annotations(struct compiler *c, arguments_ty args, } static int -compiler_visit_defaults(struct compiler *c, arguments_ty args) +compiler_visit_defaults(struct compiler *c, arguments_ty args, + location loc) { VISIT_SEQ(c, expr, args->defaults); - ADDOP_I(c, BUILD_TUPLE, asdl_seq_LEN(args->defaults)); + ADDOP_I(c, loc, BUILD_TUPLE, asdl_seq_LEN(args->defaults)); return 1; } static Py_ssize_t -compiler_default_arguments(struct compiler *c, arguments_ty args) +compiler_default_arguments(struct compiler *c, location loc, + arguments_ty args) { Py_ssize_t funcflags = 0; if (args->defaults && asdl_seq_LEN(args->defaults) > 0) { - if (!compiler_visit_defaults(c, args)) + if (!compiler_visit_defaults(c, args, loc)) return -1; funcflags |= 0x01; } if (args->kwonlyargs) { - int res = compiler_visit_kwonlydefaults(c, args->kwonlyargs, + int res = compiler_visit_kwonlydefaults(c, loc, + args->kwonlyargs, args->kw_defaults); if (res == 0) { return -1; @@ -2511,15 +2505,15 @@ compiler_default_arguments(struct compiler *c, arguments_ty args) } static int -forbidden_name(struct compiler *c, identifier name, expr_context_ty ctx) +forbidden_name(struct compiler *c, location loc, identifier name, + expr_context_ty ctx) { - if (ctx == Store && _PyUnicode_EqualToASCIIString(name, "__debug__")) { - compiler_error(c, "cannot assign to __debug__"); + compiler_error(c, loc, "cannot assign to __debug__"); return 1; } if (ctx == Del && _PyUnicode_EqualToASCIIString(name, "__debug__")) { - compiler_error(c, "cannot delete __debug__"); + compiler_error(c, loc, "cannot delete __debug__"); return 1; } return 0; @@ -2529,7 +2523,7 @@ static int compiler_check_debug_one_arg(struct compiler *c, arg_ty arg) { if (arg != NULL) { - if (forbidden_name(c, arg->arg, Store)) + if (forbidden_name(c, LOC(arg), arg->arg, Store)) return 0; } return 1; @@ -2611,12 +2605,12 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async) firstlineno = ((expr_ty)asdl_seq_GET(decos, 0))->lineno; } - funcflags = compiler_default_arguments(c, args); + location loc = LOC(s); + funcflags = compiler_default_arguments(c, loc, args); if (funcflags == -1) { return 0; } - - annotations = compiler_visit_annotations(c, args, returns); + annotations = compiler_visit_annotations(c, loc, args, returns); if (annotations == 0) { return 0; } @@ -2652,8 +2646,7 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async) Py_XDECREF(co); return 0; } - - if (!compiler_make_closure(c, co, funcflags, qualname)) { + if (!compiler_make_closure(c, loc, co, funcflags, qualname)) { Py_DECREF(qualname); Py_DECREF(co); return 0; @@ -2663,7 +2656,7 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async) if (!compiler_apply_decorators(c, decos)) return 0; - return compiler_nameop(c, name, Store); + return compiler_nameop(c, loc, name, Store); } static int @@ -2691,7 +2684,6 @@ compiler_class(struct compiler *c, stmt_ty s) is the keyword arguments and **kwds argument This borrows from compiler_call. */ - /* 1. compile the class body into a code object */ if (!compiler_enter_scope(c, s->v.ClassDef.name, COMPILER_SCOPE_CLASS, (void *)s, firstlineno)) { @@ -2699,27 +2691,28 @@ compiler_class(struct compiler *c, stmt_ty s) } /* this block represents what we do in the new scope */ { + location loc = LOCATION(firstlineno, firstlineno, 0, 0); /* use the class name for name mangling */ Py_INCREF(s->v.ClassDef.name); Py_XSETREF(c->u->u_private, s->v.ClassDef.name); /* load (global) __name__ ... */ - if (!compiler_nameop(c, &_Py_ID(__name__), Load)) { + if (!compiler_nameop(c, loc, &_Py_ID(__name__), Load)) { compiler_exit_scope(c); return 0; } /* ... and store it as __module__ */ - if (!compiler_nameop(c, &_Py_ID(__module__), Store)) { + if (!compiler_nameop(c, loc, &_Py_ID(__module__), Store)) { compiler_exit_scope(c); return 0; } assert(c->u->u_qualname); - ADDOP_LOAD_CONST(c, c->u->u_qualname); - if (!compiler_nameop(c, &_Py_ID(__qualname__), Store)) { + ADDOP_LOAD_CONST(c, loc, c->u->u_qualname); + if (!compiler_nameop(c, loc, &_Py_ID(__qualname__), Store)) { compiler_exit_scope(c); return 0; } /* compile the body proper */ - if (!compiler_body(c, s->v.ClassDef.body)) { + if (!compiler_body(c, loc, s->v.ClassDef.body)) { compiler_exit_scope(c); return 0; } @@ -2734,10 +2727,9 @@ compiler_class(struct compiler *c, stmt_ty s) return 0; } assert(i == 0); - - ADDOP_I(c, LOAD_CLOSURE, i); - ADDOP_I(c, COPY, 1); - if (!compiler_nameop(c, &_Py_ID(__classcell__), Store)) { + ADDOP_I(c, NO_LOCATION, LOAD_CLOSURE, i); + ADDOP_I(c, NO_LOCATION, COPY, 1); + if (!compiler_nameop(c, NO_LOCATION, &_Py_ID(__classcell__), Store)) { compiler_exit_scope(c); return 0; } @@ -2745,9 +2737,9 @@ compiler_class(struct compiler *c, stmt_ty s) else { /* No methods referenced __class__, so just return None */ assert(PyDict_GET_SIZE(c->u->u_cellvars) == 0); - ADDOP_LOAD_CONST(c, Py_None); + ADDOP_LOAD_CONST(c, NO_LOCATION, Py_None); } - ADDOP_IN_SCOPE(c, RETURN_VALUE); + ADDOP_IN_SCOPE(c, NO_LOCATION, RETURN_VALUE); /* create the code object */ co = assemble(c, 1); } @@ -2756,29 +2748,32 @@ compiler_class(struct compiler *c, stmt_ty s) if (co == NULL) return 0; + location loc = LOC(s); /* 2. load the 'build_class' function */ - ADDOP(c, PUSH_NULL); - ADDOP(c, LOAD_BUILD_CLASS); + ADDOP(c, loc, PUSH_NULL); + ADDOP(c, loc, LOAD_BUILD_CLASS); /* 3. load a function (or closure) made from the code object */ - if (!compiler_make_closure(c, co, 0, NULL)) { + if (!compiler_make_closure(c, loc, co, 0, NULL)) { Py_DECREF(co); return 0; } Py_DECREF(co); /* 4. load class name */ - ADDOP_LOAD_CONST(c, s->v.ClassDef.name); + ADDOP_LOAD_CONST(c, loc, s->v.ClassDef.name); /* 5. generate the rest of the code for the call */ - if (!compiler_call_helper(c, 2, s->v.ClassDef.bases, s->v.ClassDef.keywords)) + if (!compiler_call_helper(c, loc, 2, + s->v.ClassDef.bases, + s->v.ClassDef.keywords)) return 0; /* 6. apply decorators */ if (!compiler_apply_decorators(c, decos)) return 0; /* 7. store into */ - if (!compiler_nameop(c, s->v.ClassDef.name, Store)) + if (!compiler_nameop(c, loc, s->v.ClassDef.name, Store)) return 0; return 1; } @@ -2816,7 +2811,7 @@ check_compare(struct compiler *c, expr_ty e) const char *msg = (op == Is) ? "\"is\" with a literal. Did you mean \"==\"?" : "\"is not\" with a literal. Did you mean \"!=\"?"; - return compiler_warn(c, msg); + return compiler_warn(c, LOC(e), msg); } } left = right; @@ -2824,7 +2819,8 @@ check_compare(struct compiler *c, expr_ty e) return 1; } -static int compiler_addcompare(struct compiler *c, cmpop_ty op) +static int compiler_addcompare(struct compiler *c, location loc, + cmpop_ty op) { int cmp; switch (op) { @@ -2847,33 +2843,34 @@ static int compiler_addcompare(struct compiler *c, cmpop_ty op) cmp = Py_GE; break; case Is: - ADDOP_I(c, IS_OP, 0); + ADDOP_I(c, loc, IS_OP, 0); return 1; case IsNot: - ADDOP_I(c, IS_OP, 1); + ADDOP_I(c, loc, IS_OP, 1); return 1; case In: - ADDOP_I(c, CONTAINS_OP, 0); + ADDOP_I(c, loc, CONTAINS_OP, 0); return 1; case NotIn: - ADDOP_I(c, CONTAINS_OP, 1); + ADDOP_I(c, loc, CONTAINS_OP, 1); return 1; default: Py_UNREACHABLE(); } - ADDOP_I(c, COMPARE_OP, cmp); + ADDOP_I(c, loc, COMPARE_OP, cmp); return 1; } static int -compiler_jump_if(struct compiler *c, expr_ty e, jump_target_label next, int cond) +compiler_jump_if(struct compiler *c, location *ploc, + expr_ty e, jump_target_label next, int cond) { switch (e->kind) { case UnaryOp_kind: if (e->v.UnaryOp.op == Not) - return compiler_jump_if(c, e->v.UnaryOp.operand, next, !cond); + return compiler_jump_if(c, ploc, e->v.UnaryOp.operand, next, !cond); /* fallback to general implementation */ break; case BoolOp_kind: { @@ -2887,10 +2884,10 @@ compiler_jump_if(struct compiler *c, expr_ty e, jump_target_label next, int cond next2 = new_next2; } for (i = 0; i < n; ++i) { - if (!compiler_jump_if(c, (expr_ty)asdl_seq_GET(s, i), next2, cond2)) + if (!compiler_jump_if(c, ploc, (expr_ty)asdl_seq_GET(s, i), next2, cond2)) return 0; } - if (!compiler_jump_if(c, (expr_ty)asdl_seq_GET(s, n), next, cond)) + if (!compiler_jump_if(c, ploc, (expr_ty)asdl_seq_GET(s, n), next, cond)) return 0; if (!SAME_LABEL(next2, next)) { USE_LABEL(c, next2); @@ -2900,14 +2897,14 @@ compiler_jump_if(struct compiler *c, expr_ty e, jump_target_label next, int cond case IfExp_kind: { NEW_JUMP_TARGET_LABEL(c, end); NEW_JUMP_TARGET_LABEL(c, next2); - if (!compiler_jump_if(c, e->v.IfExp.test, next2, 0)) + if (!compiler_jump_if(c, ploc, e->v.IfExp.test, next2, 0)) return 0; - if (!compiler_jump_if(c, e->v.IfExp.body, next, cond)) + if (!compiler_jump_if(c, ploc, e->v.IfExp.body, next, cond)) return 0; - ADDOP_JUMP_NOLINE(c, JUMP, end); + ADDOP_JUMP(c, NO_LOCATION, JUMP, end); USE_LABEL(c, next2); - if (!compiler_jump_if(c, e->v.IfExp.orelse, next, cond)) + if (!compiler_jump_if(c, ploc, e->v.IfExp.orelse, next, cond)) return 0; USE_LABEL(c, end); @@ -2915,6 +2912,7 @@ compiler_jump_if(struct compiler *c, expr_ty e, jump_target_label next, int cond } case Compare_kind: { SET_LOC(c, e); + *ploc = LOC(e); Py_ssize_t i, n = asdl_seq_LEN(e->v.Compare.ops) - 1; if (n > 0) { if (!check_compare(c, e)) { @@ -2925,21 +2923,21 @@ compiler_jump_if(struct compiler *c, expr_ty e, jump_target_label next, int cond for (i = 0; i < n; i++) { VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, i)); - ADDOP_I(c, SWAP, 2); - ADDOP_I(c, COPY, 2); - ADDOP_COMPARE(c, asdl_seq_GET(e->v.Compare.ops, i)); - ADDOP_JUMP(c, POP_JUMP_IF_FALSE, cleanup); + ADDOP_I(c, *ploc, SWAP, 2); + ADDOP_I(c, *ploc, COPY, 2); + ADDOP_COMPARE(c, *ploc, asdl_seq_GET(e->v.Compare.ops, i)); + ADDOP_JUMP(c, *ploc, POP_JUMP_IF_FALSE, cleanup); } VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, n)); - ADDOP_COMPARE(c, asdl_seq_GET(e->v.Compare.ops, n)); - ADDOP_JUMP(c, cond ? POP_JUMP_IF_TRUE : POP_JUMP_IF_FALSE, next); + ADDOP_COMPARE(c, *ploc, asdl_seq_GET(e->v.Compare.ops, n)); + ADDOP_JUMP(c, *ploc, cond ? POP_JUMP_IF_TRUE : POP_JUMP_IF_FALSE, next); NEW_JUMP_TARGET_LABEL(c, end); - ADDOP_JUMP_NOLINE(c, JUMP, end); + ADDOP_JUMP(c, NO_LOCATION, JUMP, end); USE_LABEL(c, cleanup); - ADDOP(c, POP_TOP); + ADDOP(c, *ploc, POP_TOP); if (!cond) { - ADDOP_JUMP_NOLINE(c, JUMP, next); + ADDOP_JUMP(c, NO_LOCATION, JUMP, next); } USE_LABEL(c, end); @@ -2955,7 +2953,7 @@ compiler_jump_if(struct compiler *c, expr_ty e, jump_target_label next, int cond /* general implementation */ VISIT(c, expr, e); - ADDOP_JUMP(c, cond ? POP_JUMP_IF_TRUE : POP_JUMP_IF_FALSE, next); + ADDOP_JUMP(c, *ploc, cond ? POP_JUMP_IF_TRUE : POP_JUMP_IF_FALSE, next); return 1; } @@ -2966,10 +2964,12 @@ compiler_ifexp(struct compiler *c, expr_ty e) NEW_JUMP_TARGET_LABEL(c, end); NEW_JUMP_TARGET_LABEL(c, next); - if (!compiler_jump_if(c, e->v.IfExp.test, next, 0)) + location loc = LOC(e); + if (!compiler_jump_if(c, &loc, e->v.IfExp.test, next, 0)) { return 0; + } VISIT(c, expr, e->v.IfExp.body); - ADDOP_JUMP_NOLINE(c, JUMP, end); + ADDOP_JUMP(c, NO_LOCATION, JUMP, end); USE_LABEL(c, next); VISIT(c, expr, e->v.IfExp.orelse); @@ -2990,7 +2990,8 @@ compiler_lambda(struct compiler *c, expr_ty e) if (!compiler_check_debug_args(c, args)) return 0; - funcflags = compiler_default_arguments(c, args); + location loc = LOC(e); + funcflags = compiler_default_arguments(c, loc, args); if (funcflags == -1) { return 0; } @@ -3013,7 +3014,8 @@ compiler_lambda(struct compiler *c, expr_ty e) co = assemble(c, 0); } else { - ADDOP_IN_SCOPE(c, RETURN_VALUE); + location loc = LOCATION(e->lineno, e->lineno, 0, 0); + ADDOP_IN_SCOPE(c, loc, RETURN_VALUE); co = assemble(c, 1); } qualname = c->u->u_qualname; @@ -3024,7 +3026,7 @@ compiler_lambda(struct compiler *c, expr_ty e) return 0; } - if (!compiler_make_closure(c, co, funcflags, qualname)) { + if (!compiler_make_closure(c, loc, co, funcflags, qualname)) { Py_DECREF(qualname); Py_DECREF(co); return 0; @@ -3048,12 +3050,13 @@ compiler_if(struct compiler *c, stmt_ty s) else { next = end; } - if (!compiler_jump_if(c, s->v.If.test, next, 0)) { + location loc = LOC(s); + if (!compiler_jump_if(c, &loc, s->v.If.test, next, 0)) { return 0; } VISIT_SEQ(c, stmt, s->v.If.body); if (asdl_seq_LEN(s->v.If.orelse)) { - ADDOP_JUMP_NOLINE(c, JUMP, end); + ADDOP_JUMP(c, NO_LOCATION, JUMP, end); USE_LABEL(c, next); VISIT_SEQ(c, stmt, s->v.If.orelse); @@ -3066,26 +3069,27 @@ compiler_if(struct compiler *c, stmt_ty s) static int compiler_for(struct compiler *c, stmt_ty s) { + location loc = LOC(s); NEW_JUMP_TARGET_LABEL(c, start); NEW_JUMP_TARGET_LABEL(c, body); NEW_JUMP_TARGET_LABEL(c, cleanup); NEW_JUMP_TARGET_LABEL(c, end); - if (!compiler_push_fblock(c, FOR_LOOP, start, end, NULL)) { + if (!compiler_push_fblock(c, loc, FOR_LOOP, start, end, NULL)) { return 0; } VISIT(c, expr, s->v.For.iter); - ADDOP(c, GET_ITER); + ADDOP(c, loc, GET_ITER); USE_LABEL(c, start); - ADDOP_JUMP(c, FOR_ITER, cleanup); + ADDOP_JUMP(c, loc, FOR_ITER, cleanup); USE_LABEL(c, body); VISIT(c, expr, s->v.For.target); VISIT_SEQ(c, stmt, s->v.For.body); /* Mark jump as artificial */ UNSET_LOC(c); - ADDOP_JUMP(c, JUMP, start); + ADDOP_JUMP(c, NO_LOCATION, JUMP, start); USE_LABEL(c, cleanup); @@ -3101,10 +3105,11 @@ compiler_for(struct compiler *c, stmt_ty s) static int compiler_async_for(struct compiler *c, stmt_ty s) { + location loc = LOC(s); if (IS_TOP_LEVEL_AWAIT(c)){ c->u->u_ste->ste_coroutine = 1; } else if (c->u->u_scope_type != COMPILER_SCOPE_ASYNC_FUNCTION) { - return compiler_error(c, "'async for' outside async function"); + return compiler_error(c, loc, "'async for' outside async function"); } NEW_JUMP_TARGET_LABEL(c, start); @@ -3112,25 +3117,25 @@ compiler_async_for(struct compiler *c, stmt_ty s) NEW_JUMP_TARGET_LABEL(c, end); VISIT(c, expr, s->v.AsyncFor.iter); - ADDOP(c, GET_AITER); + ADDOP(c, loc, GET_AITER); USE_LABEL(c, start); - if (!compiler_push_fblock(c, FOR_LOOP, start, end, NULL)) { + if (!compiler_push_fblock(c, loc, FOR_LOOP, start, end, NULL)) { return 0; } /* SETUP_FINALLY to guard the __anext__ call */ - ADDOP_JUMP(c, SETUP_FINALLY, except); - ADDOP(c, GET_ANEXT); - ADDOP_LOAD_CONST(c, Py_None); - ADD_YIELD_FROM(c, 1); - ADDOP(c, POP_BLOCK); /* for SETUP_FINALLY */ + ADDOP_JUMP(c, loc, SETUP_FINALLY, except); + ADDOP(c, loc, GET_ANEXT); + ADDOP_LOAD_CONST(c, loc, Py_None); + ADD_YIELD_FROM(c, loc, 1); + ADDOP(c, loc, POP_BLOCK); /* for SETUP_FINALLY */ /* Success block for __anext__ */ VISIT(c, expr, s->v.AsyncFor.target); VISIT_SEQ(c, stmt, s->v.AsyncFor.body); /* Mark jump as artificial */ UNSET_LOC(c); - ADDOP_JUMP(c, JUMP, start); + ADDOP_JUMP(c, NO_LOCATION, JUMP, start); compiler_pop_fblock(c, FOR_LOOP, start); @@ -3140,7 +3145,8 @@ compiler_async_for(struct compiler *c, stmt_ty s) /* Use same line number as the iterator, * as the END_ASYNC_FOR succeeds the `for`, not the body. */ SET_LOC(c, s->v.AsyncFor.iter); - ADDOP(c, END_ASYNC_FOR); + loc = LOC(s->v.AsyncFor.iter); + ADDOP(c, loc, END_ASYNC_FOR); /* `else` block */ VISIT_SEQ(c, stmt, s->v.For.orelse); @@ -3152,23 +3158,25 @@ compiler_async_for(struct compiler *c, stmt_ty s) static int compiler_while(struct compiler *c, stmt_ty s) { + location loc = LOC(s); NEW_JUMP_TARGET_LABEL(c, loop); NEW_JUMP_TARGET_LABEL(c, body); NEW_JUMP_TARGET_LABEL(c, end); NEW_JUMP_TARGET_LABEL(c, anchor); USE_LABEL(c, loop); - if (!compiler_push_fblock(c, WHILE_LOOP, loop, end, NULL)) { + if (!compiler_push_fblock(c, loc, WHILE_LOOP, loop, end, NULL)) { return 0; } - if (!compiler_jump_if(c, s->v.While.test, anchor, 0)) { + if (!compiler_jump_if(c, &loc, s->v.While.test, anchor, 0)) { return 0; } USE_LABEL(c, body); VISIT_SEQ(c, stmt, s->v.While.body); SET_LOC(c, s); - if (!compiler_jump_if(c, s->v.While.test, body, 1)) { + loc = LOC(s); + if (!compiler_jump_if(c, &loc, s->v.While.test, body, 1)) { return 0; } @@ -3186,79 +3194,95 @@ compiler_while(struct compiler *c, stmt_ty s) static int compiler_return(struct compiler *c, stmt_ty s) { + location loc = LOC(s); int preserve_tos = ((s->v.Return.value != NULL) && (s->v.Return.value->kind != Constant_kind)); if (c->u->u_ste->ste_type != FunctionBlock) - return compiler_error(c, "'return' outside function"); + return compiler_error(c, loc, "'return' outside function"); if (s->v.Return.value != NULL && c->u->u_ste->ste_coroutine && c->u->u_ste->ste_generator) { return compiler_error( - c, "'return' with value in async generator"); + c, loc, "'return' with value in async generator"); } + if (preserve_tos) { VISIT(c, expr, s->v.Return.value); } else { /* Emit instruction with line number for return value */ if (s->v.Return.value != NULL) { SET_LOC(c, s->v.Return.value); - ADDOP(c, NOP); + loc = LOC(s->v.Return.value); + ADDOP(c, loc, NOP); } } if (s->v.Return.value == NULL || s->v.Return.value->lineno != s->lineno) { SET_LOC(c, s); - ADDOP(c, NOP); + loc = LOC(s); + ADDOP(c, loc, NOP); } - if (!compiler_unwind_fblock_stack(c, preserve_tos, NULL)) + if (!compiler_unwind_fblock_stack(c, &loc, preserve_tos, NULL)) return 0; if (s->v.Return.value == NULL) { - ADDOP_LOAD_CONST(c, Py_None); + ADDOP_LOAD_CONST(c, loc, Py_None); } else if (!preserve_tos) { - ADDOP_LOAD_CONST(c, s->v.Return.value->v.Constant.value); + ADDOP_LOAD_CONST(c, loc, s->v.Return.value->v.Constant.value); } - ADDOP(c, RETURN_VALUE); + ADDOP(c, loc, RETURN_VALUE); return 1; } static int -compiler_break(struct compiler *c) +compiler_break(struct compiler *c, location loc) { struct fblockinfo *loop = NULL; /* Emit instruction with line number */ - ADDOP(c, NOP); - if (!compiler_unwind_fblock_stack(c, 0, &loop)) { + ADDOP(c, loc, NOP); + if (!compiler_unwind_fblock_stack(c, &loc, 0, &loop)) { return 0; } if (loop == NULL) { - return compiler_error(c, "'break' outside loop"); + return compiler_error(c, loc, "'break' outside loop"); } - if (!compiler_unwind_fblock(c, loop, 0)) { + if (!compiler_unwind_fblock(c, &loc, loop, 0)) { return 0; } - ADDOP_JUMP(c, JUMP, loop->fb_exit); + ADDOP_JUMP(c, loc, JUMP, loop->fb_exit); return 1; } static int -compiler_continue(struct compiler *c) +compiler_continue(struct compiler *c, location loc) { struct fblockinfo *loop = NULL; /* Emit instruction with line number */ - ADDOP(c, NOP); - if (!compiler_unwind_fblock_stack(c, 0, &loop)) { + ADDOP(c, loc, NOP); + if (!compiler_unwind_fblock_stack(c, &loc, 0, &loop)) { return 0; } if (loop == NULL) { - return compiler_error(c, "'continue' not properly in loop"); + return compiler_error(c, loc, "'continue' not properly in loop"); } - ADDOP_JUMP(c, JUMP, loop->fb_block); + ADDOP_JUMP(c, loc, JUMP, loop->fb_block); return 1; } +static location +location_of_last_executing_statement(asdl_stmt_seq *stmts) +{ + for (Py_ssize_t i = asdl_seq_LEN(stmts) - 1; i >= 0; i++) { + location loc = LOC((stmt_ty)asdl_seq_GET(stmts, i)); + if (loc.lineno > 0) { + return loc; + } + } + return NO_LOCATION; +} + /* Code generated for "try: finally: " is as follows: SETUP_FINALLY L @@ -3291,16 +3315,18 @@ compiler_continue(struct compiler *c) static int compiler_try_finally(struct compiler *c, stmt_ty s) { + location loc = LOC(s); + NEW_JUMP_TARGET_LABEL(c, body); NEW_JUMP_TARGET_LABEL(c, end); NEW_JUMP_TARGET_LABEL(c, exit); NEW_JUMP_TARGET_LABEL(c, cleanup); /* `try` block */ - ADDOP_JUMP(c, SETUP_FINALLY, end); + ADDOP_JUMP(c, loc, SETUP_FINALLY, end); USE_LABEL(c, body); - if (!compiler_push_fblock(c, FINALLY_TRY, body, end, s->v.Try.finalbody)) + if (!compiler_push_fblock(c, loc, FINALLY_TRY, body, end, s->v.Try.finalbody)) return 0; if (s->v.Try.handlers && asdl_seq_LEN(s->v.Try.handlers)) { if (!compiler_try_except(c, s)) @@ -3309,25 +3335,29 @@ compiler_try_finally(struct compiler *c, stmt_ty s) else { VISIT_SEQ(c, stmt, s->v.Try.body); } - ADDOP_NOLINE(c, POP_BLOCK); + ADDOP(c, NO_LOCATION, POP_BLOCK); compiler_pop_fblock(c, FINALLY_TRY, body); VISIT_SEQ(c, stmt, s->v.Try.finalbody); - ADDOP_JUMP_NOLINE(c, JUMP, exit); + + ADDOP_JUMP(c, NO_LOCATION, JUMP, exit); /* `finally` block */ USE_LABEL(c, end); UNSET_LOC(c); - ADDOP_JUMP(c, SETUP_CLEANUP, cleanup); - ADDOP(c, PUSH_EXC_INFO); - if (!compiler_push_fblock(c, FINALLY_END, end, NO_LABEL, NULL)) + loc = NO_LOCATION; + ADDOP_JUMP(c, loc, SETUP_CLEANUP, cleanup); + ADDOP(c, loc, PUSH_EXC_INFO); + if (!compiler_push_fblock(c, loc, FINALLY_END, end, NO_LABEL, NULL)) return 0; VISIT_SEQ(c, stmt, s->v.Try.finalbody); + loc = location_of_last_executing_statement(s->v.Try.finalbody); compiler_pop_fblock(c, FINALLY_END, end); - ADDOP_I(c, RERAISE, 0); + + ADDOP_I(c, loc, RERAISE, 0); USE_LABEL(c, cleanup); - POP_EXCEPT_AND_RERAISE(c); + POP_EXCEPT_AND_RERAISE(c, loc); USE_LABEL(c, exit); return 1; @@ -3336,15 +3366,17 @@ compiler_try_finally(struct compiler *c, stmt_ty s) static int compiler_try_star_finally(struct compiler *c, stmt_ty s) { + location loc = LOC(s); + NEW_JUMP_TARGET_LABEL(c, body); NEW_JUMP_TARGET_LABEL(c, end); NEW_JUMP_TARGET_LABEL(c, exit); NEW_JUMP_TARGET_LABEL(c, cleanup); /* `try` block */ - ADDOP_JUMP(c, SETUP_FINALLY, end); + ADDOP_JUMP(c, loc, SETUP_FINALLY, end); USE_LABEL(c, body); - if (!compiler_push_fblock(c, FINALLY_TRY, body, end, s->v.TryStar.finalbody)) { + if (!compiler_push_fblock(c, loc, FINALLY_TRY, body, end, s->v.TryStar.finalbody)) { return 0; } if (s->v.TryStar.handlers && asdl_seq_LEN(s->v.TryStar.handlers)) { @@ -3355,26 +3387,30 @@ compiler_try_star_finally(struct compiler *c, stmt_ty s) else { VISIT_SEQ(c, stmt, s->v.TryStar.body); } - ADDOP_NOLINE(c, POP_BLOCK); + ADDOP(c, NO_LOCATION, POP_BLOCK); compiler_pop_fblock(c, FINALLY_TRY, body); VISIT_SEQ(c, stmt, s->v.TryStar.finalbody); - ADDOP_JUMP_NOLINE(c, JUMP, exit); + + ADDOP_JUMP(c, NO_LOCATION, JUMP, exit); /* `finally` block */ USE_LABEL(c, end); UNSET_LOC(c); - ADDOP_JUMP(c, SETUP_CLEANUP, cleanup); - ADDOP(c, PUSH_EXC_INFO); - if (!compiler_push_fblock(c, FINALLY_END, end, NO_LABEL, NULL)) { + loc = NO_LOCATION; + ADDOP_JUMP(c, loc, SETUP_CLEANUP, cleanup); + ADDOP(c, loc, PUSH_EXC_INFO); + if (!compiler_push_fblock(c, loc, FINALLY_END, end, NO_LABEL, NULL)) { return 0; } VISIT_SEQ(c, stmt, s->v.TryStar.finalbody); + loc = location_of_last_executing_statement(s->v.Try.finalbody); + compiler_pop_fblock(c, FINALLY_END, end); - ADDOP_I(c, RERAISE, 0); + ADDOP_I(c, loc, RERAISE, 0); USE_LABEL(c, cleanup); - POP_EXCEPT_AND_RERAISE(c); + POP_EXCEPT_AND_RERAISE(c, loc); USE_LABEL(c, exit); return 1; @@ -3412,6 +3448,7 @@ compiler_try_star_finally(struct compiler *c, stmt_ty s) static int compiler_try_except(struct compiler *c, stmt_ty s) { + location loc = LOC(s); Py_ssize_t i, n; NEW_JUMP_TARGET_LABEL(c, body); @@ -3419,47 +3456,48 @@ compiler_try_except(struct compiler *c, stmt_ty s) NEW_JUMP_TARGET_LABEL(c, end); NEW_JUMP_TARGET_LABEL(c, cleanup); - ADDOP_JUMP(c, SETUP_FINALLY, except); + ADDOP_JUMP(c, loc, SETUP_FINALLY, except); USE_LABEL(c, body); - if (!compiler_push_fblock(c, TRY_EXCEPT, body, NO_LABEL, NULL)) + if (!compiler_push_fblock(c, loc, TRY_EXCEPT, body, NO_LABEL, NULL)) return 0; VISIT_SEQ(c, stmt, s->v.Try.body); compiler_pop_fblock(c, TRY_EXCEPT, body); - ADDOP_NOLINE(c, POP_BLOCK); + ADDOP(c, NO_LOCATION, POP_BLOCK); if (s->v.Try.orelse && asdl_seq_LEN(s->v.Try.orelse)) { VISIT_SEQ(c, stmt, s->v.Try.orelse); } - ADDOP_JUMP_NOLINE(c, JUMP, end); + ADDOP_JUMP(c, NO_LOCATION, JUMP, end); n = asdl_seq_LEN(s->v.Try.handlers); USE_LABEL(c, except); UNSET_LOC(c); - ADDOP_JUMP(c, SETUP_CLEANUP, cleanup); - ADDOP(c, PUSH_EXC_INFO); + ADDOP_JUMP(c, NO_LOCATION, SETUP_CLEANUP, cleanup); + ADDOP(c, NO_LOCATION, PUSH_EXC_INFO); /* Runtime will push a block here, so we need to account for that */ - if (!compiler_push_fblock(c, EXCEPTION_HANDLER, NO_LABEL, NO_LABEL, NULL)) + if (!compiler_push_fblock(c, loc, EXCEPTION_HANDLER, NO_LABEL, NO_LABEL, NULL)) return 0; for (i = 0; i < n; i++) { excepthandler_ty handler = (excepthandler_ty)asdl_seq_GET( s->v.Try.handlers, i); SET_LOC(c, handler); + location loc = LOC(handler); if (!handler->v.ExceptHandler.type && i < n-1) { - return compiler_error(c, "default 'except:' must be last"); + return compiler_error(c, loc, "default 'except:' must be last"); } NEW_JUMP_TARGET_LABEL(c, next_except); except = next_except; if (handler->v.ExceptHandler.type) { VISIT(c, expr, handler->v.ExceptHandler.type); - ADDOP(c, CHECK_EXC_MATCH); - ADDOP_JUMP(c, POP_JUMP_IF_FALSE, except); + ADDOP(c, loc, CHECK_EXC_MATCH); + ADDOP_JUMP(c, loc, POP_JUMP_IF_FALSE, except); } if (handler->v.ExceptHandler.name) { NEW_JUMP_TARGET_LABEL(c, cleanup_end); NEW_JUMP_TARGET_LABEL(c, cleanup_body); - compiler_nameop(c, handler->v.ExceptHandler.name, Store); + compiler_nameop(c, loc, handler->v.ExceptHandler.name, Store); /* try: @@ -3473,24 +3511,26 @@ compiler_try_except(struct compiler *c, stmt_ty s) */ /* second try: */ - ADDOP_JUMP(c, SETUP_CLEANUP, cleanup_end); + ADDOP_JUMP(c, loc, SETUP_CLEANUP, cleanup_end); USE_LABEL(c, cleanup_body); - if (!compiler_push_fblock(c, HANDLER_CLEANUP, cleanup_body, NO_LABEL, handler->v.ExceptHandler.name)) + if (!compiler_push_fblock(c, loc, HANDLER_CLEANUP, cleanup_body, + NO_LABEL, handler->v.ExceptHandler.name)) { return 0; + } /* second # body */ VISIT_SEQ(c, stmt, handler->v.ExceptHandler.body); compiler_pop_fblock(c, HANDLER_CLEANUP, cleanup_body); /* name = None; del name; # Mark as artificial */ UNSET_LOC(c); - ADDOP(c, POP_BLOCK); - ADDOP(c, POP_BLOCK); - ADDOP(c, POP_EXCEPT); - ADDOP_LOAD_CONST(c, Py_None); - compiler_nameop(c, handler->v.ExceptHandler.name, Store); - compiler_nameop(c, handler->v.ExceptHandler.name, Del); - ADDOP_JUMP(c, JUMP, end); + ADDOP(c, NO_LOCATION, POP_BLOCK); + ADDOP(c, NO_LOCATION, POP_BLOCK); + ADDOP(c, NO_LOCATION, POP_EXCEPT); + ADDOP_LOAD_CONST(c, NO_LOCATION, Py_None); + compiler_nameop(c, NO_LOCATION, handler->v.ExceptHandler.name, Store); + compiler_nameop(c, NO_LOCATION, handler->v.ExceptHandler.name, Del); + ADDOP_JUMP(c, NO_LOCATION, JUMP, end); /* except: */ USE_LABEL(c, cleanup_end); @@ -3498,26 +3538,26 @@ compiler_try_except(struct compiler *c, stmt_ty s) /* name = None; del name; # Mark as artificial */ UNSET_LOC(c); - ADDOP_LOAD_CONST(c, Py_None); - compiler_nameop(c, handler->v.ExceptHandler.name, Store); - compiler_nameop(c, handler->v.ExceptHandler.name, Del); + ADDOP_LOAD_CONST(c, NO_LOCATION, Py_None); + compiler_nameop(c, NO_LOCATION, handler->v.ExceptHandler.name, Store); + compiler_nameop(c, NO_LOCATION, handler->v.ExceptHandler.name, Del); - ADDOP_I(c, RERAISE, 1); + ADDOP_I(c, NO_LOCATION, RERAISE, 1); } else { NEW_JUMP_TARGET_LABEL(c, cleanup_body); - ADDOP(c, POP_TOP); /* exc_value */ + ADDOP(c, loc, POP_TOP); /* exc_value */ USE_LABEL(c, cleanup_body); - if (!compiler_push_fblock(c, HANDLER_CLEANUP, cleanup_body, NO_LABEL, NULL)) + if (!compiler_push_fblock(c, loc, HANDLER_CLEANUP, cleanup_body, NO_LABEL, NULL)) return 0; VISIT_SEQ(c, stmt, handler->v.ExceptHandler.body); compiler_pop_fblock(c, HANDLER_CLEANUP, cleanup_body); UNSET_LOC(c); - ADDOP(c, POP_BLOCK); - ADDOP(c, POP_EXCEPT); - ADDOP_JUMP(c, JUMP, end); + ADDOP(c, NO_LOCATION, POP_BLOCK); + ADDOP(c, NO_LOCATION, POP_EXCEPT); + ADDOP_JUMP(c, NO_LOCATION, JUMP, end); } USE_LABEL(c, except); @@ -3525,10 +3565,10 @@ compiler_try_except(struct compiler *c, stmt_ty s) /* Mark as artificial */ UNSET_LOC(c); compiler_pop_fblock(c, EXCEPTION_HANDLER, NO_LABEL); - ADDOP_I(c, RERAISE, 0); + ADDOP_I(c, NO_LOCATION, RERAISE, 0); USE_LABEL(c, cleanup); - POP_EXCEPT_AND_RERAISE(c); + POP_EXCEPT_AND_RERAISE(c, NO_LOCATION); USE_LABEL(c, end); return 1; @@ -3586,6 +3626,8 @@ compiler_try_except(struct compiler *c, stmt_ty s) static int compiler_try_star_except(struct compiler *c, stmt_ty s) { + location loc = LOC(s); + NEW_JUMP_TARGET_LABEL(c, body); NEW_JUMP_TARGET_LABEL(c, except); NEW_JUMP_TARGET_LABEL(c, orelse); @@ -3593,25 +3635,25 @@ compiler_try_star_except(struct compiler *c, stmt_ty s) NEW_JUMP_TARGET_LABEL(c, cleanup); NEW_JUMP_TARGET_LABEL(c, reraise_star); - ADDOP_JUMP(c, SETUP_FINALLY, except); + ADDOP_JUMP(c, loc, SETUP_FINALLY, except); USE_LABEL(c, body); - if (!compiler_push_fblock(c, TRY_EXCEPT, body, NO_LABEL, NULL)) { + if (!compiler_push_fblock(c, loc, TRY_EXCEPT, body, NO_LABEL, NULL)) { return 0; } VISIT_SEQ(c, stmt, s->v.TryStar.body); compiler_pop_fblock(c, TRY_EXCEPT, body); - ADDOP_NOLINE(c, POP_BLOCK); - ADDOP_JUMP_NOLINE(c, JUMP, orelse); + ADDOP(c, NO_LOCATION, POP_BLOCK); + ADDOP_JUMP(c, NO_LOCATION, JUMP, orelse); Py_ssize_t n = asdl_seq_LEN(s->v.TryStar.handlers); USE_LABEL(c, except); UNSET_LOC(c); - ADDOP_JUMP(c, SETUP_CLEANUP, cleanup); - ADDOP(c, PUSH_EXC_INFO); + ADDOP_JUMP(c, NO_LOCATION, SETUP_CLEANUP, cleanup); + ADDOP(c, NO_LOCATION, PUSH_EXC_INFO); /* Runtime will push a block here, so we need to account for that */ - if (!compiler_push_fblock(c, EXCEPTION_GROUP_HANDLER, + if (!compiler_push_fblock(c, loc, EXCEPTION_GROUP_HANDLER, NO_LABEL, NO_LABEL, "except handler")) { return 0; } @@ -3619,6 +3661,7 @@ compiler_try_star_except(struct compiler *c, stmt_ty s) excepthandler_ty handler = (excepthandler_ty)asdl_seq_GET( s->v.TryStar.handlers, i); SET_LOC(c, handler); + location loc = LOC(handler); NEW_JUMP_TARGET_LABEL(c, next_except); except = next_except; NEW_JUMP_TARGET_LABEL(c, handle_match); @@ -3628,7 +3671,7 @@ compiler_try_star_except(struct compiler *c, stmt_ty s) [exc] COPY 1 [orig, exc] */ - ADDOP_I(c, COPY, 1); + ADDOP_I(c, loc, COPY, 1); /* create empty list for exceptions raised/reraise in the except* blocks */ /* @@ -3636,16 +3679,16 @@ compiler_try_star_except(struct compiler *c, stmt_ty s) [orig, exc, []] SWAP 2 [orig, [], exc] */ - ADDOP_I(c, BUILD_LIST, 0); - ADDOP_I(c, SWAP, 2); + ADDOP_I(c, loc, BUILD_LIST, 0); + ADDOP_I(c, loc, SWAP, 2); } if (handler->v.ExceptHandler.type) { VISIT(c, expr, handler->v.ExceptHandler.type); - ADDOP(c, CHECK_EG_MATCH); - ADDOP_I(c, COPY, 1); - ADDOP_JUMP(c, POP_JUMP_IF_NOT_NONE, handle_match); - ADDOP(c, POP_TOP); // match - ADDOP_JUMP(c, JUMP, except); + ADDOP(c, loc, CHECK_EG_MATCH); + ADDOP_I(c, loc, COPY, 1); + ADDOP_JUMP(c, loc, POP_JUMP_IF_NOT_NONE, handle_match); + ADDOP(c, loc, POP_TOP); // match + ADDOP_JUMP(c, loc, JUMP, except); } USE_LABEL(c, handle_match); @@ -3654,10 +3697,10 @@ compiler_try_star_except(struct compiler *c, stmt_ty s) NEW_JUMP_TARGET_LABEL(c, cleanup_body); if (handler->v.ExceptHandler.name) { - compiler_nameop(c, handler->v.ExceptHandler.name, Store); + compiler_nameop(c, loc, handler->v.ExceptHandler.name, Store); } else { - ADDOP(c, POP_TOP); // match + ADDOP(c, loc, POP_TOP); // match } /* @@ -3671,24 +3714,25 @@ compiler_try_star_except(struct compiler *c, stmt_ty s) del name */ /* second try: */ - ADDOP_JUMP(c, SETUP_CLEANUP, cleanup_end); + ADDOP_JUMP(c, loc, SETUP_CLEANUP, cleanup_end); USE_LABEL(c, cleanup_body); - if (!compiler_push_fblock(c, HANDLER_CLEANUP, cleanup_body, NO_LABEL, handler->v.ExceptHandler.name)) + if (!compiler_push_fblock(c, loc, HANDLER_CLEANUP, cleanup_body, NO_LABEL, handler->v.ExceptHandler.name)) { return 0; + } /* second # body */ VISIT_SEQ(c, stmt, handler->v.ExceptHandler.body); compiler_pop_fblock(c, HANDLER_CLEANUP, cleanup_body); /* name = None; del name; # Mark as artificial */ UNSET_LOC(c); - ADDOP(c, POP_BLOCK); + ADDOP(c, NO_LOCATION, POP_BLOCK); if (handler->v.ExceptHandler.name) { - ADDOP_LOAD_CONST(c, Py_None); - compiler_nameop(c, handler->v.ExceptHandler.name, Store); - compiler_nameop(c, handler->v.ExceptHandler.name, Del); + ADDOP_LOAD_CONST(c, NO_LOCATION, Py_None); + compiler_nameop(c, NO_LOCATION, handler->v.ExceptHandler.name, Store); + compiler_nameop(c, NO_LOCATION, handler->v.ExceptHandler.name, Del); } - ADDOP_JUMP(c, JUMP, except); + ADDOP_JUMP(c, NO_LOCATION, JUMP, except); /* except: */ USE_LABEL(c, cleanup_end); @@ -3697,22 +3741,22 @@ compiler_try_star_except(struct compiler *c, stmt_ty s) UNSET_LOC(c); if (handler->v.ExceptHandler.name) { - ADDOP_LOAD_CONST(c, Py_None); - compiler_nameop(c, handler->v.ExceptHandler.name, Store); - compiler_nameop(c, handler->v.ExceptHandler.name, Del); + ADDOP_LOAD_CONST(c, NO_LOCATION, Py_None); + compiler_nameop(c, NO_LOCATION, handler->v.ExceptHandler.name, Store); + compiler_nameop(c, NO_LOCATION, handler->v.ExceptHandler.name, Del); } /* add exception raised to the res list */ - ADDOP_I(c, LIST_APPEND, 3); // exc - ADDOP(c, POP_TOP); // lasti - ADDOP_JUMP(c, JUMP, except); + ADDOP_I(c, NO_LOCATION, LIST_APPEND, 3); // exc + ADDOP(c, NO_LOCATION, POP_TOP); // lasti + ADDOP_JUMP(c, NO_LOCATION, JUMP, except); USE_LABEL(c, except); if (i == n - 1) { /* Add exc to the list (if not None it's the unhandled part of the EG) */ - ADDOP_I(c, LIST_APPEND, 1); - ADDOP_JUMP(c, JUMP, reraise_star); + ADDOP_I(c, NO_LOCATION, LIST_APPEND, 1); + ADDOP_JUMP(c, NO_LOCATION, JUMP, reraise_star); } } /* Mark as artificial */ @@ -3721,24 +3765,24 @@ compiler_try_star_except(struct compiler *c, stmt_ty s) NEW_JUMP_TARGET_LABEL(c, reraise); USE_LABEL(c, reraise_star); - ADDOP(c, PREP_RERAISE_STAR); - ADDOP_I(c, COPY, 1); - ADDOP_JUMP(c, POP_JUMP_IF_NOT_NONE, reraise); + ADDOP(c, NO_LOCATION, PREP_RERAISE_STAR); + ADDOP_I(c, NO_LOCATION, COPY, 1); + ADDOP_JUMP(c, NO_LOCATION, POP_JUMP_IF_NOT_NONE, reraise); /* Nothing to reraise */ - ADDOP(c, POP_TOP); - ADDOP(c, POP_BLOCK); - ADDOP(c, POP_EXCEPT); - ADDOP_JUMP(c, JUMP, end); + ADDOP(c, NO_LOCATION, POP_TOP); + ADDOP(c, NO_LOCATION, POP_BLOCK); + ADDOP(c, NO_LOCATION, POP_EXCEPT); + ADDOP_JUMP(c, NO_LOCATION, JUMP, end); USE_LABEL(c, reraise); - ADDOP(c, POP_BLOCK); - ADDOP_I(c, SWAP, 2); - ADDOP(c, POP_EXCEPT); - ADDOP_I(c, RERAISE, 0); + ADDOP(c, NO_LOCATION, POP_BLOCK); + ADDOP_I(c, NO_LOCATION, SWAP, 2); + ADDOP(c, NO_LOCATION, POP_EXCEPT); + ADDOP_I(c, NO_LOCATION, RERAISE, 0); USE_LABEL(c, cleanup); - POP_EXCEPT_AND_RERAISE(c); + POP_EXCEPT_AND_RERAISE(c, NO_LOCATION); USE_LABEL(c, orelse); VISIT_SEQ(c, stmt, s->v.TryStar.orelse); @@ -3767,7 +3811,8 @@ compiler_try_star(struct compiler *c, stmt_ty s) } static int -compiler_import_as(struct compiler *c, identifier name, identifier asname) +compiler_import_as(struct compiler *c, location loc, + identifier name, identifier asname) { /* The IMPORT_NAME opcode was already generated. This function merely needs to bind the result to a name. @@ -3790,25 +3835,26 @@ compiler_import_as(struct compiler *c, identifier name, identifier asname) attr = PyUnicode_Substring(name, pos, (dot != -1) ? dot : len); if (!attr) return 0; - ADDOP_N(c, IMPORT_FROM, attr, names); + ADDOP_N(c, loc, IMPORT_FROM, attr, names); if (dot == -1) { break; } - ADDOP_I(c, SWAP, 2); - ADDOP(c, POP_TOP); + ADDOP_I(c, loc, SWAP, 2); + ADDOP(c, loc, POP_TOP); } - if (!compiler_nameop(c, asname, Store)) { + if (!compiler_nameop(c, loc, asname, Store)) { return 0; } - ADDOP(c, POP_TOP); + ADDOP(c, loc, POP_TOP); return 1; } - return compiler_nameop(c, asname, Store); + return compiler_nameop(c, loc, asname, Store); } static int compiler_import(struct compiler *c, stmt_ty s) { + location loc = LOC(s); /* The Import node stores a module name like a.b.c as a single string. This is convenient for all cases except import a.b.c as d @@ -3823,12 +3869,12 @@ compiler_import(struct compiler *c, stmt_ty s) alias_ty alias = (alias_ty)asdl_seq_GET(s->v.Import.names, i); int r; - ADDOP_LOAD_CONST(c, zero); - ADDOP_LOAD_CONST(c, Py_None); - ADDOP_NAME(c, IMPORT_NAME, alias->name, names); + ADDOP_LOAD_CONST(c, loc, zero); + ADDOP_LOAD_CONST(c, loc, Py_None); + ADDOP_NAME(c, loc, IMPORT_NAME, alias->name, names); if (alias->asname) { - r = compiler_import_as(c, alias->name, alias->asname); + r = compiler_import_as(c, loc, alias->name, alias->asname); if (!r) return r; } @@ -3841,7 +3887,7 @@ compiler_import(struct compiler *c, stmt_ty s) if (tmp == NULL) return 0; } - r = compiler_nameop(c, tmp, Store); + r = compiler_nameop(c, loc, tmp, Store); if (dot != -1) { Py_DECREF(tmp); } @@ -3855,10 +3901,11 @@ compiler_import(struct compiler *c, stmt_ty s) static int compiler_from_import(struct compiler *c, stmt_ty s) { + location loc = LOC(s); Py_ssize_t i, n = asdl_seq_LEN(s->v.ImportFrom.names); PyObject *names; - ADDOP_LOAD_CONST_NEW(c, PyLong_FromLong(s->v.ImportFrom.level)); + ADDOP_LOAD_CONST_NEW(c, loc, PyLong_FromLong(s->v.ImportFrom.level)); names = PyTuple_New(n); if (!names) @@ -3874,17 +3921,17 @@ compiler_from_import(struct compiler *c, stmt_ty s) if (s->lineno > c->c_future->ff_lineno && s->v.ImportFrom.module && _PyUnicode_EqualToASCIIString(s->v.ImportFrom.module, "__future__")) { Py_DECREF(names); - return compiler_error(c, "from __future__ imports must occur " + return compiler_error(c, loc, "from __future__ imports must occur " "at the beginning of the file"); } - ADDOP_LOAD_CONST_NEW(c, names); + ADDOP_LOAD_CONST_NEW(c, loc, names); if (s->v.ImportFrom.module) { - ADDOP_NAME(c, IMPORT_NAME, s->v.ImportFrom.module, names); + ADDOP_NAME(c, loc, IMPORT_NAME, s->v.ImportFrom.module, names); } else { _Py_DECLARE_STR(empty, ""); - ADDOP_NAME(c, IMPORT_NAME, &_Py_STR(empty), names); + ADDOP_NAME(c, loc, IMPORT_NAME, &_Py_STR(empty), names); } for (i = 0; i < n; i++) { alias_ty alias = (alias_ty)asdl_seq_GET(s->v.ImportFrom.names, i); @@ -3892,27 +3939,28 @@ compiler_from_import(struct compiler *c, stmt_ty s) if (i == 0 && PyUnicode_READ_CHAR(alias->name, 0) == '*') { assert(n == 1); - ADDOP(c, IMPORT_STAR); + ADDOP(c, loc, IMPORT_STAR); return 1; } - ADDOP_NAME(c, IMPORT_FROM, alias->name, names); + ADDOP_NAME(c, loc, IMPORT_FROM, alias->name, names); store_name = alias->name; if (alias->asname) store_name = alias->asname; - if (!compiler_nameop(c, store_name, Store)) { + if (!compiler_nameop(c, loc, store_name, Store)) { return 0; } } /* remove imported module */ - ADDOP(c, POP_TOP); + ADDOP(c, loc, POP_TOP); return 1; } static int compiler_assert(struct compiler *c, stmt_ty s) { + location loc = LOC(s); /* Always emit a warning if the test is a non-zero length tuple */ if ((s->v.Assert.test->kind == Tuple_kind && asdl_seq_LEN(s->v.Assert.test->v.Tuple.elts) > 0) || @@ -3920,8 +3968,8 @@ compiler_assert(struct compiler *c, stmt_ty s) PyTuple_Check(s->v.Assert.test->v.Constant.value) && PyTuple_Size(s->v.Assert.test->v.Constant.value) > 0)) { - if (!compiler_warn(c, "assertion is always true, " - "perhaps remove parentheses?")) + if (!compiler_warn(c, loc, "assertion is always true, " + "perhaps remove parentheses?")) { return 0; } @@ -3929,38 +3977,38 @@ compiler_assert(struct compiler *c, stmt_ty s) if (c->c_optimize) return 1; NEW_JUMP_TARGET_LABEL(c, end); - if (!compiler_jump_if(c, s->v.Assert.test, end, 1)) + if (!compiler_jump_if(c, &loc, s->v.Assert.test, end, 1)) return 0; - ADDOP(c, LOAD_ASSERTION_ERROR); + ADDOP(c, loc, LOAD_ASSERTION_ERROR); if (s->v.Assert.msg) { VISIT(c, expr, s->v.Assert.msg); - ADDOP_I(c, CALL, 0); + ADDOP_I(c, loc, CALL, 0); } - ADDOP_I(c, RAISE_VARARGS, 1); + ADDOP_I(c, loc, RAISE_VARARGS, 1); USE_LABEL(c, end); return 1; } static int -compiler_visit_stmt_expr(struct compiler *c, expr_ty value) +compiler_stmt_expr(struct compiler *c, location loc, expr_ty value) { if (c->c_interactive && c->c_nestlevel <= 1) { VISIT(c, expr, value); - ADDOP(c, PRINT_EXPR); + ADDOP(c, loc, PRINT_EXPR); return 1; } if (value->kind == Constant_kind) { /* ignore constant statement */ - ADDOP(c, NOP); + ADDOP(c, loc, NOP); return 1; } VISIT(c, expr, value); /* Mark POP_TOP as artificial */ UNSET_LOC(c); - ADDOP(c, POP_TOP); + ADDOP(c, NO_LOCATION, POP_TOP); return 1; } @@ -3968,7 +4016,6 @@ static int compiler_visit_stmt(struct compiler *c, stmt_ty s) { Py_ssize_t i, n; - /* Always assign a lineno to the next instruction for a stmt. */ SET_LOC(c, s); @@ -3983,16 +4030,19 @@ compiler_visit_stmt(struct compiler *c, stmt_ty s) VISIT_SEQ(c, expr, s->v.Delete.targets) break; case Assign_kind: + { n = asdl_seq_LEN(s->v.Assign.targets); VISIT(c, expr, s->v.Assign.value); + location loc = LOC(s); for (i = 0; i < n; i++) { if (i < n - 1) { - ADDOP_I(c, COPY, 1); + ADDOP_I(c, loc, COPY, 1); } VISIT(c, expr, (expr_ty)asdl_seq_GET(s->v.Assign.targets, i)); } break; + } case AugAssign_kind: return compiler_augassign(c, s); case AnnAssign_kind: @@ -4006,6 +4056,7 @@ compiler_visit_stmt(struct compiler *c, stmt_ty s) case Match_kind: return compiler_match(c, s); case Raise_kind: + { n = 0; if (s->v.Raise.exc) { VISIT(c, expr, s->v.Raise.exc); @@ -4015,8 +4066,10 @@ compiler_visit_stmt(struct compiler *c, stmt_ty s) n++; } } - ADDOP_I(c, RAISE_VARARGS, (int)n); + location loc = LOC(s); + ADDOP_I(c, loc, RAISE_VARARGS, (int)n); break; + } case Try_kind: return compiler_try(c, s); case TryStar_kind: @@ -4031,14 +4084,26 @@ compiler_visit_stmt(struct compiler *c, stmt_ty s) case Nonlocal_kind: break; case Expr_kind: - return compiler_visit_stmt_expr(c, s->v.Expr.value); + { + location loc = LOC(s); + return compiler_stmt_expr(c, loc, s->v.Expr.value); + } case Pass_kind: - ADDOP(c, NOP); + { + location loc = LOC(s); + ADDOP(c, loc, NOP); break; + } case Break_kind: - return compiler_break(c); + { + location loc = LOC(s); + return compiler_break(c, loc); + } case Continue_kind: - return compiler_continue(c); + { + location loc = LOC(s); + return compiler_continue(c, loc); + } case With_kind: return compiler_with(c, s, 0); case AsyncFunctionDef_kind: @@ -4072,7 +4137,8 @@ unaryop(unaryop_ty op) } static int -addop_binary(struct compiler *c, operator_ty binop, bool inplace) +addop_binary(struct compiler *c, location loc, operator_ty binop, + bool inplace) { int oparg; switch (binop) { @@ -4120,23 +4186,24 @@ addop_binary(struct compiler *c, operator_ty binop, bool inplace) inplace ? "inplace" : "binary", binop); return 0; } - ADDOP_I(c, BINARY_OP, oparg); + ADDOP_I(c, loc, BINARY_OP, oparg); return 1; } static int -addop_yield(struct compiler *c) { +addop_yield(struct compiler *c, location loc) { if (c->u->u_ste->ste_generator && c->u->u_ste->ste_coroutine) { - ADDOP(c, ASYNC_GEN_WRAP); + ADDOP(c, loc, ASYNC_GEN_WRAP); } - ADDOP_I(c, YIELD_VALUE, 0); - ADDOP_I(c, RESUME, 1); + ADDOP_I(c, loc, YIELD_VALUE, 0); + ADDOP_I(c, loc, RESUME, 1); return 1; } static int -compiler_nameop(struct compiler *c, identifier name, expr_context_ty ctx) +compiler_nameop(struct compiler *c, location loc, + identifier name, expr_context_ty ctx) { int op, scope; Py_ssize_t arg; @@ -4149,7 +4216,7 @@ compiler_nameop(struct compiler *c, identifier name, expr_context_ty ctx) !_PyUnicode_EqualToASCIIString(name, "True") && !_PyUnicode_EqualToASCIIString(name, "False")); - if (forbidden_name(c, name, ctx)) + if (forbidden_name(c, loc, name, ctx)) return 0; mangled = _Py_Mangle(c->u->u_private, name); @@ -4203,7 +4270,7 @@ compiler_nameop(struct compiler *c, identifier name, expr_context_ty ctx) case Store: op = STORE_FAST; break; case Del: op = DELETE_FAST; break; } - ADDOP_N(c, op, mangled, varnames); + ADDOP_N(c, loc, op, mangled, varnames); return 1; case OP_GLOBAL: switch (ctx) { @@ -4230,7 +4297,7 @@ compiler_nameop(struct compiler *c, identifier name, expr_context_ty ctx) if (op == LOAD_GLOBAL) { arg <<= 1; } - return cfg_builder_addop_i(CFG_BUILDER(c), op, arg, COMPILER_LOC(c)); + return cfg_builder_addop_i(CFG_BUILDER(c), op, arg, loc); } static int @@ -4240,6 +4307,7 @@ compiler_boolop(struct compiler *c, expr_ty e) Py_ssize_t i, n; asdl_expr_seq *s; + location loc = LOC(e); assert(e->kind == BoolOp_kind); if (e->v.BoolOp.op == And) jumpi = JUMP_IF_FALSE_OR_POP; @@ -4251,7 +4319,7 @@ compiler_boolop(struct compiler *c, expr_ty e) assert(n >= 0); for (i = 0; i < n; ++i) { VISIT(c, expr, (expr_ty)asdl_seq_GET(s, i)); - ADDOP_JUMP(c, jumpi, end); + ADDOP_JUMP(c, loc, jumpi, end); NEW_JUMP_TARGET_LABEL(c, next); USE_LABEL(c, next); @@ -4263,7 +4331,8 @@ compiler_boolop(struct compiler *c, expr_ty e) } static int -starunpack_helper(struct compiler *c, asdl_expr_seq *elts, int pushed, +starunpack_helper(struct compiler *c, location loc, + asdl_expr_seq *elts, int pushed, int build, int add, int extend, int tuple) { Py_ssize_t n = asdl_seq_LEN(elts); @@ -4279,7 +4348,7 @@ starunpack_helper(struct compiler *c, asdl_expr_seq *elts, int pushed, PyTuple_SET_ITEM(folded, i, val); } if (tuple && !pushed) { - ADDOP_LOAD_CONST_NEW(c, folded); + ADDOP_LOAD_CONST_NEW(c, loc, folded); } else { if (add == SET_ADD) { Py_SETREF(folded, PyFrozenSet_New(folded)); @@ -4287,11 +4356,11 @@ starunpack_helper(struct compiler *c, asdl_expr_seq *elts, int pushed, return 0; } } - ADDOP_I(c, build, pushed); - ADDOP_LOAD_CONST_NEW(c, folded); - ADDOP_I(c, extend, 1); + ADDOP_I(c, loc, build, pushed); + ADDOP_LOAD_CONST_NEW(c, loc, folded); + ADDOP_I(c, loc, extend, 1); if (tuple) { - ADDOP(c, LIST_TO_TUPLE); + ADDOP(c, loc, LIST_TO_TUPLE); } } return 1; @@ -4312,43 +4381,43 @@ starunpack_helper(struct compiler *c, asdl_expr_seq *elts, int pushed, VISIT(c, expr, elt); } if (tuple) { - ADDOP_I(c, BUILD_TUPLE, n+pushed); + ADDOP_I(c, loc, BUILD_TUPLE, n+pushed); } else { - ADDOP_I(c, build, n+pushed); + ADDOP_I(c, loc, build, n+pushed); } return 1; } int sequence_built = 0; if (big) { - ADDOP_I(c, build, pushed); + ADDOP_I(c, loc, build, pushed); sequence_built = 1; } for (Py_ssize_t i = 0; i < n; i++) { expr_ty elt = asdl_seq_GET(elts, i); if (elt->kind == Starred_kind) { if (sequence_built == 0) { - ADDOP_I(c, build, i+pushed); + ADDOP_I(c, loc, build, i+pushed); sequence_built = 1; } VISIT(c, expr, elt->v.Starred.value); - ADDOP_I(c, extend, 1); + ADDOP_I(c, loc, extend, 1); } else { VISIT(c, expr, elt); if (sequence_built) { - ADDOP_I(c, add, 1); + ADDOP_I(c, loc, add, 1); } } } assert(sequence_built); if (tuple) { - ADDOP(c, LIST_TO_TUPLE); + ADDOP(c, loc, LIST_TO_TUPLE); } return 1; } static int -unpack_helper(struct compiler *c, asdl_expr_seq *elts) +unpack_helper(struct compiler *c, location loc, asdl_expr_seq *elts) { Py_ssize_t n = asdl_seq_LEN(elts); int seen_star = 0; @@ -4357,28 +4426,28 @@ unpack_helper(struct compiler *c, asdl_expr_seq *elts) if (elt->kind == Starred_kind && !seen_star) { if ((i >= (1 << 8)) || (n-i-1 >= (INT_MAX >> 8))) - return compiler_error(c, + return compiler_error(c, loc, "too many expressions in " "star-unpacking assignment"); - ADDOP_I(c, UNPACK_EX, (i + ((n-i-1) << 8))); + ADDOP_I(c, loc, UNPACK_EX, (i + ((n-i-1) << 8))); seen_star = 1; } else if (elt->kind == Starred_kind) { - return compiler_error(c, + return compiler_error(c, loc, "multiple starred expressions in assignment"); } } if (!seen_star) { - ADDOP_I(c, UNPACK_SEQUENCE, n); + ADDOP_I(c, loc, UNPACK_SEQUENCE, n); } return 1; } static int -assignment_helper(struct compiler *c, asdl_expr_seq *elts) +assignment_helper(struct compiler *c, location loc, asdl_expr_seq *elts) { Py_ssize_t n = asdl_seq_LEN(elts); - RETURN_IF_FALSE(unpack_helper(c, elts)); + RETURN_IF_FALSE(unpack_helper(c, loc, elts)); for (Py_ssize_t i = 0; i < n; i++) { expr_ty elt = asdl_seq_GET(elts, i); VISIT(c, expr, elt->kind != Starred_kind ? elt : elt->v.Starred.value); @@ -4389,13 +4458,14 @@ assignment_helper(struct compiler *c, asdl_expr_seq *elts) static int compiler_list(struct compiler *c, expr_ty e) { + location loc = LOC(e); asdl_expr_seq *elts = e->v.List.elts; if (e->v.List.ctx == Store) { - return assignment_helper(c, elts); + return assignment_helper(c, loc, elts); } else if (e->v.List.ctx == Load) { - return starunpack_helper(c, elts, 0, BUILD_LIST, - LIST_APPEND, LIST_EXTEND, 0); + return starunpack_helper(c, loc, elts, 0, + BUILD_LIST, LIST_APPEND, LIST_EXTEND, 0); } else VISIT_SEQ(c, expr, elts); @@ -4405,13 +4475,14 @@ compiler_list(struct compiler *c, expr_ty e) static int compiler_tuple(struct compiler *c, expr_ty e) { + location loc = LOC(e); asdl_expr_seq *elts = e->v.Tuple.elts; if (e->v.Tuple.ctx == Store) { - return assignment_helper(c, elts); + return assignment_helper(c, loc, elts); } else if (e->v.Tuple.ctx == Load) { - return starunpack_helper(c, elts, 0, BUILD_LIST, - LIST_APPEND, LIST_EXTEND, 1); + return starunpack_helper(c, loc, elts, 0, + BUILD_LIST, LIST_APPEND, LIST_EXTEND, 1); } else VISIT_SEQ(c, expr, elts); @@ -4421,8 +4492,9 @@ compiler_tuple(struct compiler *c, expr_ty e) static int compiler_set(struct compiler *c, expr_ty e) { - return starunpack_helper(c, e->v.Set.elts, 0, BUILD_SET, - SET_ADD, SET_UPDATE, 0); + location loc = LOC(e); + return starunpack_helper(c, loc, e->v.Set.elts, 0, + BUILD_SET, SET_ADD, SET_UPDATE, 0); } static int @@ -4443,6 +4515,7 @@ compiler_subdict(struct compiler *c, expr_ty e, Py_ssize_t begin, Py_ssize_t end Py_ssize_t i, n = end - begin; PyObject *keys, *key; int big = n*2 > STACK_USE_GUIDELINE; + location loc = LOC(e); if (n > 1 && !big && are_all_items_const(e->v.Dict.keys, begin, end)) { for (i = begin; i < end; i++) { VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Dict.values, i)); @@ -4456,22 +4529,22 @@ compiler_subdict(struct compiler *c, expr_ty e, Py_ssize_t begin, Py_ssize_t end Py_INCREF(key); PyTuple_SET_ITEM(keys, i - begin, key); } - ADDOP_LOAD_CONST_NEW(c, keys); - ADDOP_I(c, BUILD_CONST_KEY_MAP, n); + ADDOP_LOAD_CONST_NEW(c, loc, keys); + ADDOP_I(c, loc, BUILD_CONST_KEY_MAP, n); return 1; } if (big) { - ADDOP_I(c, BUILD_MAP, 0); + ADDOP_I(c, loc, BUILD_MAP, 0); } for (i = begin; i < end; i++) { VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Dict.keys, i)); VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Dict.values, i)); if (big) { - ADDOP_I(c, MAP_ADD, 1); + ADDOP_I(c, loc, MAP_ADD, 1); } } if (!big) { - ADDOP_I(c, BUILD_MAP, n); + ADDOP_I(c, loc, BUILD_MAP, n); } return 1; } @@ -4479,6 +4552,7 @@ compiler_subdict(struct compiler *c, expr_ty e, Py_ssize_t begin, Py_ssize_t end static int compiler_dict(struct compiler *c, expr_ty e) { + location loc = LOC(e); Py_ssize_t i, n, elements; int have_dict; int is_unpacking = 0; @@ -4493,17 +4567,17 @@ compiler_dict(struct compiler *c, expr_ty e) return 0; } if (have_dict) { - ADDOP_I(c, DICT_UPDATE, 1); + ADDOP_I(c, loc, DICT_UPDATE, 1); } have_dict = 1; elements = 0; } if (have_dict == 0) { - ADDOP_I(c, BUILD_MAP, 0); + ADDOP_I(c, loc, BUILD_MAP, 0); have_dict = 1; } VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Dict.values, i)); - ADDOP_I(c, DICT_UPDATE, 1); + ADDOP_I(c, loc, DICT_UPDATE, 1); } else { if (elements*2 > STACK_USE_GUIDELINE) { @@ -4511,7 +4585,7 @@ compiler_dict(struct compiler *c, expr_ty e) return 0; } if (have_dict) { - ADDOP_I(c, DICT_UPDATE, 1); + ADDOP_I(c, loc, DICT_UPDATE, 1); } have_dict = 1; elements = 0; @@ -4526,12 +4600,12 @@ compiler_dict(struct compiler *c, expr_ty e) return 0; } if (have_dict) { - ADDOP_I(c, DICT_UPDATE, 1); + ADDOP_I(c, loc, DICT_UPDATE, 1); } have_dict = 1; } if (!have_dict) { - ADDOP_I(c, BUILD_MAP, 0); + ADDOP_I(c, loc, BUILD_MAP, 0); } return 1; } @@ -4539,6 +4613,7 @@ compiler_dict(struct compiler *c, expr_ty e) static int compiler_compare(struct compiler *c, expr_ty e) { + location loc = LOC(e); Py_ssize_t i, n; if (!check_compare(c, e)) { @@ -4549,26 +4624,26 @@ compiler_compare(struct compiler *c, expr_ty e) n = asdl_seq_LEN(e->v.Compare.ops) - 1; if (n == 0) { VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, 0)); - ADDOP_COMPARE(c, asdl_seq_GET(e->v.Compare.ops, 0)); + ADDOP_COMPARE(c, loc, asdl_seq_GET(e->v.Compare.ops, 0)); } else { NEW_JUMP_TARGET_LABEL(c, cleanup); for (i = 0; i < n; i++) { VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, i)); - ADDOP_I(c, SWAP, 2); - ADDOP_I(c, COPY, 2); - ADDOP_COMPARE(c, asdl_seq_GET(e->v.Compare.ops, i)); - ADDOP_JUMP(c, JUMP_IF_FALSE_OR_POP, cleanup); + ADDOP_I(c, loc, SWAP, 2); + ADDOP_I(c, loc, COPY, 2); + ADDOP_COMPARE(c, loc, asdl_seq_GET(e->v.Compare.ops, i)); + ADDOP_JUMP(c, loc, JUMP_IF_FALSE_OR_POP, cleanup); } VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, n)); - ADDOP_COMPARE(c, asdl_seq_GET(e->v.Compare.ops, n)); + ADDOP_COMPARE(c, loc, asdl_seq_GET(e->v.Compare.ops, n)); NEW_JUMP_TARGET_LABEL(c, end); - ADDOP_JUMP_NOLINE(c, JUMP, end); + ADDOP_JUMP(c, NO_LOCATION, JUMP, end); USE_LABEL(c, cleanup); - ADDOP_I(c, SWAP, 2); - ADDOP(c, POP_TOP); + ADDOP_I(c, loc, SWAP, 2); + ADDOP(c, loc, POP_TOP); USE_LABEL(c, end); } @@ -4618,10 +4693,12 @@ check_caller(struct compiler *c, expr_ty e) case SetComp_kind: case GeneratorExp_kind: case JoinedStr_kind: - case FormattedValue_kind: - return compiler_warn(c, "'%.200s' object is not callable; " - "perhaps you missed a comma?", - infer_type(e)->tp_name); + case FormattedValue_kind: { + location loc = LOC(e); + return compiler_warn(c, loc, "'%.200s' object is not callable; " + "perhaps you missed a comma?", + infer_type(e)->tp_name); + } default: return 1; } @@ -4645,10 +4722,12 @@ check_subscripter(struct compiler *c, expr_ty e) case Set_kind: case SetComp_kind: case GeneratorExp_kind: - case Lambda_kind: - return compiler_warn(c, "'%.200s' object is not subscriptable; " - "perhaps you missed a comma?", - infer_type(e)->tp_name); + case Lambda_kind: { + location loc = LOC(e); + return compiler_warn(c, loc, "'%.200s' object is not subscriptable; " + "perhaps you missed a comma?", + infer_type(e)->tp_name); + } default: return 1; } @@ -4677,12 +4756,14 @@ check_index(struct compiler *c, expr_ty e, expr_ty s) case List_kind: case ListComp_kind: case JoinedStr_kind: - case FormattedValue_kind: - return compiler_warn(c, "%.200s indices must be integers or slices, " - "not %.200s; " - "perhaps you missed a comma?", - infer_type(e)->tp_name, - index_type->tp_name); + case FormattedValue_kind: { + location loc = LOC(e); + return compiler_warn(c, loc, "%.200s indices must be integers " + "or slices, not %.200s; " + "perhaps you missed a comma?", + infer_type(e)->tp_name, + index_type->tp_name); + } default: return 1; } @@ -4707,29 +4788,30 @@ is_import_originated(struct compiler *c, expr_ty e) // If an attribute access spans multiple lines, update the current start // location to point to the attribute name. -static void -update_start_location_to_match_attr(struct compiler *c, expr_ty attr) +static location +update_start_location_to_match_attr(struct compiler *c, location loc, + expr_ty attr) { assert(attr->kind == Attribute_kind); - struct location *loc = &c->u->u_loc; - if (loc->lineno != attr->end_lineno) { - loc->lineno = attr->end_lineno; + if (loc.lineno != attr->end_lineno) { + loc.lineno = attr->end_lineno; int len = (int)PyUnicode_GET_LENGTH(attr->v.Attribute.attr); if (len <= attr->end_col_offset) { - loc->col_offset = attr->end_col_offset - len; + loc.col_offset = attr->end_col_offset - len; } else { // GH-94694: Somebody's compiling weird ASTs. Just drop the columns: - loc->col_offset = -1; - loc->end_col_offset = -1; + loc.col_offset = -1; + loc.end_col_offset = -1; } // Make sure the end position still follows the start position, even for // weird ASTs: - loc->end_lineno = Py_MAX(loc->lineno, loc->end_lineno); - if (loc->lineno == loc->end_lineno) { - loc->end_col_offset = Py_MAX(loc->col_offset, loc->end_col_offset); + loc.end_lineno = Py_MAX(loc.lineno, loc.end_lineno); + if (loc.lineno == loc.end_lineno) { + loc.end_col_offset = Py_MAX(loc.col_offset, loc.end_col_offset); } } + return loc; } // Return 1 if the method call was optimized, -1 if not, and 0 on error. @@ -4774,19 +4856,21 @@ maybe_optimize_method_call(struct compiler *c, expr_ty e) /* Alright, we can optimize the code. */ VISIT(c, expr, meth->v.Attribute.value); SET_LOC(c, meth); - update_start_location_to_match_attr(c, meth); - ADDOP_NAME(c, LOAD_METHOD, meth->v.Attribute.attr, names); + location loc = LOC(meth); + loc = update_start_location_to_match_attr(c, loc, meth); + ADDOP_NAME(c, loc, LOAD_METHOD, meth->v.Attribute.attr, names); VISIT_SEQ(c, expr, e->v.Call.args); if (kwdsl) { VISIT_SEQ(c, keyword, kwds); - if (!compiler_call_simple_kw_helper(c, kwds, kwdsl)) { + if (!compiler_call_simple_kw_helper(c, loc, kwds, kwdsl)) { return 0; }; } SET_LOC(c, e); - update_start_location_to_match_attr(c, meth); - ADDOP_I(c, CALL, argsl + kwdsl); + loc = LOC(e); + loc = update_start_location_to_match_attr(c, loc, meth); + ADDOP_I(c, loc, CALL, argsl + kwdsl); return 1; } @@ -4799,14 +4883,15 @@ validate_keywords(struct compiler *c, asdl_keyword_seq *keywords) if (key->arg == NULL) { continue; } - if (forbidden_name(c, key->arg, Store)) { + location loc = LOC(key); + if (forbidden_name(c, loc, key->arg, Store)) { return -1; } for (Py_ssize_t j = i + 1; j < nkeywords; j++) { keyword_ty other = ((keyword_ty)asdl_seq_GET(keywords, j)); if (other->arg && !PyUnicode_Compare(key->arg, other->arg)) { SET_LOC(c, other); - compiler_error(c, "keyword argument repeated: %U", key->arg); + compiler_error(c, LOC(other), "keyword argument repeated: %U", key->arg); return -1; } } @@ -4828,10 +4913,12 @@ compiler_call(struct compiler *c, expr_ty e) return 0; } SET_LOC(c, e->v.Call.func); - ADDOP(c, PUSH_NULL); + location loc = LOC(e->v.Call.func); + ADDOP(c, loc, PUSH_NULL); SET_LOC(c, e); VISIT(c, expr, e->v.Call.func); - return compiler_call_helper(c, 0, + loc = LOC(e); + return compiler_call_helper(c, loc, 0, e->v.Call.args, e->v.Call.keywords); } @@ -4839,23 +4926,23 @@ compiler_call(struct compiler *c, expr_ty e) static int compiler_joined_str(struct compiler *c, expr_ty e) { - + location loc = LOC(e); Py_ssize_t value_count = asdl_seq_LEN(e->v.JoinedStr.values); if (value_count > STACK_USE_GUIDELINE) { _Py_DECLARE_STR(empty, ""); - ADDOP_LOAD_CONST_NEW(c, Py_NewRef(&_Py_STR(empty))); - ADDOP_NAME(c, LOAD_METHOD, &_Py_ID(join), names); - ADDOP_I(c, BUILD_LIST, 0); + ADDOP_LOAD_CONST_NEW(c, loc, Py_NewRef(&_Py_STR(empty))); + ADDOP_NAME(c, loc, LOAD_METHOD, &_Py_ID(join), names); + ADDOP_I(c, loc, BUILD_LIST, 0); for (Py_ssize_t i = 0; i < asdl_seq_LEN(e->v.JoinedStr.values); i++) { VISIT(c, expr, asdl_seq_GET(e->v.JoinedStr.values, i)); - ADDOP_I(c, LIST_APPEND, 1); + ADDOP_I(c, loc, LIST_APPEND, 1); } - ADDOP_I(c, CALL, 1); + ADDOP_I(c, loc, CALL, 1); } else { VISIT_SEQ(c, expr, e->v.JoinedStr.values); if (asdl_seq_LEN(e->v.JoinedStr.values) != 1) { - ADDOP_I(c, BUILD_STRING, asdl_seq_LEN(e->v.JoinedStr.values)); + ADDOP_I(c, loc, BUILD_STRING, asdl_seq_LEN(e->v.JoinedStr.values)); } } return 1; @@ -4902,13 +4989,16 @@ compiler_formatted_value(struct compiler *c, expr_ty e) } /* And push our opcode and oparg */ - ADDOP_I(c, FORMAT_VALUE, oparg); + location loc = LOC(e); + ADDOP_I(c, loc, FORMAT_VALUE, oparg); return 1; } static int -compiler_subkwargs(struct compiler *c, asdl_keyword_seq *keywords, Py_ssize_t begin, Py_ssize_t end) +compiler_subkwargs(struct compiler *c, location loc, + asdl_keyword_seq *keywords, + Py_ssize_t begin, Py_ssize_t end) { Py_ssize_t i, n = end - begin; keyword_ty kw; @@ -4929,23 +5019,23 @@ compiler_subkwargs(struct compiler *c, asdl_keyword_seq *keywords, Py_ssize_t be Py_INCREF(key); PyTuple_SET_ITEM(keys, i - begin, key); } - ADDOP_LOAD_CONST_NEW(c, keys); - ADDOP_I(c, BUILD_CONST_KEY_MAP, n); + ADDOP_LOAD_CONST_NEW(c, loc, keys); + ADDOP_I(c, loc, BUILD_CONST_KEY_MAP, n); return 1; } if (big) { - ADDOP_I_NOLINE(c, BUILD_MAP, 0); + ADDOP_I(c, NO_LOCATION, BUILD_MAP, 0); } for (i = begin; i < end; i++) { kw = asdl_seq_GET(keywords, i); - ADDOP_LOAD_CONST(c, kw->arg); + ADDOP_LOAD_CONST(c, loc, kw->arg); VISIT(c, expr, kw->value); if (big) { - ADDOP_I_NOLINE(c, MAP_ADD, 1); + ADDOP_I(c, NO_LOCATION, MAP_ADD, 1); } } if (!big) { - ADDOP_I(c, BUILD_MAP, n); + ADDOP_I(c, loc, BUILD_MAP, n); } return 1; } @@ -4955,9 +5045,8 @@ compiler_subkwargs(struct compiler *c, asdl_keyword_seq *keywords, Py_ssize_t be * Returns 1 on success, 0 on error. */ static int -compiler_call_simple_kw_helper(struct compiler *c, - asdl_keyword_seq *keywords, - Py_ssize_t nkwelts) +compiler_call_simple_kw_helper(struct compiler *c, location loc, + asdl_keyword_seq *keywords, Py_ssize_t nkwelts) { PyObject *names; names = PyTuple_New(nkwelts); @@ -4974,14 +5063,14 @@ compiler_call_simple_kw_helper(struct compiler *c, return 0; } Py_DECREF(names); - ADDOP_I(c, KW_NAMES, arg); + ADDOP_I(c, loc, KW_NAMES, arg); return 1; } /* shared code between compiler_call and compiler_class */ static int -compiler_call_helper(struct compiler *c, +compiler_call_helper(struct compiler *c, location loc, int n, /* Args already pushed */ asdl_expr_seq *args, asdl_keyword_seq *keywords) @@ -5019,11 +5108,11 @@ compiler_call_helper(struct compiler *c, } if (nkwelts) { VISIT_SEQ(c, keyword, keywords); - if (!compiler_call_simple_kw_helper(c, keywords, nkwelts)) { + if (!compiler_call_simple_kw_helper(c, loc, keywords, nkwelts)) { return 0; }; } - ADDOP_I(c, CALL, n + nelts + nkwelts); + ADDOP_I(c, loc, CALL, n + nelts + nkwelts); return 1; ex_call: @@ -5032,7 +5121,7 @@ compiler_call_helper(struct compiler *c, if (n ==0 && nelts == 1 && ((expr_ty)asdl_seq_GET(args, 0))->kind == Starred_kind) { VISIT(c, expr, ((expr_ty)asdl_seq_GET(args, 0))->v.Starred.value); } - else if (starunpack_helper(c, args, n, BUILD_LIST, + else if (starunpack_helper(c, loc, args, n, BUILD_LIST, LIST_APPEND, LIST_EXTEND, 1) == 0) { return 0; } @@ -5047,21 +5136,21 @@ compiler_call_helper(struct compiler *c, if (kw->arg == NULL) { /* A keyword argument unpacking. */ if (nseen) { - if (!compiler_subkwargs(c, keywords, i - nseen, i)) { + if (!compiler_subkwargs(c, loc, keywords, i - nseen, i)) { return 0; } if (have_dict) { - ADDOP_I(c, DICT_MERGE, 1); + ADDOP_I(c, loc, DICT_MERGE, 1); } have_dict = 1; nseen = 0; } if (!have_dict) { - ADDOP_I(c, BUILD_MAP, 0); + ADDOP_I(c, loc, BUILD_MAP, 0); have_dict = 1; } VISIT(c, expr, kw->value); - ADDOP_I(c, DICT_MERGE, 1); + ADDOP_I(c, loc, DICT_MERGE, 1); } else { nseen++; @@ -5069,17 +5158,17 @@ compiler_call_helper(struct compiler *c, } if (nseen) { /* Pack up any trailing keyword arguments. */ - if (!compiler_subkwargs(c, keywords, nkwelts - nseen, nkwelts)) { + if (!compiler_subkwargs(c, loc, keywords, nkwelts - nseen, nkwelts)) { return 0; } if (have_dict) { - ADDOP_I(c, DICT_MERGE, 1); + ADDOP_I(c, loc, DICT_MERGE, 1); } have_dict = 1; } assert(have_dict); } - ADDOP_I(c, CALL_FUNCTION_EX, nkwelts > 0); + ADDOP_I(c, loc, CALL_FUNCTION_EX, nkwelts > 0); return 1; } @@ -5099,7 +5188,7 @@ compiler_call_helper(struct compiler *c, static int -compiler_comprehension_generator(struct compiler *c, +compiler_comprehension_generator(struct compiler *c, location *ploc, asdl_comprehension_seq *generators, int gen_index, int depth, expr_ty elt, expr_ty val, int type) @@ -5108,15 +5197,15 @@ compiler_comprehension_generator(struct compiler *c, gen = (comprehension_ty)asdl_seq_GET(generators, gen_index); if (gen->is_async) { return compiler_async_comprehension_generator( - c, generators, gen_index, depth, elt, val, type); + c, ploc, generators, gen_index, depth, elt, val, type); } else { return compiler_sync_comprehension_generator( - c, generators, gen_index, depth, elt, val, type); + c, ploc, generators, gen_index, depth, elt, val, type); } } static int -compiler_sync_comprehension_generator(struct compiler *c, +compiler_sync_comprehension_generator(struct compiler *c, location *ploc, asdl_comprehension_seq *generators, int gen_index, int depth, expr_ty elt, expr_ty val, int type) @@ -5136,7 +5225,7 @@ compiler_sync_comprehension_generator(struct compiler *c, if (gen_index == 0) { /* Receive outermost iter as an implicit argument */ c->u->u_argcount = 1; - ADDOP_I(c, LOAD_FAST, 0); + ADDOP_I(c, *ploc, LOAD_FAST, 0); } else { /* Sub-iter - calculate on the fly */ @@ -5163,13 +5252,13 @@ compiler_sync_comprehension_generator(struct compiler *c, } if (IS_LABEL(start)) { VISIT(c, expr, gen->iter); - ADDOP(c, GET_ITER); + ADDOP(c, *ploc, GET_ITER); } } if (IS_LABEL(start)) { depth++; USE_LABEL(c, start); - ADDOP_JUMP(c, FOR_ITER, anchor); + ADDOP_JUMP(c, *ploc, FOR_ITER, anchor); } VISIT(c, expr, gen->target); @@ -5177,12 +5266,12 @@ compiler_sync_comprehension_generator(struct compiler *c, n = asdl_seq_LEN(gen->ifs); for (i = 0; i < n; i++) { expr_ty e = (expr_ty)asdl_seq_GET(gen->ifs, i); - if (!compiler_jump_if(c, e, if_cleanup, 0)) + if (!compiler_jump_if(c, ploc, e, if_cleanup, 0)) return 0; } if (++gen_index < asdl_seq_LEN(generators)) - if (!compiler_comprehension_generator(c, + if (!compiler_comprehension_generator(c, ploc, generators, gen_index, depth, elt, val, type)) return 0; @@ -5193,23 +5282,23 @@ compiler_sync_comprehension_generator(struct compiler *c, switch (type) { case COMP_GENEXP: VISIT(c, expr, elt); - ADDOP_YIELD(c); - ADDOP(c, POP_TOP); + ADDOP_YIELD(c, *ploc); + ADDOP(c, *ploc, POP_TOP); break; case COMP_LISTCOMP: VISIT(c, expr, elt); - ADDOP_I(c, LIST_APPEND, depth + 1); + ADDOP_I(c, *ploc, LIST_APPEND, depth + 1); break; case COMP_SETCOMP: VISIT(c, expr, elt); - ADDOP_I(c, SET_ADD, depth + 1); + ADDOP_I(c, *ploc, SET_ADD, depth + 1); break; case COMP_DICTCOMP: /* With '{k: v}', k is evaluated before v, so we do the same. */ VISIT(c, expr, elt); VISIT(c, expr, val); - ADDOP_I(c, MAP_ADD, depth + 1); + ADDOP_I(c, *ploc, MAP_ADD, depth + 1); break; default: return 0; @@ -5218,7 +5307,7 @@ compiler_sync_comprehension_generator(struct compiler *c, USE_LABEL(c, if_cleanup); if (IS_LABEL(start)) { - ADDOP_JUMP(c, JUMP, start); + ADDOP_JUMP(c, *ploc, JUMP, start); USE_LABEL(c, anchor); } @@ -5227,7 +5316,7 @@ compiler_sync_comprehension_generator(struct compiler *c, } static int -compiler_async_comprehension_generator(struct compiler *c, +compiler_async_comprehension_generator(struct compiler *c, location *ploc, asdl_comprehension_seq *generators, int gen_index, int depth, expr_ty elt, expr_ty val, int type) @@ -5243,38 +5332,38 @@ compiler_async_comprehension_generator(struct compiler *c, if (gen_index == 0) { /* Receive outermost iter as an implicit argument */ c->u->u_argcount = 1; - ADDOP_I(c, LOAD_FAST, 0); + ADDOP_I(c, *ploc, LOAD_FAST, 0); } else { /* Sub-iter - calculate on the fly */ VISIT(c, expr, gen->iter); - ADDOP(c, GET_AITER); + ADDOP(c, *ploc, GET_AITER); } USE_LABEL(c, start); /* Runtime will push a block here, so we need to account for that */ - if (!compiler_push_fblock(c, ASYNC_COMPREHENSION_GENERATOR, start, - NO_LABEL, NULL)) { + if (!compiler_push_fblock(c, *ploc, ASYNC_COMPREHENSION_GENERATOR, + start, NO_LABEL, NULL)) { return 0; } - ADDOP_JUMP(c, SETUP_FINALLY, except); - ADDOP(c, GET_ANEXT); - ADDOP_LOAD_CONST(c, Py_None); - ADD_YIELD_FROM(c, 1); - ADDOP(c, POP_BLOCK); + ADDOP_JUMP(c, *ploc, SETUP_FINALLY, except); + ADDOP(c, *ploc, GET_ANEXT); + ADDOP_LOAD_CONST(c, *ploc, Py_None); + ADD_YIELD_FROM(c, *ploc, 1); + ADDOP(c, *ploc, POP_BLOCK); VISIT(c, expr, gen->target); n = asdl_seq_LEN(gen->ifs); for (i = 0; i < n; i++) { expr_ty e = (expr_ty)asdl_seq_GET(gen->ifs, i); - if (!compiler_jump_if(c, e, if_cleanup, 0)) + if (!compiler_jump_if(c, ploc, e, if_cleanup, 0)) return 0; } depth++; if (++gen_index < asdl_seq_LEN(generators)) - if (!compiler_comprehension_generator(c, + if (!compiler_comprehension_generator(c, ploc, generators, gen_index, depth, elt, val, type)) return 0; @@ -5285,23 +5374,23 @@ compiler_async_comprehension_generator(struct compiler *c, switch (type) { case COMP_GENEXP: VISIT(c, expr, elt); - ADDOP_YIELD(c); - ADDOP(c, POP_TOP); + ADDOP_YIELD(c, *ploc); + ADDOP(c, *ploc, POP_TOP); break; case COMP_LISTCOMP: VISIT(c, expr, elt); - ADDOP_I(c, LIST_APPEND, depth + 1); + ADDOP_I(c, *ploc, LIST_APPEND, depth + 1); break; case COMP_SETCOMP: VISIT(c, expr, elt); - ADDOP_I(c, SET_ADD, depth + 1); + ADDOP_I(c, *ploc, SET_ADD, depth + 1); break; case COMP_DICTCOMP: /* With '{k: v}', k is evaluated before v, so we do the same. */ VISIT(c, expr, elt); VISIT(c, expr, val); - ADDOP_I(c, MAP_ADD, depth + 1); + ADDOP_I(c, *ploc, MAP_ADD, depth + 1); break; default: return 0; @@ -5309,14 +5398,14 @@ compiler_async_comprehension_generator(struct compiler *c, } USE_LABEL(c, if_cleanup); - ADDOP_JUMP(c, JUMP, start); + ADDOP_JUMP(c, *ploc, JUMP, start); compiler_pop_fblock(c, ASYNC_COMPREHENSION_GENERATOR, start); USE_LABEL(c, except); //UNSET_LOC(c); - ADDOP(c, END_ASYNC_FOR); + ADDOP(c, *ploc, END_ASYNC_FOR); return 1; } @@ -5340,6 +5429,7 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, goto error; } SET_LOC(c, e); + location loc = LOC(e); is_async_generator = c->u->u_ste->ste_coroutine; @@ -5348,8 +5438,8 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, scope_type != COMPILER_SCOPE_COMPREHENSION && !is_top_level_await) { - compiler_error(c, "asynchronous comprehension outside of " - "an asynchronous function"); + compiler_error(c, loc, "asynchronous comprehension outside of " + "an asynchronous function"); goto error_in_scope; } @@ -5371,15 +5461,15 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, goto error_in_scope; } - ADDOP_I(c, op, 0); + ADDOP_I(c, loc, op, 0); } - if (!compiler_comprehension_generator(c, generators, 0, 0, elt, - val, type)) + if (!compiler_comprehension_generator(c, &loc, generators, 0, 0, + elt, val, type)) goto error_in_scope; if (type != COMP_GENEXP) { - ADDOP(c, RETURN_VALUE); + ADDOP(c, loc, RETURN_VALUE); } co = assemble(c, 1); @@ -5392,7 +5482,8 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, if (co == NULL) goto error; - if (!compiler_make_closure(c, co, 0, qualname)) { + loc = LOC(e); + if (!compiler_make_closure(c, loc, co, 0, qualname)) { goto error; } Py_DECREF(qualname); @@ -5400,18 +5491,19 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, VISIT(c, expr, outermost->iter); + loc = LOC(e); if (outermost->is_async) { - ADDOP(c, GET_AITER); + ADDOP(c, loc, GET_AITER); } else { - ADDOP(c, GET_ITER); + ADDOP(c, loc, GET_ITER); } - ADDOP_I(c, CALL, 0); + ADDOP_I(c, loc, CALL, 0); if (is_async_generator && type != COMP_GENEXP) { - ADDOP_I(c, GET_AWAITABLE, 0); - ADDOP_LOAD_CONST(c, Py_None); - ADD_YIELD_FROM(c, 1); + ADDOP_I(c, loc, GET_AWAITABLE, 0); + ADDOP_LOAD_CONST(c, loc, Py_None); + ADD_YIELD_FROM(c, loc, 1); } return 1; @@ -5477,20 +5569,20 @@ static int compiler_with_except_finish(struct compiler *c, jump_target_label cleanup) { UNSET_LOC(c); NEW_JUMP_TARGET_LABEL(c, suppress); - ADDOP_JUMP(c, POP_JUMP_IF_TRUE, suppress); - ADDOP_I(c, RERAISE, 2); + ADDOP_JUMP(c, NO_LOCATION, POP_JUMP_IF_TRUE, suppress); + ADDOP_I(c, NO_LOCATION, RERAISE, 2); USE_LABEL(c, suppress); - ADDOP(c, POP_TOP); /* exc_value */ - ADDOP(c, POP_BLOCK); - ADDOP(c, POP_EXCEPT); - ADDOP(c, POP_TOP); - ADDOP(c, POP_TOP); + ADDOP(c, NO_LOCATION, POP_TOP); /* exc_value */ + ADDOP(c, NO_LOCATION, POP_BLOCK); + ADDOP(c, NO_LOCATION, POP_EXCEPT); + ADDOP(c, NO_LOCATION, POP_TOP); + ADDOP(c, NO_LOCATION, POP_TOP); NEW_JUMP_TARGET_LABEL(c, exit); - ADDOP_JUMP(c, JUMP, exit); + ADDOP_JUMP(c, NO_LOCATION, JUMP, exit); USE_LABEL(c, cleanup); - POP_EXCEPT_AND_RERAISE(c); + POP_EXCEPT_AND_RERAISE(c, NO_LOCATION); USE_LABEL(c, exit); return 1; @@ -5523,13 +5615,14 @@ compiler_with_except_finish(struct compiler *c, jump_target_label cleanup) { static int compiler_async_with(struct compiler *c, stmt_ty s, int pos) { + location loc = LOC(s); withitem_ty item = asdl_seq_GET(s->v.AsyncWith.items, pos); assert(s->kind == AsyncWith_kind); if (IS_TOP_LEVEL_AWAIT(c)){ c->u->u_ste->ste_coroutine = 1; } else if (c->u->u_scope_type != COMPILER_SCOPE_ASYNC_FUNCTION){ - return compiler_error(c, "'async with' outside async function"); + return compiler_error(c, loc, "'async with' outside async function"); } NEW_JUMP_TARGET_LABEL(c, block); @@ -5540,16 +5633,16 @@ compiler_async_with(struct compiler *c, stmt_ty s, int pos) /* Evaluate EXPR */ VISIT(c, expr, item->context_expr); - ADDOP(c, BEFORE_ASYNC_WITH); - ADDOP_I(c, GET_AWAITABLE, 1); - ADDOP_LOAD_CONST(c, Py_None); - ADD_YIELD_FROM(c, 1); + ADDOP(c, loc, BEFORE_ASYNC_WITH); + ADDOP_I(c, loc, GET_AWAITABLE, 1); + ADDOP_LOAD_CONST(c, loc, Py_None); + ADD_YIELD_FROM(c, loc, 1); - ADDOP_JUMP(c, SETUP_WITH, final); + ADDOP_JUMP(c, loc, SETUP_WITH, final); /* SETUP_WITH pushes a finally block. */ USE_LABEL(c, block); - if (!compiler_push_fblock(c, ASYNC_WITH, block, final, s)) { + if (!compiler_push_fblock(c, loc, ASYNC_WITH, block, final, s)) { return 0; } @@ -5558,43 +5651,46 @@ compiler_async_with(struct compiler *c, stmt_ty s, int pos) } else { /* Discard result from context.__aenter__() */ - ADDOP(c, POP_TOP); + ADDOP(c, loc, POP_TOP); } pos++; - if (pos == asdl_seq_LEN(s->v.AsyncWith.items)) + if (pos == asdl_seq_LEN(s->v.AsyncWith.items)) { /* BLOCK code */ VISIT_SEQ(c, stmt, s->v.AsyncWith.body) - else if (!compiler_async_with(c, s, pos)) + } + else if (!compiler_async_with(c, s, pos)) { return 0; + } compiler_pop_fblock(c, ASYNC_WITH, block); - ADDOP(c, POP_BLOCK); + + SET_LOC(c, s); + ADDOP(c, loc, POP_BLOCK); /* End of body; start the cleanup */ /* For successful outcome: * call __exit__(None, None, None) */ - SET_LOC(c, s); - if(!compiler_call_exit_with_nones(c)) + if(!compiler_call_exit_with_nones(c, loc)) return 0; - ADDOP_I(c, GET_AWAITABLE, 2); - ADDOP_LOAD_CONST(c, Py_None); - ADD_YIELD_FROM(c, 1); + ADDOP_I(c, loc, GET_AWAITABLE, 2); + ADDOP_LOAD_CONST(c, loc, Py_None); + ADD_YIELD_FROM(c, loc, 1); - ADDOP(c, POP_TOP); + ADDOP(c, loc, POP_TOP); - ADDOP_JUMP(c, JUMP, exit); + ADDOP_JUMP(c, loc, JUMP, exit); /* For exceptional outcome: */ USE_LABEL(c, final); - ADDOP_JUMP(c, SETUP_CLEANUP, cleanup); - ADDOP(c, PUSH_EXC_INFO); - ADDOP(c, WITH_EXCEPT_START); - ADDOP_I(c, GET_AWAITABLE, 2); - ADDOP_LOAD_CONST(c, Py_None); - ADD_YIELD_FROM(c, 1); + ADDOP_JUMP(c, loc, SETUP_CLEANUP, cleanup); + ADDOP(c, loc, PUSH_EXC_INFO); + ADDOP(c, loc, WITH_EXCEPT_START); + ADDOP_I(c, loc, GET_AWAITABLE, 2); + ADDOP_LOAD_CONST(c, loc, Py_None); + ADD_YIELD_FROM(c, loc, 1); compiler_with_except_finish(c, cleanup); USE_LABEL(c, exit); @@ -5638,12 +5734,13 @@ compiler_with(struct compiler *c, stmt_ty s, int pos) /* Evaluate EXPR */ VISIT(c, expr, item->context_expr); /* Will push bound __exit__ */ - ADDOP(c, BEFORE_WITH); - ADDOP_JUMP(c, SETUP_WITH, final); + location loc = LOC(s); + ADDOP(c, loc, BEFORE_WITH); + ADDOP_JUMP(c, loc, SETUP_WITH, final); /* SETUP_WITH pushes a finally block. */ USE_LABEL(c, block); - if (!compiler_push_fblock(c, WITH, block, final, s)) { + if (!compiler_push_fblock(c, loc, WITH, block, final, s)) { return 0; } @@ -5652,7 +5749,7 @@ compiler_with(struct compiler *c, stmt_ty s, int pos) } else { /* Discard result from context.__enter__() */ - ADDOP(c, POP_TOP); + ADDOP(c, loc, POP_TOP); } pos++; @@ -5665,7 +5762,7 @@ compiler_with(struct compiler *c, stmt_ty s, int pos) /* Mark all following code as artificial */ UNSET_LOC(c); - ADDOP(c, POP_BLOCK); + ADDOP(c, NO_LOCATION, POP_BLOCK); compiler_pop_fblock(c, WITH, block); /* End of body; start the cleanup. */ @@ -5674,17 +5771,18 @@ compiler_with(struct compiler *c, stmt_ty s, int pos) * call __exit__(None, None, None) */ SET_LOC(c, s); - if (!compiler_call_exit_with_nones(c)) + loc = LOC(s); + if (!compiler_call_exit_with_nones(c, loc)) return 0; - ADDOP(c, POP_TOP); - ADDOP_JUMP(c, JUMP, exit); + ADDOP(c, loc, POP_TOP); + ADDOP_JUMP(c, loc, JUMP, exit); /* For exceptional outcome: */ USE_LABEL(c, final); - ADDOP_JUMP(c, SETUP_CLEANUP, cleanup); - ADDOP(c, PUSH_EXC_INFO); - ADDOP(c, WITH_EXCEPT_START); + ADDOP_JUMP(c, loc, SETUP_CLEANUP, cleanup); + ADDOP(c, loc, PUSH_EXC_INFO); + ADDOP(c, loc, WITH_EXCEPT_START); compiler_with_except_finish(c, cleanup); USE_LABEL(c, exit); @@ -5694,10 +5792,11 @@ compiler_with(struct compiler *c, stmt_ty s, int pos) static int compiler_visit_expr1(struct compiler *c, expr_ty e) { + location loc = LOC(e); switch (e->kind) { case NamedExpr_kind: VISIT(c, expr, e->v.NamedExpr.value); - ADDOP_I(c, COPY, 1); + ADDOP_I(c, loc, COPY, 1); VISIT(c, expr, e->v.NamedExpr.target); break; case BoolOp_kind: @@ -5705,11 +5804,11 @@ compiler_visit_expr1(struct compiler *c, expr_ty e) case BinOp_kind: VISIT(c, expr, e->v.BinOp.left); VISIT(c, expr, e->v.BinOp.right); - ADDOP_BINARY(c, e->v.BinOp.op); + ADDOP_BINARY(c, loc, e->v.BinOp.op); break; case UnaryOp_kind: VISIT(c, expr, e->v.UnaryOp.operand); - ADDOP(c, unaryop(e->v.UnaryOp.op)); + ADDOP(c, loc, unaryop(e->v.UnaryOp.op)); break; case Lambda_kind: return compiler_lambda(c, e); @@ -5729,50 +5828,50 @@ compiler_visit_expr1(struct compiler *c, expr_ty e) return compiler_dictcomp(c, e); case Yield_kind: if (c->u->u_ste->ste_type != FunctionBlock) - return compiler_error(c, "'yield' outside function"); + return compiler_error(c, loc, "'yield' outside function"); if (e->v.Yield.value) { VISIT(c, expr, e->v.Yield.value); } else { - ADDOP_LOAD_CONST(c, Py_None); + ADDOP_LOAD_CONST(c, loc, Py_None); } - ADDOP_YIELD(c); + ADDOP_YIELD(c, loc); break; case YieldFrom_kind: if (c->u->u_ste->ste_type != FunctionBlock) - return compiler_error(c, "'yield' outside function"); + return compiler_error(c, loc, "'yield' outside function"); if (c->u->u_scope_type == COMPILER_SCOPE_ASYNC_FUNCTION) - return compiler_error(c, "'yield from' inside async function"); + return compiler_error(c, loc, "'yield from' inside async function"); VISIT(c, expr, e->v.YieldFrom.value); - ADDOP(c, GET_YIELD_FROM_ITER); - ADDOP_LOAD_CONST(c, Py_None); - ADD_YIELD_FROM(c, 0); + ADDOP(c, loc, GET_YIELD_FROM_ITER); + ADDOP_LOAD_CONST(c, loc, Py_None); + ADD_YIELD_FROM(c, loc, 0); break; case Await_kind: if (!IS_TOP_LEVEL_AWAIT(c)){ if (c->u->u_ste->ste_type != FunctionBlock){ - return compiler_error(c, "'await' outside function"); + return compiler_error(c, loc, "'await' outside function"); } if (c->u->u_scope_type != COMPILER_SCOPE_ASYNC_FUNCTION && c->u->u_scope_type != COMPILER_SCOPE_COMPREHENSION){ - return compiler_error(c, "'await' outside async function"); + return compiler_error(c, loc, "'await' outside async function"); } } VISIT(c, expr, e->v.Await.value); - ADDOP_I(c, GET_AWAITABLE, 0); - ADDOP_LOAD_CONST(c, Py_None); - ADD_YIELD_FROM(c, 1); + ADDOP_I(c, loc, GET_AWAITABLE, 0); + ADDOP_LOAD_CONST(c, loc, Py_None); + ADD_YIELD_FROM(c, loc, 1); break; case Compare_kind: return compiler_compare(c, e); case Call_kind: return compiler_call(c, e); case Constant_kind: - ADDOP_LOAD_CONST(c, e->v.Constant.value); + ADDOP_LOAD_CONST(c, loc, e->v.Constant.value); break; case JoinedStr_kind: return compiler_joined_str(c, e); @@ -5781,21 +5880,20 @@ compiler_visit_expr1(struct compiler *c, expr_ty e) /* The following exprs can be assignment targets. */ case Attribute_kind: VISIT(c, expr, e->v.Attribute.value); - update_start_location_to_match_attr(c, e); + loc = LOC(e); + loc = update_start_location_to_match_attr(c, loc, e); switch (e->v.Attribute.ctx) { case Load: - { - ADDOP_NAME(c, LOAD_ATTR, e->v.Attribute.attr, names); + ADDOP_NAME(c, loc, LOAD_ATTR, e->v.Attribute.attr, names); break; - } case Store: - if (forbidden_name(c, e->v.Attribute.attr, e->v.Attribute.ctx)) { + if (forbidden_name(c, loc, e->v.Attribute.attr, e->v.Attribute.ctx)) { return 0; } - ADDOP_NAME(c, STORE_ATTR, e->v.Attribute.attr, names); + ADDOP_NAME(c, loc, STORE_ATTR, e->v.Attribute.attr, names); break; case Del: - ADDOP_NAME(c, DELETE_ATTR, e->v.Attribute.attr, names); + ADDOP_NAME(c, loc, DELETE_ATTR, e->v.Attribute.attr, names); break; } break; @@ -5806,10 +5904,10 @@ compiler_visit_expr1(struct compiler *c, expr_ty e) case Store: /* In all legitimate cases, the Starred node was already replaced * by compiler_list/compiler_tuple. XXX: is that okay? */ - return compiler_error(c, + return compiler_error(c, loc, "starred assignment target must be in a list or tuple"); default: - return compiler_error(c, + return compiler_error(c, loc, "can't use starred expression here"); } break; @@ -5819,11 +5917,11 @@ compiler_visit_expr1(struct compiler *c, expr_ty e) if (n == 0) { return 0; } - ADDOP_I(c, BUILD_SLICE, n); + ADDOP_I(c, loc, BUILD_SLICE, n); break; } case Name_kind: - return compiler_nameop(c, e->v.Name.id, e->v.Name.ctx); + return compiler_nameop(c, loc, e->v.Name.id, e->v.Name.ctx); /* child nodes of List and Tuple will have expr_context set */ case List_kind: return compiler_list(c, e); @@ -5836,10 +5934,8 @@ compiler_visit_expr1(struct compiler *c, expr_ty e) static int compiler_visit_expr(struct compiler *c, expr_ty e) { - struct location old_loc = c->u->u_loc; SET_LOC(c, e); int res = compiler_visit_expr1(c, e); - c->u->u_loc = old_loc; return res; } @@ -5856,15 +5952,15 @@ compiler_augassign(struct compiler *c, stmt_ty s) assert(s->kind == AugAssign_kind); expr_ty e = s->v.AugAssign.target; - struct location old_loc = c->u->u_loc; + location loc = LOC(e); SET_LOC(c, e); switch (e->kind) { case Attribute_kind: VISIT(c, expr, e->v.Attribute.value); - ADDOP_I(c, COPY, 1); - update_start_location_to_match_attr(c, e); - ADDOP_NAME(c, LOAD_ATTR, e->v.Attribute.attr, names); + ADDOP_I(c, loc, COPY, 1); + loc = update_start_location_to_match_attr(c, loc, e); + ADDOP_NAME(c, loc, LOAD_ATTR, e->v.Attribute.attr, names); break; case Subscript_kind: VISIT(c, expr, e->v.Subscript.value); @@ -5872,20 +5968,20 @@ compiler_augassign(struct compiler *c, stmt_ty s) if (!compiler_slice(c, e->v.Subscript.slice)) { return 0; } - ADDOP_I(c, COPY, 3); - ADDOP_I(c, COPY, 3); - ADDOP_I(c, COPY, 3); - ADDOP(c, BINARY_SLICE); + ADDOP_I(c, loc, COPY, 3); + ADDOP_I(c, loc, COPY, 3); + ADDOP_I(c, loc, COPY, 3); + ADDOP(c, loc, BINARY_SLICE); } else { VISIT(c, expr, e->v.Subscript.slice); - ADDOP_I(c, COPY, 2); - ADDOP_I(c, COPY, 2); - ADDOP(c, BINARY_SUBSCR); + ADDOP_I(c, loc, COPY, 2); + ADDOP_I(c, loc, COPY, 2); + ADDOP(c, loc, BINARY_SUBSCR); } break; case Name_kind: - if (!compiler_nameop(c, e->v.Name.id, Load)) + if (!compiler_nameop(c, loc, e->v.Name.id, Load)) return 0; break; default: @@ -5895,34 +5991,35 @@ compiler_augassign(struct compiler *c, stmt_ty s) return 0; } - c->u->u_loc = old_loc; + loc = LOC(s); VISIT(c, expr, s->v.AugAssign.value); - ADDOP_INPLACE(c, s->v.AugAssign.op); + ADDOP_INPLACE(c, loc, s->v.AugAssign.op); SET_LOC(c, e); + loc = LOC(e); switch (e->kind) { case Attribute_kind: - update_start_location_to_match_attr(c, e); - ADDOP_I(c, SWAP, 2); - ADDOP_NAME(c, STORE_ATTR, e->v.Attribute.attr, names); + loc = update_start_location_to_match_attr(c, loc, e); + ADDOP_I(c, loc, SWAP, 2); + ADDOP_NAME(c, loc, STORE_ATTR, e->v.Attribute.attr, names); break; case Subscript_kind: if (is_two_element_slice(e->v.Subscript.slice)) { - ADDOP_I(c, SWAP, 4); - ADDOP_I(c, SWAP, 3); - ADDOP_I(c, SWAP, 2); - ADDOP(c, STORE_SLICE); + ADDOP_I(c, loc, SWAP, 4); + ADDOP_I(c, loc, SWAP, 3); + ADDOP_I(c, loc, SWAP, 2); + ADDOP(c, loc, STORE_SLICE); } else { - ADDOP_I(c, SWAP, 3); - ADDOP_I(c, SWAP, 2); - ADDOP(c, STORE_SUBSCR); + ADDOP_I(c, loc, SWAP, 3); + ADDOP_I(c, loc, SWAP, 2); + ADDOP(c, loc, STORE_SUBSCR); } break; case Name_kind: - return compiler_nameop(c, e->v.Name.id, Store); + return compiler_nameop(c, loc, e->v.Name.id, Store); default: Py_UNREACHABLE(); } @@ -5933,7 +6030,7 @@ static int check_ann_expr(struct compiler *c, expr_ty e) { VISIT(c, expr, e); - ADDOP(c, POP_TOP); + ADDOP(c, LOC(e), POP_TOP); return 1; } @@ -5989,6 +6086,7 @@ check_ann_subscr(struct compiler *c, expr_ty e) static int compiler_annassign(struct compiler *c, stmt_ty s) { + location loc = LOC(s); expr_ty targ = s->v.AnnAssign.target; PyObject* mangled; @@ -6001,7 +6099,7 @@ compiler_annassign(struct compiler *c, stmt_ty s) } switch (targ->kind) { case Name_kind: - if (forbidden_name(c, targ->v.Name.id, Store)) + if (forbidden_name(c, loc, targ->v.Name.id, Store)) return 0; /* If we have a simple name in a module or class, store annotation. */ if (s->v.AnnAssign.simple && @@ -6013,14 +6111,14 @@ compiler_annassign(struct compiler *c, stmt_ty s) else { VISIT(c, expr, s->v.AnnAssign.annotation); } - ADDOP_NAME(c, LOAD_NAME, &_Py_ID(__annotations__), names); + ADDOP_NAME(c, loc, LOAD_NAME, &_Py_ID(__annotations__), names); mangled = _Py_Mangle(c->u->u_private, targ->v.Name.id); - ADDOP_LOAD_CONST_NEW(c, mangled); - ADDOP(c, STORE_SUBSCR); + ADDOP_LOAD_CONST_NEW(c, loc, mangled); + ADDOP(c, loc, STORE_SUBSCR); } break; case Attribute_kind: - if (forbidden_name(c, targ->v.Attribute.attr, Store)) + if (forbidden_name(c, loc, targ->v.Attribute.attr, Store)) return 0; if (!s->v.AnnAssign.value && !check_ann_expr(c, targ->v.Attribute.value)) { @@ -6052,7 +6150,8 @@ compiler_annassign(struct compiler *c, stmt_ty s) */ static int -compiler_error(struct compiler *c, const char *format, ...) +compiler_error(struct compiler *c, location loc, + const char *format, ...) { va_list vargs; va_start(vargs, format); @@ -6061,22 +6160,21 @@ compiler_error(struct compiler *c, const char *format, ...) if (msg == NULL) { return 0; } - PyObject *loc = PyErr_ProgramTextObject(c->c_filename, c->u->u_loc.lineno); - if (loc == NULL) { + PyObject *loc_obj = PyErr_ProgramTextObject(c->c_filename, loc.lineno); + if (loc_obj == NULL) { Py_INCREF(Py_None); - loc = Py_None; + loc_obj = Py_None; } - struct location u_loc = c->u->u_loc; PyObject *args = Py_BuildValue("O(OiiOii)", msg, c->c_filename, - u_loc.lineno, u_loc.col_offset + 1, loc, - u_loc.end_lineno, u_loc.end_col_offset + 1); + loc.lineno, loc.col_offset + 1, loc_obj, + loc.end_lineno, loc.end_col_offset + 1); Py_DECREF(msg); if (args == NULL) { goto exit; } PyErr_SetObject(PyExc_SyntaxError, args); exit: - Py_DECREF(loc); + Py_DECREF(loc_obj); Py_XDECREF(args); return 0; } @@ -6086,7 +6184,8 @@ compiler_error(struct compiler *c, const char *format, ...) and returns 0. */ static int -compiler_warn(struct compiler *c, const char *format, ...) +compiler_warn(struct compiler *c, location loc, + const char *format, ...) { va_list vargs; va_start(vargs, format); @@ -6096,14 +6195,14 @@ compiler_warn(struct compiler *c, const char *format, ...) return 0; } if (PyErr_WarnExplicitObject(PyExc_SyntaxWarning, msg, c->c_filename, - c->u->u_loc.lineno, NULL, NULL) < 0) + loc.lineno, NULL, NULL) < 0) { if (PyErr_ExceptionMatches(PyExc_SyntaxWarning)) { /* Replace the SyntaxWarning exception with a SyntaxError to get a more accurate error report */ PyErr_Clear(); assert(PyUnicode_AsUTF8(msg) != NULL); - compiler_error(c, PyUnicode_AsUTF8(msg)); + compiler_error(c, loc, PyUnicode_AsUTF8(msg)); } Py_DECREF(msg); return 0; @@ -6115,6 +6214,7 @@ compiler_warn(struct compiler *c, const char *format, ...) static int compiler_subscript(struct compiler *c, expr_ty e) { + location loc = LOC(e); expr_context_ty ctx = e->v.Subscript.ctx; int op = 0; @@ -6133,11 +6233,11 @@ compiler_subscript(struct compiler *c, expr_ty e) return 0; } if (ctx == Load) { - ADDOP(c, BINARY_SLICE); + ADDOP(c, loc, BINARY_SLICE); } else { assert(ctx == Store); - ADDOP(c, STORE_SLICE); + ADDOP(c, loc, STORE_SLICE); } } else { @@ -6148,7 +6248,7 @@ compiler_subscript(struct compiler *c, expr_ty e) case Del: op = DELETE_SUBSCR; break; } assert(op); - ADDOP(c, op); + ADDOP(c, loc, op); } return 1; } @@ -6166,14 +6266,14 @@ compiler_slice(struct compiler *c, expr_ty s) VISIT(c, expr, s->v.Slice.lower); } else { - ADDOP_LOAD_CONST(c, Py_None); + ADDOP_LOAD_CONST(c, LOC(s), Py_None); } if (s->v.Slice.upper) { VISIT(c, expr, s->v.Slice.upper); } else { - ADDOP_LOAD_CONST(c, Py_None); + ADDOP_LOAD_CONST(c, LOC(s), Py_None); } if (s->v.Slice.step) { @@ -6230,19 +6330,21 @@ ensure_fail_pop(struct compiler *c, pattern_context *pc, Py_ssize_t n) // Use op to jump to the correct fail_pop block. static int -jump_to_fail_pop(struct compiler *c, pattern_context *pc, int op) +jump_to_fail_pop(struct compiler *c, location loc, + pattern_context *pc, int op) { // Pop any items on the top of the stack, plus any objects we were going to // capture on success: Py_ssize_t pops = pc->on_top + PyList_GET_SIZE(pc->stores); RETURN_IF_FALSE(ensure_fail_pop(c, pc, pops)); - ADDOP_JUMP(c, op, pc->fail_pop[pops]); + ADDOP_JUMP(c, loc, op, pc->fail_pop[pops]); return 1; } // Build all of the fail_pop blocks and reset fail_pop. static int -emit_and_reset_fail_pop(struct compiler *c, pattern_context *pc) +emit_and_reset_fail_pop(struct compiler *c, location loc, + pattern_context *pc) { if (!pc->fail_pop_size) { assert(pc->fail_pop == NULL); @@ -6250,7 +6352,7 @@ emit_and_reset_fail_pop(struct compiler *c, pattern_context *pc) } while (--pc->fail_pop_size) { USE_LABEL(c, pc->fail_pop[pc->fail_pop_size]); - if (!cfg_builder_addop_noarg(CFG_BUILDER(c), POP_TOP, COMPILER_LOC(c))) { + if (!cfg_builder_addop_noarg(CFG_BUILDER(c), POP_TOP, loc)) { pc->fail_pop_size = 0; PyObject_Free(pc->fail_pop); pc->fail_pop = NULL; @@ -6264,29 +6366,31 @@ emit_and_reset_fail_pop(struct compiler *c, pattern_context *pc) } static int -compiler_error_duplicate_store(struct compiler *c, identifier n) +compiler_error_duplicate_store(struct compiler *c, location loc, identifier n) { - return compiler_error(c, "multiple assignments to name %R in pattern", n); + return compiler_error(c, loc, + "multiple assignments to name %R in pattern", n); } // Duplicate the effect of 3.10's ROT_* instructions using SWAPs. static int -pattern_helper_rotate(struct compiler *c, Py_ssize_t count) +pattern_helper_rotate(struct compiler *c, location loc, Py_ssize_t count) { while (1 < count) { - ADDOP_I(c, SWAP, count--); + ADDOP_I(c, loc, SWAP, count--); } return 1; } static int -pattern_helper_store_name(struct compiler *c, identifier n, pattern_context *pc) +pattern_helper_store_name(struct compiler *c, location loc, + identifier n, pattern_context *pc) { if (n == NULL) { - ADDOP(c, POP_TOP); + ADDOP(c, loc, POP_TOP); return 1; } - if (forbidden_name(c, n, Store)) { + if (forbidden_name(c, loc, n, Store)) { return 0; } // Can't assign to the same name twice: @@ -6295,17 +6399,18 @@ pattern_helper_store_name(struct compiler *c, identifier n, pattern_context *pc) return 0; } if (duplicate) { - return compiler_error_duplicate_store(c, n); + return compiler_error_duplicate_store(c, loc, n); } // Rotate this object underneath any items we need to preserve: Py_ssize_t rotations = pc->on_top + PyList_GET_SIZE(pc->stores) + 1; - RETURN_IF_FALSE(pattern_helper_rotate(c, rotations)); + RETURN_IF_FALSE(pattern_helper_rotate(c, loc, rotations)); return !PyList_Append(pc->stores, n); } static int -pattern_unpack_helper(struct compiler *c, asdl_pattern_seq *elts) +pattern_unpack_helper(struct compiler *c, location loc, + asdl_pattern_seq *elts) { Py_ssize_t n = asdl_seq_LEN(elts); int seen_star = 0; @@ -6314,28 +6419,29 @@ pattern_unpack_helper(struct compiler *c, asdl_pattern_seq *elts) if (elt->kind == MatchStar_kind && !seen_star) { if ((i >= (1 << 8)) || (n-i-1 >= (INT_MAX >> 8))) - return compiler_error(c, + return compiler_error(c, loc, "too many expressions in " "star-unpacking sequence pattern"); - ADDOP_I(c, UNPACK_EX, (i + ((n-i-1) << 8))); + ADDOP_I(c, loc, UNPACK_EX, (i + ((n-i-1) << 8))); seen_star = 1; } else if (elt->kind == MatchStar_kind) { - return compiler_error(c, + return compiler_error(c, loc, "multiple starred expressions in sequence pattern"); } } if (!seen_star) { - ADDOP_I(c, UNPACK_SEQUENCE, n); + ADDOP_I(c, loc, UNPACK_SEQUENCE, n); } return 1; } static int -pattern_helper_sequence_unpack(struct compiler *c, asdl_pattern_seq *patterns, - Py_ssize_t star, pattern_context *pc) +pattern_helper_sequence_unpack(struct compiler *c, location *ploc, + asdl_pattern_seq *patterns, Py_ssize_t star, + pattern_context *pc) { - RETURN_IF_FALSE(pattern_unpack_helper(c, patterns)); + RETURN_IF_FALSE(pattern_unpack_helper(c, *ploc, patterns)); Py_ssize_t size = asdl_seq_LEN(patterns); // We've now got a bunch of new subjects on the stack. They need to remain // there after each subpattern match: @@ -6344,7 +6450,7 @@ pattern_helper_sequence_unpack(struct compiler *c, asdl_pattern_seq *patterns, // One less item to keep track of each time we loop through: pc->on_top--; pattern_ty pattern = asdl_seq_GET(patterns, i); - RETURN_IF_FALSE(compiler_pattern_subpattern(c, pattern, pc)); + RETURN_IF_FALSE(compiler_pattern_subpattern(c, ploc, pattern, pc)); } return 1; } @@ -6353,8 +6459,9 @@ pattern_helper_sequence_unpack(struct compiler *c, asdl_pattern_seq *patterns, // UNPACK_SEQUENCE / UNPACK_EX. This is more efficient for patterns with a // starred wildcard like [first, *_] / [first, *_, last] / [*_, last] / etc. static int -pattern_helper_sequence_subscr(struct compiler *c, asdl_pattern_seq *patterns, - Py_ssize_t star, pattern_context *pc) +pattern_helper_sequence_subscr(struct compiler *c, location *ploc, + asdl_pattern_seq *patterns, Py_ssize_t star, + pattern_context *pc) { // We need to keep the subject around for extracting elements: pc->on_top++; @@ -6368,39 +6475,41 @@ pattern_helper_sequence_subscr(struct compiler *c, asdl_pattern_seq *patterns, assert(WILDCARD_STAR_CHECK(pattern)); continue; } - ADDOP_I(c, COPY, 1); + ADDOP_I(c, *ploc, COPY, 1); if (i < star) { - ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(i)); + ADDOP_LOAD_CONST_NEW(c, *ploc, PyLong_FromSsize_t(i)); } else { // The subject may not support negative indexing! Compute a // nonnegative index: - ADDOP(c, GET_LEN); - ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(size - i)); - ADDOP_BINARY(c, Sub); + ADDOP(c, *ploc, GET_LEN); + ADDOP_LOAD_CONST_NEW(c, *ploc, PyLong_FromSsize_t(size - i)); + ADDOP_BINARY(c, *ploc, Sub); } - ADDOP(c, BINARY_SUBSCR); - RETURN_IF_FALSE(compiler_pattern_subpattern(c, pattern, pc)); + ADDOP(c, *ploc, BINARY_SUBSCR); + RETURN_IF_FALSE(compiler_pattern_subpattern(c, ploc, pattern, pc)); } // Pop the subject, we're done with it: pc->on_top--; - ADDOP(c, POP_TOP); + ADDOP(c, *ploc, POP_TOP); return 1; } // Like compiler_pattern, but turn off checks for irrefutability. static int -compiler_pattern_subpattern(struct compiler *c, pattern_ty p, pattern_context *pc) +compiler_pattern_subpattern(struct compiler *c, location *ploc, + pattern_ty p, pattern_context *pc) { int allow_irrefutable = pc->allow_irrefutable; pc->allow_irrefutable = 1; - RETURN_IF_FALSE(compiler_pattern(c, p, pc)); + RETURN_IF_FALSE(compiler_pattern(c, ploc, p, pc)); pc->allow_irrefutable = allow_irrefutable; return 1; } static int -compiler_pattern_as(struct compiler *c, pattern_ty p, pattern_context *pc) +compiler_pattern_as(struct compiler *c, location *ploc, + pattern_ty p, pattern_context *pc) { assert(p->kind == MatchAs_kind); if (p->v.MatchAs.pattern == NULL) { @@ -6408,20 +6517,20 @@ compiler_pattern_as(struct compiler *c, pattern_ty p, pattern_context *pc) if (!pc->allow_irrefutable) { if (p->v.MatchAs.name) { const char *e = "name capture %R makes remaining patterns unreachable"; - return compiler_error(c, e, p->v.MatchAs.name); + return compiler_error(c, *ploc, e, p->v.MatchAs.name); } const char *e = "wildcard makes remaining patterns unreachable"; - return compiler_error(c, e); + return compiler_error(c, *ploc, e); } - return pattern_helper_store_name(c, p->v.MatchAs.name, pc); + return pattern_helper_store_name(c, *ploc, p->v.MatchAs.name, pc); } // Need to make a copy for (possibly) storing later: pc->on_top++; - ADDOP_I(c, COPY, 1); - RETURN_IF_FALSE(compiler_pattern(c, p->v.MatchAs.pattern, pc)); + ADDOP_I(c, *ploc, COPY, 1); + RETURN_IF_FALSE(compiler_pattern(c, ploc, p->v.MatchAs.pattern, pc)); // Success! Store it: pc->on_top--; - RETURN_IF_FALSE(pattern_helper_store_name(c, p->v.MatchAs.name, pc)); + RETURN_IF_FALSE(pattern_helper_store_name(c, *ploc, p->v.MatchAs.name, pc)); return 1; } @@ -6429,7 +6538,8 @@ static int compiler_pattern_star(struct compiler *c, pattern_ty p, pattern_context *pc) { assert(p->kind == MatchStar_kind); - RETURN_IF_FALSE(pattern_helper_store_name(c, p->v.MatchStar.name, pc)); + location loc = LOC(p); + RETURN_IF_FALSE(pattern_helper_store_name(c, loc, p->v.MatchStar.name, pc)); return 1; } @@ -6442,14 +6552,16 @@ validate_kwd_attrs(struct compiler *c, asdl_identifier_seq *attrs, asdl_pattern_ for (Py_ssize_t i = 0; i < nattrs; i++) { identifier attr = ((identifier)asdl_seq_GET(attrs, i)); SET_LOC(c, ((pattern_ty) asdl_seq_GET(patterns, i))); - if (forbidden_name(c, attr, Store)) { + location loc = LOC((pattern_ty) asdl_seq_GET(patterns, i)); + if (forbidden_name(c, loc, attr, Store)) { return -1; } for (Py_ssize_t j = i + 1; j < nattrs; j++) { identifier other = ((identifier)asdl_seq_GET(attrs, j)); if (!PyUnicode_Compare(attr, other)) { + location loc = LOC((pattern_ty) asdl_seq_GET(patterns, j)); SET_LOC(c, ((pattern_ty) asdl_seq_GET(patterns, j))); - compiler_error(c, "attribute name repeated in class pattern: %U", attr); + compiler_error(c, loc, "attribute name repeated in class pattern: %U", attr); return -1; } } @@ -6458,7 +6570,8 @@ validate_kwd_attrs(struct compiler *c, asdl_identifier_seq *attrs, asdl_pattern_ } static int -compiler_pattern_class(struct compiler *c, pattern_ty p, pattern_context *pc) +compiler_pattern_class(struct compiler *c, location *ploc, + pattern_ty p, pattern_context *pc) { assert(p->kind == MatchClass_kind); asdl_pattern_seq *patterns = p->v.MatchClass.patterns; @@ -6471,11 +6584,11 @@ compiler_pattern_class(struct compiler *c, pattern_ty p, pattern_context *pc) // AST validator shouldn't let this happen, but if it does, // just fail, don't crash out of the interpreter const char * e = "kwd_attrs (%d) / kwd_patterns (%d) length mismatch in class pattern"; - return compiler_error(c, e, nattrs, nkwd_patterns); + return compiler_error(c, *ploc, e, nattrs, nkwd_patterns); } if (INT_MAX < nargs || INT_MAX < nargs + nattrs - 1) { const char *e = "too many sub-patterns in class pattern %R"; - return compiler_error(c, e, p->v.MatchClass.cls); + return compiler_error(c, *ploc, e, p->v.MatchClass.cls); } if (nattrs) { RETURN_IF_FALSE(!validate_kwd_attrs(c, kwd_attrs, kwd_patterns)); @@ -6490,15 +6603,15 @@ compiler_pattern_class(struct compiler *c, pattern_ty p, pattern_context *pc) Py_INCREF(name); PyTuple_SET_ITEM(attr_names, i, name); } - ADDOP_LOAD_CONST_NEW(c, attr_names); - ADDOP_I(c, MATCH_CLASS, nargs); - ADDOP_I(c, COPY, 1); - ADDOP_LOAD_CONST(c, Py_None); - ADDOP_I(c, IS_OP, 1); + ADDOP_LOAD_CONST_NEW(c, *ploc, attr_names); + ADDOP_I(c, *ploc, MATCH_CLASS, nargs); + ADDOP_I(c, *ploc, COPY, 1); + ADDOP_LOAD_CONST(c, *ploc, Py_None); + ADDOP_I(c, *ploc, IS_OP, 1); // TOS is now a tuple of (nargs + nattrs) attributes (or None): pc->on_top++; - RETURN_IF_FALSE(jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); - ADDOP_I(c, UNPACK_SEQUENCE, nargs + nattrs); + RETURN_IF_FALSE(jump_to_fail_pop(c, *ploc, pc, POP_JUMP_IF_FALSE)); + ADDOP_I(c, *ploc, UNPACK_SEQUENCE, nargs + nattrs); pc->on_top += nargs + nattrs - 1; for (i = 0; i < nargs + nattrs; i++) { pc->on_top--; @@ -6512,17 +6625,19 @@ compiler_pattern_class(struct compiler *c, pattern_ty p, pattern_context *pc) pattern = asdl_seq_GET(kwd_patterns, i - nargs); } if (WILDCARD_CHECK(pattern)) { - ADDOP(c, POP_TOP); + ADDOP(c, *ploc, POP_TOP); continue; } - RETURN_IF_FALSE(compiler_pattern_subpattern(c, pattern, pc)); + *ploc = LOC(pattern); + RETURN_IF_FALSE(compiler_pattern_subpattern(c, ploc, pattern, pc)); } // Success! Pop the tuple of attributes: return 1; } static int -compiler_pattern_mapping(struct compiler *c, pattern_ty p, pattern_context *pc) +compiler_pattern_mapping(struct compiler *c, location *ploc, + pattern_ty p, pattern_context *pc) { assert(p->kind == MatchMapping_kind); asdl_expr_seq *keys = p->v.MatchMapping.keys; @@ -6533,29 +6648,29 @@ compiler_pattern_mapping(struct compiler *c, pattern_ty p, pattern_context *pc) // AST validator shouldn't let this happen, but if it does, // just fail, don't crash out of the interpreter const char * e = "keys (%d) / patterns (%d) length mismatch in mapping pattern"; - return compiler_error(c, e, size, npatterns); + return compiler_error(c, *ploc, e, size, npatterns); } // We have a double-star target if "rest" is set PyObject *star_target = p->v.MatchMapping.rest; // We need to keep the subject on top during the mapping and length checks: pc->on_top++; - ADDOP(c, MATCH_MAPPING); - RETURN_IF_FALSE(jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); + ADDOP(c, *ploc, MATCH_MAPPING); + RETURN_IF_FALSE(jump_to_fail_pop(c, *ploc, pc, POP_JUMP_IF_FALSE)); if (!size && !star_target) { // If the pattern is just "{}", we're done! Pop the subject: pc->on_top--; - ADDOP(c, POP_TOP); + ADDOP(c, *ploc, POP_TOP); return 1; } if (size) { // If the pattern has any keys in it, perform a length check: - ADDOP(c, GET_LEN); - ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(size)); - ADDOP_COMPARE(c, GtE); - RETURN_IF_FALSE(jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); + ADDOP(c, *ploc, GET_LEN); + ADDOP_LOAD_CONST_NEW(c, *ploc, PyLong_FromSsize_t(size)); + ADDOP_COMPARE(c, *ploc, GtE); + RETURN_IF_FALSE(jump_to_fail_pop(c, *ploc, pc, POP_JUMP_IF_FALSE)); } if (INT_MAX < size - 1) { - return compiler_error(c, "too many sub-patterns in mapping pattern"); + return compiler_error(c, *ploc, "too many sub-patterns in mapping pattern"); } // Collect all of the keys into a tuple for MATCH_KEYS and // **rest. They can either be dotted names or literals: @@ -6573,8 +6688,9 @@ compiler_pattern_mapping(struct compiler *c, pattern_ty p, pattern_context *pc) if (key == NULL) { const char *e = "can't use NULL keys in MatchMapping " "(set 'rest' parameter instead)"; - SET_LOC(c, ((pattern_ty) asdl_seq_GET(patterns, i))); - compiler_error(c, e); + location loc = LOC((pattern_ty) asdl_seq_GET(patterns, i)); + SET_LOC(c, (pattern_ty) asdl_seq_GET(patterns, i)); + compiler_error(c, loc, e); goto error; } @@ -6585,7 +6701,7 @@ compiler_pattern_mapping(struct compiler *c, pattern_ty p, pattern_context *pc) } if (in_seen) { const char *e = "mapping pattern checks duplicate key (%R)"; - compiler_error(c, e, key->v.Constant.value); + compiler_error(c, *ploc, e, key->v.Constant.value); goto error; } if (PySet_Add(seen, key->v.Constant.value)) { @@ -6595,7 +6711,7 @@ compiler_pattern_mapping(struct compiler *c, pattern_ty p, pattern_context *pc) else if (key->kind != Attribute_kind) { const char *e = "mapping pattern keys may only match literals and attribute lookups"; - compiler_error(c, e); + compiler_error(c, *ploc, e); goto error; } if (!compiler_visit_expr(c, key)) { @@ -6606,22 +6722,22 @@ compiler_pattern_mapping(struct compiler *c, pattern_ty p, pattern_context *pc) // all keys have been checked; there are no duplicates Py_DECREF(seen); - ADDOP_I(c, BUILD_TUPLE, size); - ADDOP(c, MATCH_KEYS); + ADDOP_I(c, *ploc, BUILD_TUPLE, size); + ADDOP(c, *ploc, MATCH_KEYS); // There's now a tuple of keys and a tuple of values on top of the subject: pc->on_top += 2; - ADDOP_I(c, COPY, 1); - ADDOP_LOAD_CONST(c, Py_None); - ADDOP_I(c, IS_OP, 1); - RETURN_IF_FALSE(jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); + ADDOP_I(c, *ploc, COPY, 1); + ADDOP_LOAD_CONST(c, *ploc, Py_None); + ADDOP_I(c, *ploc, IS_OP, 1); + RETURN_IF_FALSE(jump_to_fail_pop(c, *ploc, pc, POP_JUMP_IF_FALSE)); // So far so good. Use that tuple of values on the stack to match // sub-patterns against: - ADDOP_I(c, UNPACK_SEQUENCE, size); + ADDOP_I(c, *ploc, UNPACK_SEQUENCE, size); pc->on_top += size - 1; for (Py_ssize_t i = 0; i < size; i++) { pc->on_top--; pattern_ty pattern = asdl_seq_GET(patterns, i); - RETURN_IF_FALSE(compiler_pattern_subpattern(c, pattern, pc)); + RETURN_IF_FALSE(compiler_pattern_subpattern(c, ploc, pattern, pc)); } // If we get this far, it's a match! Whatever happens next should consume // the tuple of keys and the subject: @@ -6633,20 +6749,20 @@ compiler_pattern_mapping(struct compiler *c, pattern_ty p, pattern_context *pc) // rest = dict(TOS1) // for key in TOS: // del rest[key] - ADDOP_I(c, BUILD_MAP, 0); // [subject, keys, empty] - ADDOP_I(c, SWAP, 3); // [empty, keys, subject] - ADDOP_I(c, DICT_UPDATE, 2); // [copy, keys] - ADDOP_I(c, UNPACK_SEQUENCE, size); // [copy, keys...] + ADDOP_I(c, *ploc, BUILD_MAP, 0); // [subject, keys, empty] + ADDOP_I(c, *ploc, SWAP, 3); // [empty, keys, subject] + ADDOP_I(c, *ploc, DICT_UPDATE, 2); // [copy, keys] + ADDOP_I(c, *ploc, UNPACK_SEQUENCE, size); // [copy, keys...] while (size) { - ADDOP_I(c, COPY, 1 + size--); // [copy, keys..., copy] - ADDOP_I(c, SWAP, 2); // [copy, keys..., copy, key] - ADDOP(c, DELETE_SUBSCR); // [copy, keys...] + ADDOP_I(c, *ploc, COPY, 1 + size--); // [copy, keys..., copy] + ADDOP_I(c, *ploc, SWAP, 2); // [copy, keys..., copy, key] + ADDOP(c, *ploc, DELETE_SUBSCR); // [copy, keys...] } - RETURN_IF_FALSE(pattern_helper_store_name(c, star_target, pc)); + RETURN_IF_FALSE(pattern_helper_store_name(c, *ploc, star_target, pc)); } else { - ADDOP(c, POP_TOP); // Tuple of keys. - ADDOP(c, POP_TOP); // Subject. + ADDOP(c, *ploc, POP_TOP); // Tuple of keys. + ADDOP(c, *ploc, POP_TOP); // Subject. } return 1; @@ -6656,7 +6772,8 @@ compiler_pattern_mapping(struct compiler *c, pattern_ty p, pattern_context *pc) } static int -compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) +compiler_pattern_or(struct compiler *c, location *ploc, + pattern_ty p, pattern_context *pc) { assert(p->kind == MatchOr_kind); NEW_JUMP_TARGET_LABEL(c, end); @@ -6683,8 +6800,9 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) pc->fail_pop = NULL; pc->fail_pop_size = 0; pc->on_top = 0; - if (!cfg_builder_addop_i(CFG_BUILDER(c), COPY, 1, COMPILER_LOC(c)) || - !compiler_pattern(c, alt, pc)) { + *ploc = LOC(alt); + if (!cfg_builder_addop_i(CFG_BUILDER(c), COPY, 1, *ploc) || + !compiler_pattern(c, ploc, alt, pc)) { goto error; } // Success! @@ -6739,7 +6857,7 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) // Do the same thing to the stack, using several // rotations: while (rotations--) { - if (!pattern_helper_rotate(c, icontrol + 1)){ + if (!pattern_helper_rotate(c, *ploc, icontrol + 1)){ goto error; } } @@ -6747,8 +6865,8 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) } } assert(control); - if (!cfg_builder_addop_j(CFG_BUILDER(c), JUMP, end, COMPILER_LOC(c)) || - !emit_and_reset_fail_pop(c, pc)) + if (!cfg_builder_addop_j(CFG_BUILDER(c), *ploc, JUMP, end) || + !emit_and_reset_fail_pop(c, *ploc, pc)) { goto error; } @@ -6759,7 +6877,8 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) // Need to NULL this for the PyObject_Free call in the error block. old_pc.fail_pop = NULL; // No match. Pop the remaining copy of the subject and fail: - if (!cfg_builder_addop_noarg(CFG_BUILDER(c), POP_TOP, COMPILER_LOC(c)) || !jump_to_fail_pop(c, pc, JUMP)) { + if (!cfg_builder_addop_noarg(CFG_BUILDER(c), POP_TOP, *ploc) || + !jump_to_fail_pop(c, *ploc, pc, JUMP)) { goto error; } @@ -6774,7 +6893,7 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) Py_ssize_t nrots = nstores + 1 + pc->on_top + PyList_GET_SIZE(pc->stores); for (Py_ssize_t i = 0; i < nstores; i++) { // Rotate this capture to its proper place on the stack: - if (!pattern_helper_rotate(c, nrots)) { + if (!pattern_helper_rotate(c, *ploc, nrots)) { goto error; } // Update the list of previous stores with this new name, checking for @@ -6785,7 +6904,7 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) goto error; } if (dupe) { - compiler_error_duplicate_store(c, name); + compiler_error_duplicate_store(c, *ploc, name); goto error; } if (PyList_Append(pc->stores, name)) { @@ -6796,10 +6915,10 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) Py_DECREF(control); // NOTE: Returning macros are safe again. // Pop the copy of the subject: - ADDOP(c, POP_TOP); + ADDOP(c, *ploc, POP_TOP); return 1; diff: - compiler_error(c, "alternative patterns bind different names"); + compiler_error(c, *ploc, "alternative patterns bind different names"); error: PyObject_Free(old_pc.fail_pop); Py_DECREF(old_pc.stores); @@ -6809,7 +6928,8 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) static int -compiler_pattern_sequence(struct compiler *c, pattern_ty p, pattern_context *pc) +compiler_pattern_sequence(struct compiler *c, location *ploc, + pattern_ty p, pattern_context *pc) { assert(p->kind == MatchSequence_kind); asdl_pattern_seq *patterns = p->v.MatchSequence.patterns; @@ -6823,7 +6943,7 @@ compiler_pattern_sequence(struct compiler *c, pattern_ty p, pattern_context *pc) if (pattern->kind == MatchStar_kind) { if (star >= 0) { const char *e = "multiple starred names in sequence pattern"; - return compiler_error(c, e); + return compiler_error(c, *ploc, e); } star_wildcard = WILDCARD_STAR_CHECK(pattern); only_wildcard &= star_wildcard; @@ -6834,33 +6954,33 @@ compiler_pattern_sequence(struct compiler *c, pattern_ty p, pattern_context *pc) } // We need to keep the subject on top during the sequence and length checks: pc->on_top++; - ADDOP(c, MATCH_SEQUENCE); - RETURN_IF_FALSE(jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); + ADDOP(c, *ploc, MATCH_SEQUENCE); + RETURN_IF_FALSE(jump_to_fail_pop(c, *ploc, pc, POP_JUMP_IF_FALSE)); if (star < 0) { // No star: len(subject) == size - ADDOP(c, GET_LEN); - ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(size)); - ADDOP_COMPARE(c, Eq); - RETURN_IF_FALSE(jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); + ADDOP(c, *ploc, GET_LEN); + ADDOP_LOAD_CONST_NEW(c, *ploc, PyLong_FromSsize_t(size)); + ADDOP_COMPARE(c, *ploc, Eq); + RETURN_IF_FALSE(jump_to_fail_pop(c, *ploc, pc, POP_JUMP_IF_FALSE)); } else if (size > 1) { // Star: len(subject) >= size - 1 - ADDOP(c, GET_LEN); - ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(size - 1)); - ADDOP_COMPARE(c, GtE); - RETURN_IF_FALSE(jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); + ADDOP(c, *ploc, GET_LEN); + ADDOP_LOAD_CONST_NEW(c, *ploc, PyLong_FromSsize_t(size - 1)); + ADDOP_COMPARE(c, *ploc, GtE); + RETURN_IF_FALSE(jump_to_fail_pop(c, *ploc, pc, POP_JUMP_IF_FALSE)); } // Whatever comes next should consume the subject: pc->on_top--; if (only_wildcard) { // Patterns like: [] / [_] / [_, _] / [*_] / [_, *_] / [_, _, *_] / etc. - ADDOP(c, POP_TOP); + ADDOP(c, *ploc, POP_TOP); } else if (star_wildcard) { - RETURN_IF_FALSE(pattern_helper_sequence_subscr(c, patterns, star, pc)); + RETURN_IF_FALSE(pattern_helper_sequence_subscr(c, ploc, patterns, star, pc)); } else { - RETURN_IF_FALSE(pattern_helper_sequence_unpack(c, patterns, star, pc)); + RETURN_IF_FALSE(pattern_helper_sequence_unpack(c, ploc, patterns, star, pc)); } return 1; } @@ -6869,14 +6989,15 @@ static int compiler_pattern_value(struct compiler *c, pattern_ty p, pattern_context *pc) { assert(p->kind == MatchValue_kind); + location loc = LOC(p); expr_ty value = p->v.MatchValue.value; if (!MATCH_VALUE_EXPR(value)) { const char *e = "patterns may only match literals and attribute lookups"; - return compiler_error(c, e); + return compiler_error(c, loc, e); } VISIT(c, expr, value); - ADDOP_COMPARE(c, Eq); - RETURN_IF_FALSE(jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); + ADDOP_COMPARE(c, loc, Eq); + RETURN_IF_FALSE(jump_to_fail_pop(c, loc, pc, POP_JUMP_IF_FALSE)); return 1; } @@ -6884,38 +7005,41 @@ static int compiler_pattern_singleton(struct compiler *c, pattern_ty p, pattern_context *pc) { assert(p->kind == MatchSingleton_kind); - ADDOP_LOAD_CONST(c, p->v.MatchSingleton.value); - ADDOP_COMPARE(c, Is); - RETURN_IF_FALSE(jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); + location loc = LOC(p); + ADDOP_LOAD_CONST(c, loc, p->v.MatchSingleton.value); + ADDOP_COMPARE(c, loc, Is); + RETURN_IF_FALSE(jump_to_fail_pop(c, loc, pc, POP_JUMP_IF_FALSE)); return 1; } static int -compiler_pattern(struct compiler *c, pattern_ty p, pattern_context *pc) +compiler_pattern(struct compiler *c, location *ploc, + pattern_ty p, pattern_context *pc) { SET_LOC(c, p); + *ploc = LOC(p); switch (p->kind) { case MatchValue_kind: return compiler_pattern_value(c, p, pc); case MatchSingleton_kind: return compiler_pattern_singleton(c, p, pc); case MatchSequence_kind: - return compiler_pattern_sequence(c, p, pc); + return compiler_pattern_sequence(c, ploc, p, pc); case MatchMapping_kind: - return compiler_pattern_mapping(c, p, pc); + return compiler_pattern_mapping(c, ploc, p, pc); case MatchClass_kind: - return compiler_pattern_class(c, p, pc); + return compiler_pattern_class(c, ploc, p, pc); case MatchStar_kind: return compiler_pattern_star(c, p, pc); case MatchAs_kind: - return compiler_pattern_as(c, p, pc); + return compiler_pattern_as(c, ploc, p, pc); case MatchOr_kind: - return compiler_pattern_or(c, p, pc); + return compiler_pattern_or(c, ploc, p, pc); } // AST validator shouldn't let this happen, but if it does, // just fail, don't crash out of the interpreter const char *e = "invalid match pattern node in AST (kind=%d)"; - return compiler_error(c, e, p->kind); + return compiler_error(c, *ploc, e, p->kind); } static int @@ -6931,8 +7055,9 @@ compiler_match_inner(struct compiler *c, stmt_ty s, pattern_context *pc) m = asdl_seq_GET(s->v.Match.cases, i); SET_LOC(c, m->pattern); // Only copy the subject if we're *not* on the last case: + location loc = LOC(m->pattern); if (i != cases - has_default - 1) { - ADDOP_I(c, COPY, 1); + ADDOP_I(c, loc, COPY, 1); } RETURN_IF_FALSE(pc->stores = PyList_New(0)); // Irrefutable cases must be either guarded, last, or both: @@ -6941,7 +7066,7 @@ compiler_match_inner(struct compiler *c, stmt_ty s, pattern_context *pc) pc->fail_pop_size = 0; pc->on_top = 0; // NOTE: Can't use returning macros here (they'll leak pc->stores)! - if (!compiler_pattern(c, m->pattern, pc)) { + if (!compiler_pattern(c, &loc, m->pattern, pc)) { Py_DECREF(pc->stores); return 0; } @@ -6950,7 +7075,7 @@ compiler_match_inner(struct compiler *c, stmt_ty s, pattern_context *pc) Py_ssize_t nstores = PyList_GET_SIZE(pc->stores); for (Py_ssize_t n = 0; n < nstores; n++) { PyObject *name = PyList_GET_ITEM(pc->stores, n); - if (!compiler_nameop(c, name, Store)) { + if (!compiler_nameop(c, loc, name, Store)) { Py_DECREF(pc->stores); return 0; } @@ -6959,35 +7084,36 @@ compiler_match_inner(struct compiler *c, stmt_ty s, pattern_context *pc) // NOTE: Returning macros are safe again. if (m->guard) { RETURN_IF_FALSE(ensure_fail_pop(c, pc, 0)); - RETURN_IF_FALSE(compiler_jump_if(c, m->guard, pc->fail_pop[0], 0)); + RETURN_IF_FALSE(compiler_jump_if(c, &loc, m->guard, pc->fail_pop[0], 0)); } // Success! Pop the subject off, we're done with it: if (i != cases - has_default - 1) { - ADDOP(c, POP_TOP); + ADDOP(c, loc, POP_TOP); } VISIT_SEQ(c, stmt, m->body); - ADDOP_JUMP(c, JUMP, end); + ADDOP_JUMP(c, NO_LOCATION, JUMP, end); // If the pattern fails to match, we want the line number of the // cleanup to be associated with the failed pattern, not the last line // of the body SET_LOC(c, m->pattern); - RETURN_IF_FALSE(emit_and_reset_fail_pop(c, pc)); + RETURN_IF_FALSE(emit_and_reset_fail_pop(c, LOC(m->pattern), pc)); } if (has_default) { // A trailing "case _" is common, and lets us save a bit of redundant // pushing and popping in the loop above: m = asdl_seq_GET(s->v.Match.cases, cases - 1); SET_LOC(c, m->pattern); + location loc = LOC(m->pattern); if (cases == 1) { // No matches. Done with the subject: - ADDOP(c, POP_TOP); + ADDOP(c, loc, POP_TOP); } else { // Show line coverage for default case (it doesn't create bytecode) - ADDOP(c, NOP); + ADDOP(c, loc, NOP); } if (m->guard) { - RETURN_IF_FALSE(compiler_jump_if(c, m->guard, end, 0)); + RETURN_IF_FALSE(compiler_jump_if(c, &loc, m->guard, end, 0)); } VISIT_SEQ(c, stmt, m->body); } @@ -8585,9 +8711,10 @@ assemble(struct compiler *c, int addNone) /* Make sure every block that falls off the end returns None. */ if (!basicblock_returns(CFG_BUILDER(c)->g_curblock)) { UNSET_LOC(c); - if (addNone) - ADDOP_LOAD_CONST(c, Py_None); - ADDOP(c, RETURN_VALUE); + if (addNone) { + ADDOP_LOAD_CONST(c, NO_LOCATION, Py_None); + } + ADDOP(c, NO_LOCATION, RETURN_VALUE); } assert(PyDict_GET_SIZE(c->u->u_varnames) < INT_MAX); @@ -9437,7 +9564,7 @@ propagate_line_numbers(basicblock *entryblock) { continue; } - struct location prev_location = NO_LOCATION; + location prev_location = NO_LOCATION; for (int i = 0; i < b->b_iused; i++) { if (b->b_instr[i].i_loc.lineno < 0) { b->b_instr[i].i_loc = prev_location; @@ -9695,7 +9822,7 @@ instructions_to_cfg(PyObject *instructions, cfg_builder *g) if (PyErr_Occurred()) { return -1; } - struct location loc; + location loc; loc.lineno = PyLong_AsLong(PyTuple_GET_ITEM(item, 2)); if (PyErr_Occurred()) { return -1; @@ -9743,7 +9870,7 @@ cfg_to_instructions(cfg_builder *g) Py_DECREF(lbl); for (int i = 0; i < b->b_iused; i++) { struct instr *instr = &b->b_instr[i]; - struct location loc = instr->i_loc; + location loc = instr->i_loc; int arg = HAS_TARGET(instr->i_opcode) ? instr->i_target->b_label : instr->i_oparg; PyObject *inst_tuple = Py_BuildValue( "(iiiiii)", instr->i_opcode, arg, From webhook-mailer at python.org Mon Oct 17 11:27:08 2022 From: webhook-mailer at python.org (gvanrossum) Date: Mon, 17 Oct 2022 15:27:08 -0000 Subject: [Python-checkins] GH-98327: Reduce scope of catch_warnings() in _make_subprocess_transport (#98333) Message-ID: https://github.com/python/cpython/commit/72c10d3f1a6d42b70cc4b843295361db17cc0964 commit: 72c10d3f1a6d42b70cc4b843295361db17cc0964 branch: main author: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> committer: gvanrossum date: 2022-10-17T08:27:02-07:00 summary: GH-98327: Reduce scope of catch_warnings() in _make_subprocess_transport (#98333) Alas, warnings.catch_warnings() has global scope, not thread scope, so this is still not perfect, but it reduces the time during which warnings are ignored. Better solution welcome. files: M Lib/asyncio/unix_events.py M Lib/test/test_asyncio/test_subprocess.py diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py index ea7010ee1073..2de7a1bfd681 100644 --- a/Lib/asyncio/unix_events.py +++ b/Lib/asyncio/unix_events.py @@ -197,30 +197,31 @@ async def _make_subprocess_transport(self, protocol, args, shell, extra=None, **kwargs): with warnings.catch_warnings(): warnings.simplefilter('ignore', DeprecationWarning) - with events.get_child_watcher() as watcher: - if not watcher.is_active(): - # Check early. - # Raising exception before process creation - # prevents subprocess execution if the watcher - # is not ready to handle it. - raise RuntimeError("asyncio.get_child_watcher() is not activated, " - "subprocess support is not installed.") - waiter = self.create_future() - transp = _UnixSubprocessTransport(self, protocol, args, shell, - stdin, stdout, stderr, bufsize, - waiter=waiter, extra=extra, - **kwargs) - - watcher.add_child_handler(transp.get_pid(), - self._child_watcher_callback, transp) - try: - await waiter - except (SystemExit, KeyboardInterrupt): - raise - except BaseException: - transp.close() - await transp._wait() - raise + watcher = events.get_child_watcher() + + with watcher: + if not watcher.is_active(): + # Check early. + # Raising exception before process creation + # prevents subprocess execution if the watcher + # is not ready to handle it. + raise RuntimeError("asyncio.get_child_watcher() is not activated, " + "subprocess support is not installed.") + waiter = self.create_future() + transp = _UnixSubprocessTransport(self, protocol, args, shell, + stdin, stdout, stderr, bufsize, + waiter=waiter, extra=extra, + **kwargs) + watcher.add_child_handler(transp.get_pid(), + self._child_watcher_callback, transp) + try: + await waiter + except (SystemExit, KeyboardInterrupt): + raise + except BaseException: + transp.close() + await transp._wait() + raise return transp diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py index 8e5511559061..fe1d060c77d4 100644 --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -752,15 +752,11 @@ def _get_watcher(self): class GenericWatcherTests(test_utils.TestCase): def test_create_subprocess_fails_with_inactive_watcher(self): - watcher = mock.create_autospec( - asyncio.AbstractChildWatcher, - **{"__enter__.return_value.is_active.return_value": False} - ) + watcher = mock.create_autospec(asyncio.AbstractChildWatcher) + watcher.is_active.return_value = False async def execute(): - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - asyncio.set_child_watcher(watcher) + asyncio.set_child_watcher(watcher) with self.assertRaises(RuntimeError): await subprocess.create_subprocess_exec( @@ -774,9 +770,9 @@ async def execute(): self.assertIsNone(runner.run(execute())) self.assertListEqual(watcher.mock_calls, [ mock.call.__enter__(), - mock.call.__enter__().is_active(), + mock.call.is_active(), mock.call.__exit__(RuntimeError, mock.ANY, mock.ANY), - ]) + ], watcher.mock_calls) @unittest.skipUnless( From webhook-mailer at python.org Mon Oct 17 11:46:04 2022 From: webhook-mailer at python.org (gvanrossum) Date: Mon, 17 Oct 2022 15:46:04 -0000 Subject: [Python-checkins] gh-98174: Handle EPROTOTYPE under macOS in test_sendfile_fallback_close_peer_in_the_middle_of_receiving (#98316) Message-ID: https://github.com/python/cpython/commit/3e82ad05b18d004e4d01fdb643344d6a2bf11900 commit: 3e82ad05b18d004e4d01fdb643344d6a2bf11900 branch: main author: fancidev committer: gvanrossum date: 2022-10-17T08:45:38-07:00 summary: gh-98174: Handle EPROTOTYPE under macOS in test_sendfile_fallback_close_peer_in_the_middle_of_receiving (#98316) Co-authored-by: Nikita Sobolev files: M Lib/test/test_asyncio/test_sendfile.py diff --git a/Lib/test/test_asyncio/test_sendfile.py b/Lib/test/test_asyncio/test_sendfile.py index a10504b1c413..0198da21d770 100644 --- a/Lib/test/test_asyncio/test_sendfile.py +++ b/Lib/test/test_asyncio/test_sendfile.py @@ -1,6 +1,7 @@ """Tests for sendfile functionality.""" import asyncio +import errno import os import socket import sys @@ -484,8 +485,17 @@ def sendfile_native(transp, file, offset, count): srv_proto, cli_proto = self.prepare_sendfile(close_after=1024) with self.assertRaises(ConnectionError): - self.run_loop( - self.loop.sendfile(cli_proto.transport, self.file)) + try: + self.run_loop( + self.loop.sendfile(cli_proto.transport, self.file)) + except OSError as e: + # macOS may raise OSError of EPROTOTYPE when writing to a + # socket that is in the process of closing down. + if e.errno == errno.EPROTOTYPE and sys.platform == "darwin": + raise ConnectionError + else: + raise + self.run_loop(srv_proto.done) self.assertTrue(1024 <= srv_proto.nbytes < len(self.DATA), From webhook-mailer at python.org Mon Oct 17 12:13:46 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 17 Oct 2022 16:13:46 -0000 Subject: [Python-checkins] gh-98174: Handle EPROTOTYPE under macOS in test_sendfile_fallback_close_peer_in_the_middle_of_receiving (GH-98316) Message-ID: https://github.com/python/cpython/commit/3adf23471ee951a435f2ffa336a52bc6800a209a commit: 3adf23471ee951a435f2ffa336a52bc6800a209a branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-17T09:13:37-07:00 summary: gh-98174: Handle EPROTOTYPE under macOS in test_sendfile_fallback_close_peer_in_the_middle_of_receiving (GH-98316) Co-authored-by: Nikita Sobolev (cherry picked from commit 3e82ad05b18d004e4d01fdb643344d6a2bf11900) Co-authored-by: fancidev files: M Lib/test/test_asyncio/test_sendfile.py diff --git a/Lib/test/test_asyncio/test_sendfile.py b/Lib/test/test_asyncio/test_sendfile.py index effca6644c06..aaaad9df8eb8 100644 --- a/Lib/test/test_asyncio/test_sendfile.py +++ b/Lib/test/test_asyncio/test_sendfile.py @@ -1,6 +1,7 @@ """Tests for sendfile functionality.""" import asyncio +import errno import os import socket import sys @@ -484,8 +485,17 @@ def sendfile_native(transp, file, offset, count): srv_proto, cli_proto = self.prepare_sendfile(close_after=1024) with self.assertRaises(ConnectionError): - self.run_loop( - self.loop.sendfile(cli_proto.transport, self.file)) + try: + self.run_loop( + self.loop.sendfile(cli_proto.transport, self.file)) + except OSError as e: + # macOS may raise OSError of EPROTOTYPE when writing to a + # socket that is in the process of closing down. + if e.errno == errno.EPROTOTYPE and sys.platform == "darwin": + raise ConnectionError + else: + raise + self.run_loop(srv_proto.done) self.assertTrue(1024 <= srv_proto.nbytes < len(self.DATA), From webhook-mailer at python.org Mon Oct 17 12:38:43 2022 From: webhook-mailer at python.org (benjaminp) Date: Mon, 17 Oct 2022 16:38:43 -0000 Subject: [Python-checkins] Remove unused arrange_output_buffer function from zlibmodule.c. (GH-98358) Message-ID: https://github.com/python/cpython/commit/0f156c1c5642d3102317e6b4c315098226e6e3ff commit: 0f156c1c5642d3102317e6b4c315098226e6e3ff branch: main author: Benjamin Peterson committer: benjaminp date: 2022-10-17T09:38:34-07:00 summary: Remove unused arrange_output_buffer function from zlibmodule.c. (GH-98358) files: M Modules/zlibmodule.c diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c index 88d2dd556353..2a490ed5d183 100644 --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -1440,22 +1440,6 @@ arrange_output_buffer_with_maximum(uint32_t *avail_out, return length; } -static inline Py_ssize_t -arrange_output_buffer(uint32_t *avail_out, - uint8_t **next_out, - PyObject **buffer, - Py_ssize_t length) -{ - Py_ssize_t ret; - - ret = arrange_output_buffer_with_maximum(avail_out, next_out, buffer, - length, - PY_SSIZE_T_MAX); - if (ret == -2) - PyErr_NoMemory(); - return ret; -} - /* Decompress data of length self->avail_in_real in self->state.next_in. The output buffer is allocated dynamically and returned. If the max_length is of sufficiently low size, max_length is allocated immediately. At most From webhook-mailer at python.org Mon Oct 17 15:16:43 2022 From: webhook-mailer at python.org (vstinner) Date: Mon, 17 Oct 2022 19:16:43 -0000 Subject: [Python-checkins] gh-95914: Add What's New item describing PEP 670 changes (#98315) Message-ID: https://github.com/python/cpython/commit/aafc53c0a6d1450dcfbc3f994318025ffb49ce73 commit: aafc53c0a6d1450dcfbc3f994318025ffb49ce73 branch: main author: C.A.M. Gerlach committer: vstinner date: 2022-10-17T21:16:37+02:00 summary: gh-95914: Add What's New item describing PEP 670 changes (#98315) files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 73e23a1a9e7f..1e93fcaaf791 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1895,6 +1895,17 @@ New Features Porting to Python 3.11 ---------------------- +* Some macros have been converted to static inline functions to avoid + `macro pitfalls `_. + The change should be mostly transparent to users, + as the replacement functions will cast their arguments to the expected types + to avoid compiler warnings due to static type checks. + However, when the limited C API is set to >=3.11, + these casts are not done, + and callers will need to cast arguments to their expected types. + See :pep:`670` for more details. + (Contributed by Victor Stinner and Erlend E. Aasland in :gh:`89653`.) + * :c:func:`PyErr_SetExcInfo()` no longer uses the ``type`` and ``traceback`` arguments, the interpreter now derives those values from the exception instance (the ``value`` argument). The function still steals references From webhook-mailer at python.org Mon Oct 17 15:25:24 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 17 Oct 2022 19:25:24 -0000 Subject: [Python-checkins] gh-95914: Add What's New item describing PEP 670 changes (GH-98315) Message-ID: https://github.com/python/cpython/commit/f4a0b80250576a71e342d09a8b1143f29cd5adc1 commit: f4a0b80250576a71e342d09a8b1143f29cd5adc1 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-17T12:25:18-07:00 summary: gh-95914: Add What's New item describing PEP 670 changes (GH-98315) (cherry picked from commit aafc53c0a6d1450dcfbc3f994318025ffb49ce73) Co-authored-by: C.A.M. Gerlach files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 24ee491d28e2..b765b1a11b18 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1899,6 +1899,17 @@ New Features Porting to Python 3.11 ---------------------- +* Some macros have been converted to static inline functions to avoid + `macro pitfalls `_. + The change should be mostly transparent to users, + as the replacement functions will cast their arguments to the expected types + to avoid compiler warnings due to static type checks. + However, when the limited C API is set to >=3.11, + these casts are not done, + and callers will need to cast arguments to their expected types. + See :pep:`670` for more details. + (Contributed by Victor Stinner and Erlend E. Aasland in :gh:`89653`.) + * :c:func:`PyErr_SetExcInfo()` no longer uses the ``type`` and ``traceback`` arguments, the interpreter now derives those values from the exception instance (the ``value`` argument). The function still steals references From webhook-mailer at python.org Mon Oct 17 15:59:27 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 17 Oct 2022 19:59:27 -0000 Subject: [Python-checkins] gh-95913: Move subinterpreter exper removal to 3.11 WhatsNew (GH-98345) Message-ID: https://github.com/python/cpython/commit/5fe043147493e33f2af6ab74610735130add1fe9 commit: 5fe043147493e33f2af6ab74610735130add1fe9 branch: main author: C.A.M. Gerlach committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-17T12:59:22-07:00 summary: gh-95913: Move subinterpreter exper removal to 3.11 WhatsNew (GH-98345) Part of #95913 Forward port of #93306, which was a backport of #93185, to address #84694 This adds the What's New entry for the removal of the subinterpreter-related env variable, build-time flag, etc. As @ericsnowcurrently was author of the original changes, I added him as a co-author to the commit. This addition to the Python 3.11 What's New document were only made to the Python 3.11 branch during the backport process, and not added to the version in `main`. Forward-porting it ensures the docs retain these additions for the future, rather than being lost in a legacy Python versions, allows it to be be edited as part of #95913 , and avoids merge conflicts with routine back-ports of PRs touching it. I've pulled in the addition exactly as-is with no modifications; any editing will be done in future PRs (and therefore can be reviewed and backported accordingly). The one other such addition is forward-ported in #98344 files: M Doc/whatsnew/3.11.rst M Doc/whatsnew/3.12.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 1e93fcaaf791..bb9538338e48 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1678,6 +1678,10 @@ Removed Python's test suite." (Contributed by Victor Stinner in :issue:`46852`.) +* The ``--experimental-isolated-subinterpreters`` configure flag + (and corresponding ``EXPERIMENTAL_ISOLATED_SUBINTERPRETERS``) + have been removed. + * Pynche --- The Pythonically Natural Color and Hue Editor --- has been moved out of ``Tools/scripts`` and is `being developed independently `_ from the Python source tree. diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index ecc74e9beba2..ad0270ae19b8 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -401,10 +401,6 @@ Removed (Contributed by Erlend E. Aasland in :gh:`92548`.) -* The ``--experimental-isolated-subinterpreters`` configure flag - (and corresponding ``EXPERIMENTAL_ISOLATED_SUBINTERPRETERS``) - have been removed. - * ``smtpd`` has been removed according to the schedule in :pep:`594`, having been deprecated in Python 3.4.7 and 3.5.4. Use aiosmtpd_ PyPI module or any other From webhook-mailer at python.org Mon Oct 17 18:08:18 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 17 Oct 2022 22:08:18 -0000 Subject: [Python-checkins] gh-85525: Remove extra row in doc (GH-98337) Message-ID: https://github.com/python/cpython/commit/6c7f7ec8199f9172224e8ccc9391e20cf7023e13 commit: 6c7f7ec8199f9172224e8ccc9391e20cf7023e13 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-17T15:08:10-07:00 summary: gh-85525: Remove extra row in doc (GH-98337) * remove extra row * ?? Added by blurb_it. Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> (cherry picked from commit 5c9302d03a57759225dab9e2d7bdd38e79009441) Co-authored-by: Joannah Nanjekye <33177550+nanjekyejoannah at users.noreply.github.com> files: A Misc/NEWS.d/next/Documentation/2022-10-16-17-34-45.gh-issue-85525.DvkD0v.rst M Doc/library/sndhdr.rst diff --git a/Doc/library/sndhdr.rst b/Doc/library/sndhdr.rst index 8c5c0bfc617b..fa9323e18dc3 100644 --- a/Doc/library/sndhdr.rst +++ b/Doc/library/sndhdr.rst @@ -68,7 +68,6 @@ from :func:`whathdr`: and :func:`what`: +------------+------------------------------------+ | ``'hcom'`` | HCOM Files | +------------+------------------------------------+ -+------------+------------------------------------+ | ``'sndt'`` | Sndtool Sound Files | +------------+------------------------------------+ | ``'voc'`` | Creative Labs Audio Files | diff --git a/Misc/NEWS.d/next/Documentation/2022-10-16-17-34-45.gh-issue-85525.DvkD0v.rst b/Misc/NEWS.d/next/Documentation/2022-10-16-17-34-45.gh-issue-85525.DvkD0v.rst new file mode 100644 index 000000000000..292e16998acd --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2022-10-16-17-34-45.gh-issue-85525.DvkD0v.rst @@ -0,0 +1 @@ +Remove extra row From webhook-mailer at python.org Mon Oct 17 18:31:00 2022 From: webhook-mailer at python.org (rhettinger) Date: Mon, 17 Oct 2022 22:31:00 -0000 Subject: [Python-checkins] Move random selection recipes from itertools.rst to random.rst (GH-98369) Message-ID: https://github.com/python/cpython/commit/70732d8a4c98cdf3cc9efa5241ce33fb9bc323ca commit: 70732d8a4c98cdf3cc9efa5241ce33fb9bc323ca branch: main author: Raymond Hettinger committer: rhettinger date: 2022-10-17T17:30:49-05:00 summary: Move random selection recipes from itertools.rst to random.rst (GH-98369) files: M Doc/library/itertools.rst M Doc/library/random.rst diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 88e1e5aa6ef7..9f7ec10729cd 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -1000,31 +1000,6 @@ which incur interpreter overhead. # first_true([a,b], x, f) --> a if f(a) else b if f(b) else x return next(filter(pred, iterable), default) - def random_product(*args, repeat=1): - "Random selection from itertools.product(*args, **kwds)" - pools = [tuple(pool) for pool in args] * repeat - return tuple(map(random.choice, pools)) - - def random_permutation(iterable, r=None): - "Random selection from itertools.permutations(iterable, r)" - pool = tuple(iterable) - r = len(pool) if r is None else r - return tuple(random.sample(pool, r)) - - def random_combination(iterable, r): - "Random selection from itertools.combinations(iterable, r)" - pool = tuple(iterable) - n = len(pool) - indices = sorted(random.sample(range(n), r)) - return tuple(pool[i] for i in indices) - - def random_combination_with_replacement(iterable, r): - "Random selection from itertools.combinations_with_replacement(iterable, r)" - pool = tuple(iterable) - n = len(pool) - indices = sorted(random.choices(range(n), k=r)) - return tuple(pool[i] for i in indices) - def nth_combination(iterable, r, index): "Equivalent to list(combinations(iterable, r))[index]" pool = tuple(iterable) diff --git a/Doc/library/random.rst b/Doc/library/random.rst index 7e527a9b401a..669204ba65b7 100644 --- a/Doc/library/random.rst +++ b/Doc/library/random.rst @@ -582,6 +582,37 @@ Simulation of arrival times and service deliveries for a multiserver queue:: Recipes ------- +These recipes show how to efficiently make random selections +from the combinatoric iterators in the :mod:`itertools` module: + +.. testcode:: + import random + + def random_product(*args, repeat=1): + "Random selection from itertools.product(*args, **kwds)" + pools = [tuple(pool) for pool in args] * repeat + return tuple(map(random.choice, pools)) + + def random_permutation(iterable, r=None): + "Random selection from itertools.permutations(iterable, r)" + pool = tuple(iterable) + r = len(pool) if r is None else r + return tuple(random.sample(pool, r)) + + def random_combination(iterable, r): + "Random selection from itertools.combinations(iterable, r)" + pool = tuple(iterable) + n = len(pool) + indices = sorted(random.sample(range(n), r)) + return tuple(pool[i] for i in indices) + + def random_combination_with_replacement(iterable, r): + "Random selection from itertools.combinations_with_replacement(iterable, r)" + pool = tuple(iterable) + n = len(pool) + indices = sorted(random.choices(range(n), k=r)) + return tuple(pool[i] for i in indices) + The default :func:`.random` returns multiples of 2??? in the range *0.0 ? x < 1.0*. All such numbers are evenly spaced and are exactly representable as Python floats. However, many other representable From webhook-mailer at python.org Mon Oct 17 18:38:30 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 17 Oct 2022 22:38:30 -0000 Subject: [Python-checkins] Move random selection recipes from itertools.rst to random.rst (GH-98369) Message-ID: https://github.com/python/cpython/commit/9cb30bb339fedf76cb7c3950114bb07c5d35efeb commit: 9cb30bb339fedf76cb7c3950114bb07c5d35efeb branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-17T15:38:22-07:00 summary: Move random selection recipes from itertools.rst to random.rst (GH-98369) (cherry picked from commit 70732d8a4c98cdf3cc9efa5241ce33fb9bc323ca) Co-authored-by: Raymond Hettinger files: M Doc/library/itertools.rst M Doc/library/random.rst diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 49fb8407890c..26ede4b49a01 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -1000,31 +1000,6 @@ which incur interpreter overhead. # first_true([a,b], x, f) --> a if f(a) else b if f(b) else x return next(filter(pred, iterable), default) - def random_product(*args, repeat=1): - "Random selection from itertools.product(*args, **kwds)" - pools = [tuple(pool) for pool in args] * repeat - return tuple(map(random.choice, pools)) - - def random_permutation(iterable, r=None): - "Random selection from itertools.permutations(iterable, r)" - pool = tuple(iterable) - r = len(pool) if r is None else r - return tuple(random.sample(pool, r)) - - def random_combination(iterable, r): - "Random selection from itertools.combinations(iterable, r)" - pool = tuple(iterable) - n = len(pool) - indices = sorted(random.sample(range(n), r)) - return tuple(pool[i] for i in indices) - - def random_combination_with_replacement(iterable, r): - "Random selection from itertools.combinations_with_replacement(iterable, r)" - pool = tuple(iterable) - n = len(pool) - indices = sorted(random.choices(range(n), k=r)) - return tuple(pool[i] for i in indices) - def nth_combination(iterable, r, index): "Equivalent to list(combinations(iterable, r))[index]" pool = tuple(iterable) diff --git a/Doc/library/random.rst b/Doc/library/random.rst index 94215daad112..2b87a36f7c52 100644 --- a/Doc/library/random.rst +++ b/Doc/library/random.rst @@ -564,6 +564,37 @@ Simulation of arrival times and service deliveries for a multiserver queue:: Recipes ------- +These recipes show how to efficiently make random selections +from the combinatoric iterators in the :mod:`itertools` module: + +.. testcode:: + import random + + def random_product(*args, repeat=1): + "Random selection from itertools.product(*args, **kwds)" + pools = [tuple(pool) for pool in args] * repeat + return tuple(map(random.choice, pools)) + + def random_permutation(iterable, r=None): + "Random selection from itertools.permutations(iterable, r)" + pool = tuple(iterable) + r = len(pool) if r is None else r + return tuple(random.sample(pool, r)) + + def random_combination(iterable, r): + "Random selection from itertools.combinations(iterable, r)" + pool = tuple(iterable) + n = len(pool) + indices = sorted(random.sample(range(n), r)) + return tuple(pool[i] for i in indices) + + def random_combination_with_replacement(iterable, r): + "Random selection from itertools.combinations_with_replacement(iterable, r)" + pool = tuple(iterable) + n = len(pool) + indices = sorted(random.choices(range(n), k=r)) + return tuple(pool[i] for i in indices) + The default :func:`.random` returns multiples of 2??? in the range *0.0 ? x < 1.0*. All such numbers are evenly spaced and are exactly representable as Python floats. However, many other representable From webhook-mailer at python.org Mon Oct 17 19:49:44 2022 From: webhook-mailer at python.org (ezio-melotti) Date: Mon, 17 Oct 2022 23:49:44 -0000 Subject: [Python-checkins] [3.11] Docs: Fix backtick errors found by sphinx-lint (GH-97998) (#98371) Message-ID: https://github.com/python/cpython/commit/ea19c28512b4bd815834de064cf0ef9803cc03a2 commit: ea19c28512b4bd815834de064cf0ef9803cc03a2 branch: 3.11 author: C.A.M. Gerlach committer: ezio-melotti date: 2022-10-18T01:49:38+02:00 summary: [3.11] Docs: Fix backtick errors found by sphinx-lint (GH-97998) (#98371) Co-authored-by: Ezio Melotti . (cherry picked from commit fa2d43e5184f5eaf3391844ec2400342a1b2ead4) Co-authored-by: Hugo van Kemenade Co-authored-by: Hugo van Kemenade files: M Doc/c-api/init.rst M Doc/c-api/type.rst M Doc/faq/design.rst M Doc/howto/enum.rst M Doc/howto/logging-cookbook.rst M Doc/howto/logging.rst M Doc/install/index.rst M Doc/library/asyncio-protocol.rst M Doc/library/asyncio-task.rst M Doc/library/bdb.rst M Doc/library/bz2.rst M Doc/library/concurrent.futures.rst M Doc/library/ctypes.rst M Doc/library/curses.rst M Doc/library/datetime.rst M Doc/library/decimal.rst M Doc/library/dis.rst M Doc/library/email.compat32-message.rst M Doc/library/email.headerregistry.rst M Doc/library/functools.rst M Doc/library/hashlib.rst M Doc/library/io.rst M Doc/library/lzma.rst M Doc/library/os.rst M Doc/library/select.rst M Doc/library/socket.rst M Doc/library/statistics.rst M Doc/library/sys.rst M Doc/library/unittest.mock-examples.rst M Doc/library/xml.dom.minidom.rst M Doc/library/xmlrpc.client.rst M Doc/library/xmlrpc.server.rst M Doc/reference/expressions.rst M Doc/reference/import.rst M Doc/reference/simple_stmts.rst M Doc/requirements.txt M Doc/using/configure.rst M Doc/using/unix.rst M Doc/using/windows.rst M Doc/whatsnew/2.6.rst M Doc/whatsnew/2.7.rst M Doc/whatsnew/3.10.rst M Doc/whatsnew/3.11.rst M Doc/whatsnew/3.2.rst M Doc/whatsnew/3.3.rst M Doc/whatsnew/3.5.rst M Doc/whatsnew/3.6.rst M Doc/whatsnew/3.7.rst M Doc/whatsnew/3.9.rst M Misc/NEWS.d/next/Core and Builtins/2022-10-01-08-55-09.gh-issue-97591.pw6kkH.rst diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index dd9847c3e3d2..511d24da4fb7 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -1796,7 +1796,7 @@ is not possible due to its implementation being opaque at build time. Free the given *key* allocated by :c:func:`PyThread_tss_alloc`, after first calling :c:func:`PyThread_tss_delete` to ensure any associated thread locals have been unassigned. This is a no-op if the *key* - argument is `NULL`. + argument is ``NULL``. .. note:: A freed key becomes a dangling pointer. You should reset the key to diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst index d740e4eb0897..ac352047798e 100644 --- a/Doc/c-api/type.rst +++ b/Doc/c-api/type.rst @@ -40,7 +40,7 @@ Type Objects .. c:function:: unsigned long PyType_GetFlags(PyTypeObject* type) Return the :c:member:`~PyTypeObject.tp_flags` member of *type*. This function is primarily - meant for use with `Py_LIMITED_API`; the individual flag bits are + meant for use with ``Py_LIMITED_API``; the individual flag bits are guaranteed to be stable across Python releases, but access to :c:member:`~PyTypeObject.tp_flags` itself is not part of the limited API. diff --git a/Doc/faq/design.rst b/Doc/faq/design.rst index 9da1d01abd6f..9dbfacd73cc6 100644 --- a/Doc/faq/design.rst +++ b/Doc/faq/design.rst @@ -155,7 +155,7 @@ Why can't I use an assignment in an expression? Starting in Python 3.8, you can! -Assignment expressions using the walrus operator `:=` assign a variable in an +Assignment expressions using the walrus operator ``:=`` assign a variable in an expression:: while chunk := fp.read(200): diff --git a/Doc/howto/enum.rst b/Doc/howto/enum.rst index 7b1cf75fa81f..bad5e508b019 100644 --- a/Doc/howto/enum.rst +++ b/Doc/howto/enum.rst @@ -1120,7 +1120,7 @@ Enum Classes The :class:`EnumType` metaclass is responsible for providing the :meth:`__contains__`, :meth:`__dir__`, :meth:`__iter__` and other methods that allow one to do things with an :class:`Enum` class that fail on a typical -class, such as `list(Color)` or `some_enum_var in Color`. :class:`EnumType` is +class, such as ``list(Color)`` or ``some_enum_var in Color``. :class:`EnumType` is responsible for ensuring that various other methods on the final :class:`Enum` class are correct (such as :meth:`__new__`, :meth:`__getnewargs__`, :meth:`__str__` and :meth:`__repr__`). diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst index acbc708e2f5c..eac34aaab3aa 100644 --- a/Doc/howto/logging-cookbook.rst +++ b/Doc/howto/logging-cookbook.rst @@ -769,7 +769,7 @@ To run a logging listener in production, you may need to use a process-managemen such as `Supervisor `_. `Here `_ is a Gist which provides the bare-bones files to run the above functionality using Supervisor: you -will need to change the `/path/to/` parts in the Gist to reflect the actual paths you +will need to change the ``/path/to/`` parts in the Gist to reflect the actual paths you want to use. @@ -2981,7 +2981,7 @@ Formatting times using UTC (GMT) via configuration -------------------------------------------------- Sometimes you want to format times using UTC, which can be done using a class -such as `UTCFormatter`, shown below:: +such as ``UTCFormatter``, shown below:: import logging import time diff --git a/Doc/howto/logging.rst b/Doc/howto/logging.rst index f98876a3352e..87065273dab7 100644 --- a/Doc/howto/logging.rst +++ b/Doc/howto/logging.rst @@ -552,14 +552,14 @@ raw message. If there is no date format string, the default date format is: %Y-%m-%d %H:%M:%S -with the milliseconds tacked on at the end. The ``style`` is one of `%`, '{' -or '$'. If one of these is not specified, then '%' will be used. +with the milliseconds tacked on at the end. The ``style`` is one of ``'%'``, +``'{'``, or ``'$'``. If one of these is not specified, then ``'%'`` will be used. -If the ``style`` is '%', the message format string uses +If the ``style`` is ``'%'``, the message format string uses ``%()s`` styled string substitution; the possible keys are -documented in :ref:`logrecord-attributes`. If the style is '{', the message +documented in :ref:`logrecord-attributes`. If the style is ``'{'``, the message format string is assumed to be compatible with :meth:`str.format` (using -keyword arguments), while if the style is '$' then the message format string +keyword arguments), while if the style is ``'$'`` then the message format string should conform to what is expected by :meth:`string.Template.substitute`. .. versionchanged:: 3.2 diff --git a/Doc/install/index.rst b/Doc/install/index.rst index 84df5e7cb368..d2d8e567c03c 100644 --- a/Doc/install/index.rst +++ b/Doc/install/index.rst @@ -761,7 +761,7 @@ And on Windows, the configuration files are: +--------------+-------------------------------------------------+-------+ On all platforms, the "personal" file can be temporarily disabled by -passing the `--no-user-cfg` option. +passing the ``--no-user-cfg`` option. Notes: diff --git a/Doc/library/asyncio-protocol.rst b/Doc/library/asyncio-protocol.rst index 8b67f4b8957e..969354ceb163 100644 --- a/Doc/library/asyncio-protocol.rst +++ b/Doc/library/asyncio-protocol.rst @@ -553,7 +553,7 @@ accept factories that return streaming protocols. a connection is open. However, :meth:`protocol.eof_received() ` - is called at most once. Once `eof_received()` is called, + is called at most once. Once ``eof_received()`` is called, ``data_received()`` is not called anymore. .. method:: Protocol.eof_received() diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index c6b8716073fe..f795f2552593 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -631,7 +631,7 @@ Timeouts Change the time the timeout will trigger. - If *when* is `None`, any current deadline will be removed, and the + If *when* is ``None``, any current deadline will be removed, and the context manager will wait indefinitely. If *when* is a float, it is set as the new deadline. @@ -867,17 +867,17 @@ Running in Threads # blocking_io complete at 19:50:54 # finished main at 19:50:54 - Directly calling `blocking_io()` in any coroutine would block the event loop + Directly calling ``blocking_io()`` in any coroutine would block the event loop for its duration, resulting in an additional 1 second of run time. Instead, - by using `asyncio.to_thread()`, we can run it in a separate thread without + by using ``asyncio.to_thread()``, we can run it in a separate thread without blocking the event loop. .. note:: - Due to the :term:`GIL`, `asyncio.to_thread()` can typically only be used + Due to the :term:`GIL`, ``asyncio.to_thread()`` can typically only be used to make IO-bound functions non-blocking. However, for extension modules that release the GIL or alternative Python implementations that don't - have one, `asyncio.to_thread()` can also be used for CPU-bound functions. + have one, ``asyncio.to_thread()`` can also be used for CPU-bound functions. .. versionadded:: 3.9 diff --git a/Doc/library/bdb.rst b/Doc/library/bdb.rst index 7b74bbd652be..d201dc963b59 100644 --- a/Doc/library/bdb.rst +++ b/Doc/library/bdb.rst @@ -143,7 +143,7 @@ The :mod:`bdb` module also defines two classes: For real file names, the canonical form is an operating-system-dependent, :func:`case-normalized ` :func:`absolute path - `. A *filename* with angle brackets, such as `""` + `. A *filename* with angle brackets, such as ``""`` generated in interactive mode, is returned unchanged. .. method:: reset() diff --git a/Doc/library/bz2.rst b/Doc/library/bz2.rst index 999892e95f47..ae5a1598f84b 100644 --- a/Doc/library/bz2.rst +++ b/Doc/library/bz2.rst @@ -206,7 +206,7 @@ Incremental (de)compression will be set to ``True``. Attempting to decompress data after the end of stream is reached - raises an `EOFError`. Any data found after the end of the + raises an :exc:`EOFError`. Any data found after the end of the stream is ignored and saved in the :attr:`~.unused_data` attribute. .. versionchanged:: 3.5 @@ -303,7 +303,7 @@ Using :class:`BZ2Compressor` for incremental compression: >>> out = out + comp.flush() The example above uses a very "nonrandom" stream of data -(a stream of `b"z"` chunks). Random data tends to compress poorly, +(a stream of ``b"z"`` chunks). Random data tends to compress poorly, while ordered, repetitive data usually yields a high compression ratio. Writing and reading a bzip2-compressed file in binary mode: diff --git a/Doc/library/concurrent.futures.rst b/Doc/library/concurrent.futures.rst index 95c9e5099142..8106cc235e5a 100644 --- a/Doc/library/concurrent.futures.rst +++ b/Doc/library/concurrent.futures.rst @@ -152,7 +152,7 @@ And:: All threads enqueued to ``ThreadPoolExecutor`` will be joined before the interpreter can exit. Note that the exit handler which does this is - executed *before* any exit handlers added using `atexit`. This means + executed *before* any exit handlers added using ``atexit``. This means exceptions in the main thread must be caught and handled in order to signal threads to exit gracefully. For this reason, it is recommended that ``ThreadPoolExecutor`` not be used for long-running tasks. @@ -411,13 +411,13 @@ The :class:`Future` class encapsulates the asynchronous execution of a callable. tests. If the method returns ``False`` then the :class:`Future` was cancelled, - i.e. :meth:`Future.cancel` was called and returned `True`. Any threads + i.e. :meth:`Future.cancel` was called and returned ``True``. Any threads waiting on the :class:`Future` completing (i.e. through :func:`as_completed` or :func:`wait`) will be woken up. If the method returns ``True`` then the :class:`Future` was not cancelled and has been put in the running state, i.e. calls to - :meth:`Future.running` will return `True`. + :meth:`Future.running` will return ``True``. This method can only be called once and cannot be called after :meth:`Future.set_result` or :meth:`Future.set_exception` have been diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index 99c35a8e595f..2900f77589e3 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -1934,7 +1934,7 @@ Utility functions .. function:: GetLastError() Windows only: Returns the last error code set by Windows in the calling thread. - This function calls the Windows `GetLastError()` function directly, + This function calls the Windows ``GetLastError()`` function directly, it does not return the ctypes-private copy of the error code. .. function:: get_errno() diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst index a7cc49527780..83e19fac6520 100644 --- a/Doc/library/curses.rst +++ b/Doc/library/curses.rst @@ -278,7 +278,7 @@ The module :mod:`curses` defines the following functions: Change the definition of a color, taking the number of the color to be changed followed by three RGB values (for the amounts of red, green, and blue components). The value of *color_number* must be between ``0`` and - `COLORS - 1`. Each of *r*, *g*, *b*, must be a value between ``0`` and + ``COLORS - 1``. Each of *r*, *g*, *b*, must be a value between ``0`` and ``1000``. When :func:`init_color` is used, all occurrences of that color on the screen immediately change to the new definition. This function is a no-op on most terminals; it is active only if :func:`can_change_color` returns ``True``. diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst index b4580d1879c0..8a7d99999f5d 100644 --- a/Doc/library/datetime.rst +++ b/Doc/library/datetime.rst @@ -1769,7 +1769,7 @@ Other constructor: ISO 8601 format, with the following exceptions: 1. Time zone offsets may have fractional seconds. - 2. The leading `T`, normally required in cases where there may be ambiguity between + 2. The leading ``T``, normally required in cases where there may be ambiguity between a date and a time, is not required. 3. Fractional seconds may have any number of digits (anything beyond 6 will be truncated). @@ -2265,7 +2265,7 @@ where historical changes have been made to civil time. two digits of ``offset.hours`` and ``offset.minutes`` respectively. .. versionchanged:: 3.6 - Name generated from ``offset=timedelta(0)`` is now plain `'UTC'`, not + Name generated from ``offset=timedelta(0)`` is now plain ``'UTC'``, not ``'UTC+00:00'``. diff --git a/Doc/library/decimal.rst b/Doc/library/decimal.rst index b7e836308fa8..260108136df7 100644 --- a/Doc/library/decimal.rst +++ b/Doc/library/decimal.rst @@ -576,11 +576,11 @@ Decimal objects Alternative constructor that only accepts instances of :class:`float` or :class:`int`. - Note `Decimal.from_float(0.1)` is not the same as `Decimal('0.1')`. + Note ``Decimal.from_float(0.1)`` is not the same as ``Decimal('0.1')``. Since 0.1 is not exactly representable in binary floating point, the value is stored as the nearest representable value which is - `0x1.999999999999ap-4`. That equivalent value in decimal is - `0.1000000000000000055511151231257827021181583404541015625`. + ``0x1.999999999999ap-4``. That equivalent value in decimal is + ``0.1000000000000000055511151231257827021181583404541015625``. .. note:: From Python 3.2 onwards, a :class:`Decimal` instance can also be constructed directly from a :class:`float`. @@ -1209,7 +1209,7 @@ In addition to the three supplied contexts, new contexts can be created with the .. method:: exp(x) - Returns `e ** x`. + Returns ``e ** x``. .. method:: fma(x, y, z) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index d2925929c6c9..98866b72a30a 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -373,7 +373,7 @@ details of bytecode instructions as :class:`Instruction` instances: .. class:: Positions - In case the information is not available, some fields might be `None`. + In case the information is not available, some fields might be ``None``. .. data:: lineno .. data:: end_lineno diff --git a/Doc/library/email.compat32-message.rst b/Doc/library/email.compat32-message.rst index 4eaa9d588ca3..5bef155a4af3 100644 --- a/Doc/library/email.compat32-message.rst +++ b/Doc/library/email.compat32-message.rst @@ -298,7 +298,7 @@ Here are the methods of the :class:`Message` class: In a model generated from bytes, any header values that (in contravention of the RFCs) contain non-ASCII bytes will, when retrieved through this interface, be represented as :class:`~email.header.Header` objects with - a charset of `unknown-8bit`. + a charset of ``unknown-8bit``. .. method:: __len__() diff --git a/Doc/library/email.headerregistry.rst b/Doc/library/email.headerregistry.rst index 98527cea43da..00a954e0307e 100644 --- a/Doc/library/email.headerregistry.rst +++ b/Doc/library/email.headerregistry.rst @@ -153,7 +153,7 @@ headers. specified as ``-0000`` (indicating it is in UTC but contains no information about the source timezone), then :attr:`.datetime` will be a naive :class:`~datetime.datetime`. If a specific timezone offset is - found (including `+0000`), then :attr:`.datetime` will contain an aware + found (including ``+0000``), then :attr:`.datetime` will contain an aware ``datetime`` that uses :class:`datetime.timezone` to record the timezone offset. diff --git a/Doc/library/functools.rst b/Doc/library/functools.rst index d6792ed6fb77..9beebd2a85e5 100644 --- a/Doc/library/functools.rst +++ b/Doc/library/functools.rst @@ -144,7 +144,7 @@ The :mod:`functools` module defines the following functions: arguments to the function must be hashable. Distinct argument patterns may be considered to be distinct calls with - separate cache entries. For example, `f(a=1, b=2)` and `f(b=2, a=1)` + separate cache entries. For example, ``f(a=1, b=2)`` and ``f(b=2, a=1)`` differ in their keyword argument order and may have two separate cache entries. @@ -191,7 +191,7 @@ The :mod:`functools` module defines the following functions: The cache keeps references to the arguments and return values until they age out of the cache or until the cache is cleared. - If a method is cached, the `self` instance argument is included in the + If a method is cached, the ``self`` instance argument is included in the cache. See :ref:`faq-cache-method-calls` An `LRU (least recently used) cache diff --git a/Doc/library/hashlib.rst b/Doc/library/hashlib.rst index 0906ce7cb7a2..a96fc8b8ff7e 100644 --- a/Doc/library/hashlib.rst +++ b/Doc/library/hashlib.rst @@ -432,7 +432,7 @@ Constructor functions also accept the following tree hashing parameters: BLAKE2s, 0 in sequential mode). * *last_node*: boolean indicating whether the processed node is the last - one (`False` for sequential mode). + one (``False`` for sequential mode). .. figure:: hashlib-blake2-tree.png :alt: Explanation of tree mode parameters. diff --git a/Doc/library/io.rst b/Doc/library/io.rst index 8fd6b3537019..0968509fbafe 100644 --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -1055,10 +1055,10 @@ Text I/O The initial value of the buffer can be set by providing *initial_value*. If newline translation is enabled, newlines will be encoded as if by :meth:`~TextIOBase.write`. The stream is positioned at the start of the - buffer which emulates opening an existing file in a `w+` mode, making it + buffer which emulates opening an existing file in a ``w+`` mode, making it ready for an immediate write from the beginning or for a write that - would overwrite the initial value. To emulate opening a file in an `a+` - mode ready for appending, use `f.seek(0, io.SEEK_END)` to reposition the + would overwrite the initial value. To emulate opening a file in an ``a+`` + mode ready for appending, use ``f.seek(0, io.SEEK_END)`` to reposition the stream at the end of the buffer. The *newline* argument works like that of :class:`TextIOWrapper`, diff --git a/Doc/library/lzma.rst b/Doc/library/lzma.rst index 21092645366d..868d4dcfb6c9 100644 --- a/Doc/library/lzma.rst +++ b/Doc/library/lzma.rst @@ -258,7 +258,7 @@ Compressing and decompressing data in memory will be set to ``True``. Attempting to decompress data after the end of stream is reached - raises an `EOFError`. Any data found after the end of the + raises an :exc:`EOFError`. Any data found after the end of the stream is ignored and saved in the :attr:`~.unused_data` attribute. .. versionchanged:: 3.5 diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 9311bf187f0b..74125aef0579 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -3180,7 +3180,7 @@ features: system records access and modification times; see :func:`~os.stat`. The best way to preserve exact times is to use the *st_atime_ns* and *st_mtime_ns* fields from the :func:`os.stat` result object with the *ns* parameter to - `utime`. + :func:`utime`. This function can support :ref:`specifying a file descriptor `, :ref:`paths relative to directory descriptors ` and :ref:`not @@ -4072,7 +4072,7 @@ written in Python, such as a mail server's external command delivery program. library :c:data:`POSIX_SPAWN_RESETIDS` flag. If the *setsid* argument is ``True``, it will create a new session ID - for `posix_spawn`. *setsid* requires :c:data:`POSIX_SPAWN_SETSID` + for ``posix_spawn``. *setsid* requires :c:data:`POSIX_SPAWN_SETSID` or :c:data:`POSIX_SPAWN_SETSID_NP` flag. Otherwise, :exc:`NotImplementedError` is raised. diff --git a/Doc/library/select.rst b/Doc/library/select.rst index a8df81f5bd1f..2890706bab72 100644 --- a/Doc/library/select.rst +++ b/Doc/library/select.rst @@ -61,7 +61,7 @@ The module defines the following: events. *sizehint* informs epoll about the expected number of events to be - registered. It must be positive, or `-1` to use the default. It is only + registered. It must be positive, or ``-1`` to use the default. It is only used on older systems where :c:func:`epoll_create1` is not available; otherwise it has no effect (though its value is still checked). diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst index b1c2ab07740f..8c260897dbaa 100644 --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -642,7 +642,7 @@ The following functions all create :ref:`socket objects `. When :const:`SOCK_NONBLOCK` or :const:`SOCK_CLOEXEC` bit flags are applied to *type* they are cleared, and :attr:`socket.type` will not reflect them. They are still passed - to the underlying system `socket()` call. Therefore, + to the underlying system ``socket()`` call. Therefore, :: diff --git a/Doc/library/statistics.rst b/Doc/library/statistics.rst index bf869903c0f8..78c4bc521fdd 100644 --- a/Doc/library/statistics.rst +++ b/Doc/library/statistics.rst @@ -813,7 +813,7 @@ of applications in statistics. The relative likelihood is computed as the probability of a sample occurring in a narrow range divided by the width of the range (hence the word "density"). Since the likelihood is relative to other points, - its value can be greater than `1.0`. + its value can be greater than ``1.0``. .. method:: NormalDist.cdf(x) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index aab3f6aa83fc..542b08b1878e 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -250,7 +250,7 @@ always available. Print low-level information to stderr about the state of CPython's memory allocator. - If Python is `built in debug mode ` (:option:`configure + If Python is :ref:`built in debug mode ` (:option:`configure --with-pydebug option <--with-pydebug>`), it also performs some expensive internal consistency checks. @@ -349,7 +349,7 @@ always available. files to (and read them from) a parallel directory tree rooted at this directory, rather than from ``__pycache__`` directories in the source code tree. Any ``__pycache__`` directories in the source code tree will be ignored - and new `.pyc` files written within the pycache prefix. Thus if you use + and new ``.pyc`` files written within the pycache prefix. Thus if you use :mod:`compileall` as a pre-build step, you must ensure you run it with the same pycache prefix (if any) that you will use at runtime. @@ -874,7 +874,7 @@ always available. .. function:: get_asyncgen_hooks() Returns an *asyncgen_hooks* object, which is similar to a - :class:`~collections.namedtuple` of the form `(firstiter, finalizer)`, + :class:`~collections.namedtuple` of the form ``(firstiter, finalizer)``, where *firstiter* and *finalizer* are expected to be either ``None`` or functions which take an :term:`asynchronous generator iterator` as an argument, and are used to schedule finalization of an asynchronous diff --git a/Doc/library/unittest.mock-examples.rst b/Doc/library/unittest.mock-examples.rst index 054efa812663..f9a207bad690 100644 --- a/Doc/library/unittest.mock-examples.rst +++ b/Doc/library/unittest.mock-examples.rst @@ -1116,7 +1116,7 @@ on first use). That aside there is a way to use ``mock`` to affect the results of an import. Importing fetches an *object* from the :data:`sys.modules` dictionary. Note that it fetches an *object*, which need not be a module. Importing a module for the -first time results in a module object being put in `sys.modules`, so usually +first time results in a module object being put in ``sys.modules``, so usually when you import something you get a module back. This need not be the case however. diff --git a/Doc/library/xml.dom.minidom.rst b/Doc/library/xml.dom.minidom.rst index 82e5d6aea231..72a7a98c2ac4 100644 --- a/Doc/library/xml.dom.minidom.rst +++ b/Doc/library/xml.dom.minidom.rst @@ -148,8 +148,8 @@ module documentation. This section lists the differences between the API and Similarly, explicitly stating the *standalone* argument causes the standalone document declarations to be added to the prologue of the XML document. - If the value is set to `True`, `standalone="yes"` is added, - otherwise it is set to `"no"`. + If the value is set to ``True``, ``standalone="yes"`` is added, + otherwise it is set to ``"no"``. Not stating the argument will omit the declaration from the document. .. versionchanged:: 3.8 diff --git a/Doc/library/xmlrpc.client.rst b/Doc/library/xmlrpc.client.rst index 8b09acd4bd30..bd2c49a6edab 100644 --- a/Doc/library/xmlrpc.client.rst +++ b/Doc/library/xmlrpc.client.rst @@ -60,7 +60,7 @@ between conformable Python objects and XML on the wire. may be passed to calls. The *headers* parameter is an optional sequence of HTTP headers to send with each request, expressed as a sequence of 2-tuples representing the header - name and value. (e.g. `[('Header-Name', 'value')]`). + name and value. (e.g. ``[('Header-Name', 'value')]``). The obsolete *use_datetime* flag is similar to *use_builtin_types* but it applies only to date/time values. diff --git a/Doc/library/xmlrpc.server.rst b/Doc/library/xmlrpc.server.rst index 9778a859da1f..016369d2b89d 100644 --- a/Doc/library/xmlrpc.server.rst +++ b/Doc/library/xmlrpc.server.rst @@ -263,7 +263,7 @@ This ExampleService demo can be invoked from the command line:: The client that interacts with the above server is included in -`Lib/xmlrpc/client.py`:: +``Lib/xmlrpc/client.py``:: server = ServerProxy("http://localhost:8000") diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst index 6b5e0e1628f1..cc969752d5d7 100644 --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -1551,7 +1551,7 @@ built-in types. true). * Mappings (instances of :class:`dict`) compare equal if and only if they have - equal `(key, value)` pairs. Equality comparison of the keys and values + equal ``(key, value)`` pairs. Equality comparison of the keys and values enforces reflexivity. Order comparisons (``<``, ``>``, ``<=``, and ``>=``) raise :exc:`TypeError`. diff --git a/Doc/reference/import.rst b/Doc/reference/import.rst index 0d8c02955008..70d946ab4db9 100644 --- a/Doc/reference/import.rst +++ b/Doc/reference/import.rst @@ -816,7 +816,7 @@ The path based finder iterates over every entry in the search path, and for each of these, looks for an appropriate :term:`path entry finder` (:class:`~importlib.abc.PathEntryFinder`) for the path entry. Because this can be an expensive operation (e.g. there may be -`stat()` call overheads for this search), the path based finder maintains +``stat()`` call overheads for this search), the path based finder maintains a cache mapping path entries to path entry finders. This cache is maintained in :data:`sys.path_importer_cache` (despite the name, this cache actually stores finder objects rather than being limited to :term:`importer` objects). diff --git a/Doc/reference/simple_stmts.rst b/Doc/reference/simple_stmts.rst index 8311de0457f6..5c9937fb5b6d 100644 --- a/Doc/reference/simple_stmts.rst +++ b/Doc/reference/simple_stmts.rst @@ -994,20 +994,12 @@ The :keyword:`!nonlocal` statement .. productionlist:: python-grammar nonlocal_stmt: "nonlocal" `identifier` ("," `identifier`)* -.. XXX add when implemented - : ["=" (`target_list` "=")+ starred_expression] - : | "nonlocal" identifier augop expression_list - The :keyword:`nonlocal` statement causes the listed identifiers to refer to previously bound variables in the nearest enclosing scope excluding globals. This is important because the default behavior for binding is to search the local namespace first. The statement allows encapsulated code to rebind variables outside of the local scope besides the global (module) scope. -.. XXX not implemented - The :keyword:`nonlocal` statement may prepend an assignment or augmented - assignment, but not an expression. - Names listed in a :keyword:`nonlocal` statement, unlike those listed in a :keyword:`global` statement, must refer to pre-existing bindings in an enclosing scope (the scope in which a new binding should be created cannot diff --git a/Doc/requirements.txt b/Doc/requirements.txt index 960ac54d7b91..7f82dc32113a 100644 --- a/Doc/requirements.txt +++ b/Doc/requirements.txt @@ -10,7 +10,7 @@ blurb # sphinx-lint 0.6.2 yields many default role errors due to the new regular # expression used for default role detection, so we don't use the version # until the errors are fixed. -sphinx-lint==0.6.1 +sphinx-lint==0.6.4 # The theme used by the documentation is stored separately, so we need # to install that as well. diff --git a/Doc/using/configure.rst b/Doc/using/configure.rst index 8ce9884c76fe..c387528d87cd 100644 --- a/Doc/using/configure.rst +++ b/Doc/using/configure.rst @@ -750,12 +750,12 @@ Compiler flags In particular, :envvar:`CFLAGS` should not contain: - * the compiler flag `-I` (for setting the search path for include files). - The `-I` flags are processed from left to right, and any flags in - :envvar:`CFLAGS` would take precedence over user- and package-supplied `-I` + * the compiler flag ``-I`` (for setting the search path for include files). + The ``-I`` flags are processed from left to right, and any flags in + :envvar:`CFLAGS` would take precedence over user- and package-supplied ``-I`` flags. - * hardening flags such as `-Werror` because distributions cannot control + * hardening flags such as ``-Werror`` because distributions cannot control whether packages installed by users conform to such heightened standards. @@ -873,9 +873,9 @@ Linker flags In particular, :envvar:`LDFLAGS` should not contain: - * the compiler flag `-L` (for setting the search path for libraries). - The `-L` flags are processed from left to right, and any flags in - :envvar:`LDFLAGS` would take precedence over user- and package-supplied `-L` + * the compiler flag ``-L`` (for setting the search path for libraries). + The ``-L`` flags are processed from left to right, and any flags in + :envvar:`LDFLAGS` would take precedence over user- and package-supplied ``-L`` flags. .. envvar:: CONFIGURE_LDFLAGS_NODIST diff --git a/Doc/using/unix.rst b/Doc/using/unix.rst index 061cfa5be88f..24c02c99f871 100644 --- a/Doc/using/unix.rst +++ b/Doc/using/unix.rst @@ -170,7 +170,7 @@ Custom OpenSSL $ popd 3. Build Python with custom OpenSSL - (see the configure `--with-openssl` and `--with-openssl-rpath` options) + (see the configure ``--with-openssl`` and ``--with-openssl-rpath`` options) .. code-block:: shell-session diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst index e338b11e1aa0..4ab68e140b9e 100644 --- a/Doc/using/windows.rst +++ b/Doc/using/windows.rst @@ -203,7 +203,7 @@ of available options is shown below. +---------------------------+--------------------------------------+--------------------------+ | Include_pip | Install bundled pip and setuptools | 1 | +---------------------------+--------------------------------------+--------------------------+ -| Include_symbols | Install debugging symbols (`*`.pdb) | 0 | +| Include_symbols | Install debugging symbols (``*.pdb``)| 0 | +---------------------------+--------------------------------------+--------------------------+ | Include_tcltk | Install Tcl/Tk support and IDLE | 1 | +---------------------------+--------------------------------------+--------------------------+ diff --git a/Doc/whatsnew/2.6.rst b/Doc/whatsnew/2.6.rst index 731ce6aac691..34f2656f765c 100644 --- a/Doc/whatsnew/2.6.rst +++ b/Doc/whatsnew/2.6.rst @@ -717,13 +717,13 @@ This will produce the output:: PEP 3101: Advanced String Formatting ===================================================== -In Python 3.0, the `%` operator is supplemented by a more powerful string +In Python 3.0, the ``%`` operator is supplemented by a more powerful string formatting method, :meth:`format`. Support for the :meth:`str.format` method has been backported to Python 2.6. -In 2.6, both 8-bit and Unicode strings have a `.format()` method that +In 2.6, both 8-bit and Unicode strings have a ``.format()`` method that treats the string as a template and takes the arguments to be formatted. -The formatting template uses curly brackets (`{`, `}`) as special characters:: +The formatting template uses curly brackets (``{``, ``}``) as special characters:: >>> # Substitute positional argument 0 into the string. >>> "User ID: {0}".format("root") diff --git a/Doc/whatsnew/2.7.rst b/Doc/whatsnew/2.7.rst index 3df9f8a4798f..82f5ea3b3127 100644 --- a/Doc/whatsnew/2.7.rst +++ b/Doc/whatsnew/2.7.rst @@ -2485,8 +2485,8 @@ In the standard library: * The ElementTree library, :mod:`xml.etree`, no longer escapes ampersands and angle brackets when outputting an XML processing - instruction (which looks like ``) - or comment (which looks like ``). + instruction (which looks like ````) + or comment (which looks like ````). (Patch by Neil Muller; :issue:`2746`.) * The :meth:`~StringIO.StringIO.readline` method of :class:`~StringIO.StringIO` objects now does diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index db8d9281b1f2..24d5bba66e33 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -1183,7 +1183,7 @@ and will be incorrect in some rare cases, including some ``_``-s in New in 3.10 maintenance releases. -Apply syntax highlighting to `.pyi` files. (Contributed by Alex +Apply syntax highlighting to ``.pyi`` files. (Contributed by Alex Waygood and Terry Jan Reedy in :issue:`45447`.) Include prompts when saving Shell with inputs and outputs. diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index b765b1a11b18..bb9538338e48 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -734,7 +734,7 @@ hashlib IDLE and idlelib ---------------- -* Apply syntax highlighting to `.pyi` files. (Contributed by Alex +* Apply syntax highlighting to ``.pyi`` files. (Contributed by Alex Waygood and Terry Jan Reedy in :issue:`45447`.) * Include prompts when saving Shell with inputs and outputs. diff --git a/Doc/whatsnew/3.2.rst b/Doc/whatsnew/3.2.rst index 7b12e631fd81..3becd3f71928 100644 --- a/Doc/whatsnew/3.2.rst +++ b/Doc/whatsnew/3.2.rst @@ -1746,7 +1746,7 @@ names. instead of module names for running specific tests (:issue:`10620`). The new test discovery can find tests within packages, locating any test importable from the top-level directory. The top-level directory can be specified with - the `-t` option, a pattern for matching files with ``-p``, and a directory to + the ``-t`` option, a pattern for matching files with ``-p``, and a directory to start discovery with ``-s``: .. code-block:: shell-session @@ -1858,7 +1858,7 @@ asyncore :class:`asyncore.dispatcher` now provides a :meth:`~asyncore.dispatcher.handle_accepted()` method -returning a `(sock, addr)` pair which is called when a connection has actually +returning a ``(sock, addr)`` pair which is called when a connection has actually been established with a new remote endpoint. This is supposed to be used as a replacement for old :meth:`~asyncore.dispatcher.handle_accept()` and avoids the user to call :meth:`~asyncore.dispatcher.accept()` directly. diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst index fef1a8ac4c01..96a632577b2c 100644 --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -2389,10 +2389,10 @@ Porting Python code :attr:`sys.path_importer_cache` where it represents the use of implicit finders, but semantically it should not change anything. -* :class:`importlib.abc.Finder` no longer specifies a `find_module()` abstract +* :class:`importlib.abc.Finder` no longer specifies a ``find_module()`` abstract method that must be implemented. If you were relying on subclasses to implement that method, make sure to check for the method's existence first. - You will probably want to check for `find_loader()` first, though, in the + You will probably want to check for ``find_loader()`` first, though, in the case of working with :term:`path entry finders `. * :mod:`pkgutil` has been converted to use :mod:`importlib` internally. This diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst index 625373d50898..f9cceecbcbb9 100644 --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -2469,11 +2469,11 @@ Changes in the Python API ``opt-`` tag in ``.pyc`` file names. The :func:`importlib.util.cache_from_source` has gained an *optimization* parameter to help control the ``opt-`` tag. Because of this, the - *debug_override* parameter of the function is now deprecated. `.pyo` files + *debug_override* parameter of the function is now deprecated. ``.pyo`` files are also no longer supported as a file argument to the Python interpreter and thus serve no purpose when distributed on their own (i.e. sourceless code distribution). Due to the fact that the magic number for bytecode has changed - in Python 3.5, all old `.pyo` files from previous versions of Python are + in Python 3.5, all old ``.pyo`` files from previous versions of Python are invalid regardless of this PEP. * The :mod:`socket` module now exports the :data:`~socket.CAN_RAW_FD_FRAMES` diff --git a/Doc/whatsnew/3.6.rst b/Doc/whatsnew/3.6.rst index bcca28d2f7ba..70e45258654f 100644 --- a/Doc/whatsnew/3.6.rst +++ b/Doc/whatsnew/3.6.rst @@ -960,8 +960,8 @@ contextlib The :class:`contextlib.AbstractContextManager` class has been added to provide an abstract base class for context managers. It provides a -sensible default implementation for `__enter__()` which returns -``self`` and leaves `__exit__()` an abstract method. A matching +sensible default implementation for ``__enter__()`` which returns +``self`` and leaves ``__exit__()`` an abstract method. A matching class has been added to the :mod:`typing` module as :class:`typing.ContextManager`. (Contributed by Brett Cannon in :issue:`25609`.) @@ -1388,7 +1388,7 @@ are treated as punctuation. site ---- -When specifying paths to add to :attr:`sys.path` in a `.pth` file, +When specifying paths to add to :attr:`sys.path` in a ``.pth`` file, you may now specify file paths on top of directories (e.g. zip files). (Contributed by Wolfgang Langner in :issue:`26587`). diff --git a/Doc/whatsnew/3.7.rst b/Doc/whatsnew/3.7.rst index 5bb3d2a436b6..de03e5bedeaa 100644 --- a/Doc/whatsnew/3.7.rst +++ b/Doc/whatsnew/3.7.rst @@ -2497,7 +2497,7 @@ number of other issues). Some known details affected: * :c:func:`PySys_AddWarnOptionUnicode` is not currently usable by embedding applications due to the requirement to create a Unicode object prior to - calling `Py_Initialize`. Use :c:func:`PySys_AddWarnOption` instead. + calling ``Py_Initialize``. Use :c:func:`PySys_AddWarnOption` instead. * warnings filters added by an embedding application with :c:func:`PySys_AddWarnOption` should now more consistently take precedence diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index ff01a6577299..624e71f9254c 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -500,7 +500,7 @@ Reedy in :issue:`40468`.) Move the indent space setting from the Font tab to the new Windows tab. (Contributed by Mark Roseman and Terry Jan Reedy in :issue:`33962`.) -Apply syntax highlighting to `.pyi` files. (Contributed by Alex +Apply syntax highlighting to ``.pyi`` files. (Contributed by Alex Waygood and Terry Jan Reedy in :issue:`45447`.) imaplib diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-01-08-55-09.gh-issue-97591.pw6kkH.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-01-08-55-09.gh-issue-97591.pw6kkH.rst index d3a5867db7fc..6f07529f15bb 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2022-10-01-08-55-09.gh-issue-97591.pw6kkH.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-01-08-55-09.gh-issue-97591.pw6kkH.rst @@ -1,2 +1,2 @@ -Fixed a missing incref/decref pair in `Exception.__setstate__()`. +Fixed a missing incref/decref pair in ``Exception.__setstate__()``. Patch by Ofey Chan. From webhook-mailer at python.org Mon Oct 17 19:49:52 2022 From: webhook-mailer at python.org (ezio-melotti) Date: Mon, 17 Oct 2022 23:49:52 -0000 Subject: [Python-checkins] [3.10] Docs: Fix backtick errors found by sphinx-lint (GH-97998) (#98373) Message-ID: https://github.com/python/cpython/commit/b2db1c208066b67bdf57bf3799de50352fe63416 commit: b2db1c208066b67bdf57bf3799de50352fe63416 branch: 3.10 author: C.A.M. Gerlach committer: ezio-melotti date: 2022-10-18T01:49:47+02:00 summary: [3.10] Docs: Fix backtick errors found by sphinx-lint (GH-97998) (#98373) Co-authored-by: Ezio Melotti . (cherry picked from commit fa2d43e5184f5eaf3391844ec2400342a1b2ead4) Co-authored-by: Hugo van Kemenade Co-authored-by: Hugo van Kemenade files: M Doc/README.rst M Doc/c-api/init.rst M Doc/c-api/type.rst M Doc/faq/design.rst M Doc/howto/logging.rst M Doc/install/index.rst M Doc/library/asyncio-protocol.rst M Doc/library/asyncio-task.rst M Doc/library/bdb.rst M Doc/library/bz2.rst M Doc/library/concurrent.futures.rst M Doc/library/ctypes.rst M Doc/library/curses.rst M Doc/library/datetime.rst M Doc/library/decimal.rst M Doc/library/email.compat32-message.rst M Doc/library/email.errors.rst M Doc/library/email.headerregistry.rst M Doc/library/hashlib.rst M Doc/library/lzma.rst M Doc/library/os.rst M Doc/library/select.rst M Doc/library/socket.rst M Doc/library/statistics.rst M Doc/library/sys.rst M Doc/library/tk.rst M Doc/library/tkinter.colorchooser.rst M Doc/library/tkinter.dnd.rst M Doc/library/tkinter.messagebox.rst M Doc/library/types.rst M Doc/library/unittest.mock-examples.rst M Doc/library/xml.dom.minidom.rst M Doc/library/xmlrpc.client.rst M Doc/library/xmlrpc.server.rst M Doc/reference/expressions.rst M Doc/reference/import.rst M Doc/reference/simple_stmts.rst M Doc/using/configure.rst M Doc/using/unix.rst M Doc/using/windows.rst M Doc/whatsnew/2.6.rst M Doc/whatsnew/2.7.rst M Doc/whatsnew/3.10.rst M Doc/whatsnew/3.2.rst M Doc/whatsnew/3.3.rst M Doc/whatsnew/3.5.rst M Doc/whatsnew/3.6.rst M Doc/whatsnew/3.7.rst M Doc/whatsnew/3.9.rst diff --git a/Doc/README.rst b/Doc/README.rst index 729f4f85c7f8..5c85ad7c2512 100644 --- a/Doc/README.rst +++ b/Doc/README.rst @@ -91,7 +91,7 @@ Available make targets are: * "pydoc-topics", which builds a Python module containing a dictionary with plain text documentation for the labels defined in - `tools/pyspecific.py` -- pydoc needs these to show topic and keyword help. + ``tools/pyspecific.py`` -- pydoc needs these to show topic and keyword help. * "suspicious", which checks the parsed markup for text that looks like malformed and thus unconverted reST. diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index 31921896687c..483bcd990ca7 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -1722,7 +1722,7 @@ is not possible due to its implementation being opaque at build time. Free the given *key* allocated by :c:func:`PyThread_tss_alloc`, after first calling :c:func:`PyThread_tss_delete` to ensure any associated thread locals have been unassigned. This is a no-op if the *key* - argument is `NULL`. + argument is ``NULL``. .. note:: A freed key becomes a dangling pointer. You should reset the key to diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst index 01d00bede544..97816948e9e4 100644 --- a/Doc/c-api/type.rst +++ b/Doc/c-api/type.rst @@ -40,7 +40,7 @@ Type Objects .. c:function:: unsigned long PyType_GetFlags(PyTypeObject* type) Return the :c:member:`~PyTypeObject.tp_flags` member of *type*. This function is primarily - meant for use with `Py_LIMITED_API`; the individual flag bits are + meant for use with ``Py_LIMITED_API``; the individual flag bits are guaranteed to be stable across Python releases, but access to :c:member:`~PyTypeObject.tp_flags` itself is not part of the limited API. diff --git a/Doc/faq/design.rst b/Doc/faq/design.rst index 9da1d01abd6f..9dbfacd73cc6 100644 --- a/Doc/faq/design.rst +++ b/Doc/faq/design.rst @@ -155,7 +155,7 @@ Why can't I use an assignment in an expression? Starting in Python 3.8, you can! -Assignment expressions using the walrus operator `:=` assign a variable in an +Assignment expressions using the walrus operator ``:=`` assign a variable in an expression:: while chunk := fp.read(200): diff --git a/Doc/howto/logging.rst b/Doc/howto/logging.rst index 0115a941afd6..b22765957149 100644 --- a/Doc/howto/logging.rst +++ b/Doc/howto/logging.rst @@ -552,14 +552,14 @@ raw message. If there is no date format string, the default date format is: %Y-%m-%d %H:%M:%S -with the milliseconds tacked on at the end. The ``style`` is one of `%`, '{' -or '$'. If one of these is not specified, then '%' will be used. +with the milliseconds tacked on at the end. The ``style`` is one of ``'%'``, +``'{'``, or ``'$'``. If one of these is not specified, then ``'%'`` will be used. -If the ``style`` is '%', the message format string uses +If the ``style`` is ``'%'``, the message format string uses ``%()s`` styled string substitution; the possible keys are -documented in :ref:`logrecord-attributes`. If the style is '{', the message +documented in :ref:`logrecord-attributes`. If the style is ``'{'``, the message format string is assumed to be compatible with :meth:`str.format` (using -keyword arguments), while if the style is '$' then the message format string +keyword arguments), while if the style is ``'$'`` then the message format string should conform to what is expected by :meth:`string.Template.substitute`. .. versionchanged:: 3.2 diff --git a/Doc/install/index.rst b/Doc/install/index.rst index 84df5e7cb368..d2d8e567c03c 100644 --- a/Doc/install/index.rst +++ b/Doc/install/index.rst @@ -761,7 +761,7 @@ And on Windows, the configuration files are: +--------------+-------------------------------------------------+-------+ On all platforms, the "personal" file can be temporarily disabled by -passing the `--no-user-cfg` option. +passing the ``--no-user-cfg`` option. Notes: diff --git a/Doc/library/asyncio-protocol.rst b/Doc/library/asyncio-protocol.rst index 8b67f4b8957e..969354ceb163 100644 --- a/Doc/library/asyncio-protocol.rst +++ b/Doc/library/asyncio-protocol.rst @@ -553,7 +553,7 @@ accept factories that return streaming protocols. a connection is open. However, :meth:`protocol.eof_received() ` - is called at most once. Once `eof_received()` is called, + is called at most once. Once ``eof_received()`` is called, ``data_received()`` is not called anymore. .. method:: Protocol.eof_received() diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index 8f9cef727463..a43484bf78b6 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -707,17 +707,17 @@ Running in Threads # blocking_io complete at 19:50:54 # finished main at 19:50:54 - Directly calling `blocking_io()` in any coroutine would block the event loop + Directly calling ``blocking_io()`` in any coroutine would block the event loop for its duration, resulting in an additional 1 second of run time. Instead, - by using `asyncio.to_thread()`, we can run it in a separate thread without + by using ``asyncio.to_thread()``, we can run it in a separate thread without blocking the event loop. .. note:: - Due to the :term:`GIL`, `asyncio.to_thread()` can typically only be used + Due to the :term:`GIL`, ``asyncio.to_thread()`` can typically only be used to make IO-bound functions non-blocking. However, for extension modules that release the GIL or alternative Python implementations that don't - have one, `asyncio.to_thread()` can also be used for CPU-bound functions. + have one, ``asyncio.to_thread()`` can also be used for CPU-bound functions. .. versionadded:: 3.9 diff --git a/Doc/library/bdb.rst b/Doc/library/bdb.rst index 7b74bbd652be..d201dc963b59 100644 --- a/Doc/library/bdb.rst +++ b/Doc/library/bdb.rst @@ -143,7 +143,7 @@ The :mod:`bdb` module also defines two classes: For real file names, the canonical form is an operating-system-dependent, :func:`case-normalized ` :func:`absolute path - `. A *filename* with angle brackets, such as `""` + `. A *filename* with angle brackets, such as ``""`` generated in interactive mode, is returned unchanged. .. method:: reset() diff --git a/Doc/library/bz2.rst b/Doc/library/bz2.rst index 999892e95f47..ae5a1598f84b 100644 --- a/Doc/library/bz2.rst +++ b/Doc/library/bz2.rst @@ -206,7 +206,7 @@ Incremental (de)compression will be set to ``True``. Attempting to decompress data after the end of stream is reached - raises an `EOFError`. Any data found after the end of the + raises an :exc:`EOFError`. Any data found after the end of the stream is ignored and saved in the :attr:`~.unused_data` attribute. .. versionchanged:: 3.5 @@ -303,7 +303,7 @@ Using :class:`BZ2Compressor` for incremental compression: >>> out = out + comp.flush() The example above uses a very "nonrandom" stream of data -(a stream of `b"z"` chunks). Random data tends to compress poorly, +(a stream of ``b"z"`` chunks). Random data tends to compress poorly, while ordered, repetitive data usually yields a high compression ratio. Writing and reading a bzip2-compressed file in binary mode: diff --git a/Doc/library/concurrent.futures.rst b/Doc/library/concurrent.futures.rst index 8c43590ce2b1..a25ad09c0a89 100644 --- a/Doc/library/concurrent.futures.rst +++ b/Doc/library/concurrent.futures.rst @@ -151,7 +151,7 @@ And:: All threads enqueued to ``ThreadPoolExecutor`` will be joined before the interpreter can exit. Note that the exit handler which does this is - executed *before* any exit handlers added using `atexit`. This means + executed *before* any exit handlers added using ``atexit``. This means exceptions in the main thread must be caught and handled in order to signal threads to exit gracefully. For this reason, it is recommended that ``ThreadPoolExecutor`` not be used for long-running tasks. @@ -398,13 +398,13 @@ The :class:`Future` class encapsulates the asynchronous execution of a callable. tests. If the method returns ``False`` then the :class:`Future` was cancelled, - i.e. :meth:`Future.cancel` was called and returned `True`. Any threads + i.e. :meth:`Future.cancel` was called and returned ``True``. Any threads waiting on the :class:`Future` completing (i.e. through :func:`as_completed` or :func:`wait`) will be woken up. If the method returns ``True`` then the :class:`Future` was not cancelled and has been put in the running state, i.e. calls to - :meth:`Future.running` will return `True`. + :meth:`Future.running` will return ``True``. This method can only be called once and cannot be called after :meth:`Future.set_result` or :meth:`Future.set_exception` have been diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index 822a9b0dfec5..18a942751bef 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -1935,7 +1935,7 @@ Utility functions .. function:: GetLastError() Windows only: Returns the last error code set by Windows in the calling thread. - This function calls the Windows `GetLastError()` function directly, + This function calls the Windows ``GetLastError()`` function directly, it does not return the ctypes-private copy of the error code. .. function:: get_errno() diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst index efbece437af2..2158fba35eab 100644 --- a/Doc/library/curses.rst +++ b/Doc/library/curses.rst @@ -292,7 +292,7 @@ The module :mod:`curses` defines the following functions: Change the definition of a color, taking the number of the color to be changed followed by three RGB values (for the amounts of red, green, and blue components). The value of *color_number* must be between ``0`` and - `COLORS - 1`. Each of *r*, *g*, *b*, must be a value between ``0`` and + ``COLORS - 1``. Each of *r*, *g*, *b*, must be a value between ``0`` and ``1000``. When :func:`init_color` is used, all occurrences of that color on the screen immediately change to the new definition. This function is a no-op on most terminals; it is active only if :func:`can_change_color` returns ``True``. diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst index 2f51dc3523a1..c2d7715a52cf 100644 --- a/Doc/library/datetime.rst +++ b/Doc/library/datetime.rst @@ -2246,7 +2246,7 @@ where historical changes have been made to civil time. two digits of ``offset.hours`` and ``offset.minutes`` respectively. .. versionchanged:: 3.6 - Name generated from ``offset=timedelta(0)`` is now plain `'UTC'`, not + Name generated from ``offset=timedelta(0)`` is now plain ``'UTC'``, not ``'UTC+00:00'``. diff --git a/Doc/library/decimal.rst b/Doc/library/decimal.rst index ab3d3b8d8f34..38ebb44cc661 100644 --- a/Doc/library/decimal.rst +++ b/Doc/library/decimal.rst @@ -576,11 +576,11 @@ Decimal objects Alternative constructor that only accepts instances of :class:`float` or :class:`int`. - Note `Decimal.from_float(0.1)` is not the same as `Decimal('0.1')`. + Note ``Decimal.from_float(0.1)`` is not the same as ``Decimal('0.1')``. Since 0.1 is not exactly representable in binary floating point, the value is stored as the nearest representable value which is - `0x1.999999999999ap-4`. That equivalent value in decimal is - `0.1000000000000000055511151231257827021181583404541015625`. + ``0x1.999999999999ap-4``. That equivalent value in decimal is + ``0.1000000000000000055511151231257827021181583404541015625``. .. note:: From Python 3.2 onwards, a :class:`Decimal` instance can also be constructed directly from a :class:`float`. @@ -1193,7 +1193,7 @@ In addition to the three supplied contexts, new contexts can be created with the .. method:: exp(x) - Returns `e ** x`. + Returns ``e ** x``. .. method:: fma(x, y, z) diff --git a/Doc/library/email.compat32-message.rst b/Doc/library/email.compat32-message.rst index 4eaa9d588ca3..5bef155a4af3 100644 --- a/Doc/library/email.compat32-message.rst +++ b/Doc/library/email.compat32-message.rst @@ -298,7 +298,7 @@ Here are the methods of the :class:`Message` class: In a model generated from bytes, any header values that (in contravention of the RFCs) contain non-ASCII bytes will, when retrieved through this interface, be represented as :class:`~email.header.Header` objects with - a charset of `unknown-8bit`. + a charset of ``unknown-8bit``. .. method:: __len__() diff --git a/Doc/library/email.errors.rst b/Doc/library/email.errors.rst index 7a77640571cb..194a98696f43 100644 --- a/Doc/library/email.errors.rst +++ b/Doc/library/email.errors.rst @@ -114,4 +114,4 @@ All defect classes are subclassed from :class:`email.errors.MessageDefect`. a multiple of 4). The encoded block was kept as-is. * :class:`InvalidDateDefect` -- When decoding an invalid or unparsable date field. - The original value is kept as-is. \ No newline at end of file + The original value is kept as-is. diff --git a/Doc/library/email.headerregistry.rst b/Doc/library/email.headerregistry.rst index 3e1d97a03264..528c9af45852 100644 --- a/Doc/library/email.headerregistry.rst +++ b/Doc/library/email.headerregistry.rst @@ -153,7 +153,7 @@ headers. specified as ``-0000`` (indicating it is in UTC but contains no information about the source timezone), then :attr:`.datetime` will be a naive :class:`~datetime.datetime`. If a specific timezone offset is - found (including `+0000`), then :attr:`.datetime` will contain an aware + found (including ``+0000``), then :attr:`.datetime` will contain an aware ``datetime`` that uses :class:`datetime.timezone` to record the timezone offset. diff --git a/Doc/library/hashlib.rst b/Doc/library/hashlib.rst index 2e7537456527..f642d04d229d 100644 --- a/Doc/library/hashlib.rst +++ b/Doc/library/hashlib.rst @@ -391,7 +391,7 @@ Constructor functions also accept the following tree hashing parameters: BLAKE2s, 0 in sequential mode). * *last_node*: boolean indicating whether the processed node is the last - one (`False` for sequential mode). + one (``False`` for sequential mode). .. figure:: hashlib-blake2-tree.png :alt: Explanation of tree mode parameters. diff --git a/Doc/library/lzma.rst b/Doc/library/lzma.rst index 21092645366d..868d4dcfb6c9 100644 --- a/Doc/library/lzma.rst +++ b/Doc/library/lzma.rst @@ -258,7 +258,7 @@ Compressing and decompressing data in memory will be set to ``True``. Attempting to decompress data after the end of stream is reached - raises an `EOFError`. Any data found after the end of the + raises an :exc:`EOFError`. Any data found after the end of the stream is ignored and saved in the :attr:`~.unused_data` attribute. .. versionchanged:: 3.5 diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 8753132429d6..90ecc42294aa 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -3107,7 +3107,7 @@ features: system records access and modification times; see :func:`~os.stat`. The best way to preserve exact times is to use the *st_atime_ns* and *st_mtime_ns* fields from the :func:`os.stat` result object with the *ns* parameter to - `utime`. + :func:`utime`. This function can support :ref:`specifying a file descriptor `, :ref:`paths relative to directory descriptors ` and :ref:`not @@ -3984,7 +3984,7 @@ written in Python, such as a mail server's external command delivery program. library :c:data:`POSIX_SPAWN_RESETIDS` flag. If the *setsid* argument is ``True``, it will create a new session ID - for `posix_spawn`. *setsid* requires :c:data:`POSIX_SPAWN_SETSID` + for ``posix_spawn``. *setsid* requires :c:data:`POSIX_SPAWN_SETSID` or :c:data:`POSIX_SPAWN_SETSID_NP` flag. Otherwise, :exc:`NotImplementedError` is raised. diff --git a/Doc/library/select.rst b/Doc/library/select.rst index 1c3d10ef2093..1cbe97d110c3 100644 --- a/Doc/library/select.rst +++ b/Doc/library/select.rst @@ -60,7 +60,7 @@ The module defines the following: events. *sizehint* informs epoll about the expected number of events to be - registered. It must be positive, or `-1` to use the default. It is only + registered. It must be positive, or ``-1`` to use the default. It is only used on older systems where :c:func:`epoll_create1` is not available; otherwise it has no effect (though its value is still checked). diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst index 205d08bf82cf..0a8f35eed4c8 100644 --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -604,7 +604,7 @@ The following functions all create :ref:`socket objects `. When :const:`SOCK_NONBLOCK` or :const:`SOCK_CLOEXEC` bit flags are applied to *type* they are cleared, and :attr:`socket.type` will not reflect them. They are still passed - to the underlying system `socket()` call. Therefore, + to the underlying system ``socket()`` call. Therefore, :: diff --git a/Doc/library/statistics.rst b/Doc/library/statistics.rst index 1ff6faec151f..afa2bea9e393 100644 --- a/Doc/library/statistics.rst +++ b/Doc/library/statistics.rst @@ -786,7 +786,7 @@ of applications in statistics. The relative likelihood is computed as the probability of a sample occurring in a narrow range divided by the width of the range (hence the word "density"). Since the likelihood is relative to other points, - its value can be greater than `1.0`. + its value can be greater than ``1.0``. .. method:: NormalDist.cdf(x) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index b39ba5ff7fe6..88a2e68c63d7 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -250,7 +250,7 @@ always available. Print low-level information to stderr about the state of CPython's memory allocator. - If Python is `built in debug mode ` (:option:`configure + If Python is :ref:`built in debug mode ` (:option:`configure --with-pydebug option <--with-pydebug>`), it also performs some expensive internal consistency checks. @@ -320,7 +320,7 @@ always available. files to (and read them from) a parallel directory tree rooted at this directory, rather than from ``__pycache__`` directories in the source code tree. Any ``__pycache__`` directories in the source code tree will be ignored - and new `.pyc` files written within the pycache prefix. Thus if you use + and new ``.pyc`` files written within the pycache prefix. Thus if you use :mod:`compileall` as a pre-build step, you must ensure you run it with the same pycache prefix (if any) that you will use at runtime. @@ -828,7 +828,7 @@ always available. .. function:: get_asyncgen_hooks() Returns an *asyncgen_hooks* object, which is similar to a - :class:`~collections.namedtuple` of the form `(firstiter, finalizer)`, + :class:`~collections.namedtuple` of the form ``(firstiter, finalizer)``, where *firstiter* and *finalizer* are expected to be either ``None`` or functions which take an :term:`asynchronous generator iterator` as an argument, and are used to schedule finalization of an asynchronous diff --git a/Doc/library/tk.rst b/Doc/library/tk.rst index 0cb8fda4e32e..3dc2130539c2 100644 --- a/Doc/library/tk.rst +++ b/Doc/library/tk.rst @@ -44,4 +44,4 @@ alternative `GUI frameworks and tools ``, ``<=``, and ``>=``) raise :exc:`TypeError`. diff --git a/Doc/reference/import.rst b/Doc/reference/import.rst index 383797501397..3f55a0b79008 100644 --- a/Doc/reference/import.rst +++ b/Doc/reference/import.rst @@ -812,7 +812,7 @@ The path based finder iterates over every entry in the search path, and for each of these, looks for an appropriate :term:`path entry finder` (:class:`~importlib.abc.PathEntryFinder`) for the path entry. Because this can be an expensive operation (e.g. there may be -`stat()` call overheads for this search), the path based finder maintains +``stat()`` call overheads for this search), the path based finder maintains a cache mapping path entries to path entry finders. This cache is maintained in :data:`sys.path_importer_cache` (despite the name, this cache actually stores finder objects rather than being limited to :term:`importer` objects). diff --git a/Doc/reference/simple_stmts.rst b/Doc/reference/simple_stmts.rst index d5f1e045e980..ea9993da459e 100644 --- a/Doc/reference/simple_stmts.rst +++ b/Doc/reference/simple_stmts.rst @@ -988,20 +988,12 @@ The :keyword:`!nonlocal` statement .. productionlist:: python-grammar nonlocal_stmt: "nonlocal" `identifier` ("," `identifier`)* -.. XXX add when implemented - : ["=" (`target_list` "=")+ starred_expression] - : | "nonlocal" identifier augop expression_list - The :keyword:`nonlocal` statement causes the listed identifiers to refer to previously bound variables in the nearest enclosing scope excluding globals. This is important because the default behavior for binding is to search the local namespace first. The statement allows encapsulated code to rebind variables outside of the local scope besides the global (module) scope. -.. XXX not implemented - The :keyword:`nonlocal` statement may prepend an assignment or augmented - assignment, but not an expression. - Names listed in a :keyword:`nonlocal` statement, unlike those listed in a :keyword:`global` statement, must refer to pre-existing bindings in an enclosing scope (the scope in which a new binding should be created cannot diff --git a/Doc/using/configure.rst b/Doc/using/configure.rst index 13c339465c1f..872283615f64 100644 --- a/Doc/using/configure.rst +++ b/Doc/using/configure.rst @@ -654,12 +654,12 @@ Compiler flags In particular, :envvar:`CFLAGS` should not contain: - * the compiler flag `-I` (for setting the search path for include files). - The `-I` flags are processed from left to right, and any flags in - :envvar:`CFLAGS` would take precedence over user- and package-supplied `-I` + * the compiler flag ``-I`` (for setting the search path for include files). + The ``-I`` flags are processed from left to right, and any flags in + :envvar:`CFLAGS` would take precedence over user- and package-supplied ``-I`` flags. - * hardening flags such as `-Werror` because distributions cannot control + * hardening flags such as ``-Werror`` because distributions cannot control whether packages installed by users conform to such heightened standards. @@ -777,9 +777,9 @@ Linker flags In particular, :envvar:`LDFLAGS` should not contain: - * the compiler flag `-L` (for setting the search path for libraries). - The `-L` flags are processed from left to right, and any flags in - :envvar:`LDFLAGS` would take precedence over user- and package-supplied `-L` + * the compiler flag ``-L`` (for setting the search path for libraries). + The ``-L`` flags are processed from left to right, and any flags in + :envvar:`LDFLAGS` would take precedence over user- and package-supplied ``-L`` flags. .. envvar:: CONFIGURE_LDFLAGS_NODIST diff --git a/Doc/using/unix.rst b/Doc/using/unix.rst index 061cfa5be88f..24c02c99f871 100644 --- a/Doc/using/unix.rst +++ b/Doc/using/unix.rst @@ -170,7 +170,7 @@ Custom OpenSSL $ popd 3. Build Python with custom OpenSSL - (see the configure `--with-openssl` and `--with-openssl-rpath` options) + (see the configure ``--with-openssl`` and ``--with-openssl-rpath`` options) .. code-block:: shell-session diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst index 35e26eb2b20c..9489609b4b48 100644 --- a/Doc/using/windows.rst +++ b/Doc/using/windows.rst @@ -199,7 +199,7 @@ of available options is shown below. +---------------------------+--------------------------------------+--------------------------+ | Include_pip | Install bundled pip and setuptools | 1 | +---------------------------+--------------------------------------+--------------------------+ -| Include_symbols | Install debugging symbols (`*`.pdb) | 0 | +| Include_symbols | Install debugging symbols (``*.pdb``)| 0 | +---------------------------+--------------------------------------+--------------------------+ | Include_tcltk | Install Tcl/Tk support and IDLE | 1 | +---------------------------+--------------------------------------+--------------------------+ diff --git a/Doc/whatsnew/2.6.rst b/Doc/whatsnew/2.6.rst index 731ce6aac691..34f2656f765c 100644 --- a/Doc/whatsnew/2.6.rst +++ b/Doc/whatsnew/2.6.rst @@ -717,13 +717,13 @@ This will produce the output:: PEP 3101: Advanced String Formatting ===================================================== -In Python 3.0, the `%` operator is supplemented by a more powerful string +In Python 3.0, the ``%`` operator is supplemented by a more powerful string formatting method, :meth:`format`. Support for the :meth:`str.format` method has been backported to Python 2.6. -In 2.6, both 8-bit and Unicode strings have a `.format()` method that +In 2.6, both 8-bit and Unicode strings have a ``.format()`` method that treats the string as a template and takes the arguments to be formatted. -The formatting template uses curly brackets (`{`, `}`) as special characters:: +The formatting template uses curly brackets (``{``, ``}``) as special characters:: >>> # Substitute positional argument 0 into the string. >>> "User ID: {0}".format("root") diff --git a/Doc/whatsnew/2.7.rst b/Doc/whatsnew/2.7.rst index fbfcc5db5f5f..08aa11022121 100644 --- a/Doc/whatsnew/2.7.rst +++ b/Doc/whatsnew/2.7.rst @@ -2485,8 +2485,8 @@ In the standard library: * The ElementTree library, :mod:`xml.etree`, no longer escapes ampersands and angle brackets when outputting an XML processing - instruction (which looks like ``) - or comment (which looks like ``). + instruction (which looks like ````) + or comment (which looks like ````). (Patch by Neil Muller; :issue:`2746`.) * The :meth:`~StringIO.StringIO.readline` method of :class:`~StringIO.StringIO` objects now does diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index 67eaeffa772a..8434de2fbe55 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -1172,7 +1172,7 @@ and will be incorrect in some rare cases, including some ``_``-s in New in 3.10 maintenance releases. -Apply syntax highlighting to `.pyi` files. (Contributed by Alex +Apply syntax highlighting to ``.pyi`` files. (Contributed by Alex Waygood and Terry Jan Reedy in :issue:`45447`.) Include prompts when saving Shell with inputs and outputs. diff --git a/Doc/whatsnew/3.2.rst b/Doc/whatsnew/3.2.rst index 9b5bbd3c2d20..a4a9779af4d2 100644 --- a/Doc/whatsnew/3.2.rst +++ b/Doc/whatsnew/3.2.rst @@ -1745,7 +1745,7 @@ names. instead of module names for running specific tests (:issue:`10620`). The new test discovery can find tests within packages, locating any test importable from the top-level directory. The top-level directory can be specified with - the `-t` option, a pattern for matching files with ``-p``, and a directory to + the ``-t`` option, a pattern for matching files with ``-p``, and a directory to start discovery with ``-s``: .. code-block:: shell-session @@ -1857,7 +1857,7 @@ asyncore :class:`asyncore.dispatcher` now provides a :meth:`~asyncore.dispatcher.handle_accepted()` method -returning a `(sock, addr)` pair which is called when a connection has actually +returning a ``(sock, addr)`` pair which is called when a connection has actually been established with a new remote endpoint. This is supposed to be used as a replacement for old :meth:`~asyncore.dispatcher.handle_accept()` and avoids the user to call :meth:`~asyncore.dispatcher.accept()` directly. diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst index fef1a8ac4c01..96a632577b2c 100644 --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -2389,10 +2389,10 @@ Porting Python code :attr:`sys.path_importer_cache` where it represents the use of implicit finders, but semantically it should not change anything. -* :class:`importlib.abc.Finder` no longer specifies a `find_module()` abstract +* :class:`importlib.abc.Finder` no longer specifies a ``find_module()`` abstract method that must be implemented. If you were relying on subclasses to implement that method, make sure to check for the method's existence first. - You will probably want to check for `find_loader()` first, though, in the + You will probably want to check for ``find_loader()`` first, though, in the case of working with :term:`path entry finders `. * :mod:`pkgutil` has been converted to use :mod:`importlib` internally. This diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst index 625373d50898..f9cceecbcbb9 100644 --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -2469,11 +2469,11 @@ Changes in the Python API ``opt-`` tag in ``.pyc`` file names. The :func:`importlib.util.cache_from_source` has gained an *optimization* parameter to help control the ``opt-`` tag. Because of this, the - *debug_override* parameter of the function is now deprecated. `.pyo` files + *debug_override* parameter of the function is now deprecated. ``.pyo`` files are also no longer supported as a file argument to the Python interpreter and thus serve no purpose when distributed on their own (i.e. sourceless code distribution). Due to the fact that the magic number for bytecode has changed - in Python 3.5, all old `.pyo` files from previous versions of Python are + in Python 3.5, all old ``.pyo`` files from previous versions of Python are invalid regardless of this PEP. * The :mod:`socket` module now exports the :data:`~socket.CAN_RAW_FD_FRAMES` diff --git a/Doc/whatsnew/3.6.rst b/Doc/whatsnew/3.6.rst index d1a9aa7dee17..cbde9395bd3b 100644 --- a/Doc/whatsnew/3.6.rst +++ b/Doc/whatsnew/3.6.rst @@ -960,8 +960,8 @@ contextlib The :class:`contextlib.AbstractContextManager` class has been added to provide an abstract base class for context managers. It provides a -sensible default implementation for `__enter__()` which returns -``self`` and leaves `__exit__()` an abstract method. A matching +sensible default implementation for ``__enter__()`` which returns +``self`` and leaves ``__exit__()`` an abstract method. A matching class has been added to the :mod:`typing` module as :class:`typing.ContextManager`. (Contributed by Brett Cannon in :issue:`25609`.) @@ -1388,7 +1388,7 @@ are treated as punctuation. site ---- -When specifying paths to add to :attr:`sys.path` in a `.pth` file, +When specifying paths to add to :attr:`sys.path` in a ``.pth`` file, you may now specify file paths on top of directories (e.g. zip files). (Contributed by Wolfgang Langner in :issue:`26587`). @@ -1422,7 +1422,7 @@ The socket module now supports the address family Victor Stinner.) New Linux constants ``TCP_USER_TIMEOUT`` and ``TCP_CONGESTION`` were added. -(Contributed by Omar Sandoval, issue:`26273`). +(Contributed by Omar Sandoval, :issue:`26273`). socketserver diff --git a/Doc/whatsnew/3.7.rst b/Doc/whatsnew/3.7.rst index ece406983b94..f45eaf8234d1 100644 --- a/Doc/whatsnew/3.7.rst +++ b/Doc/whatsnew/3.7.rst @@ -2497,7 +2497,7 @@ number of other issues). Some known details affected: * :c:func:`PySys_AddWarnOptionUnicode` is not currently usable by embedding applications due to the requirement to create a Unicode object prior to - calling `Py_Initialize`. Use :c:func:`PySys_AddWarnOption` instead. + calling ``Py_Initialize``. Use :c:func:`PySys_AddWarnOption` instead. * warnings filters added by an embedding application with :c:func:`PySys_AddWarnOption` should now more consistently take precedence diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index 20d79defeed1..34fd1c116bc3 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -500,7 +500,7 @@ Reedy in :issue:`40468`.) Move the indent space setting from the Font tab to the new Windows tab. (Contributed by Mark Roseman and Terry Jan Reedy in :issue:`33962`.) -Apply syntax highlighting to `.pyi` files. (Contributed by Alex +Apply syntax highlighting to ``.pyi`` files. (Contributed by Alex Waygood and Terry Jan Reedy in :issue:`45447`.) imaplib From webhook-mailer at python.org Mon Oct 17 19:53:50 2022 From: webhook-mailer at python.org (rhettinger) Date: Mon, 17 Oct 2022 23:53:50 -0000 Subject: [Python-checkins] GH-98363: Add itertools.batched() (GH-98364) Message-ID: https://github.com/python/cpython/commit/de3ece769a8bc10c207a648c8a446f520504fa7e commit: de3ece769a8bc10c207a648c8a446f520504fa7e branch: main author: Raymond Hettinger committer: rhettinger date: 2022-10-17T18:53:45-05:00 summary: GH-98363: Add itertools.batched() (GH-98364) files: A Misc/NEWS.d/next/Library/2022-10-17-12-49-02.gh-issue-98363.aFmSP-.rst M Doc/library/itertools.rst M Lib/test/test_itertools.py M Modules/clinic/itertoolsmodule.c.h M Modules/itertoolsmodule.c diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 9f7ec10729cd..35a71335b35f 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -48,6 +48,7 @@ Iterator Arguments Results Iterator Arguments Results Example ============================ ============================ ================================================= ============================================================= :func:`accumulate` p [,func] p0, p0+p1, p0+p1+p2, ... ``accumulate([1,2,3,4,5]) --> 1 3 6 10 15`` +:func:`batched` p, n [p0, p1, ..., p_n-1], ... ``batched('ABCDEFG', n=3) --> ABC DEF G`` :func:`chain` p, q, ... p0, p1, ... plast, q0, q1, ... ``chain('ABC', 'DEF') --> A B C D E F`` :func:`chain.from_iterable` iterable p0, p1, ... plast, q0, q1, ... ``chain.from_iterable(['ABC', 'DEF']) --> A B C D E F`` :func:`compress` data, selectors (d[0] if s[0]), (d[1] if s[1]), ... ``compress('ABCDEF', [1,0,1,0,1,1]) --> A C E F`` @@ -170,6 +171,44 @@ loops that truncate the stream. .. versionchanged:: 3.8 Added the optional *initial* parameter. + +.. function:: batched(iterable, n) + + Batch data from the *iterable* into lists of length *n*. The last + batch may be shorter than *n*. + + Loops over the input iterable and accumulates data into lists up to + size *n*. The input is consumed lazily, just enough to fill a list. + The result is yielded as soon as the batch is full or when the input + iterable is exhausted: + + .. doctest:: + + >>> flattened_data = ['roses', 'red', 'violets', 'blue', 'sugar', 'sweet'] + >>> unflattened = list(batched(flattened_data, 2)) + >>> unflattened + [['roses', 'red'], ['violets', 'blue'], ['sugar', 'sweet']] + + >>> for batch in batched('ABCDEFG', 3): + ... print(batch) + ... + ['A', 'B', 'C'] + ['D', 'E', 'F'] + ['G'] + + Roughly equivalent to:: + + def batched(iterable, n): + # batched('ABCDEFG', 3) --> ABC DEF G + if n < 1: + raise ValueError('n must be at least one') + it = iter(iterable) + while (batch := list(islice(it, n))): + yield batch + + .. versionadded:: 3.12 + + .. function:: chain(*iterables) Make an iterator that returns elements from the first iterable until it is @@ -858,13 +897,6 @@ which incur interpreter overhead. else: raise ValueError('Expected fill, strict, or ignore') - def batched(iterable, n): - "Batch data into lists of length n. The last batch may be shorter." - # batched('ABCDEFG', 3) --> ABC DEF G - it = iter(iterable) - while (batch := list(islice(it, n))): - yield batch - def triplewise(iterable): "Return overlapping triplets from an iterable" # triplewise('ABCDEFG') --> ABC BCD CDE DEF EFG @@ -1211,36 +1243,6 @@ which incur interpreter overhead. >>> list(grouper('abcdefg', n=3, incomplete='ignore')) [('a', 'b', 'c'), ('d', 'e', 'f')] - >>> list(batched('ABCDEFG', 3)) - [['A', 'B', 'C'], ['D', 'E', 'F'], ['G']] - >>> list(batched('ABCDEF', 3)) - [['A', 'B', 'C'], ['D', 'E', 'F']] - >>> list(batched('ABCDE', 3)) - [['A', 'B', 'C'], ['D', 'E']] - >>> list(batched('ABCD', 3)) - [['A', 'B', 'C'], ['D']] - >>> list(batched('ABC', 3)) - [['A', 'B', 'C']] - >>> list(batched('AB', 3)) - [['A', 'B']] - >>> list(batched('A', 3)) - [['A']] - >>> list(batched('', 3)) - [] - >>> list(batched('ABCDEFG', 2)) - [['A', 'B'], ['C', 'D'], ['E', 'F'], ['G']] - >>> list(batched('ABCDEFG', 1)) - [['A'], ['B'], ['C'], ['D'], ['E'], ['F'], ['G']] - >>> list(batched('ABCDEFG', 0)) - [] - >>> list(batched('ABCDEFG', -1)) - Traceback (most recent call last): - ... - ValueError: Stop argument for islice() must be None or an integer: 0 <= x <= sys.maxsize. - >>> s = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' - >>> all(list(flatten(batched(s[:n], 5))) == list(s[:n]) for n in range(len(s))) - True - >>> list(triplewise('ABCDEFG')) [('A', 'B', 'C'), ('B', 'C', 'D'), ('C', 'D', 'E'), ('D', 'E', 'F'), ('E', 'F', 'G')] diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py index f469bfe185e6..c0e35711a2b3 100644 --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -159,6 +159,44 @@ def test_accumulate(self): with self.assertRaises(TypeError): list(accumulate([10, 20], 100)) + def test_batched(self): + self.assertEqual(list(batched('ABCDEFG', 3)), + [['A', 'B', 'C'], ['D', 'E', 'F'], ['G']]) + self.assertEqual(list(batched('ABCDEFG', 2)), + [['A', 'B'], ['C', 'D'], ['E', 'F'], ['G']]) + self.assertEqual(list(batched('ABCDEFG', 1)), + [['A'], ['B'], ['C'], ['D'], ['E'], ['F'], ['G']]) + + with self.assertRaises(TypeError): # Too few arguments + list(batched('ABCDEFG')) + with self.assertRaises(TypeError): + list(batched('ABCDEFG', 3, None)) # Too many arguments + with self.assertRaises(TypeError): + list(batched(None, 3)) # Non-iterable input + with self.assertRaises(TypeError): + list(batched('ABCDEFG', 'hello')) # n is a string + with self.assertRaises(ValueError): + list(batched('ABCDEFG', 0)) # n is zero + with self.assertRaises(ValueError): + list(batched('ABCDEFG', -1)) # n is negative + + data = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + for n in range(1, 6): + for i in range(len(data)): + s = data[:i] + batches = list(batched(s, n)) + with self.subTest(s=s, n=n, batches=batches): + # Order is preserved and no data is lost + self.assertEqual(''.join(chain(*batches)), s) + # Each batch is an exact list + self.assertTrue(all(type(batch) is list for batch in batches)) + # All but the last batch is of size n + if batches: + last_batch = batches.pop() + self.assertTrue(all(len(batch) == n for batch in batches)) + self.assertTrue(len(last_batch) <= n) + batches.append(last_batch) + def test_chain(self): def chain2(*iterables): @@ -1737,6 +1775,31 @@ def test_takewhile(self): class TestPurePythonRoughEquivalents(unittest.TestCase): + def test_batched_recipe(self): + def batched_recipe(iterable, n): + "Batch data into lists of length n. The last batch may be shorter." + # batched('ABCDEFG', 3) --> ABC DEF G + if n < 1: + raise ValueError('n must be at least one') + it = iter(iterable) + while (batch := list(islice(it, n))): + yield batch + + for iterable, n in product( + ['', 'a', 'ab', 'abc', 'abcd', 'abcde', 'abcdef', 'abcdefg', None], + [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, None]): + with self.subTest(iterable=iterable, n=n): + try: + e1, r1 = None, list(batched(iterable, n)) + except Exception as e: + e1, r1 = type(e), None + try: + e2, r2 = None, list(batched_recipe(iterable, n)) + except Exception as e: + e2, r2 = type(e), None + self.assertEqual(r1, r2) + self.assertEqual(e1, e2) + @staticmethod def islice(iterable, *args): s = slice(*args) @@ -1788,6 +1851,10 @@ def test_accumulate(self): a = [] self.makecycle(accumulate([1,2,a,3]), a) + def test_batched(self): + a = [] + self.makecycle(batched([1,2,a,3], 2), a) + def test_chain(self): a = [] self.makecycle(chain(a), a) @@ -1972,6 +2039,18 @@ def test_accumulate(self): self.assertRaises(TypeError, accumulate, N(s)) self.assertRaises(ZeroDivisionError, list, accumulate(E(s))) + def test_batched(self): + s = 'abcde' + r = [['a', 'b'], ['c', 'd'], ['e']] + n = 2 + for g in (G, I, Ig, L, R): + with self.subTest(g=g): + self.assertEqual(list(batched(g(s), n)), r) + self.assertEqual(list(batched(S(s), 2)), []) + self.assertRaises(TypeError, batched, X(s), 2) + self.assertRaises(TypeError, batched, N(s), 2) + self.assertRaises(ZeroDivisionError, list, batched(E(s), 2)) + def test_chain(self): for s in ("123", "", range(1000), ('do', 1.2), range(2000,2200,5)): for g in (G, I, Ig, S, L, R): diff --git a/Misc/NEWS.d/next/Library/2022-10-17-12-49-02.gh-issue-98363.aFmSP-.rst b/Misc/NEWS.d/next/Library/2022-10-17-12-49-02.gh-issue-98363.aFmSP-.rst new file mode 100644 index 000000000000..9c6e7552a3f4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-17-12-49-02.gh-issue-98363.aFmSP-.rst @@ -0,0 +1,2 @@ +Added itertools.batched() to batch data into lists of a given length with +the last list possibly being shorter than the others. diff --git a/Modules/clinic/itertoolsmodule.c.h b/Modules/clinic/itertoolsmodule.c.h index 8806606d85be..17f9ebb24939 100644 --- a/Modules/clinic/itertoolsmodule.c.h +++ b/Modules/clinic/itertoolsmodule.c.h @@ -8,6 +8,85 @@ preserve #endif +PyDoc_STRVAR(batched_new__doc__, +"batched(iterable, n)\n" +"--\n" +"\n" +"Batch data into lists of length n. The last batch may be shorter than n.\n" +"\n" +"Loops over the input iterable and accumulates data into lists\n" +"up to size n. The input is consumed lazily, just enough to\n" +"fill a list. The result is yielded as soon as a batch is full\n" +"or when the input iterable is exhausted.\n" +"\n" +" >>> for batch in batched(\'ABCDEFG\', 3):\n" +" ... print(batch)\n" +" ...\n" +" [\'A\', \'B\', \'C\']\n" +" [\'D\', \'E\', \'F\']\n" +" [\'G\']"); + +static PyObject * +batched_new_impl(PyTypeObject *type, PyObject *iterable, Py_ssize_t n); + +static PyObject * +batched_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(iterable), &_Py_ID(n), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"iterable", "n", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "batched", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + PyObject * const *fastargs; + Py_ssize_t nargs = PyTuple_GET_SIZE(args); + PyObject *iterable; + Py_ssize_t n; + + fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 2, 2, 0, argsbuf); + if (!fastargs) { + goto exit; + } + iterable = fastargs[0]; + { + Py_ssize_t ival = -1; + PyObject *iobj = _PyNumber_Index(fastargs[1]); + if (iobj != NULL) { + ival = PyLong_AsSsize_t(iobj); + Py_DECREF(iobj); + } + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + n = ival; + } + return_value = batched_new_impl(type, iterable, n); + +exit: + return return_value; +} + PyDoc_STRVAR(pairwise_new__doc__, "pairwise(iterable, /)\n" "--\n" @@ -834,4 +913,4 @@ itertools_count(PyTypeObject *type, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=b1056d63f68a9059 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=efea8cd1e647bd17 input=a9049054013a1b77]*/ diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index 4a7a95730395..99dc30eb412c 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -16,6 +16,7 @@ class itertools.groupby "groupbyobject *" "&groupby_type" class itertools._grouper "_grouperobject *" "&_grouper_type" class itertools.teedataobject "teedataobject *" "&teedataobject_type" class itertools._tee "teeobject *" "&tee_type" +class itertools.batched "batchedobject *" "&batched_type" class itertools.cycle "cycleobject *" "&cycle_type" class itertools.dropwhile "dropwhileobject *" "&dropwhile_type" class itertools.takewhile "takewhileobject *" "&takewhile_type" @@ -30,12 +31,13 @@ class itertools.filterfalse "filterfalseobject *" "&filterfalse_type" class itertools.count "countobject *" "&count_type" class itertools.pairwise "pairwiseobject *" "&pairwise_type" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=6498ed21fbe1bf94]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=1168b274011ce21b]*/ static PyTypeObject groupby_type; static PyTypeObject _grouper_type; static PyTypeObject teedataobject_type; static PyTypeObject tee_type; +static PyTypeObject batched_type; static PyTypeObject cycle_type; static PyTypeObject dropwhile_type; static PyTypeObject takewhile_type; @@ -51,6 +53,171 @@ static PyTypeObject pairwise_type; #include "clinic/itertoolsmodule.c.h" +/* batched object ************************************************************/ + +/* Note: The built-in zip() function includes a "strict" argument + that is needed because that function can silently truncate data + and there is no easy way for a user to detect that condition. + The same reasoning does not apply to batches() which never drops + data. Instead, it produces a shorter list which can be handled + as the user sees fit. + */ + +typedef struct { + PyObject_HEAD + PyObject *it; + Py_ssize_t batch_size; +} batchedobject; + +/*[clinic input] + at classmethod +itertools.batched.__new__ as batched_new + iterable: object + n: Py_ssize_t +Batch data into lists of length n. The last batch may be shorter than n. + +Loops over the input iterable and accumulates data into lists +up to size n. The input is consumed lazily, just enough to +fill a list. The result is yielded as soon as a batch is full +or when the input iterable is exhausted. + + >>> for batch in batched('ABCDEFG', 3): + ... print(batch) + ... + ['A', 'B', 'C'] + ['D', 'E', 'F'] + ['G'] + +[clinic start generated code]*/ + +static PyObject * +batched_new_impl(PyTypeObject *type, PyObject *iterable, Py_ssize_t n) +/*[clinic end generated code: output=7ebc954d655371b6 input=f28fd12cb52365f0]*/ +{ + PyObject *it; + batchedobject *bo; + + if (n < 1) { + /* We could define the n==0 case to return an empty iterator + but that is add odds with the idea that batching should + never throw-away input data. + */ + PyErr_SetString(PyExc_ValueError, "n must be at least one"); + return NULL; + } + it = PyObject_GetIter(iterable); + if (it == NULL) { + return NULL; + } + + /* create batchedobject structure */ + bo = (batchedobject *)type->tp_alloc(type, 0); + if (bo == NULL) { + Py_DECREF(it); + return NULL; + } + bo->batch_size = n; + bo->it = it; + return (PyObject *)bo; +} + +static void +batched_dealloc(batchedobject *bo) +{ + PyObject_GC_UnTrack(bo); + Py_XDECREF(bo->it); + Py_TYPE(bo)->tp_free(bo); +} + +static int +batched_traverse(batchedobject *bo, visitproc visit, void *arg) +{ + if (bo->it != NULL) { + Py_VISIT(bo->it); + } + return 0; +} + +static PyObject * +batched_next(batchedobject *bo) +{ + Py_ssize_t i; + PyObject *it = bo->it; + PyObject *item; + PyObject *result; + + if (it == NULL) { + return NULL; + } + result = PyList_New(0); + if (result == NULL) { + return NULL; + } + for (i=0 ; i < bo->batch_size ; i++) { + item = PyIter_Next(it); + if (item == NULL) { + break; + } + if (PyList_Append(result, item) < 0) { + Py_DECREF(item); + Py_DECREF(result); + return NULL; + } + Py_DECREF(item); + } + if (PyList_GET_SIZE(result) > 0) { + return result; + } + Py_CLEAR(bo->it); + Py_DECREF(result); + return NULL; +} + +static PyTypeObject batched_type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "itertools.batched", /* tp_name */ + sizeof(batchedobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)batched_dealloc, /* tp_dealloc */ + 0, /* tp_vectorcall_offset */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_as_async */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + batched_new__doc__, /* tp_doc */ + (traverseproc)batched_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)batched_next, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + batched_new, /* tp_new */ + PyObject_GC_Del, /* tp_free */ +}; + + /* pairwise object ***********************************************************/ typedef struct { @@ -4815,6 +4982,7 @@ repeat(elem [,n]) --> elem, elem, elem, ... endlessly or up to n times\n\ \n\ Iterators terminating on the shortest input sequence:\n\ accumulate(p[, func]) --> p0, p0+p1, p0+p1+p2\n\ +batched(p, n) --> [p0, p1, ..., p_n-1], [p_n, p_n+1, ..., p_2n-1], ...\n\ chain(p, q, ...) --> p0, p1, ... plast, q0, q1, ...\n\ chain.from_iterable([p, q, ...]) --> p0, p1, ... plast, q0, q1, ...\n\ compress(data, selectors) --> (d[0] if s[0]), (d[1] if s[1]), ...\n\ @@ -4841,6 +5009,7 @@ itertoolsmodule_exec(PyObject *m) { PyTypeObject *typelist[] = { &accumulate_type, + &batched_type, &combinations_type, &cwr_type, &cycle_type, From webhook-mailer at python.org Mon Oct 17 22:01:46 2022 From: webhook-mailer at python.org (rhettinger) Date: Tue, 18 Oct 2022 02:01:46 -0000 Subject: [Python-checkins] Fix typos in comments (GH-98375) Message-ID: https://github.com/python/cpython/commit/9608bef84afd797ba6d16ec97439909f2f0d1095 commit: 9608bef84afd797ba6d16ec97439909f2f0d1095 branch: main author: Raymond Hettinger committer: rhettinger date: 2022-10-17T21:01:28-05:00 summary: Fix typos in comments (GH-98375) files: M Modules/itertoolsmodule.c diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index 99dc30eb412c..a5bbba14c280 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -58,7 +58,7 @@ static PyTypeObject pairwise_type; /* Note: The built-in zip() function includes a "strict" argument that is needed because that function can silently truncate data and there is no easy way for a user to detect that condition. - The same reasoning does not apply to batches() which never drops + The same reasoning does not apply to batched() which never drops data. Instead, it produces a shorter list which can be handled as the user sees fit. */ @@ -99,7 +99,7 @@ batched_new_impl(PyTypeObject *type, PyObject *iterable, Py_ssize_t n) if (n < 1) { /* We could define the n==0 case to return an empty iterator - but that is add odds with the idea that batching should + but that is at odds with the idea that batching should never throw-away input data. */ PyErr_SetString(PyExc_ValueError, "n must be at least one"); From webhook-mailer at python.org Tue Oct 18 04:42:07 2022 From: webhook-mailer at python.org (ezio-melotti) Date: Tue, 18 Oct 2022 08:42:07 -0000 Subject: [Python-checkins] gh-95913: Prepare remaining Whatsnew sections for editing (#98342) Message-ID: https://github.com/python/cpython/commit/0a0c7e5a7a516607a1268c310a2e05d574a71efc commit: 0a0c7e5a7a516607a1268c310a2e05d574a71efc branch: main author: C.A.M. Gerlach committer: ezio-melotti date: 2022-10-18T10:41:57+02:00 summary: gh-95913: Prepare remaining Whatsnew sections for editing (#98342) * Add line breaks & ref targets to Whatsnew to prepare for future changes * Use standard heading underbar symbols for H4 sections * Flatten Porting subsection; clarify scope of/link Python->CAPI sections * Move C API pending deprecations to C API section, to match the others files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index bb9538338e48..d6ad79edefb5 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -556,6 +556,8 @@ New Modules (Contributed by Sebastian Rittau in :issue:`42012`.) +.. _whatsnew311-improved-modules: + Improved Modules ================ @@ -1088,6 +1090,8 @@ fcntl the ``FD_CLOEXEC`` flag in addition. +.. _whatsnew311-optimizations: + Optimizations ============= @@ -1120,6 +1124,8 @@ Optimizations faster than Python 3.10. +.. _whatsnew311-faster-cpython: + Faster CPython ============== @@ -1132,11 +1138,16 @@ could be up to 10-60% faster. This project focuses on two major areas in Python: faster startup and faster runtime. Other optimizations not under this project are listed in `Optimizations`_. + +.. _whatsnew311-faster-startup: + Faster Startup -------------- +.. _whatsnew311-faster-imports: + Frozen imports / Static code objects -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Python caches bytecode in the :ref:`__pycache__` directory to speed up module loading. @@ -1161,11 +1172,16 @@ impact for short-running programs using Python. (Contributed by Eric Snow, Guido van Rossum and Kumar Aditya in numerous issues.) +.. _whatsnew311-faster-runtime: + Faster Runtime -------------- +.. _whatsnew311-lazy-python-frames: + Cheaper, lazy Python frames -~~~~~~~~~~~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + Python frames are created whenever Python calls a Python function. This frame holds execution information. The following are new frame optimizations: @@ -1182,10 +1198,13 @@ up significantly. We measured a 3-7% speedup in pyperformance. (Contributed by Mark Shannon in :issue:`44590`.) + .. _inline-calls: +.. _whatsnew311-inline-calls: Inlined Python function calls -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + During a Python function call, Python will call an evaluating C function to interpret that function's code. This effectively limits pure Python recursion to what's safe for the C stack. @@ -1202,8 +1221,12 @@ We measured a 1-3% improvement in pyperformance. (Contributed by Pablo Galindo and Mark Shannon in :issue:`45256`.) + +.. _whatsnew311-pep659: + PEP 659: Specializing Adaptive Interpreter -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + :pep:`659` is one of the key parts of the faster CPython project. The general idea is that while Python is a dynamic language, most code has regions where objects and types rarely change. This concept is known as *type stability*. @@ -1285,6 +1308,8 @@ Bucher, with additional help from Irit Katriel and Dennis Sweeney.) be sped up by :issue:`45947`. +.. _whatsnew311-faster-cpython-misc: + Misc ---- @@ -1296,6 +1321,9 @@ Misc time required for catching an exception by about 10%. (Contributed by Irit Katriel in :issue:`45711`.) + +.. _whatsnew311-faster-cpython-faq: + FAQ --- @@ -1330,6 +1358,8 @@ FAQ | A: No. We're still exploring other optimizations. +.. _whatsnew311-faster-cpython-about: + About ----- @@ -1339,6 +1369,8 @@ funded by Bloomberg LP to work on the project part-time. Finally, many contributors are volunteers from the community. +.. _whatsnew311-bytecode-changes: + CPython bytecode changes ======================== @@ -1395,9 +1427,17 @@ CPython bytecode changes * :opcode:`RESUME` has been added. It is a no-op. Performs internal tracing, debugging and optimization checks. + +.. _whatsnew311-deprecated: +.. _whatsnew311-python-api-deprecated: + Deprecated ========== +This section lists Python APIs that have been deprecated in Python 3.11. + +Deprecated C APIs are :ref:`listed separately `. + * Chaining :class:`classmethod` descriptors (introduced in :issue:`19072`) is now deprecated. It can no longer be used to wrap other descriptors such as :class:`property`. The core design of this feature was flawed @@ -1536,13 +1576,17 @@ Deprecated (Contributed by Serhiy Storchaka and Miro Hron?ok in :gh:`92728`.) +.. _whatsnew311-pending-removal: +.. _whatsnew311-python-api-pending-removal: + Pending Removal in Python 3.12 ============================== -The following APIs have been deprecated in earlier Python releases, +The following Python APIs have been deprecated in earlier Python releases, and will be removed in Python 3.12. -Python API: +C APIs pending removal are +:ref:`listed separately `. * :class:`pkgutil.ImpImporter` * :class:`pkgutil.ImpLoader` @@ -1571,29 +1615,17 @@ Python API: * :func:`sqlite3.OptimizedUnicode` * :func:`sqlite3.enable_shared_cache` -C API: - -* :c:func:`PyUnicode_AS_DATA` -* :c:func:`PyUnicode_AS_UNICODE` -* :c:func:`PyUnicode_AsUnicodeAndSize` -* :c:func:`PyUnicode_AsUnicode` -* :c:func:`PyUnicode_FromUnicode` -* :c:func:`PyUnicode_GET_DATA_SIZE` -* :c:func:`PyUnicode_GET_SIZE` -* :c:func:`PyUnicode_GetSize` -* :c:func:`PyUnicode_IS_COMPACT` -* :c:func:`PyUnicode_IS_READY` -* :c:func:`PyUnicode_READY` -* :c:func:`Py_UNICODE_WSTR_LENGTH` -* :c:func:`_PyUnicode_AsUnicode` -* :c:macro:`PyUnicode_WCHAR_KIND` -* :c:type:`PyUnicodeObject` -* :c:func:`PyUnicode_InternImmortal()` +.. _whatsnew311-removed: +.. _whatsnew311-python-api-removed: Removed ======= +This section lists Python APIs that have been removed in Python 3.12. + +Removed C APIs are :ref:`listed separately `. + * :class:`smtpd.MailmanProxy` is now removed as it is unusable without an external module, ``mailman``. (Contributed by Dong-hee Na in :issue:`35800`.) @@ -1686,15 +1718,18 @@ Removed of ``Tools/scripts`` and is `being developed independently `_ from the Python source tree. + +.. _whatsnew311-porting: +.. _whatsnew311-python-api-porting: + Porting to Python 3.11 ====================== This section lists previously described changes and other bugfixes -that may require changes to your code. +in the Python API that may require changes to your Python code. - -Changes in the Python API -------------------------- +Porting notes for the C API are +:ref:`listed separately `. * Prohibited passing non-:class:`concurrent.futures.ThreadPoolExecutor` executors to :meth:`loop.set_default_executor` following a deprecation in @@ -1743,6 +1778,9 @@ Changes in the Python API as meaningless when read. To get the pointer to the object's dictionary call :c:func:`PyObject_GenericGetDict` instead. + +.. _whatsnew311-build-changes: + Build Changes ============= @@ -1830,9 +1868,13 @@ Build Changes (Contributed by Serhiy Storchaka in :issue:`46996`.) +.. _whatsnew311-c-api: + C API Changes ============= +.. _whatsnew311-c-api-new-features: + New Features ------------ @@ -1896,6 +1938,9 @@ New Features * Added the :c:member:`PyConfig.safe_path` member. (Contributed by Victor Stinner in :gh:`57684`.) + +.. _whatsnew311-c-api-porting: + Porting to Python 3.11 ---------------------- @@ -2193,6 +2238,9 @@ Porting to Python 3.11 paths and then modify them, finish initialization and use :c:func:`PySys_GetObject` to retrieve :data:`sys.path` as a Python list object and modify it directly. + +.. _whatsnew311-c-api-deprecated: + Deprecated ---------- @@ -2218,6 +2266,35 @@ Deprecated * Deprecate the ``ob_shash`` member of the :c:type:`PyBytesObject`. Use :c:func:`PyObject_Hash` instead. (Contributed by Inada Naoki in :issue:`46864`.) + +.. _whatsnew311-c-api-pending-removal: + +Pending Removal in Python 3.12 +------------------------------ + +The following C APIs have been deprecated in earlier Python releases, +and will be removed in Python 3.12. + +* :c:func:`PyUnicode_AS_DATA` +* :c:func:`PyUnicode_AS_UNICODE` +* :c:func:`PyUnicode_AsUnicodeAndSize` +* :c:func:`PyUnicode_AsUnicode` +* :c:func:`PyUnicode_FromUnicode` +* :c:func:`PyUnicode_GET_DATA_SIZE` +* :c:func:`PyUnicode_GET_SIZE` +* :c:func:`PyUnicode_GetSize` +* :c:func:`PyUnicode_IS_COMPACT` +* :c:func:`PyUnicode_IS_READY` +* :c:func:`PyUnicode_READY` +* :c:func:`Py_UNICODE_WSTR_LENGTH` +* :c:func:`_PyUnicode_AsUnicode` +* :c:macro:`PyUnicode_WCHAR_KIND` +* :c:type:`PyUnicodeObject` +* :c:func:`PyUnicode_InternImmortal()` + + +.. _whatsnew311-c-api-removed: + Removed ------- From webhook-mailer at python.org Tue Oct 18 04:54:00 2022 From: webhook-mailer at python.org (miss-islington) Date: Tue, 18 Oct 2022 08:54:00 -0000 Subject: [Python-checkins] gh-95913: Prepare remaining Whatsnew sections for editing (GH-98342) Message-ID: https://github.com/python/cpython/commit/c84d4cee025b5cbcded210ed85638ffc7ef0bf09 commit: c84d4cee025b5cbcded210ed85638ffc7ef0bf09 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-18T01:53:52-07:00 summary: gh-95913: Prepare remaining Whatsnew sections for editing (GH-98342) * Add line breaks & ref targets to Whatsnew to prepare for future changes * Use standard heading underbar symbols for H4 sections * Flatten Porting subsection; clarify scope of/link Python->CAPI sections * Move C API pending deprecations to C API section, to match the others (cherry picked from commit 0a0c7e5a7a516607a1268c310a2e05d574a71efc) Co-authored-by: C.A.M. Gerlach files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index bb9538338e48..d6ad79edefb5 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -556,6 +556,8 @@ New Modules (Contributed by Sebastian Rittau in :issue:`42012`.) +.. _whatsnew311-improved-modules: + Improved Modules ================ @@ -1088,6 +1090,8 @@ fcntl the ``FD_CLOEXEC`` flag in addition. +.. _whatsnew311-optimizations: + Optimizations ============= @@ -1120,6 +1124,8 @@ Optimizations faster than Python 3.10. +.. _whatsnew311-faster-cpython: + Faster CPython ============== @@ -1132,11 +1138,16 @@ could be up to 10-60% faster. This project focuses on two major areas in Python: faster startup and faster runtime. Other optimizations not under this project are listed in `Optimizations`_. + +.. _whatsnew311-faster-startup: + Faster Startup -------------- +.. _whatsnew311-faster-imports: + Frozen imports / Static code objects -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Python caches bytecode in the :ref:`__pycache__` directory to speed up module loading. @@ -1161,11 +1172,16 @@ impact for short-running programs using Python. (Contributed by Eric Snow, Guido van Rossum and Kumar Aditya in numerous issues.) +.. _whatsnew311-faster-runtime: + Faster Runtime -------------- +.. _whatsnew311-lazy-python-frames: + Cheaper, lazy Python frames -~~~~~~~~~~~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + Python frames are created whenever Python calls a Python function. This frame holds execution information. The following are new frame optimizations: @@ -1182,10 +1198,13 @@ up significantly. We measured a 3-7% speedup in pyperformance. (Contributed by Mark Shannon in :issue:`44590`.) + .. _inline-calls: +.. _whatsnew311-inline-calls: Inlined Python function calls -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + During a Python function call, Python will call an evaluating C function to interpret that function's code. This effectively limits pure Python recursion to what's safe for the C stack. @@ -1202,8 +1221,12 @@ We measured a 1-3% improvement in pyperformance. (Contributed by Pablo Galindo and Mark Shannon in :issue:`45256`.) + +.. _whatsnew311-pep659: + PEP 659: Specializing Adaptive Interpreter -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + :pep:`659` is one of the key parts of the faster CPython project. The general idea is that while Python is a dynamic language, most code has regions where objects and types rarely change. This concept is known as *type stability*. @@ -1285,6 +1308,8 @@ Bucher, with additional help from Irit Katriel and Dennis Sweeney.) be sped up by :issue:`45947`. +.. _whatsnew311-faster-cpython-misc: + Misc ---- @@ -1296,6 +1321,9 @@ Misc time required for catching an exception by about 10%. (Contributed by Irit Katriel in :issue:`45711`.) + +.. _whatsnew311-faster-cpython-faq: + FAQ --- @@ -1330,6 +1358,8 @@ FAQ | A: No. We're still exploring other optimizations. +.. _whatsnew311-faster-cpython-about: + About ----- @@ -1339,6 +1369,8 @@ funded by Bloomberg LP to work on the project part-time. Finally, many contributors are volunteers from the community. +.. _whatsnew311-bytecode-changes: + CPython bytecode changes ======================== @@ -1395,9 +1427,17 @@ CPython bytecode changes * :opcode:`RESUME` has been added. It is a no-op. Performs internal tracing, debugging and optimization checks. + +.. _whatsnew311-deprecated: +.. _whatsnew311-python-api-deprecated: + Deprecated ========== +This section lists Python APIs that have been deprecated in Python 3.11. + +Deprecated C APIs are :ref:`listed separately `. + * Chaining :class:`classmethod` descriptors (introduced in :issue:`19072`) is now deprecated. It can no longer be used to wrap other descriptors such as :class:`property`. The core design of this feature was flawed @@ -1536,13 +1576,17 @@ Deprecated (Contributed by Serhiy Storchaka and Miro Hron?ok in :gh:`92728`.) +.. _whatsnew311-pending-removal: +.. _whatsnew311-python-api-pending-removal: + Pending Removal in Python 3.12 ============================== -The following APIs have been deprecated in earlier Python releases, +The following Python APIs have been deprecated in earlier Python releases, and will be removed in Python 3.12. -Python API: +C APIs pending removal are +:ref:`listed separately `. * :class:`pkgutil.ImpImporter` * :class:`pkgutil.ImpLoader` @@ -1571,29 +1615,17 @@ Python API: * :func:`sqlite3.OptimizedUnicode` * :func:`sqlite3.enable_shared_cache` -C API: - -* :c:func:`PyUnicode_AS_DATA` -* :c:func:`PyUnicode_AS_UNICODE` -* :c:func:`PyUnicode_AsUnicodeAndSize` -* :c:func:`PyUnicode_AsUnicode` -* :c:func:`PyUnicode_FromUnicode` -* :c:func:`PyUnicode_GET_DATA_SIZE` -* :c:func:`PyUnicode_GET_SIZE` -* :c:func:`PyUnicode_GetSize` -* :c:func:`PyUnicode_IS_COMPACT` -* :c:func:`PyUnicode_IS_READY` -* :c:func:`PyUnicode_READY` -* :c:func:`Py_UNICODE_WSTR_LENGTH` -* :c:func:`_PyUnicode_AsUnicode` -* :c:macro:`PyUnicode_WCHAR_KIND` -* :c:type:`PyUnicodeObject` -* :c:func:`PyUnicode_InternImmortal()` +.. _whatsnew311-removed: +.. _whatsnew311-python-api-removed: Removed ======= +This section lists Python APIs that have been removed in Python 3.12. + +Removed C APIs are :ref:`listed separately `. + * :class:`smtpd.MailmanProxy` is now removed as it is unusable without an external module, ``mailman``. (Contributed by Dong-hee Na in :issue:`35800`.) @@ -1686,15 +1718,18 @@ Removed of ``Tools/scripts`` and is `being developed independently `_ from the Python source tree. + +.. _whatsnew311-porting: +.. _whatsnew311-python-api-porting: + Porting to Python 3.11 ====================== This section lists previously described changes and other bugfixes -that may require changes to your code. +in the Python API that may require changes to your Python code. - -Changes in the Python API -------------------------- +Porting notes for the C API are +:ref:`listed separately `. * Prohibited passing non-:class:`concurrent.futures.ThreadPoolExecutor` executors to :meth:`loop.set_default_executor` following a deprecation in @@ -1743,6 +1778,9 @@ Changes in the Python API as meaningless when read. To get the pointer to the object's dictionary call :c:func:`PyObject_GenericGetDict` instead. + +.. _whatsnew311-build-changes: + Build Changes ============= @@ -1830,9 +1868,13 @@ Build Changes (Contributed by Serhiy Storchaka in :issue:`46996`.) +.. _whatsnew311-c-api: + C API Changes ============= +.. _whatsnew311-c-api-new-features: + New Features ------------ @@ -1896,6 +1938,9 @@ New Features * Added the :c:member:`PyConfig.safe_path` member. (Contributed by Victor Stinner in :gh:`57684`.) + +.. _whatsnew311-c-api-porting: + Porting to Python 3.11 ---------------------- @@ -2193,6 +2238,9 @@ Porting to Python 3.11 paths and then modify them, finish initialization and use :c:func:`PySys_GetObject` to retrieve :data:`sys.path` as a Python list object and modify it directly. + +.. _whatsnew311-c-api-deprecated: + Deprecated ---------- @@ -2218,6 +2266,35 @@ Deprecated * Deprecate the ``ob_shash`` member of the :c:type:`PyBytesObject`. Use :c:func:`PyObject_Hash` instead. (Contributed by Inada Naoki in :issue:`46864`.) + +.. _whatsnew311-c-api-pending-removal: + +Pending Removal in Python 3.12 +------------------------------ + +The following C APIs have been deprecated in earlier Python releases, +and will be removed in Python 3.12. + +* :c:func:`PyUnicode_AS_DATA` +* :c:func:`PyUnicode_AS_UNICODE` +* :c:func:`PyUnicode_AsUnicodeAndSize` +* :c:func:`PyUnicode_AsUnicode` +* :c:func:`PyUnicode_FromUnicode` +* :c:func:`PyUnicode_GET_DATA_SIZE` +* :c:func:`PyUnicode_GET_SIZE` +* :c:func:`PyUnicode_GetSize` +* :c:func:`PyUnicode_IS_COMPACT` +* :c:func:`PyUnicode_IS_READY` +* :c:func:`PyUnicode_READY` +* :c:func:`Py_UNICODE_WSTR_LENGTH` +* :c:func:`_PyUnicode_AsUnicode` +* :c:macro:`PyUnicode_WCHAR_KIND` +* :c:type:`PyUnicodeObject` +* :c:func:`PyUnicode_InternImmortal()` + + +.. _whatsnew311-c-api-removed: + Removed ------- From webhook-mailer at python.org Tue Oct 18 05:26:59 2022 From: webhook-mailer at python.org (ezio-melotti) Date: Tue, 18 Oct 2022 09:26:59 -0000 Subject: [Python-checkins] gh-95913: Copyedit, xref and organize enum section (#98295) Message-ID: https://github.com/python/cpython/commit/73e5180faf37e2d362e13f4ef12955a8b8535d7b commit: 73e5180faf37e2d362e13f4ef12955a8b8535d7b branch: main author: C.A.M. Gerlach committer: ezio-melotti date: 2022-10-18T11:26:24+02:00 summary: gh-95913: Copyedit, xref and organize enum section (#98295) * Whatsnew: Convert literals in enum section to actual x-references * Whatsnew: Rewrite enum section for clear and consistant phrasing * Whatsnew: Combine directly related enum items instead of seperating them * gh-98250: Describe __str__/__format__ changes more clearly/accurately * Tweak enum section language per feedback from Ethan files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index d6ad79edefb5..97e8600b5f9b 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -632,48 +632,74 @@ datetime formats (barring only those that support fractional hours and minutes). (Contributed by Paul Ganssle in :gh:`80010`.) -enum ----- - -* ``EnumMeta`` renamed to ``EnumType`` (``EnumMeta`` kept as alias). - -* ``StrEnum`` added -- enum members are and must be strings. - -* ``ReprEnum`` added -- causes only the ``__repr__`` to be modified, not the - ``__str__`` nor the ``__format__``. - -* ``FlagBoundary`` added -- controls behavior when invalid values are given to - a flag. - -* ``EnumCheck`` added -- used by ``verify`` to ensure various constraints. -* ``verify`` added -- function to ensure given ``EnumCheck`` constraints. +.. _whatsnew311-enum: -* ``member`` added -- decorator to ensure given object is converted to an enum - member. - -* ``nonmember`` added -- decorator to ensure given object is not converted to - an enum member. - -* ``property`` added -- use instead of ``types.DynamicClassAttribute``. - -* ``global_enum`` added -- enum decorator to adjust ``__repr__`` and ``__str__`` - to show members in the global context -- see ``re.RegexFlag`` for an example. - -* ``Flag`` enhancements: members support length, iteration, and containment - checks. - -* ``Enum``/``Flag`` fixes: members are now defined before ``__init_subclass__`` - is called; ``dir()`` now includes methods, etc., from mixed-in data types. +enum +---- -* ``Flag`` fixes: only primary values (power of two) are considered canonical - while composite values (3, 6, 10, etc.) are considered aliases; inverted - flags are coerced to their positive equivalent. +* Renamed :class:`!EnumMeta` to :class:`~enum.EnumType` + (:class:`!EnumMeta` kept as an alias). + +* Added :class:`~enum.StrEnum`, + with members that can be used as (and must be) strings. + +* Added :class:`~enum.ReprEnum`, + which only modifies the :meth:`~object.__repr__` of members + while returning their literal values (rather than names) + for :meth:`~object.__str__` and :meth:`~object.__format__` + (used by :func:`str`, :func:`format` and :term:`f-string`\s). + +* Changed :class:`~enum.IntEnum`, :class:`~enum.IntFlag` and :class:`~enum.StrEnum` + to now inherit from :class:`ReprEnum`, + so their :func:`str` output now matches :func:`format` + (both ``str(AnIntEnum.ONE)`` and ``format(AnIntEnum.ONE)`` return ``'1'``, + whereas before ``str(AnIntEnum.ONE)`` returned ``'AnIntEnum.ONE'``. + +* Changed :meth:`Enum.__format__() ` + (the default for :func:`format`, :meth:`str.format` and :term:`f-string`\s) + of enums with mixed-in types (e.g. :class:`int`, :class:`str`) + to also include the class name in the output, not just the member's key. + This matches the existing behavior of :meth:`enum.Enum.__str__`, + returning e.g. ``'AnEnum.MEMBER'`` for an enum ``AnEnum(str, Enum)`` + instead of just ``'MEMBER'``. + +* Added a new *boundary* class parameter to :class:`~enum.Flag` enums + and the :class:`~enum.FlagBoundary` enum with its options, + to control how to handle out-of-range flag values. + +* Added the :func:`~enum.verify` enum decorator + and the :class:`~enum.EnumCheck` enum with its options, + to check enum classes against several specific constraints. + +* Added the :func:`~enum.member` and :func:`~enum.nonmember` decorators, + to ensure the decorated object is/is not converted to an enum member. + +* Added the :func:`~enum.property` decorator, + which works like :func:`property` except for enums. + Use this instead of :func:`types.DynamicClassAttribute`. + +* Added the :func:`~enum.global_enum` enum decorator, + which adjusts :meth:`~object.__repr__` and :meth:`~object.__str__` + to show values as members of their module rather than the enum class. + For example, ``'re.ASCII'`` for the :data:`~re.ASCII` member + of :class:`re.RegexFlag` rather than ``'RegexFlag.ASCII'``. + +* Enhanced :class:`~enum.Flag` to support + :func:`len`, iteration and :keyword:`in`/:keyword:`not in` on its members. + For example, the following now works: + ``len(AFlag(3)) == 2 and list(AFlag(3)) == (AFlag.ONE, AFlag.TWO)`` + +* Changed :class:`~enum.Enum` and :class:`~enum.Flag` + so that members are now defined + before :meth:`~object.__init_subclass__` is called; + :func:`dir` now includes methods, etc., from mixed-in data types. + +* Changed :class:`~enum.Flag` + to only consider primary values (power of two) canonical + while composite values (``3``, ``6``, ``10``, etc.) are considered aliases; + inverted flags are coerced to their positive equivalent. -* ``IntEnum`` / ``IntFlag`` / ``StrEnum`` fixes: these now inherit from - ``ReprEnum`` so the ``str()`` output now matches ``format()`` output, - which is the data types' (so both ``str(AnIntEnum.ONE)`` and - ``format(AnIntEnum.ONE)`` is equal to ``'1'``). fractions --------- From webhook-mailer at python.org Tue Oct 18 05:34:52 2022 From: webhook-mailer at python.org (miss-islington) Date: Tue, 18 Oct 2022 09:34:52 -0000 Subject: [Python-checkins] gh-95913: Copyedit, xref and organize enum section (GH-98295) Message-ID: https://github.com/python/cpython/commit/d798b595ffed4560f1de068206cae8c2bf567085 commit: d798b595ffed4560f1de068206cae8c2bf567085 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-18T02:34:47-07:00 summary: gh-95913: Copyedit, xref and organize enum section (GH-98295) * Whatsnew: Convert literals in enum section to actual x-references * Whatsnew: Rewrite enum section for clear and consistant phrasing * Whatsnew: Combine directly related enum items instead of seperating them * gh-98250: Describe __str__/__format__ changes more clearly/accurately * Tweak enum section language per feedback from Ethan (cherry picked from commit 73e5180faf37e2d362e13f4ef12955a8b8535d7b) Co-authored-by: C.A.M. Gerlach files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index d6ad79edefb5..97e8600b5f9b 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -632,48 +632,74 @@ datetime formats (barring only those that support fractional hours and minutes). (Contributed by Paul Ganssle in :gh:`80010`.) -enum ----- - -* ``EnumMeta`` renamed to ``EnumType`` (``EnumMeta`` kept as alias). - -* ``StrEnum`` added -- enum members are and must be strings. - -* ``ReprEnum`` added -- causes only the ``__repr__`` to be modified, not the - ``__str__`` nor the ``__format__``. - -* ``FlagBoundary`` added -- controls behavior when invalid values are given to - a flag. - -* ``EnumCheck`` added -- used by ``verify`` to ensure various constraints. -* ``verify`` added -- function to ensure given ``EnumCheck`` constraints. +.. _whatsnew311-enum: -* ``member`` added -- decorator to ensure given object is converted to an enum - member. - -* ``nonmember`` added -- decorator to ensure given object is not converted to - an enum member. - -* ``property`` added -- use instead of ``types.DynamicClassAttribute``. - -* ``global_enum`` added -- enum decorator to adjust ``__repr__`` and ``__str__`` - to show members in the global context -- see ``re.RegexFlag`` for an example. - -* ``Flag`` enhancements: members support length, iteration, and containment - checks. - -* ``Enum``/``Flag`` fixes: members are now defined before ``__init_subclass__`` - is called; ``dir()`` now includes methods, etc., from mixed-in data types. +enum +---- -* ``Flag`` fixes: only primary values (power of two) are considered canonical - while composite values (3, 6, 10, etc.) are considered aliases; inverted - flags are coerced to their positive equivalent. +* Renamed :class:`!EnumMeta` to :class:`~enum.EnumType` + (:class:`!EnumMeta` kept as an alias). + +* Added :class:`~enum.StrEnum`, + with members that can be used as (and must be) strings. + +* Added :class:`~enum.ReprEnum`, + which only modifies the :meth:`~object.__repr__` of members + while returning their literal values (rather than names) + for :meth:`~object.__str__` and :meth:`~object.__format__` + (used by :func:`str`, :func:`format` and :term:`f-string`\s). + +* Changed :class:`~enum.IntEnum`, :class:`~enum.IntFlag` and :class:`~enum.StrEnum` + to now inherit from :class:`ReprEnum`, + so their :func:`str` output now matches :func:`format` + (both ``str(AnIntEnum.ONE)`` and ``format(AnIntEnum.ONE)`` return ``'1'``, + whereas before ``str(AnIntEnum.ONE)`` returned ``'AnIntEnum.ONE'``. + +* Changed :meth:`Enum.__format__() ` + (the default for :func:`format`, :meth:`str.format` and :term:`f-string`\s) + of enums with mixed-in types (e.g. :class:`int`, :class:`str`) + to also include the class name in the output, not just the member's key. + This matches the existing behavior of :meth:`enum.Enum.__str__`, + returning e.g. ``'AnEnum.MEMBER'`` for an enum ``AnEnum(str, Enum)`` + instead of just ``'MEMBER'``. + +* Added a new *boundary* class parameter to :class:`~enum.Flag` enums + and the :class:`~enum.FlagBoundary` enum with its options, + to control how to handle out-of-range flag values. + +* Added the :func:`~enum.verify` enum decorator + and the :class:`~enum.EnumCheck` enum with its options, + to check enum classes against several specific constraints. + +* Added the :func:`~enum.member` and :func:`~enum.nonmember` decorators, + to ensure the decorated object is/is not converted to an enum member. + +* Added the :func:`~enum.property` decorator, + which works like :func:`property` except for enums. + Use this instead of :func:`types.DynamicClassAttribute`. + +* Added the :func:`~enum.global_enum` enum decorator, + which adjusts :meth:`~object.__repr__` and :meth:`~object.__str__` + to show values as members of their module rather than the enum class. + For example, ``'re.ASCII'`` for the :data:`~re.ASCII` member + of :class:`re.RegexFlag` rather than ``'RegexFlag.ASCII'``. + +* Enhanced :class:`~enum.Flag` to support + :func:`len`, iteration and :keyword:`in`/:keyword:`not in` on its members. + For example, the following now works: + ``len(AFlag(3)) == 2 and list(AFlag(3)) == (AFlag.ONE, AFlag.TWO)`` + +* Changed :class:`~enum.Enum` and :class:`~enum.Flag` + so that members are now defined + before :meth:`~object.__init_subclass__` is called; + :func:`dir` now includes methods, etc., from mixed-in data types. + +* Changed :class:`~enum.Flag` + to only consider primary values (power of two) canonical + while composite values (``3``, ``6``, ``10``, etc.) are considered aliases; + inverted flags are coerced to their positive equivalent. -* ``IntEnum`` / ``IntFlag`` / ``StrEnum`` fixes: these now inherit from - ``ReprEnum`` so the ``str()`` output now matches ``format()`` output, - which is the data types' (so both ``str(AnIntEnum.ONE)`` and - ``format(AnIntEnum.ONE)`` is equal to ``'1'``). fractions --------- From webhook-mailer at python.org Tue Oct 18 09:28:25 2022 From: webhook-mailer at python.org (JulienPalard) Date: Tue, 18 Oct 2022 13:28:25 -0000 Subject: [Python-checkins] Doc: missing underscore in hyperlink. (GH-98391) Message-ID: https://github.com/python/cpython/commit/0bbea545e35d17b10ea95d0d10f34e9b5a4e6c53 commit: 0bbea545e35d17b10ea95d0d10f34e9b5a4e6c53 branch: main author: Julien Palard committer: JulienPalard date: 2022-10-18T15:28:19+02:00 summary: Doc: missing underscore in hyperlink. (GH-98391) files: M Doc/library/importlib.metadata.rst diff --git a/Doc/library/importlib.metadata.rst b/Doc/library/importlib.metadata.rst index 094c2688a8cd..4b94ccc49c47 100644 --- a/Doc/library/importlib.metadata.rst +++ b/Doc/library/importlib.metadata.rst @@ -211,7 +211,7 @@ all the metadata in a JSON-compatible form per :PEP:`566`:: The actual type of the object returned by ``metadata()`` is an implementation detail and should be accessed only through the interface described by the - `PackageMetadata protocol `. + `PackageMetadata protocol `_. .. versionchanged:: 3.10 The ``Description`` is now included in the metadata when presented From webhook-mailer at python.org Tue Oct 18 09:42:16 2022 From: webhook-mailer at python.org (miss-islington) Date: Tue, 18 Oct 2022 13:42:16 -0000 Subject: [Python-checkins] gh-98378: Add small format string example to strftime comments (GH-98379) Message-ID: https://github.com/python/cpython/commit/6ccca69d0d313135b2fbb2aa92c69c315be779c6 commit: 6ccca69d0d313135b2fbb2aa92c69c315be779c6 branch: main author: Alex Zvorygin committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-18T06:42:10-07:00 summary: gh-98378: Add small format string example to strftime comments (GH-98379) A small example of what a full date and time would look like would help a lot of developers who may not realize that they should investigate `time.h`'s `strftime`, run `man strftime`, or click through a series of docs on the python docs before they get to the actual [definition here](https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes) which still doesn't have an obvious copy-pastable example of "what the heck format does this thing actually expect?". Automerge-Triggered-By: GH:rhettinger files: M Lib/datetime.py diff --git a/Lib/datetime.py b/Lib/datetime.py index 007114ae6220..01742680a95b 100644 --- a/Lib/datetime.py +++ b/Lib/datetime.py @@ -1033,7 +1033,11 @@ def ctime(self): self._day, self._year) def strftime(self, fmt): - "Format using strftime()." + """ + Format using strftime(). + + Example: "%d/%m/%Y, %H:%M:%S" + """ return _wrap_strftime(self, fmt, self.timetuple()) def __format__(self, fmt): From webhook-mailer at python.org Tue Oct 18 09:46:24 2022 From: webhook-mailer at python.org (JulienPalard) Date: Tue, 18 Oct 2022 13:46:24 -0000 Subject: [Python-checkins] Doc: Found some remaining default roles. (GH-98392) Message-ID: https://github.com/python/cpython/commit/2eb503e4dde9c9b0443e799e02d55bc053ef1c64 commit: 2eb503e4dde9c9b0443e799e02d55bc053ef1c64 branch: main author: Julien Palard committer: JulienPalard date: 2022-10-18T15:46:18+02:00 summary: Doc: Found some remaining default roles. (GH-98392) files: M Doc/c-api/init.rst M Doc/library/asyncio-api-index.rst M Doc/library/pathlib.rst M Doc/library/subprocess.rst diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index 9b7383373e98..afb17719a77a 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -1933,7 +1933,7 @@ is not possible due to its implementation being opaque at build time. .. note:: A freed key becomes a dangling pointer. You should reset the key to - `NULL`. + ``NULL``. Methods diff --git a/Doc/library/asyncio-api-index.rst b/Doc/library/asyncio-api-index.rst index 54c1cd6582e4..ad475150fe7d 100644 --- a/Doc/library/asyncio-api-index.rst +++ b/Doc/library/asyncio-api-index.rst @@ -57,7 +57,7 @@ await on multiple things with timeouts. - Monitor for completion. * - :func:`timeout` - - Run with a timeout. Useful in cases when `wait_for` is not suitable. + - Run with a timeout. Useful in cases when ``wait_for`` is not suitable. * - :func:`to_thread` - Asynchronously run a function in a separate OS thread. diff --git a/Doc/library/pathlib.rst b/Doc/library/pathlib.rst index 1375ce1aef95..4e9ea39895b4 100644 --- a/Doc/library/pathlib.rst +++ b/Doc/library/pathlib.rst @@ -391,7 +391,7 @@ Pure paths provide the following methods and properties: If you want to walk an arbitrary filesystem path upwards, it is recommended to first call :meth:`Path.resolve` so as to resolve - symlinks and eliminate `".."` components. + symlinks and eliminate ``".."`` components. .. data:: PurePath.name diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst index dee5bd879db5..51b9e38b7b6c 100644 --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -829,7 +829,7 @@ Instances of the :class:`Popen` class have the following methods: On Windows, SIGTERM is an alias for :meth:`terminate`. CTRL_C_EVENT and CTRL_BREAK_EVENT can be sent to processes started with a *creationflags* - parameter which includes `CREATE_NEW_PROCESS_GROUP`. + parameter which includes ``CREATE_NEW_PROCESS_GROUP``. .. method:: Popen.terminate() From webhook-mailer at python.org Tue Oct 18 10:48:26 2022 From: webhook-mailer at python.org (pfmoore) Date: Tue, 18 Oct 2022 14:48:26 -0000 Subject: [Python-checkins] gh-98331: Update bundled pip to 22.3 (#98332) Message-ID: https://github.com/python/cpython/commit/9da5215000920870eeddd78af92da4c98099706c commit: 9da5215000920870eeddd78af92da4c98099706c branch: main author: Paul Moore committer: pfmoore date: 2022-10-18T15:48:14+01:00 summary: gh-98331: Update bundled pip to 22.3 (#98332) files: A Lib/ensurepip/_bundled/pip-22.3-py3-none-any.whl A Lib/ensurepip/_bundled/setuptools-65.5.0-py3-none-any.whl A Misc/NEWS.d/next/Library/2022-10-16-15-31-50.gh-issue-98331.Y5kPOX.rst D Lib/ensurepip/_bundled/pip-22.2.2-py3-none-any.whl D Lib/ensurepip/_bundled/setuptools-63.2.0-py3-none-any.whl M Lib/ensurepip/__init__.py diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py index 33c91801b0aa..4a6ba9cedf3d 100644 --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -10,8 +10,8 @@ __all__ = ["version", "bootstrap"] _PACKAGE_NAMES = ('setuptools', 'pip') -_SETUPTOOLS_VERSION = "63.2.0" -_PIP_VERSION = "22.2.2" +_SETUPTOOLS_VERSION = "65.5.0" +_PIP_VERSION = "22.3" _PROJECTS = [ ("setuptools", _SETUPTOOLS_VERSION, "py3"), ("pip", _PIP_VERSION, "py3"), diff --git a/Lib/ensurepip/_bundled/pip-22.2.2-py3-none-any.whl b/Lib/ensurepip/_bundled/pip-22.3-py3-none-any.whl similarity index 62% rename from Lib/ensurepip/_bundled/pip-22.2.2-py3-none-any.whl rename to Lib/ensurepip/_bundled/pip-22.3-py3-none-any.whl index 03099718b0bc..d6fccd9de92a 100644 Binary files a/Lib/ensurepip/_bundled/pip-22.2.2-py3-none-any.whl and b/Lib/ensurepip/_bundled/pip-22.3-py3-none-any.whl differ diff --git a/Lib/ensurepip/_bundled/setuptools-63.2.0-py3-none-any.whl b/Lib/ensurepip/_bundled/setuptools-65.5.0-py3-none-any.whl similarity index 61% rename from Lib/ensurepip/_bundled/setuptools-63.2.0-py3-none-any.whl rename to Lib/ensurepip/_bundled/setuptools-65.5.0-py3-none-any.whl index e3b5446eb59c..123a13e2c6b2 100644 Binary files a/Lib/ensurepip/_bundled/setuptools-63.2.0-py3-none-any.whl and b/Lib/ensurepip/_bundled/setuptools-65.5.0-py3-none-any.whl differ diff --git a/Misc/NEWS.d/next/Library/2022-10-16-15-31-50.gh-issue-98331.Y5kPOX.rst b/Misc/NEWS.d/next/Library/2022-10-16-15-31-50.gh-issue-98331.Y5kPOX.rst new file mode 100644 index 000000000000..b4cf94310af6 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-16-15-31-50.gh-issue-98331.Y5kPOX.rst @@ -0,0 +1 @@ +Update the bundled copies of pip and setuptools to versions 22.3 and 65.5.0 respectively. From webhook-mailer at python.org Tue Oct 18 11:22:12 2022 From: webhook-mailer at python.org (gvanrossum) Date: Tue, 18 Oct 2022 15:22:12 -0000 Subject: [Python-checkins] [3.11] gh-98174: Handle EPROTOTYPE under macOS in test_sendfile_fallback_close_peer_in_the_middle_of_receiving (GH-98316) (#98357) Message-ID: https://github.com/python/cpython/commit/0bba980c5f67e72e8fe4803957ac82748d3b483e commit: 0bba980c5f67e72e8fe4803957ac82748d3b483e branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: gvanrossum date: 2022-10-18T08:21:58-07:00 summary: [3.11] gh-98174: Handle EPROTOTYPE under macOS in test_sendfile_fallback_close_peer_in_the_middle_of_receiving (GH-98316) (#98357) Co-authored-by: Nikita Sobolev (cherry picked from commit 3e82ad05b18d004e4d01fdb643344d6a2bf11900) Co-authored-by: fancidev files: M Lib/test/test_asyncio/test_sendfile.py diff --git a/Lib/test/test_asyncio/test_sendfile.py b/Lib/test/test_asyncio/test_sendfile.py index a10504b1c413..0198da21d770 100644 --- a/Lib/test/test_asyncio/test_sendfile.py +++ b/Lib/test/test_asyncio/test_sendfile.py @@ -1,6 +1,7 @@ """Tests for sendfile functionality.""" import asyncio +import errno import os import socket import sys @@ -484,8 +485,17 @@ def sendfile_native(transp, file, offset, count): srv_proto, cli_proto = self.prepare_sendfile(close_after=1024) with self.assertRaises(ConnectionError): - self.run_loop( - self.loop.sendfile(cli_proto.transport, self.file)) + try: + self.run_loop( + self.loop.sendfile(cli_proto.transport, self.file)) + except OSError as e: + # macOS may raise OSError of EPROTOTYPE when writing to a + # socket that is in the process of closing down. + if e.errno == errno.EPROTOTYPE and sys.platform == "darwin": + raise ConnectionError + else: + raise + self.run_loop(srv_proto.done) self.assertTrue(1024 <= srv_proto.nbytes < len(self.DATA), From webhook-mailer at python.org Tue Oct 18 11:36:29 2022 From: webhook-mailer at python.org (pfmoore) Date: Tue, 18 Oct 2022 15:36:29 -0000 Subject: [Python-checkins] [3.10] gh-98331: Update bundled pip to 22.3 (GH-98332) (gh-98399) Message-ID: https://github.com/python/cpython/commit/676cdea18fc1635ecdb19e6f4f58c40251987442 commit: 676cdea18fc1635ecdb19e6f4f58c40251987442 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: pfmoore date: 2022-10-18T16:36:23+01:00 summary: [3.10] gh-98331: Update bundled pip to 22.3 (GH-98332) (gh-98399) files: A Lib/ensurepip/_bundled/pip-22.3-py3-none-any.whl A Lib/ensurepip/_bundled/setuptools-65.5.0-py3-none-any.whl A Misc/NEWS.d/next/Library/2022-10-16-15-31-50.gh-issue-98331.Y5kPOX.rst D Lib/ensurepip/_bundled/pip-22.2.2-py3-none-any.whl D Lib/ensurepip/_bundled/setuptools-63.2.0-py3-none-any.whl M Lib/ensurepip/__init__.py diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py index 1826cdcf91ab..ba07d590b8b2 100644 --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -11,8 +11,8 @@ __all__ = ["version", "bootstrap"] _PACKAGE_NAMES = ('setuptools', 'pip') -_SETUPTOOLS_VERSION = "63.2.0" -_PIP_VERSION = "22.2.2" +_SETUPTOOLS_VERSION = "65.5.0" +_PIP_VERSION = "22.3" _PROJECTS = [ ("setuptools", _SETUPTOOLS_VERSION, "py3"), ("pip", _PIP_VERSION, "py3"), diff --git a/Lib/ensurepip/_bundled/pip-22.2.2-py3-none-any.whl b/Lib/ensurepip/_bundled/pip-22.3-py3-none-any.whl similarity index 62% rename from Lib/ensurepip/_bundled/pip-22.2.2-py3-none-any.whl rename to Lib/ensurepip/_bundled/pip-22.3-py3-none-any.whl index 03099718b0bc..d6fccd9de92a 100644 Binary files a/Lib/ensurepip/_bundled/pip-22.2.2-py3-none-any.whl and b/Lib/ensurepip/_bundled/pip-22.3-py3-none-any.whl differ diff --git a/Lib/ensurepip/_bundled/setuptools-63.2.0-py3-none-any.whl b/Lib/ensurepip/_bundled/setuptools-65.5.0-py3-none-any.whl similarity index 61% rename from Lib/ensurepip/_bundled/setuptools-63.2.0-py3-none-any.whl rename to Lib/ensurepip/_bundled/setuptools-65.5.0-py3-none-any.whl index e3b5446eb59c..123a13e2c6b2 100644 Binary files a/Lib/ensurepip/_bundled/setuptools-63.2.0-py3-none-any.whl and b/Lib/ensurepip/_bundled/setuptools-65.5.0-py3-none-any.whl differ diff --git a/Misc/NEWS.d/next/Library/2022-10-16-15-31-50.gh-issue-98331.Y5kPOX.rst b/Misc/NEWS.d/next/Library/2022-10-16-15-31-50.gh-issue-98331.Y5kPOX.rst new file mode 100644 index 000000000000..b4cf94310af6 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-16-15-31-50.gh-issue-98331.Y5kPOX.rst @@ -0,0 +1 @@ +Update the bundled copies of pip and setuptools to versions 22.3 and 65.5.0 respectively. From webhook-mailer at python.org Tue Oct 18 11:36:49 2022 From: webhook-mailer at python.org (pfmoore) Date: Tue, 18 Oct 2022 15:36:49 -0000 Subject: [Python-checkins] [3.11] gh-98331: Update bundled pip to 22.3 (GH-98332) (gh-98400) Message-ID: https://github.com/python/cpython/commit/651a7300dc7962bf6f9f62c886af8cbdcf1334da commit: 651a7300dc7962bf6f9f62c886af8cbdcf1334da branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: pfmoore date: 2022-10-18T16:36:42+01:00 summary: [3.11] gh-98331: Update bundled pip to 22.3 (GH-98332) (gh-98400) files: A Lib/ensurepip/_bundled/pip-22.3-py3-none-any.whl A Lib/ensurepip/_bundled/setuptools-65.5.0-py3-none-any.whl A Misc/NEWS.d/next/Library/2022-10-16-15-31-50.gh-issue-98331.Y5kPOX.rst D Lib/ensurepip/_bundled/pip-22.2.2-py3-none-any.whl D Lib/ensurepip/_bundled/setuptools-63.2.0-py3-none-any.whl M Lib/ensurepip/__init__.py diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py index 33c91801b0aa..4a6ba9cedf3d 100644 --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -10,8 +10,8 @@ __all__ = ["version", "bootstrap"] _PACKAGE_NAMES = ('setuptools', 'pip') -_SETUPTOOLS_VERSION = "63.2.0" -_PIP_VERSION = "22.2.2" +_SETUPTOOLS_VERSION = "65.5.0" +_PIP_VERSION = "22.3" _PROJECTS = [ ("setuptools", _SETUPTOOLS_VERSION, "py3"), ("pip", _PIP_VERSION, "py3"), diff --git a/Lib/ensurepip/_bundled/pip-22.2.2-py3-none-any.whl b/Lib/ensurepip/_bundled/pip-22.3-py3-none-any.whl similarity index 62% rename from Lib/ensurepip/_bundled/pip-22.2.2-py3-none-any.whl rename to Lib/ensurepip/_bundled/pip-22.3-py3-none-any.whl index 03099718b0bc..d6fccd9de92a 100644 Binary files a/Lib/ensurepip/_bundled/pip-22.2.2-py3-none-any.whl and b/Lib/ensurepip/_bundled/pip-22.3-py3-none-any.whl differ diff --git a/Lib/ensurepip/_bundled/setuptools-63.2.0-py3-none-any.whl b/Lib/ensurepip/_bundled/setuptools-65.5.0-py3-none-any.whl similarity index 61% rename from Lib/ensurepip/_bundled/setuptools-63.2.0-py3-none-any.whl rename to Lib/ensurepip/_bundled/setuptools-65.5.0-py3-none-any.whl index e3b5446eb59c..123a13e2c6b2 100644 Binary files a/Lib/ensurepip/_bundled/setuptools-63.2.0-py3-none-any.whl and b/Lib/ensurepip/_bundled/setuptools-65.5.0-py3-none-any.whl differ diff --git a/Misc/NEWS.d/next/Library/2022-10-16-15-31-50.gh-issue-98331.Y5kPOX.rst b/Misc/NEWS.d/next/Library/2022-10-16-15-31-50.gh-issue-98331.Y5kPOX.rst new file mode 100644 index 000000000000..b4cf94310af6 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-16-15-31-50.gh-issue-98331.Y5kPOX.rst @@ -0,0 +1 @@ +Update the bundled copies of pip and setuptools to versions 22.3 and 65.5.0 respectively. From webhook-mailer at python.org Tue Oct 18 11:38:45 2022 From: webhook-mailer at python.org (vsajip) Date: Tue, 18 Oct 2022 15:38:45 -0000 Subject: [Python-checkins] [3.11] gh-93858: Prevent error when activating venv in nested fish instances (GH-93931) (GH-98402) Message-ID: https://github.com/python/cpython/commit/11e1ed0aed8a653c39a9b4f6c868247c35b61ac2 commit: 11e1ed0aed8a653c39a9b4f6c868247c35b61ac2 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: vsajip date: 2022-10-18T16:38:39+01:00 summary: [3.11] gh-93858: Prevent error when activating venv in nested fish instances (GH-93931) (GH-98402) Co-authored-by: Thomas B. Brunner files: A Misc/NEWS.d/next/Library/2022-06-17-12-02-30.gh-issue-93858.R49ARc.rst M Lib/venv/scripts/posix/activate.fish diff --git a/Lib/venv/scripts/posix/activate.fish b/Lib/venv/scripts/posix/activate.fish index e40a1d714894..9aa4446005f4 100644 --- a/Lib/venv/scripts/posix/activate.fish +++ b/Lib/venv/scripts/posix/activate.fish @@ -13,10 +13,13 @@ function deactivate -d "Exit virtual environment and return to normal shell env end if test -n "$_OLD_FISH_PROMPT_OVERRIDE" - functions -e fish_prompt set -e _OLD_FISH_PROMPT_OVERRIDE - functions -c _old_fish_prompt fish_prompt - functions -e _old_fish_prompt + # prevents error when using nested fish instances (Issue #93858) + if functions -q _old_fish_prompt + functions -e fish_prompt + functions -c _old_fish_prompt fish_prompt + functions -e _old_fish_prompt + end end set -e VIRTUAL_ENV diff --git a/Misc/NEWS.d/next/Library/2022-06-17-12-02-30.gh-issue-93858.R49ARc.rst b/Misc/NEWS.d/next/Library/2022-06-17-12-02-30.gh-issue-93858.R49ARc.rst new file mode 100644 index 000000000000..508ba626bab4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-06-17-12-02-30.gh-issue-93858.R49ARc.rst @@ -0,0 +1 @@ +Prevent error when activating venv in nested fish instances. From webhook-mailer at python.org Tue Oct 18 11:39:12 2022 From: webhook-mailer at python.org (vsajip) Date: Tue, 18 Oct 2022 15:39:12 -0000 Subject: [Python-checkins] [3.10] gh-93858: Prevent error when activating venv in nested fish instances (GH-93931) (GH-98403) Message-ID: https://github.com/python/cpython/commit/ce87ab4dc5683fcc990c05e3875eff982824a144 commit: ce87ab4dc5683fcc990c05e3875eff982824a144 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: vsajip date: 2022-10-18T16:39:06+01:00 summary: [3.10] gh-93858: Prevent error when activating venv in nested fish instances (GH-93931) (GH-98403) Co-authored-by: Thomas B. Brunner files: A Misc/NEWS.d/next/Library/2022-06-17-12-02-30.gh-issue-93858.R49ARc.rst M Lib/venv/scripts/posix/activate.fish diff --git a/Lib/venv/scripts/posix/activate.fish b/Lib/venv/scripts/posix/activate.fish index e40a1d714894..9aa4446005f4 100644 --- a/Lib/venv/scripts/posix/activate.fish +++ b/Lib/venv/scripts/posix/activate.fish @@ -13,10 +13,13 @@ function deactivate -d "Exit virtual environment and return to normal shell env end if test -n "$_OLD_FISH_PROMPT_OVERRIDE" - functions -e fish_prompt set -e _OLD_FISH_PROMPT_OVERRIDE - functions -c _old_fish_prompt fish_prompt - functions -e _old_fish_prompt + # prevents error when using nested fish instances (Issue #93858) + if functions -q _old_fish_prompt + functions -e fish_prompt + functions -c _old_fish_prompt fish_prompt + functions -e _old_fish_prompt + end end set -e VIRTUAL_ENV diff --git a/Misc/NEWS.d/next/Library/2022-06-17-12-02-30.gh-issue-93858.R49ARc.rst b/Misc/NEWS.d/next/Library/2022-06-17-12-02-30.gh-issue-93858.R49ARc.rst new file mode 100644 index 000000000000..508ba626bab4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-06-17-12-02-30.gh-issue-93858.R49ARc.rst @@ -0,0 +1 @@ +Prevent error when activating venv in nested fish instances. From webhook-mailer at python.org Tue Oct 18 11:52:51 2022 From: webhook-mailer at python.org (vstinner) Date: Tue, 18 Oct 2022 15:52:51 -0000 Subject: [Python-checkins] gh-98393: os module reject bytes-like, only accept bytes (#98394) Message-ID: https://github.com/python/cpython/commit/db03c8066a6b12fa23618f9add0eb795936726b4 commit: db03c8066a6b12fa23618f9add0eb795936726b4 branch: main author: Victor Stinner committer: vstinner date: 2022-10-18T17:52:31+02:00 summary: gh-98393: os module reject bytes-like, only accept bytes (#98394) The os module and the PyUnicode_FSDecoder() function no longer accept bytes-like paths, like bytearray and memoryview types: only the exact bytes type is accepted for bytes strings. files: A Misc/NEWS.d/next/C API/2022-10-18-16-16-27.gh-issue-98393.55u4BF.rst A Misc/NEWS.d/next/Library/2022-10-18-15-41-37.gh-issue-98393.vhPu4L.rst M Doc/whatsnew/3.12.rst M Lib/test/test_compile.py M Lib/test/test_os.py M Lib/test/test_posix.py M Lib/test/test_symtable.py M Modules/posixmodule.c M Objects/unicodeobject.c diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index ad0270ae19b8..525efc405c85 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -515,6 +515,11 @@ Changes in the Python API in Python 3.9. (Contributed by Victor Stinner in :gh:`94352`.) +* The :mod:`os` module no longer accepts bytes-like paths, like + :class:`bytearray` and :class:`memoryview` types: only the exact + :class:`bytes` type is accepted for bytes strings. + (Contributed by Victor Stinner in :gh:`98393`.) + Build Changes ============= @@ -631,6 +636,11 @@ Porting to Python 3.12 to traverse and clear their instance's dictionaries. To clear weakrefs, call :c:func:`PyObject_ClearWeakRefs`, as before. +* The :c:func:`PyUnicode_FSDecoder` function no longer accepts bytes-like + paths, like :class:`bytearray` and :class:`memoryview` types: only the exact + :class:`bytes` type is accepted for bytes strings. + (Contributed by Victor Stinner in :gh:`98393`.) + Deprecated ---------- diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index 8bf8470ff16f..f5c0c7647832 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -494,9 +494,8 @@ def test_compile_filename(self): code = compile('pass', filename, 'exec') self.assertEqual(code.co_filename, 'file.py') for filename in bytearray(b'file.py'), memoryview(b'file.py'): - with self.assertWarns(DeprecationWarning): - code = compile('pass', filename, 'exec') - self.assertEqual(code.co_filename, 'file.py') + with self.assertRaises(TypeError): + compile('pass', filename, 'exec') self.assertRaises(TypeError, compile, 'pass', list(b'file.py'), 'exec') @support.cpython_only diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index 2dafb78ebe0e..10dbb2bd15df 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -3860,18 +3860,18 @@ def test_oserror_filename(self): for filenames, func, *func_args in funcs: for name in filenames: - try: - if isinstance(name, (str, bytes)): + if not isinstance(name, (str, bytes)): + with self.assertRaises(TypeError): func(name, *func_args) - else: - with self.assertWarnsRegex(DeprecationWarning, 'should be'): - func(name, *func_args) - except OSError as err: - self.assertIs(err.filename, name, str(func)) - except UnicodeDecodeError: - pass else: - self.fail("No exception thrown by {}".format(func)) + try: + func(name, *func_args) + except OSError as err: + self.assertIs(err.filename, name, str(func)) + except UnicodeDecodeError: + pass + else: + self.fail("No exception thrown by {}".format(func)) class CPUCountTests(unittest.TestCase): def test_cpu_count(self): @@ -4350,16 +4350,8 @@ def test_bytes_like(self): for cls in bytearray, memoryview: path_bytes = cls(os.fsencode(self.path)) - with self.assertWarns(DeprecationWarning): - entries = list(os.scandir(path_bytes)) - self.assertEqual(len(entries), 1, entries) - entry = entries[0] - - self.assertEqual(entry.name, b'file.txt') - self.assertEqual(entry.path, - os.fsencode(os.path.join(self.path, 'file.txt'))) - self.assertIs(type(entry.name), bytes) - self.assertIs(type(entry.path), bytes) + with self.assertRaises(TypeError): + list(os.scandir(path_bytes)) @unittest.skipUnless(os.listdir in os.supports_fd, 'fd support for listdir required for this test.') diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py index e643d8e5a4ce..be561afc4cff 100644 --- a/Lib/test/test_posix.py +++ b/Lib/test/test_posix.py @@ -634,7 +634,7 @@ def test_stat(self): self.assertTrue(posix.stat(os_helper.TESTFN)) self.assertTrue(posix.stat(os.fsencode(os_helper.TESTFN))) - self.assertWarnsRegex(DeprecationWarning, + self.assertRaisesRegex(TypeError, 'should be string, bytes, os.PathLike or integer, not', posix.stat, bytearray(os.fsencode(os_helper.TESTFN))) self.assertRaisesRegex(TypeError, @@ -841,11 +841,8 @@ def test_listdir_bytes(self): def test_listdir_bytes_like(self): for cls in bytearray, memoryview: - with self.assertWarns(DeprecationWarning): - names = posix.listdir(cls(b'.')) - self.assertIn(os.fsencode(os_helper.TESTFN), names) - for name in names: - self.assertIs(type(name), bytes) + with self.assertRaises(TypeError): + posix.listdir(cls(b'.')) @unittest.skipUnless(posix.listdir in os.supports_fd, "test needs fd support for posix.listdir()") diff --git a/Lib/test/test_symtable.py b/Lib/test/test_symtable.py index 819354e4eee9..25714aecda3a 100644 --- a/Lib/test/test_symtable.py +++ b/Lib/test/test_symtable.py @@ -222,10 +222,9 @@ def checkfilename(brokencode, offset): checkfilename("def f(x): foo)(", 14) # parse-time checkfilename("def f(x): global x", 11) # symtable-build-time symtable.symtable("pass", b"spam", "exec") - with self.assertWarns(DeprecationWarning), \ - self.assertRaises(TypeError): + with self.assertRaises(TypeError): symtable.symtable("pass", bytearray(b"spam"), "exec") - with self.assertWarns(DeprecationWarning): + with self.assertRaises(TypeError): symtable.symtable("pass", memoryview(b"spam"), "exec") with self.assertRaises(TypeError): symtable.symtable("pass", list(b"spam"), "exec") diff --git a/Misc/NEWS.d/next/C API/2022-10-18-16-16-27.gh-issue-98393.55u4BF.rst b/Misc/NEWS.d/next/C API/2022-10-18-16-16-27.gh-issue-98393.55u4BF.rst new file mode 100644 index 000000000000..658f587348a3 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2022-10-18-16-16-27.gh-issue-98393.55u4BF.rst @@ -0,0 +1,3 @@ +The :c:func:`PyUnicode_FSDecoder` function no longer accepts bytes-like +paths, like :class:`bytearray` and :class:`memoryview` types: only the exact +:class:`bytes` type is accepted for bytes strings. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Library/2022-10-18-15-41-37.gh-issue-98393.vhPu4L.rst b/Misc/NEWS.d/next/Library/2022-10-18-15-41-37.gh-issue-98393.vhPu4L.rst new file mode 100644 index 000000000000..54e45bb900b2 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-18-15-41-37.gh-issue-98393.vhPu4L.rst @@ -0,0 +1,3 @@ +The :mod:`os` module no longer accepts bytes-like paths, like +:class:`bytearray` and :class:`memoryview` types: only the exact +:class:`bytes` type is accepted for bytes strings. Patch by Victor Stinner. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 1e556fc904b7..39198cb7ddcd 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -1120,7 +1120,7 @@ path_converter(PyObject *o, void *p) path_t *path = (path_t *)p; PyObject *bytes = NULL; Py_ssize_t length = 0; - int is_index, is_buffer, is_bytes, is_unicode; + int is_index, is_bytes, is_unicode; const char *narrow; #ifdef MS_WINDOWS PyObject *wo = NULL; @@ -1158,11 +1158,10 @@ path_converter(PyObject *o, void *p) /* Only call this here so that we don't treat the return value of os.fspath() as an fd or buffer. */ is_index = path->allow_fd && PyIndex_Check(o); - is_buffer = PyObject_CheckBuffer(o); is_bytes = PyBytes_Check(o); is_unicode = PyUnicode_Check(o); - if (!is_index && !is_buffer && !is_unicode && !is_bytes) { + if (!is_index && !is_unicode && !is_bytes) { /* Inline PyOS_FSPath() for better error messages. */ PyObject *func, *res; @@ -1225,27 +1224,6 @@ path_converter(PyObject *o, void *p) bytes = o; Py_INCREF(bytes); } - else if (is_buffer) { - /* XXX Replace PyObject_CheckBuffer with PyBytes_Check in other code - after removing support of non-bytes buffer objects. */ - if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, - "%s%s%s should be %s, not %.200s", - path->function_name ? path->function_name : "", - path->function_name ? ": " : "", - path->argument_name ? path->argument_name : "path", - path->allow_fd && path->nullable ? "string, bytes, os.PathLike, " - "integer or None" : - path->allow_fd ? "string, bytes, os.PathLike or integer" : - path->nullable ? "string, bytes, os.PathLike or None" : - "string, bytes or os.PathLike", - _PyType_Name(Py_TYPE(o)))) { - goto error_exit; - } - bytes = PyBytes_FromObject(o); - if (!bytes) { - goto error_exit; - } - } else if (is_index) { if (!_fd_converter(o, &path->fd)) { goto error_exit; @@ -4126,8 +4104,8 @@ _posix_listdir(path_t *path, PyObject *list) const char *name; if (path->narrow) { name = path->narrow; - /* only return bytes if they specified a bytes-like object */ - return_str = !PyObject_CheckBuffer(path->object); + /* only return bytes if they specified a bytes object */ + return_str = !PyBytes_Check(path->object); } else { name = "."; @@ -14049,7 +14027,7 @@ DirEntry_from_posix_info(PyObject *module, path_t *path, const char *name, goto error; } - if (!path->narrow || !PyObject_CheckBuffer(path->object)) { + if (!path->narrow || !PyBytes_Check(path->object)) { entry->name = PyUnicode_DecodeFSDefaultAndSize(name, name_len); if (joined_path) entry->path = PyUnicode_DecodeFSDefault(joined_path); diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 5b737f1b596e..d090915146f8 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -3619,48 +3619,25 @@ PyUnicode_FSConverter(PyObject* arg, void* addr) int PyUnicode_FSDecoder(PyObject* arg, void* addr) { - int is_buffer = 0; - PyObject *path = NULL; - PyObject *output = NULL; if (arg == NULL) { Py_DECREF(*(PyObject**)addr); *(PyObject**)addr = NULL; return 1; } - is_buffer = PyObject_CheckBuffer(arg); - if (!is_buffer) { - path = PyOS_FSPath(arg); - if (path == NULL) { - return 0; - } - } - else { - path = arg; - Py_INCREF(arg); + PyObject *path = PyOS_FSPath(arg); + if (path == NULL) { + return 0; } + PyObject *output = NULL; if (PyUnicode_Check(path)) { output = path; } - else if (PyBytes_Check(path) || is_buffer) { - PyObject *path_bytes = NULL; - - if (!PyBytes_Check(path) && - PyErr_WarnFormat(PyExc_DeprecationWarning, 1, - "path should be string, bytes, or os.PathLike, not %.200s", - Py_TYPE(arg)->tp_name)) { - Py_DECREF(path); - return 0; - } - path_bytes = PyBytes_FromObject(path); + else if (PyBytes_Check(path)) { + output = PyUnicode_DecodeFSDefaultAndSize(PyBytes_AS_STRING(path), + PyBytes_GET_SIZE(path)); Py_DECREF(path); - if (!path_bytes) { - return 0; - } - output = PyUnicode_DecodeFSDefaultAndSize(PyBytes_AS_STRING(path_bytes), - PyBytes_GET_SIZE(path_bytes)); - Py_DECREF(path_bytes); if (!output) { return 0; } @@ -3672,6 +3649,7 @@ PyUnicode_FSDecoder(PyObject* arg, void* addr) Py_DECREF(path); return 0; } + if (findchar(PyUnicode_DATA(output), PyUnicode_KIND(output), PyUnicode_GET_LENGTH(output), 0, 1) >= 0) { PyErr_SetString(PyExc_ValueError, "embedded null character"); From webhook-mailer at python.org Tue Oct 18 11:59:11 2022 From: webhook-mailer at python.org (iritkatriel) Date: Tue, 18 Oct 2022 15:59:11 -0000 Subject: [Python-checkins] gh-92886: Fixing tests that fail when running with optimizations (`-O`) in `test_sys_settrace.py` (GH-93234) Message-ID: https://github.com/python/cpython/commit/debacd9ad51eaeedac5517404de5ead3f2258c22 commit: debacd9ad51eaeedac5517404de5ead3f2258c22 branch: main author: Jack Hindmarch <1750152+jackh-ncl at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2022-10-18T16:59:05+01:00 summary: gh-92886: Fixing tests that fail when running with optimizations (`-O`) in `test_sys_settrace.py` (GH-93234) files: A Misc/NEWS.d/next/Tests/2022-05-25-22-43-11.gh-issue-92886.9HQb9e.rst M Lib/test/test_sys_settrace.py diff --git a/Lib/test/test_sys_settrace.py b/Lib/test/test_sys_settrace.py index aa61f8b18588..4f577c2ea5da 100644 --- a/Lib/test/test_sys_settrace.py +++ b/Lib/test/test_sys_settrace.py @@ -834,9 +834,8 @@ def func(): (5, 'line'), (6, 'line'), (7, 'line'), - (10, 'line'), - (13, 'line'), - (13, 'return')]) + (10, 'line')] + + ([(13, 'line'), (13, 'return')] if __debug__ else [(10, 'return')])) def test_continue_through_finally(self): @@ -871,9 +870,8 @@ def func(): (6, 'line'), (7, 'line'), (10, 'line'), - (3, 'line'), - (13, 'line'), - (13, 'return')]) + (3, 'line')] + + ([(13, 'line'), (13, 'return')] if __debug__ else [(3, 'return')])) def test_return_through_finally(self): diff --git a/Misc/NEWS.d/next/Tests/2022-05-25-22-43-11.gh-issue-92886.9HQb9e.rst b/Misc/NEWS.d/next/Tests/2022-05-25-22-43-11.gh-issue-92886.9HQb9e.rst new file mode 100644 index 000000000000..0c5870441c3b --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2022-05-25-22-43-11.gh-issue-92886.9HQb9e.rst @@ -0,0 +1 @@ +Fixing tests that fail when running with optimizations (``-O``) in ``test_sys_settrace.py``. From webhook-mailer at python.org Tue Oct 18 12:18:44 2022 From: webhook-mailer at python.org (iritkatriel) Date: Tue, 18 Oct 2022 16:18:44 -0000 Subject: [Python-checkins] gh-98390: Fix source locations of boolean sub-expressions (GH-98396) Message-ID: https://github.com/python/cpython/commit/c051d55ddb29c4ff7b1fcc65971535f78369ffc0 commit: c051d55ddb29c4ff7b1fcc65971535f78369ffc0 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2022-10-18T17:18:38+01:00 summary: gh-98390: Fix source locations of boolean sub-expressions (GH-98396) files: A Misc/NEWS.d/next/Core and Builtins/2022-10-18-14-11-32.gh-issue-98390.H1sxJu.rst M Lib/test/test_compile.py M Python/compile.c diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index f5c0c7647832..a5434d6fd512 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -1207,6 +1207,32 @@ def test_multiline_expression(self): self.assertOpcodeSourcePositionIs(compiled_code, 'CALL', line=1, end_line=3, column=0, end_column=1) + def test_multiline_boolean_expression(self): + snippet = """\ +if (a or + (b and not c) or + not ( + d > 0)): + x = 42 +""" + + compiled_code, _ = self.check_positions_against_ast(snippet) + # jump if a is true: + self.assertOpcodeSourcePositionIs(compiled_code, 'POP_JUMP_IF_TRUE', + line=1, end_line=1, column=4, end_column=5, occurrence=1) + # jump if b is false: + self.assertOpcodeSourcePositionIs(compiled_code, 'POP_JUMP_IF_FALSE', + line=2, end_line=2, column=5, end_column=6, occurrence=1) + # jump if c is false: + self.assertOpcodeSourcePositionIs(compiled_code, 'POP_JUMP_IF_FALSE', + line=2, end_line=2, column=15, end_column=16, occurrence=2) + # compare d and 0 + self.assertOpcodeSourcePositionIs(compiled_code, 'COMPARE_OP', + line=4, end_line=4, column=8, end_column=13, occurrence=1) + # jump if comparison it True + self.assertOpcodeSourcePositionIs(compiled_code, 'POP_JUMP_IF_TRUE', + line=4, end_line=4, column=8, end_column=13, occurrence=2) + def test_very_long_line_end_offset(self): # Make sure we get the correct column offset for offsets # too large to store in a byte. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-18-14-11-32.gh-issue-98390.H1sxJu.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-18-14-11-32.gh-issue-98390.H1sxJu.rst new file mode 100644 index 000000000000..6dac72b905c9 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-18-14-11-32.gh-issue-98390.H1sxJu.rst @@ -0,0 +1 @@ +Fix location of sub-expressions of boolean expressions, by reducing their scope to that of the sub-expression. diff --git a/Python/compile.c b/Python/compile.c index 5fbf6fe10d13..4d5b41aa1300 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -2953,7 +2953,7 @@ compiler_jump_if(struct compiler *c, location *ploc, /* general implementation */ VISIT(c, expr, e); - ADDOP_JUMP(c, *ploc, cond ? POP_JUMP_IF_TRUE : POP_JUMP_IF_FALSE, next); + ADDOP_JUMP(c, LOC(e), cond ? POP_JUMP_IF_TRUE : POP_JUMP_IF_FALSE, next); return 1; } From webhook-mailer at python.org Tue Oct 18 15:09:46 2022 From: webhook-mailer at python.org (rhettinger) Date: Tue, 18 Oct 2022 19:09:46 -0000 Subject: [Python-checkins] General improvements to the itertools docs (GH-98408) Message-ID: https://github.com/python/cpython/commit/f4ead4874b558efa6379e3a130b0c491fec3acb1 commit: f4ead4874b558efa6379e3a130b0c491fec3acb1 branch: main author: Raymond Hettinger committer: rhettinger date: 2022-10-18T14:09:34-05:00 summary: General improvements to the itertools docs (GH-98408) files: M Doc/library/itertools.rst diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 35a71335b35f..07bb08625375 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -10,6 +10,10 @@ .. testsetup:: from itertools import * + import collections + import math + import operator + import random -------------- @@ -133,10 +137,9 @@ loops that truncate the stream. There are a number of uses for the *func* argument. It can be set to :func:`min` for a running minimum, :func:`max` for a running maximum, or :func:`operator.mul` for a running product. Amortization tables can be - built by accumulating interest and applying payments. First-order - `recurrence relations `_ - can be modeled by supplying the initial value in the iterable and using only - the accumulated total in *func* argument:: + built by accumulating interest and applying payments: + + .. doctest:: >>> data = [3, 4, 6, 2, 1, 9, 0, 7, 5, 8] >>> list(accumulate(data, operator.mul)) # running product @@ -149,17 +152,6 @@ loops that truncate the stream. >>> list(accumulate(cashflows, lambda bal, pmt: bal*1.05 + pmt)) [1000, 960.0, 918.0, 873.9000000000001, 827.5950000000001] - # Chaotic recurrence relation https://en.wikipedia.org/wiki/Logistic_map - >>> logistic_map = lambda x, _: r * x * (1 - x) - >>> r = 3.8 - >>> x0 = 0.4 - >>> inputs = repeat(x0, 36) # only the initial value is used - >>> [format(x, '.2f') for x in accumulate(inputs, logistic_map)] - ['0.40', '0.91', '0.30', '0.81', '0.60', '0.92', '0.29', '0.79', '0.63', - '0.88', '0.39', '0.90', '0.33', '0.84', '0.52', '0.95', '0.18', '0.57', - '0.93', '0.25', '0.71', '0.79', '0.63', '0.88', '0.39', '0.91', '0.32', - '0.83', '0.54', '0.95', '0.20', '0.60', '0.91', '0.30', '0.80', '0.60'] - See :func:`functools.reduce` for a similar function that returns only the final accumulated value. @@ -241,10 +233,10 @@ loops that truncate the stream. The combination tuples are emitted in lexicographic ordering according to the order of the input *iterable*. So, if the input *iterable* is sorted, - the combination tuples will be produced in sorted order. + the output tuples will be produced in sorted order. Elements are treated as unique based on their position, not on their - value. So if the input elements are unique, there will be no repeat + value. So if the input elements are unique, there will be no repeated values in each combination. Roughly equivalent to:: @@ -290,7 +282,7 @@ loops that truncate the stream. The combination tuples are emitted in lexicographic ordering according to the order of the input *iterable*. So, if the input *iterable* is sorted, - the combination tuples will be produced in sorted order. + the output tuples will be produced in sorted order. Elements are treated as unique based on their position, not on their value. So if the input elements are unique, the generated combinations @@ -449,14 +441,17 @@ loops that truncate the stream. class groupby: # [k for k, g in groupby('AAAABBBCCDAABBB')] --> A B C D A B # [list(g) for k, g in groupby('AAAABBBCCD')] --> AAAA BBB CC D + def __init__(self, iterable, key=None): if key is None: key = lambda x: x self.keyfunc = key self.it = iter(iterable) self.tgtkey = self.currkey = self.currvalue = object() + def __iter__(self): return self + def __next__(self): self.id = object() while self.currkey == self.tgtkey: @@ -464,6 +459,7 @@ loops that truncate the stream. self.currkey = self.keyfunc(self.currvalue) self.tgtkey = self.currkey return (self.currkey, self._grouper(self.tgtkey, self.id)) + def _grouper(self, tgtkey, id): while self.id is id and self.currkey == tgtkey: yield self.currvalue @@ -482,10 +478,17 @@ loops that truncate the stream. Afterward, elements are returned consecutively unless *step* is set higher than one which results in items being skipped. If *stop* is ``None``, then iteration continues until the iterator is exhausted, if at all; otherwise, it stops at the - specified position. Unlike regular slicing, :func:`islice` does not support - negative values for *start*, *stop*, or *step*. Can be used to extract related - fields from data where the internal structure has been flattened (for example, a - multi-line report may list a name field on every third line). Roughly equivalent to:: + specified position. + + If *start* is ``None``, then iteration starts at zero. If *step* is ``None``, + then the step defaults to one. + + Unlike regular slicing, :func:`islice` does not support negative values for + *start*, *stop*, or *step*. Can be used to extract related fields from + data where the internal structure has been flattened (for example, a + multi-line report may list a name field on every third line). + + Roughly equivalent to:: def islice(iterable, *args): # islice('ABCDEFG', 2) --> A B @@ -512,8 +515,6 @@ loops that truncate the stream. for i, element in zip(range(i + 1, stop), iterable): pass - If *start* is ``None``, then iteration starts at zero. If *step* is ``None``, - then the step defaults to one. .. function:: pairwise(iterable) @@ -542,13 +543,13 @@ loops that truncate the stream. of the *iterable* and all possible full-length permutations are generated. - The permutation tuples are emitted in lexicographic ordering according to + The permutation tuples are emitted in lexicographic order according to the order of the input *iterable*. So, if the input *iterable* is sorted, - the combination tuples will be produced in sorted order. + the output tuples will be produced in sorted order. Elements are treated as unique based on their position, not on their - value. So if the input elements are unique, there will be no repeat - values in each permutation. + value. So if the input elements are unique, there will be no repeated + values within a permutation. Roughly equivalent to:: @@ -628,9 +629,7 @@ loops that truncate the stream. .. function:: repeat(object[, times]) Make an iterator that returns *object* over and over again. Runs indefinitely - unless the *times* argument is specified. Used as argument to :func:`map` for - invariant parameters to the called function. Also used with :func:`zip` to - create an invariant part of a tuple record. + unless the *times* argument is specified. Roughly equivalent to:: @@ -644,7 +643,9 @@ loops that truncate the stream. yield object A common use for *repeat* is to supply a stream of constant values to *map* - or *zip*:: + or *zip*: + + .. doctest:: >>> list(map(pow, range(10), repeat(2))) [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] @@ -653,9 +654,12 @@ loops that truncate the stream. Make an iterator that computes the function using arguments obtained from the iterable. Used instead of :func:`map` when argument parameters are already - grouped in tuples from a single iterable (the data has been "pre-zipped"). The - difference between :func:`map` and :func:`starmap` parallels the distinction - between ``function(a,b)`` and ``function(*c)``. Roughly equivalent to:: + grouped in tuples from a single iterable (when the data has been + "pre-zipped"). + + The difference between :func:`map` and :func:`starmap` parallels the + distinction between ``function(a,b)`` and ``function(*c)``. Roughly + equivalent to:: def starmap(function, iterable): # starmap(pow, [(2,5), (3,2), (10,3)]) --> 32 9 1000 @@ -683,9 +687,7 @@ loops that truncate the stream. The following Python code helps explain what *tee* does (although the actual implementation is more complex and uses only a single underlying - :abbr:`FIFO (first-in, first-out)` queue). - - Roughly equivalent to:: + :abbr:`FIFO (first-in, first-out)` queue):: def tee(iterable, n=2): it = iter(iterable) @@ -702,7 +704,7 @@ loops that truncate the stream. yield mydeque.popleft() return tuple(gen(d) for d in deques) - Once :func:`tee` has made a split, the original *iterable* should not be + Once a :func:`tee` has been created, the original *iterable* should not be used anywhere else; otherwise, the *iterable* could get advanced without the tee objects being informed. @@ -756,14 +758,28 @@ Itertools Recipes This section shows recipes for creating an extended toolset using the existing itertools as building blocks. +The primary purpose of the itertools recipes is educational. The recipes show +various ways of thinking about individual tools ? for example, that +``chain.from_iterable`` is related to the concept of flattening. The recipes +also give ideas about ways that the tools can be combined ? for example, how +`compress()` and `range()` can work together. The recipes also show patterns +for using itertools with the :mod:`operator` and :mod:`collections` modules as +well as with the built-in itertools such as ``map()``, ``filter()``, +``reversed()``, and ``enumerate()``. + +A secondary purpose of the recipes is to serve as an incubator. The +``accumulate()``, ``compress()``, and ``pairwise()`` itertools started out as +recipes. Currently, the ``iter_index()`` recipe is being tested to see +whether it proves its worth. + Substantially all of these recipes and many, many others can be installed from the `more-itertools project `_ found on the Python Package Index:: python -m pip install more-itertools -The extended tools offer the same high performance as the underlying toolset. -The superior memory performance is kept by processing elements one at a time +Many of the recipes offer the same high performance as the underlying toolset. +Superior memory performance is kept by processing elements one at a time rather than bringing the whole iterable into memory all at once. Code volume is kept small by linking the tools together in a functional style which helps eliminate temporary variables. High speed is retained by preferring @@ -848,15 +864,25 @@ which incur interpreter overhead. for k in range(len(roots) + 1) ] - def iter_index(seq, value, start=0): - "Return indices where a value occurs in a sequence." + def iter_index(iterable, value, start=0): + "Return indices where a value occurs in a sequence or iterable." # iter_index('AABCADEAF', 'A') --> 0 1 4 7 - i = start - 1 try: - while True: - yield (i := seq.index(value, i+1)) - except ValueError: - pass + seq_index = iterable.index + except AttributeError: + # Slow path for general iterables + it = islice(iterable, start, None) + for i, element in enumerate(it, start): + if element is value or element == value: + yield i + else: + # Fast path for sequences + i = start - 1 + try: + while True: + yield (i := seq_index(value, i+1)) + except ValueError: + pass def sieve(n): "Primes less than n" @@ -978,16 +1004,19 @@ which incur interpreter overhead. # unique_everseen('AAAABBBCCDAABBB') --> A B C D # unique_everseen('ABBCcAD', str.lower) --> A B C D seen = set() - seen_add = seen.add if key is None: for element in filterfalse(seen.__contains__, iterable): - seen_add(element) + seen.add(element) yield element + # Note: The steps shown above are intended to demonstrate + # filterfalse(). For order preserving deduplication, + # a better solution is: + # yield from dict.fromkeys(iterable) else: for element in iterable: k = key(element) if k not in seen: - seen_add(k) + seen.add(k) yield element def unique_justseen(iterable, key=None): @@ -1196,6 +1225,18 @@ which incur interpreter overhead. [] >>> list(iter_index('', 'X')) [] + >>> list(iter_index('AABCADEAF', 'A', 1)) + [1, 4, 7] + >>> list(iter_index(iter('AABCADEAF'), 'A', 1)) + [1, 4, 7] + >>> list(iter_index('AABCADEAF', 'A', 2)) + [4, 7] + >>> list(iter_index(iter('AABCADEAF'), 'A', 2)) + [4, 7] + >>> list(iter_index('AABCADEAF', 'A', 10)) + [] + >>> list(iter_index(iter('AABCADEAF'), 'A', 10)) + [] >>> list(sieve(30)) [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] From webhook-mailer at python.org Tue Oct 18 15:17:46 2022 From: webhook-mailer at python.org (miss-islington) Date: Tue, 18 Oct 2022 19:17:46 -0000 Subject: [Python-checkins] General improvements to the itertools docs (GH-98408) Message-ID: https://github.com/python/cpython/commit/f1a240abab37c95848b1d686992be1e6fecd30a6 commit: f1a240abab37c95848b1d686992be1e6fecd30a6 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-18T12:17:40-07:00 summary: General improvements to the itertools docs (GH-98408) (cherry picked from commit f4ead4874b558efa6379e3a130b0c491fec3acb1) Co-authored-by: Raymond Hettinger files: M Doc/library/itertools.rst diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 26ede4b49a01..0f295741e655 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -10,6 +10,10 @@ .. testsetup:: from itertools import * + import collections + import math + import operator + import random -------------- @@ -132,10 +136,9 @@ loops that truncate the stream. There are a number of uses for the *func* argument. It can be set to :func:`min` for a running minimum, :func:`max` for a running maximum, or :func:`operator.mul` for a running product. Amortization tables can be - built by accumulating interest and applying payments. First-order - `recurrence relations `_ - can be modeled by supplying the initial value in the iterable and using only - the accumulated total in *func* argument:: + built by accumulating interest and applying payments: + + .. doctest:: >>> data = [3, 4, 6, 2, 1, 9, 0, 7, 5, 8] >>> list(accumulate(data, operator.mul)) # running product @@ -148,17 +151,6 @@ loops that truncate the stream. >>> list(accumulate(cashflows, lambda bal, pmt: bal*1.05 + pmt)) [1000, 960.0, 918.0, 873.9000000000001, 827.5950000000001] - # Chaotic recurrence relation https://en.wikipedia.org/wiki/Logistic_map - >>> logistic_map = lambda x, _: r * x * (1 - x) - >>> r = 3.8 - >>> x0 = 0.4 - >>> inputs = repeat(x0, 36) # only the initial value is used - >>> [format(x, '.2f') for x in accumulate(inputs, logistic_map)] - ['0.40', '0.91', '0.30', '0.81', '0.60', '0.92', '0.29', '0.79', '0.63', - '0.88', '0.39', '0.90', '0.33', '0.84', '0.52', '0.95', '0.18', '0.57', - '0.93', '0.25', '0.71', '0.79', '0.63', '0.88', '0.39', '0.91', '0.32', - '0.83', '0.54', '0.95', '0.20', '0.60', '0.91', '0.30', '0.80', '0.60'] - See :func:`functools.reduce` for a similar function that returns only the final accumulated value. @@ -202,10 +194,10 @@ loops that truncate the stream. The combination tuples are emitted in lexicographic ordering according to the order of the input *iterable*. So, if the input *iterable* is sorted, - the combination tuples will be produced in sorted order. + the output tuples will be produced in sorted order. Elements are treated as unique based on their position, not on their - value. So if the input elements are unique, there will be no repeat + value. So if the input elements are unique, there will be no repeated values in each combination. Roughly equivalent to:: @@ -251,7 +243,7 @@ loops that truncate the stream. The combination tuples are emitted in lexicographic ordering according to the order of the input *iterable*. So, if the input *iterable* is sorted, - the combination tuples will be produced in sorted order. + the output tuples will be produced in sorted order. Elements are treated as unique based on their position, not on their value. So if the input elements are unique, the generated combinations @@ -410,14 +402,17 @@ loops that truncate the stream. class groupby: # [k for k, g in groupby('AAAABBBCCDAABBB')] --> A B C D A B # [list(g) for k, g in groupby('AAAABBBCCD')] --> AAAA BBB CC D + def __init__(self, iterable, key=None): if key is None: key = lambda x: x self.keyfunc = key self.it = iter(iterable) self.tgtkey = self.currkey = self.currvalue = object() + def __iter__(self): return self + def __next__(self): self.id = object() while self.currkey == self.tgtkey: @@ -425,6 +420,7 @@ loops that truncate the stream. self.currkey = self.keyfunc(self.currvalue) self.tgtkey = self.currkey return (self.currkey, self._grouper(self.tgtkey, self.id)) + def _grouper(self, tgtkey, id): while self.id is id and self.currkey == tgtkey: yield self.currvalue @@ -443,10 +439,17 @@ loops that truncate the stream. Afterward, elements are returned consecutively unless *step* is set higher than one which results in items being skipped. If *stop* is ``None``, then iteration continues until the iterator is exhausted, if at all; otherwise, it stops at the - specified position. Unlike regular slicing, :func:`islice` does not support - negative values for *start*, *stop*, or *step*. Can be used to extract related - fields from data where the internal structure has been flattened (for example, a - multi-line report may list a name field on every third line). Roughly equivalent to:: + specified position. + + If *start* is ``None``, then iteration starts at zero. If *step* is ``None``, + then the step defaults to one. + + Unlike regular slicing, :func:`islice` does not support negative values for + *start*, *stop*, or *step*. Can be used to extract related fields from + data where the internal structure has been flattened (for example, a + multi-line report may list a name field on every third line). + + Roughly equivalent to:: def islice(iterable, *args): # islice('ABCDEFG', 2) --> A B @@ -473,8 +476,6 @@ loops that truncate the stream. for i, element in zip(range(i + 1, stop), iterable): pass - If *start* is ``None``, then iteration starts at zero. If *step* is ``None``, - then the step defaults to one. .. function:: pairwise(iterable) @@ -503,13 +504,13 @@ loops that truncate the stream. of the *iterable* and all possible full-length permutations are generated. - The permutation tuples are emitted in lexicographic ordering according to + The permutation tuples are emitted in lexicographic order according to the order of the input *iterable*. So, if the input *iterable* is sorted, - the combination tuples will be produced in sorted order. + the output tuples will be produced in sorted order. Elements are treated as unique based on their position, not on their - value. So if the input elements are unique, there will be no repeat - values in each permutation. + value. So if the input elements are unique, there will be no repeated + values within a permutation. Roughly equivalent to:: @@ -589,9 +590,7 @@ loops that truncate the stream. .. function:: repeat(object[, times]) Make an iterator that returns *object* over and over again. Runs indefinitely - unless the *times* argument is specified. Used as argument to :func:`map` for - invariant parameters to the called function. Also used with :func:`zip` to - create an invariant part of a tuple record. + unless the *times* argument is specified. Roughly equivalent to:: @@ -605,7 +604,9 @@ loops that truncate the stream. yield object A common use for *repeat* is to supply a stream of constant values to *map* - or *zip*:: + or *zip*: + + .. doctest:: >>> list(map(pow, range(10), repeat(2))) [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] @@ -614,9 +615,12 @@ loops that truncate the stream. Make an iterator that computes the function using arguments obtained from the iterable. Used instead of :func:`map` when argument parameters are already - grouped in tuples from a single iterable (the data has been "pre-zipped"). The - difference between :func:`map` and :func:`starmap` parallels the distinction - between ``function(a,b)`` and ``function(*c)``. Roughly equivalent to:: + grouped in tuples from a single iterable (when the data has been + "pre-zipped"). + + The difference between :func:`map` and :func:`starmap` parallels the + distinction between ``function(a,b)`` and ``function(*c)``. Roughly + equivalent to:: def starmap(function, iterable): # starmap(pow, [(2,5), (3,2), (10,3)]) --> 32 9 1000 @@ -644,9 +648,7 @@ loops that truncate the stream. The following Python code helps explain what *tee* does (although the actual implementation is more complex and uses only a single underlying - :abbr:`FIFO (first-in, first-out)` queue). - - Roughly equivalent to:: + :abbr:`FIFO (first-in, first-out)` queue):: def tee(iterable, n=2): it = iter(iterable) @@ -663,7 +665,7 @@ loops that truncate the stream. yield mydeque.popleft() return tuple(gen(d) for d in deques) - Once :func:`tee` has made a split, the original *iterable* should not be + Once a :func:`tee` has been created, the original *iterable* should not be used anywhere else; otherwise, the *iterable* could get advanced without the tee objects being informed. @@ -717,14 +719,28 @@ Itertools Recipes This section shows recipes for creating an extended toolset using the existing itertools as building blocks. +The primary purpose of the itertools recipes is educational. The recipes show +various ways of thinking about individual tools ? for example, that +``chain.from_iterable`` is related to the concept of flattening. The recipes +also give ideas about ways that the tools can be combined ? for example, how +`compress()` and `range()` can work together. The recipes also show patterns +for using itertools with the :mod:`operator` and :mod:`collections` modules as +well as with the built-in itertools such as ``map()``, ``filter()``, +``reversed()``, and ``enumerate()``. + +A secondary purpose of the recipes is to serve as an incubator. The +``accumulate()``, ``compress()``, and ``pairwise()`` itertools started out as +recipes. Currently, the ``iter_index()`` recipe is being tested to see +whether it proves its worth. + Substantially all of these recipes and many, many others can be installed from the `more-itertools project `_ found on the Python Package Index:: python -m pip install more-itertools -The extended tools offer the same high performance as the underlying toolset. -The superior memory performance is kept by processing elements one at a time +Many of the recipes offer the same high performance as the underlying toolset. +Superior memory performance is kept by processing elements one at a time rather than bringing the whole iterable into memory all at once. Code volume is kept small by linking the tools together in a functional style which helps eliminate temporary variables. High speed is retained by preferring @@ -809,15 +825,25 @@ which incur interpreter overhead. for k in range(len(roots) + 1) ] - def iter_index(seq, value, start=0): - "Return indices where a value occurs in a sequence." + def iter_index(iterable, value, start=0): + "Return indices where a value occurs in a sequence or iterable." # iter_index('AABCADEAF', 'A') --> 0 1 4 7 - i = start - 1 try: - while True: - yield (i := seq.index(value, i+1)) - except ValueError: - pass + seq_index = iterable.index + except AttributeError: + # Slow path for general iterables + it = islice(iterable, start, None) + for i, element in enumerate(it, start): + if element is value or element == value: + yield i + else: + # Fast path for sequences + i = start - 1 + try: + while True: + yield (i := seq_index(value, i+1)) + except ValueError: + pass def sieve(n): "Primes less than n" @@ -946,16 +972,19 @@ which incur interpreter overhead. # unique_everseen('AAAABBBCCDAABBB') --> A B C D # unique_everseen('ABBCcAD', str.lower) --> A B C D seen = set() - seen_add = seen.add if key is None: for element in filterfalse(seen.__contains__, iterable): - seen_add(element) + seen.add(element) yield element + # Note: The steps shown above are intended to demonstrate + # filterfalse(). For order preserving deduplication, + # a better solution is: + # yield from dict.fromkeys(iterable) else: for element in iterable: k = key(element) if k not in seen: - seen_add(k) + seen.add(k) yield element def unique_justseen(iterable, key=None): @@ -1164,6 +1193,18 @@ which incur interpreter overhead. [] >>> list(iter_index('', 'X')) [] + >>> list(iter_index('AABCADEAF', 'A', 1)) + [1, 4, 7] + >>> list(iter_index(iter('AABCADEAF'), 'A', 1)) + [1, 4, 7] + >>> list(iter_index('AABCADEAF', 'A', 2)) + [4, 7] + >>> list(iter_index(iter('AABCADEAF'), 'A', 2)) + [4, 7] + >>> list(iter_index('AABCADEAF', 'A', 10)) + [] + >>> list(iter_index(iter('AABCADEAF'), 'A', 10)) + [] >>> list(sieve(30)) [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] From webhook-mailer at python.org Tue Oct 18 19:10:40 2022 From: webhook-mailer at python.org (ezio-melotti) Date: Tue, 18 Oct 2022 23:10:40 -0000 Subject: [Python-checkins] gh-95914: Add links to 3.11 WhatsNew Summary items (#98416) Message-ID: https://github.com/python/cpython/commit/fcae1954a2ad009d23fc4170b40dcfb2d0e1a153 commit: fcae1954a2ad009d23fc4170b40dcfb2d0e1a153 branch: main author: C.A.M. Gerlach committer: ezio-melotti date: 2022-10-19T01:10:35+02:00 summary: gh-95914: Add links to 3.11 WhatsNew Summary items (#98416) Add links to Summary items to where readers can learn more files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 97e8600b5f9b..79afc1f99e99 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -58,44 +58,49 @@ Summary -- Release highlights .. This section singles out the most important changes in Python 3.11. Brevity is key. -- Python 3.11 is between 10-60% faster than Python 3.10. On average, we measured a - 1.25x speedup on the standard benchmark suite. See `Faster CPython`_ for details. +* Python 3.11 is between 10-60% faster than Python 3.10. + On average, we measured a 1.25x speedup on the standard benchmark suite. + See :ref:`whatsnew311-faster-cpython` for details. .. PEP-sized items next. New syntax features: -* :pep:`654`: Exception Groups and ``except*``. +* :ref:`whatsnew311-pep654` New built-in features: -* :pep:`678`: Enriching Exceptions with Notes. +* :ref:`whatsnew311-pep678` New standard library modules: -* :pep:`680`: ``tomllib`` ? Support for Parsing TOML in the Standard Library. +* :pep:`680`: :mod:`tomllib` ? + Support for parsing `TOML `_ in the Standard Library Interpreter improvements: -* :pep:`657`: Include Fine Grained Error Locations in Tracebacks. +* :ref:`whatsnew311-pep657` * New :option:`-P` command line option and :envvar:`PYTHONSAFEPATH` environment - variable to disable automatically prepending a potentially unsafe path - (the working dir or script directory, depending on invocation) - to :data:`sys.path`. + variable to :ref:`disable automatically prepending potentially unsafe paths + ` to :data:`sys.path` New typing features: -* :pep:`646`: Variadic generics. -* :pep:`655`: Marking individual TypedDict items as required or potentially missing. -* :pep:`673`: ``Self`` type. -* :pep:`675`: Arbitrary literal string type. -* :pep:`681`: Data Class Transforms. +* :ref:`whatsnew311-pep646` +* :ref:`whatsnew311-pep655` +* :ref:`whatsnew311-pep673` +* :ref:`whatsnew311-pep675` +* :ref:`whatsnew311-pep681` -Important deprecations, removals or restrictions: +Important deprecations, removals and restrictions: -* :pep:`594`: Removing dead batteries from the standard library. -* :pep:`624`: Remove ``Py_UNICODE`` encoder APIs. -* :pep:`670`: Convert macros to functions in the Python C API. +* :pep:`594`: + :ref:`Many legacy standard library modules have been deprecated + ` and will be removed in Python 3.13 +* :pep:`624`: + :ref:`Py_UNICODE encoder APIs have been removed ` +* :pep:`670`: + :ref:`Macros converted to static inline functions ` .. _whatsnew311-features: @@ -105,8 +110,8 @@ New Features .. _whatsnew311-pep657: -PEP 657: Enhanced error locations in tracebacks ------------------------------------------------ +PEP 657: Fine-grained error locations in tracebacks +--------------------------------------------------- When printing tracebacks, the interpreter will now point to the exact expression that caused the error, instead of just the line. For example: @@ -381,7 +386,7 @@ Kumar Srinivasan and Graham Bleaney.) .. _whatsnew311-pep681: -PEP 681: Data Class Transforms +PEP 681: Data class transforms ------------------------------ :data:`~typing.dataclass_transform` may be used to @@ -457,6 +462,8 @@ Other Language Changes pickles instance attributes implemented as :term:`slots <__slots__>`. (Contributed by Serhiy Storchaka in :issue:`26579`.) +.. _whatsnew311-pythonsafepath: + * Added a :option:`-P` command line option and a :envvar:`PYTHONSAFEPATH` environment variable, which disable the automatic prepending to :data:`sys.path` @@ -1546,11 +1553,7 @@ Deprecated C APIs are :ref:`listed separately `. removed in Python 3.13. Use ``locale.setlocale(locale.LC_ALL, "")`` instead. (Contributed by Victor Stinner in :gh:`90817`.) -* The :mod:`asynchat`, :mod:`asyncore` and :mod:`smtpd` modules have been - deprecated since at least Python 3.6. Their documentation and deprecation - warnings have now been updated to note they will removed in Python 3.12 - (:pep:`594`). - (Contributed by Hugo van Kemenade in :issue:`47022`.) +.. _whatsnew311-pep594: * :pep:`594` led to the deprecations of the following modules which are slated for removal in Python 3.13: @@ -1578,6 +1581,11 @@ Deprecated C APIs are :ref:`listed separately `. (Contributed by Brett Cannon in :issue:`47061` and Victor Stinner in :gh:`68966`.) +* The :mod:`asynchat`, :mod:`asyncore` and :mod:`smtpd` modules have been + deprecated since at least Python 3.6. Their documentation and deprecation + warnings have now been updated to note they will removed in Python 3.12. + (Contributed by Hugo van Kemenade in :issue:`47022`.) + * More strict rules will be applied now applied for numerical group references and group names in regular expressions in future Python versions. Only sequence of ASCII digits will be now accepted as a numerical reference. @@ -1970,6 +1978,8 @@ New Features Porting to Python 3.11 ---------------------- +.. _whatsnew311-pep670: + * Some macros have been converted to static inline functions to avoid `macro pitfalls `_. The change should be mostly transparent to users, @@ -2378,6 +2388,8 @@ Removed API). (Contributed by Victor Stinner in :issue:`45412`.) +.. _whatsnew311-pep624: + * Remove the :c:type:`Py_UNICODE` encoder APIs, as they have been deprecated since Python 3.3, are little used From webhook-mailer at python.org Tue Oct 18 19:20:26 2022 From: webhook-mailer at python.org (miss-islington) Date: Tue, 18 Oct 2022 23:20:26 -0000 Subject: [Python-checkins] gh-95914: Add links to 3.11 WhatsNew Summary items (GH-98416) Message-ID: https://github.com/python/cpython/commit/75357cdcf14429e8592aec9c3eb57829fa12bc81 commit: 75357cdcf14429e8592aec9c3eb57829fa12bc81 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-18T16:20:19-07:00 summary: gh-95914: Add links to 3.11 WhatsNew Summary items (GH-98416) Add links to Summary items to where readers can learn more (cherry picked from commit fcae1954a2ad009d23fc4170b40dcfb2d0e1a153) Co-authored-by: C.A.M. Gerlach files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 97e8600b5f9b..79afc1f99e99 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -58,44 +58,49 @@ Summary -- Release highlights .. This section singles out the most important changes in Python 3.11. Brevity is key. -- Python 3.11 is between 10-60% faster than Python 3.10. On average, we measured a - 1.25x speedup on the standard benchmark suite. See `Faster CPython`_ for details. +* Python 3.11 is between 10-60% faster than Python 3.10. + On average, we measured a 1.25x speedup on the standard benchmark suite. + See :ref:`whatsnew311-faster-cpython` for details. .. PEP-sized items next. New syntax features: -* :pep:`654`: Exception Groups and ``except*``. +* :ref:`whatsnew311-pep654` New built-in features: -* :pep:`678`: Enriching Exceptions with Notes. +* :ref:`whatsnew311-pep678` New standard library modules: -* :pep:`680`: ``tomllib`` ? Support for Parsing TOML in the Standard Library. +* :pep:`680`: :mod:`tomllib` ? + Support for parsing `TOML `_ in the Standard Library Interpreter improvements: -* :pep:`657`: Include Fine Grained Error Locations in Tracebacks. +* :ref:`whatsnew311-pep657` * New :option:`-P` command line option and :envvar:`PYTHONSAFEPATH` environment - variable to disable automatically prepending a potentially unsafe path - (the working dir or script directory, depending on invocation) - to :data:`sys.path`. + variable to :ref:`disable automatically prepending potentially unsafe paths + ` to :data:`sys.path` New typing features: -* :pep:`646`: Variadic generics. -* :pep:`655`: Marking individual TypedDict items as required or potentially missing. -* :pep:`673`: ``Self`` type. -* :pep:`675`: Arbitrary literal string type. -* :pep:`681`: Data Class Transforms. +* :ref:`whatsnew311-pep646` +* :ref:`whatsnew311-pep655` +* :ref:`whatsnew311-pep673` +* :ref:`whatsnew311-pep675` +* :ref:`whatsnew311-pep681` -Important deprecations, removals or restrictions: +Important deprecations, removals and restrictions: -* :pep:`594`: Removing dead batteries from the standard library. -* :pep:`624`: Remove ``Py_UNICODE`` encoder APIs. -* :pep:`670`: Convert macros to functions in the Python C API. +* :pep:`594`: + :ref:`Many legacy standard library modules have been deprecated + ` and will be removed in Python 3.13 +* :pep:`624`: + :ref:`Py_UNICODE encoder APIs have been removed ` +* :pep:`670`: + :ref:`Macros converted to static inline functions ` .. _whatsnew311-features: @@ -105,8 +110,8 @@ New Features .. _whatsnew311-pep657: -PEP 657: Enhanced error locations in tracebacks ------------------------------------------------ +PEP 657: Fine-grained error locations in tracebacks +--------------------------------------------------- When printing tracebacks, the interpreter will now point to the exact expression that caused the error, instead of just the line. For example: @@ -381,7 +386,7 @@ Kumar Srinivasan and Graham Bleaney.) .. _whatsnew311-pep681: -PEP 681: Data Class Transforms +PEP 681: Data class transforms ------------------------------ :data:`~typing.dataclass_transform` may be used to @@ -457,6 +462,8 @@ Other Language Changes pickles instance attributes implemented as :term:`slots <__slots__>`. (Contributed by Serhiy Storchaka in :issue:`26579`.) +.. _whatsnew311-pythonsafepath: + * Added a :option:`-P` command line option and a :envvar:`PYTHONSAFEPATH` environment variable, which disable the automatic prepending to :data:`sys.path` @@ -1546,11 +1553,7 @@ Deprecated C APIs are :ref:`listed separately `. removed in Python 3.13. Use ``locale.setlocale(locale.LC_ALL, "")`` instead. (Contributed by Victor Stinner in :gh:`90817`.) -* The :mod:`asynchat`, :mod:`asyncore` and :mod:`smtpd` modules have been - deprecated since at least Python 3.6. Their documentation and deprecation - warnings have now been updated to note they will removed in Python 3.12 - (:pep:`594`). - (Contributed by Hugo van Kemenade in :issue:`47022`.) +.. _whatsnew311-pep594: * :pep:`594` led to the deprecations of the following modules which are slated for removal in Python 3.13: @@ -1578,6 +1581,11 @@ Deprecated C APIs are :ref:`listed separately `. (Contributed by Brett Cannon in :issue:`47061` and Victor Stinner in :gh:`68966`.) +* The :mod:`asynchat`, :mod:`asyncore` and :mod:`smtpd` modules have been + deprecated since at least Python 3.6. Their documentation and deprecation + warnings have now been updated to note they will removed in Python 3.12. + (Contributed by Hugo van Kemenade in :issue:`47022`.) + * More strict rules will be applied now applied for numerical group references and group names in regular expressions in future Python versions. Only sequence of ASCII digits will be now accepted as a numerical reference. @@ -1970,6 +1978,8 @@ New Features Porting to Python 3.11 ---------------------- +.. _whatsnew311-pep670: + * Some macros have been converted to static inline functions to avoid `macro pitfalls `_. The change should be mostly transparent to users, @@ -2378,6 +2388,8 @@ Removed API). (Contributed by Victor Stinner in :issue:`45412`.) +.. _whatsnew311-pep624: + * Remove the :c:type:`Py_UNICODE` encoder APIs, as they have been deprecated since Python 3.3, are little used From webhook-mailer at python.org Tue Oct 18 20:37:22 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Wed, 19 Oct 2022 00:37:22 -0000 Subject: [Python-checkins] =?utf-8?b?WzMuMTFdIGdoLTk0ODA4OiBDb3ZlciBgUHlG?= =?utf-8?b?dW5jdGlvbl9HZXRDb2RlYCwgYFB5RnVuY3Rpb25fR2V0R2xvYmFsc2As4oCm?= =?utf-8?b?ICgjOTgzMTcp?= Message-ID: https://github.com/python/cpython/commit/39eaca884fd598890fce69e5dfefb0fd370809fe commit: 39eaca884fd598890fce69e5dfefb0fd370809fe branch: 3.11 author: Jelle Zijlstra committer: JelleZijlstra date: 2022-10-18T17:37:16-07:00 summary: [3.11] gh-94808: Cover `PyFunction_GetCode`, `PyFunction_GetGlobals`,? (#98317) [3.11] gh-94808: Cover `PyFunction_GetCode`, `PyFunction_GetGlobals`, `PyFunction_GetModule` (GH-98158). (cherry picked from commit 7b48d02933639c91ebd957b2326d8c352d8eddec) Co-authored-by: Nikita Sobolev files: M Lib/test/test_capi.py M Modules/_testcapimodule.c diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py index 6e56016a47cc..d5012a76a600 100644 --- a/Lib/test/test_capi.py +++ b/Lib/test/test_capi.py @@ -739,6 +739,41 @@ def method_example(self): ... self.assertEqual(_testcapi.eval_get_func_name(sum), "sum") # c function self.assertEqual(_testcapi.eval_get_func_name(A), "type") + def test_function_get_code(self): + import types + + def some(): + pass + + code = _testcapi.function_get_code(some) + self.assertIsInstance(code, types.CodeType) + self.assertEqual(code, some.__code__) + + with self.assertRaises(SystemError): + _testcapi.function_get_code(None) # not a function + + def test_function_get_globals(self): + def some(): + pass + + globals_ = _testcapi.function_get_globals(some) + self.assertIsInstance(globals_, dict) + self.assertEqual(globals_, some.__globals__) + + with self.assertRaises(SystemError): + _testcapi.function_get_globals(None) # not a function + + def test_function_get_module(self): + def some(): + pass + + module = _testcapi.function_get_module(some) + self.assertIsInstance(module, str) + self.assertEqual(module, some.__module__) + + with self.assertRaises(SystemError): + _testcapi.function_get_module(None) # not a function + class TestPendingCalls(unittest.TestCase): diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 69703be186d1..bab8d6027cfe 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -6081,6 +6081,43 @@ settrace_to_record(PyObject *self, PyObject *list) } static PyObject *negative_dictoffset(PyObject *, PyObject *); + +static PyObject * +function_get_code(PyObject *self, PyObject *func) +{ + PyObject *code = PyFunction_GetCode(func); + if (code != NULL) { + Py_INCREF(code); + return code; + } else { + return NULL; + } +} + +static PyObject * +function_get_globals(PyObject *self, PyObject *func) +{ + PyObject *globals = PyFunction_GetGlobals(func); + if (globals != NULL) { + Py_INCREF(globals); + return globals; + } else { + return NULL; + } +} + +static PyObject * +function_get_module(PyObject *self, PyObject *func) +{ + PyObject *module = PyFunction_GetModule(func); + if (module != NULL) { + Py_INCREF(module); + return module; + } else { + return NULL; + } +} + static PyObject *test_buildvalue_issue38913(PyObject *, PyObject *); static PyObject *getargs_s_hash_int(PyObject *, PyObject *, PyObject*); static PyObject *getargs_s_hash_int2(PyObject *, PyObject *, PyObject*); @@ -6382,6 +6419,9 @@ static PyMethodDef TestMethods[] = { {"get_feature_macros", get_feature_macros, METH_NOARGS, NULL}, {"test_code_api", test_code_api, METH_NOARGS, NULL}, {"settrace_to_record", settrace_to_record, METH_O, NULL}, + {"function_get_code", function_get_code, METH_O, NULL}, + {"function_get_globals", function_get_globals, METH_O, NULL}, + {"function_get_module", function_get_module, METH_O, NULL}, {NULL, NULL} /* sentinel */ }; From webhook-mailer at python.org Tue Oct 18 21:14:46 2022 From: webhook-mailer at python.org (rhettinger) Date: Wed, 19 Oct 2022 01:14:46 -0000 Subject: [Python-checkins] Fix markup indentation (GH-98424) Message-ID: https://github.com/python/cpython/commit/a53f637368c1e3b8bc5513cb2b0c3d7a3dff321a commit: a53f637368c1e3b8bc5513cb2b0c3d7a3dff321a branch: main author: Raymond Hettinger committer: rhettinger date: 2022-10-18T20:14:41-05:00 summary: Fix markup indentation (GH-98424) Fix markup files: M Doc/library/itertools.rst diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 07bb08625375..4f5b61ce62cb 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -198,7 +198,7 @@ loops that truncate the stream. while (batch := list(islice(it, n))): yield batch - .. versionadded:: 3.12 + .. versionadded:: 3.12 .. function:: chain(*iterables) From webhook-mailer at python.org Wed Oct 19 00:26:08 2022 From: webhook-mailer at python.org (ezio-melotti) Date: Wed, 19 Oct 2022 04:26:08 -0000 Subject: [Python-checkins] gh-95913: Add WhatsNew section for new logging APIs (#98320) Message-ID: https://github.com/python/cpython/commit/251b8ccd2a4354840ed2d3aeb9b643a999ba792f commit: 251b8ccd2a4354840ed2d3aeb9b643a999ba792f branch: main author: C.A.M. Gerlach committer: ezio-melotti date: 2022-10-19T06:25:58+02:00 summary: gh-95913: Add WhatsNew section for new logging APIs (#98320) * Add entry for new logging.getLevelNamesMapping function * Add entry for SysLogHandler.createSocket to whatsnew * Add missing line break between logging bullet list items files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 79afc1f99e99..a8dbe06b00b6 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -799,6 +799,26 @@ locale ``locale.getpreferredencoding(False)`` but ignores the :ref:`Python UTF-8 Mode `. + +.. _whatsnew311-logging: + +logging +------- + +* Added :func:`~logging.getLevelNamesMapping` + to return a mapping from logging level names (e.g. ``'CRITICAL'``) + to the values of their corresponding :ref:`levels` (e.g. ``50``, by default). + (Contributed by Andrei Kulakovin in :gh:`88024`.) + +* Added a :meth:`~logging.handlers.SysLogHandler.createSocket` method + to :class:`~logging.handlers.SysLogHandler`, to match + :meth:`SocketHandler.createSocket() + `. + It is called automatically during handler initialization + and when emitting an event, if there is no active socket. + (Contributed by Kirill Pinchuk in :gh:`88457`.) + + math ---- From webhook-mailer at python.org Wed Oct 19 00:33:57 2022 From: webhook-mailer at python.org (ezio-melotti) Date: Wed, 19 Oct 2022 04:33:57 -0000 Subject: [Python-checkins] gh-95913: Edit zipfile Whatsnew section & add new APIs (#98314) Message-ID: https://github.com/python/cpython/commit/ed827d560831b054d262818b1777f7879e8fbd3e commit: ed827d560831b054d262818b1777f7879e8fbd3e branch: main author: C.A.M. Gerlach committer: ezio-melotti date: 2022-10-19T06:33:50+02:00 summary: gh-95913: Edit zipfile Whatsnew section & add new APIs (#98314) * Link ZipFile in What's New entry discussing it * Add entry for new ZipFile.mkdir method * Add entry for new zipfile.Path.stem/suffix/suffixes methods * Add missing line breaks between zipfile bullet list items files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index a8dbe06b00b6..46c5692c8449 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1128,13 +1128,25 @@ warnings providing a more concise way to locally ignore warnings or convert them to errors. (Contributed by Zac Hatfield-Dodds in :issue:`47074`.) + +.. _whatsnew311-zipfile: + zipfile ------- -* Added support for specifying member name encoding for reading - metadata in the zipfile's directory and file headers. +* Added support for specifying member name encoding for reading metadata + in a :class:`~zipfile.ZipFile`'s directory and file headers. (Contributed by Stephen J. Turnbull and Serhiy Storchaka in :issue:`28080`.) +* Added :meth:`ZipFile.mkdir() ` + for creating new directories inside ZIP archives. + (Contributed by Sam Ezeh in :gh:`49083`.) + +* Added :attr:`~zipfile.Path.stem`, :attr:`~zipfile.Path.suffix` + and :attr:`~zipfile.Path.suffixes` to :class:`zipfile.Path`. + (Contributed by Miguel Brito in :gh:`88261`.) + + fcntl ----- From webhook-mailer at python.org Wed Oct 19 00:34:46 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 19 Oct 2022 04:34:46 -0000 Subject: [Python-checkins] gh-95913: Add WhatsNew section for new logging APIs (GH-98320) Message-ID: https://github.com/python/cpython/commit/202eb48a766503511e6b6441a96dd06d163964f8 commit: 202eb48a766503511e6b6441a96dd06d163964f8 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-18T21:34:40-07:00 summary: gh-95913: Add WhatsNew section for new logging APIs (GH-98320) * Add entry for new logging.getLevelNamesMapping function * Add entry for SysLogHandler.createSocket to whatsnew * Add missing line break between logging bullet list items (cherry picked from commit 251b8ccd2a4354840ed2d3aeb9b643a999ba792f) Co-authored-by: C.A.M. Gerlach files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 79afc1f99e99..a8dbe06b00b6 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -799,6 +799,26 @@ locale ``locale.getpreferredencoding(False)`` but ignores the :ref:`Python UTF-8 Mode `. + +.. _whatsnew311-logging: + +logging +------- + +* Added :func:`~logging.getLevelNamesMapping` + to return a mapping from logging level names (e.g. ``'CRITICAL'``) + to the values of their corresponding :ref:`levels` (e.g. ``50``, by default). + (Contributed by Andrei Kulakovin in :gh:`88024`.) + +* Added a :meth:`~logging.handlers.SysLogHandler.createSocket` method + to :class:`~logging.handlers.SysLogHandler`, to match + :meth:`SocketHandler.createSocket() + `. + It is called automatically during handler initialization + and when emitting an event, if there is no active socket. + (Contributed by Kirill Pinchuk in :gh:`88457`.) + + math ---- From webhook-mailer at python.org Wed Oct 19 00:40:53 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 19 Oct 2022 04:40:53 -0000 Subject: [Python-checkins] gh-95913: Edit zipfile Whatsnew section & add new APIs (GH-98314) Message-ID: https://github.com/python/cpython/commit/1b7922e058efef592df9b62899d079a361b15026 commit: 1b7922e058efef592df9b62899d079a361b15026 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-18T21:40:47-07:00 summary: gh-95913: Edit zipfile Whatsnew section & add new APIs (GH-98314) * Link ZipFile in What's New entry discussing it * Add entry for new ZipFile.mkdir method * Add entry for new zipfile.Path.stem/suffix/suffixes methods * Add missing line breaks between zipfile bullet list items (cherry picked from commit ed827d560831b054d262818b1777f7879e8fbd3e) Co-authored-by: C.A.M. Gerlach files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index a8dbe06b00b6..46c5692c8449 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1128,13 +1128,25 @@ warnings providing a more concise way to locally ignore warnings or convert them to errors. (Contributed by Zac Hatfield-Dodds in :issue:`47074`.) + +.. _whatsnew311-zipfile: + zipfile ------- -* Added support for specifying member name encoding for reading - metadata in the zipfile's directory and file headers. +* Added support for specifying member name encoding for reading metadata + in a :class:`~zipfile.ZipFile`'s directory and file headers. (Contributed by Stephen J. Turnbull and Serhiy Storchaka in :issue:`28080`.) +* Added :meth:`ZipFile.mkdir() ` + for creating new directories inside ZIP archives. + (Contributed by Sam Ezeh in :gh:`49083`.) + +* Added :attr:`~zipfile.Path.stem`, :attr:`~zipfile.Path.suffix` + and :attr:`~zipfile.Path.suffixes` to :class:`zipfile.Path`. + (Contributed by Miguel Brito in :gh:`88261`.) + + fcntl ----- From webhook-mailer at python.org Wed Oct 19 02:18:20 2022 From: webhook-mailer at python.org (serhiy-storchaka) Date: Wed, 19 Oct 2022 06:18:20 -0000 Subject: [Python-checkins] gh-97928: Add tests for tkinter.Text.count() (GH-98269) Message-ID: https://github.com/python/cpython/commit/1b684c8f5f738b56f859e5c87b7280610b90399f commit: 1b684c8f5f738b56f859e5c87b7280610b90399f branch: main author: Serhiy Storchaka committer: serhiy-storchaka date: 2022-10-19T09:17:45+03:00 summary: gh-97928: Add tests for tkinter.Text.count() (GH-98269) files: M Lib/test/test_tkinter/test_text.py diff --git a/Lib/test/test_tkinter/test_text.py b/Lib/test/test_tkinter/test_text.py index d1583f0b20aa..b8dfde62070b 100644 --- a/Lib/test/test_tkinter/test_text.py +++ b/Lib/test/test_tkinter/test_text.py @@ -40,6 +40,60 @@ def test_search(self): self.assertEqual(text.search('-test', '1.0', 'end'), '1.2') self.assertEqual(text.search('test', '1.0', 'end'), '1.3') + def test_count(self): + # XXX Some assertions do not check against the intended result, + # but instead check the current result to prevent regression. + text = self.text + text.insert('1.0', + 'Lorem ipsum dolor sit amet,\n' + 'consectetur adipiscing elit,\n' + 'sed do eiusmod tempor incididunt\n' + 'ut labore et dolore magna aliqua.') + + options = ('chars', 'indices', 'lines', + 'displaychars', 'displayindices', 'displaylines', + 'xpixels', 'ypixels') + if self.wantobjects: + self.assertEqual(len(text.count('1.0', 'end', *options)), 8) + else: + text.count('1.0', 'end', *options) + self.assertEqual(text.count('1.0', 'end', 'chars', 'lines'), (124, 4) + if self.wantobjects else '124 4') + self.assertEqual(text.count('1.3', '4.5', 'chars', 'lines'), (92, 3) + if self.wantobjects else '92 3') + self.assertEqual(text.count('4.5', '1.3', 'chars', 'lines'), (-92, -3) + if self.wantobjects else '-92 -3') + self.assertEqual(text.count('1.3', '1.3', 'chars', 'lines'), (0, 0) + if self.wantobjects else '0 0') + self.assertEqual(text.count('1.0', 'end', 'lines'), (4,) + if self.wantobjects else ('4',)) + self.assertEqual(text.count('end', '1.0', 'lines'), (-4,) + if self.wantobjects else ('-4',)) + self.assertEqual(text.count('1.3', '1.5', 'lines'), None + if self.wantobjects else ('0',)) + self.assertEqual(text.count('1.3', '1.3', 'lines'), None + if self.wantobjects else ('0',)) + self.assertEqual(text.count('1.0', 'end'), (124,) # 'indices' by default + if self.wantobjects else ('124',)) + self.assertRaises(tkinter.TclError, text.count, '1.0', 'end', 'spam') + # '-lines' is ignored, 'indices' is used by default + self.assertEqual(text.count('1.0', 'end', '-lines'), (124,) + if self.wantobjects else ('124',)) + + self.assertIsInstance(text.count('1.3', '1.5', 'ypixels'), tuple) + self.assertIsInstance(text.count('1.3', '1.5', 'update', 'ypixels'), int + if self.wantobjects else str) + self.assertEqual(text.count('1.3', '1.3', 'update', 'ypixels'), None + if self.wantobjects else '0') + self.assertEqual(text.count('1.3', '1.5', 'update', 'indices'), 2 + if self.wantobjects else '2') + self.assertEqual(text.count('1.3', '1.3', 'update', 'indices'), None + if self.wantobjects else '0') + self.assertEqual(text.count('1.3', '1.5', 'update'), (2,) + if self.wantobjects else ('2',)) + self.assertEqual(text.count('1.3', '1.3', 'update'), None + if self.wantobjects else ('0',)) + if __name__ == "__main__": unittest.main() From webhook-mailer at python.org Wed Oct 19 02:40:46 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 19 Oct 2022 06:40:46 -0000 Subject: [Python-checkins] gh-97928: Add tests for tkinter.Text.count() (GH-98269) Message-ID: https://github.com/python/cpython/commit/d0ed05c0189d85f04164ea51c7a36ea6bbb02764 commit: d0ed05c0189d85f04164ea51c7a36ea6bbb02764 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-18T23:40:40-07:00 summary: gh-97928: Add tests for tkinter.Text.count() (GH-98269) (cherry picked from commit 1b684c8f5f738b56f859e5c87b7280610b90399f) Co-authored-by: Serhiy Storchaka files: M Lib/tkinter/test/test_tkinter/test_text.py diff --git a/Lib/tkinter/test/test_tkinter/test_text.py b/Lib/tkinter/test/test_tkinter/test_text.py index 482f150df559..f0b101b5803b 100644 --- a/Lib/tkinter/test/test_tkinter/test_text.py +++ b/Lib/tkinter/test/test_tkinter/test_text.py @@ -40,6 +40,60 @@ def test_search(self): self.assertEqual(text.search('-test', '1.0', 'end'), '1.2') self.assertEqual(text.search('test', '1.0', 'end'), '1.3') + def test_count(self): + # XXX Some assertions do not check against the intended result, + # but instead check the current result to prevent regression. + text = self.text + text.insert('1.0', + 'Lorem ipsum dolor sit amet,\n' + 'consectetur adipiscing elit,\n' + 'sed do eiusmod tempor incididunt\n' + 'ut labore et dolore magna aliqua.') + + options = ('chars', 'indices', 'lines', + 'displaychars', 'displayindices', 'displaylines', + 'xpixels', 'ypixels') + if self.wantobjects: + self.assertEqual(len(text.count('1.0', 'end', *options)), 8) + else: + text.count('1.0', 'end', *options) + self.assertEqual(text.count('1.0', 'end', 'chars', 'lines'), (124, 4) + if self.wantobjects else '124 4') + self.assertEqual(text.count('1.3', '4.5', 'chars', 'lines'), (92, 3) + if self.wantobjects else '92 3') + self.assertEqual(text.count('4.5', '1.3', 'chars', 'lines'), (-92, -3) + if self.wantobjects else '-92 -3') + self.assertEqual(text.count('1.3', '1.3', 'chars', 'lines'), (0, 0) + if self.wantobjects else '0 0') + self.assertEqual(text.count('1.0', 'end', 'lines'), (4,) + if self.wantobjects else ('4',)) + self.assertEqual(text.count('end', '1.0', 'lines'), (-4,) + if self.wantobjects else ('-4',)) + self.assertEqual(text.count('1.3', '1.5', 'lines'), None + if self.wantobjects else ('0',)) + self.assertEqual(text.count('1.3', '1.3', 'lines'), None + if self.wantobjects else ('0',)) + self.assertEqual(text.count('1.0', 'end'), (124,) # 'indices' by default + if self.wantobjects else ('124',)) + self.assertRaises(tkinter.TclError, text.count, '1.0', 'end', 'spam') + # '-lines' is ignored, 'indices' is used by default + self.assertEqual(text.count('1.0', 'end', '-lines'), (124,) + if self.wantobjects else ('124',)) + + self.assertIsInstance(text.count('1.3', '1.5', 'ypixels'), tuple) + self.assertIsInstance(text.count('1.3', '1.5', 'update', 'ypixels'), int + if self.wantobjects else str) + self.assertEqual(text.count('1.3', '1.3', 'update', 'ypixels'), None + if self.wantobjects else '0') + self.assertEqual(text.count('1.3', '1.5', 'update', 'indices'), 2 + if self.wantobjects else '2') + self.assertEqual(text.count('1.3', '1.3', 'update', 'indices'), None + if self.wantobjects else '0') + self.assertEqual(text.count('1.3', '1.5', 'update'), (2,) + if self.wantobjects else ('2',)) + self.assertEqual(text.count('1.3', '1.3', 'update'), None + if self.wantobjects else ('0',)) + if __name__ == "__main__": unittest.main() From webhook-mailer at python.org Wed Oct 19 02:44:49 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 19 Oct 2022 06:44:49 -0000 Subject: [Python-checkins] gh-97928: Add tests for tkinter.Text.count() (GH-98269) Message-ID: https://github.com/python/cpython/commit/a847255cbbe5e52b871c0746ebafa07a00a335f4 commit: a847255cbbe5e52b871c0746ebafa07a00a335f4 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-18T23:44:43-07:00 summary: gh-97928: Add tests for tkinter.Text.count() (GH-98269) (cherry picked from commit 1b684c8f5f738b56f859e5c87b7280610b90399f) Co-authored-by: Serhiy Storchaka files: M Lib/tkinter/test/test_tkinter/test_text.py diff --git a/Lib/tkinter/test/test_tkinter/test_text.py b/Lib/tkinter/test/test_tkinter/test_text.py index 482f150df559..f0b101b5803b 100644 --- a/Lib/tkinter/test/test_tkinter/test_text.py +++ b/Lib/tkinter/test/test_tkinter/test_text.py @@ -40,6 +40,60 @@ def test_search(self): self.assertEqual(text.search('-test', '1.0', 'end'), '1.2') self.assertEqual(text.search('test', '1.0', 'end'), '1.3') + def test_count(self): + # XXX Some assertions do not check against the intended result, + # but instead check the current result to prevent regression. + text = self.text + text.insert('1.0', + 'Lorem ipsum dolor sit amet,\n' + 'consectetur adipiscing elit,\n' + 'sed do eiusmod tempor incididunt\n' + 'ut labore et dolore magna aliqua.') + + options = ('chars', 'indices', 'lines', + 'displaychars', 'displayindices', 'displaylines', + 'xpixels', 'ypixels') + if self.wantobjects: + self.assertEqual(len(text.count('1.0', 'end', *options)), 8) + else: + text.count('1.0', 'end', *options) + self.assertEqual(text.count('1.0', 'end', 'chars', 'lines'), (124, 4) + if self.wantobjects else '124 4') + self.assertEqual(text.count('1.3', '4.5', 'chars', 'lines'), (92, 3) + if self.wantobjects else '92 3') + self.assertEqual(text.count('4.5', '1.3', 'chars', 'lines'), (-92, -3) + if self.wantobjects else '-92 -3') + self.assertEqual(text.count('1.3', '1.3', 'chars', 'lines'), (0, 0) + if self.wantobjects else '0 0') + self.assertEqual(text.count('1.0', 'end', 'lines'), (4,) + if self.wantobjects else ('4',)) + self.assertEqual(text.count('end', '1.0', 'lines'), (-4,) + if self.wantobjects else ('-4',)) + self.assertEqual(text.count('1.3', '1.5', 'lines'), None + if self.wantobjects else ('0',)) + self.assertEqual(text.count('1.3', '1.3', 'lines'), None + if self.wantobjects else ('0',)) + self.assertEqual(text.count('1.0', 'end'), (124,) # 'indices' by default + if self.wantobjects else ('124',)) + self.assertRaises(tkinter.TclError, text.count, '1.0', 'end', 'spam') + # '-lines' is ignored, 'indices' is used by default + self.assertEqual(text.count('1.0', 'end', '-lines'), (124,) + if self.wantobjects else ('124',)) + + self.assertIsInstance(text.count('1.3', '1.5', 'ypixels'), tuple) + self.assertIsInstance(text.count('1.3', '1.5', 'update', 'ypixels'), int + if self.wantobjects else str) + self.assertEqual(text.count('1.3', '1.3', 'update', 'ypixels'), None + if self.wantobjects else '0') + self.assertEqual(text.count('1.3', '1.5', 'update', 'indices'), 2 + if self.wantobjects else '2') + self.assertEqual(text.count('1.3', '1.3', 'update', 'indices'), None + if self.wantobjects else '0') + self.assertEqual(text.count('1.3', '1.5', 'update'), (2,) + if self.wantobjects else ('2',)) + self.assertEqual(text.count('1.3', '1.3', 'update'), None + if self.wantobjects else ('0',)) + if __name__ == "__main__": unittest.main() From webhook-mailer at python.org Wed Oct 19 05:30:50 2022 From: webhook-mailer at python.org (serhiy-storchaka) Date: Wed, 19 Oct 2022 09:30:50 -0000 Subject: [Python-checkins] gh-97928: Fix handling options starting with "-" in tkinter.Text.count() (GH-98436) Message-ID: https://github.com/python/cpython/commit/e4ec8de6fa6f0a07e64f6a3e3f894926b4b0652d commit: e4ec8de6fa6f0a07e64f6a3e3f894926b4b0652d branch: main author: Serhiy Storchaka committer: serhiy-storchaka date: 2022-10-19T12:30:14+03:00 summary: gh-97928: Fix handling options starting with "-" in tkinter.Text.count() (GH-98436) Previously they were silently ignored. Now they are errors. files: A Misc/NEWS.d/next/Library/2022-10-19-09-29-12.gh-issue-97928.xj3im7.rst M Lib/test/test_tkinter/test_text.py M Lib/tkinter/__init__.py diff --git a/Lib/test/test_tkinter/test_text.py b/Lib/test/test_tkinter/test_text.py index b8dfde62070b..328e4256ce07 100644 --- a/Lib/test/test_tkinter/test_text.py +++ b/Lib/test/test_tkinter/test_text.py @@ -76,9 +76,7 @@ def test_count(self): self.assertEqual(text.count('1.0', 'end'), (124,) # 'indices' by default if self.wantobjects else ('124',)) self.assertRaises(tkinter.TclError, text.count, '1.0', 'end', 'spam') - # '-lines' is ignored, 'indices' is used by default - self.assertEqual(text.count('1.0', 'end', '-lines'), (124,) - if self.wantobjects else ('124',)) + self.assertRaises(tkinter.TclError, text.count, '1.0', 'end', '-lines') self.assertIsInstance(text.count('1.3', '1.5', 'ypixels'), tuple) self.assertIsInstance(text.count('1.3', '1.5', 'update', 'ypixels'), int diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index 356446911e0a..a8e7bf490ad4 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -3648,7 +3648,7 @@ def count(self, index1, index2, *args): # new in Tk 8.5 "lines", "xpixels" and "ypixels". There is an additional possible option "update", which if given then all subsequent options ensure that any possible out of date information is recalculated.""" - args = ['-%s' % arg for arg in args if not arg.startswith('-')] + args = ['-%s' % arg for arg in args] args += [index1, index2] res = self.tk.call(self._w, 'count', *args) or None if res is not None and len(args) <= 3: diff --git a/Misc/NEWS.d/next/Library/2022-10-19-09-29-12.gh-issue-97928.xj3im7.rst b/Misc/NEWS.d/next/Library/2022-10-19-09-29-12.gh-issue-97928.xj3im7.rst new file mode 100644 index 000000000000..cf33db7548f6 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-19-09-29-12.gh-issue-97928.xj3im7.rst @@ -0,0 +1,2 @@ +:meth:`tkinter.Text.count` raises now an exception for options starting with +"-" instead of silently ignoring them. From webhook-mailer at python.org Wed Oct 19 05:49:01 2022 From: webhook-mailer at python.org (iritkatriel) Date: Wed, 19 Oct 2022 09:49:01 -0000 Subject: [Python-checkins] gh-98398: Fix source locations for 'assert' bytecode (GH-98405) Message-ID: https://github.com/python/cpython/commit/9be05df3997de3fe9d34525871baa375cbccd7fc commit: 9be05df3997de3fe9d34525871baa375cbccd7fc branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2022-10-19T10:48:50+01:00 summary: gh-98398: Fix source locations for 'assert' bytecode (GH-98405) files: A Misc/NEWS.d/next/Core and Builtins/2022-10-18-16-17-44.gh-issue-98398.x4rYK_.rst M Lib/test/test_compile.py M Python/compile.c diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index a5434d6fd512..85f05a8dd257 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -1215,7 +1215,6 @@ def test_multiline_boolean_expression(self): d > 0)): x = 42 """ - compiled_code, _ = self.check_positions_against_ast(snippet) # jump if a is true: self.assertOpcodeSourcePositionIs(compiled_code, 'POP_JUMP_IF_TRUE', @@ -1233,6 +1232,23 @@ def test_multiline_boolean_expression(self): self.assertOpcodeSourcePositionIs(compiled_code, 'POP_JUMP_IF_TRUE', line=4, end_line=4, column=8, end_column=13, occurrence=2) + def test_multiline_assert(self): + snippet = """\ +assert (a > 0 and + bb > 0 and + ccc == 4), "error msg" +""" + compiled_code, _ = self.check_positions_against_ast(snippet) + self.assertOpcodeSourcePositionIs(compiled_code, 'LOAD_ASSERTION_ERROR', + line=1, end_line=3, column=0, end_column=30, occurrence=1) + # The "error msg": + self.assertOpcodeSourcePositionIs(compiled_code, 'LOAD_CONST', + line=3, end_line=3, column=19, end_column=30, occurrence=4) + self.assertOpcodeSourcePositionIs(compiled_code, 'CALL', + line=1, end_line=3, column=0, end_column=30, occurrence=1) + self.assertOpcodeSourcePositionIs(compiled_code, 'RAISE_VARARGS', + line=1, end_line=3, column=0, end_column=30, occurrence=1) + def test_very_long_line_end_offset(self): # Make sure we get the correct column offset for offsets # too large to store in a byte. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-18-16-17-44.gh-issue-98398.x4rYK_.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-18-16-17-44.gh-issue-98398.x4rYK_.rst new file mode 100644 index 000000000000..35d33c90a690 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-18-16-17-44.gh-issue-98398.x4rYK_.rst @@ -0,0 +1 @@ +Fix source location of 'assert' bytecodes. diff --git a/Python/compile.c b/Python/compile.c index 4d5b41aa1300..c888f4064c79 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -3960,7 +3960,6 @@ compiler_from_import(struct compiler *c, stmt_ty s) static int compiler_assert(struct compiler *c, stmt_ty s) { - location loc = LOC(s); /* Always emit a warning if the test is a non-zero length tuple */ if ((s->v.Assert.test->kind == Tuple_kind && asdl_seq_LEN(s->v.Assert.test->v.Tuple.elts) > 0) || @@ -3968,23 +3967,26 @@ compiler_assert(struct compiler *c, stmt_ty s) PyTuple_Check(s->v.Assert.test->v.Constant.value) && PyTuple_Size(s->v.Assert.test->v.Constant.value) > 0)) { - if (!compiler_warn(c, loc, "assertion is always true, " - "perhaps remove parentheses?")) + if (!compiler_warn(c, LOC(s), "assertion is always true, " + "perhaps remove parentheses?")) { return 0; } } - if (c->c_optimize) + if (c->c_optimize) { return 1; + } NEW_JUMP_TARGET_LABEL(c, end); - if (!compiler_jump_if(c, &loc, s->v.Assert.test, end, 1)) + location loc = LOC(s); + if (!compiler_jump_if(c, &loc, s->v.Assert.test, end, 1)) { return 0; - ADDOP(c, loc, LOAD_ASSERTION_ERROR); + } + ADDOP(c, LOC(s), LOAD_ASSERTION_ERROR); if (s->v.Assert.msg) { VISIT(c, expr, s->v.Assert.msg); - ADDOP_I(c, loc, CALL, 0); + ADDOP_I(c, LOC(s), CALL, 0); } - ADDOP_I(c, loc, RAISE_VARARGS, 1); + ADDOP_I(c, LOC(s), RAISE_VARARGS, 1); USE_LABEL(c, end); return 1; From webhook-mailer at python.org Wed Oct 19 05:57:51 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 19 Oct 2022 09:57:51 -0000 Subject: [Python-checkins] gh-97928: Fix handling options starting with "-" in tkinter.Text.count() (GH-98436) Message-ID: https://github.com/python/cpython/commit/eee8b99dc3e461e6a0664c8bf449887eb7a1d4c3 commit: eee8b99dc3e461e6a0664c8bf449887eb7a1d4c3 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-19T02:57:18-07:00 summary: gh-97928: Fix handling options starting with "-" in tkinter.Text.count() (GH-98436) Previously they were silently ignored. Now they are errors. (cherry picked from commit e4ec8de6fa6f0a07e64f6a3e3f894926b4b0652d) Co-authored-by: Serhiy Storchaka files: A Misc/NEWS.d/next/Library/2022-10-19-09-29-12.gh-issue-97928.xj3im7.rst M Lib/tkinter/__init__.py M Lib/tkinter/test/test_tkinter/test_text.py diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index c7176e69e529..d42d9a013dd6 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -3621,7 +3621,7 @@ def count(self, index1, index2, *args): # new in Tk 8.5 "lines", "xpixels" and "ypixels". There is an additional possible option "update", which if given then all subsequent options ensure that any possible out of date information is recalculated.""" - args = ['-%s' % arg for arg in args if not arg.startswith('-')] + args = ['-%s' % arg for arg in args] args += [index1, index2] res = self.tk.call(self._w, 'count', *args) or None if res is not None and len(args) <= 3: diff --git a/Lib/tkinter/test/test_tkinter/test_text.py b/Lib/tkinter/test/test_tkinter/test_text.py index f0b101b5803b..ea557586c770 100644 --- a/Lib/tkinter/test/test_tkinter/test_text.py +++ b/Lib/tkinter/test/test_tkinter/test_text.py @@ -76,9 +76,7 @@ def test_count(self): self.assertEqual(text.count('1.0', 'end'), (124,) # 'indices' by default if self.wantobjects else ('124',)) self.assertRaises(tkinter.TclError, text.count, '1.0', 'end', 'spam') - # '-lines' is ignored, 'indices' is used by default - self.assertEqual(text.count('1.0', 'end', '-lines'), (124,) - if self.wantobjects else ('124',)) + self.assertRaises(tkinter.TclError, text.count, '1.0', 'end', '-lines') self.assertIsInstance(text.count('1.3', '1.5', 'ypixels'), tuple) self.assertIsInstance(text.count('1.3', '1.5', 'update', 'ypixels'), int diff --git a/Misc/NEWS.d/next/Library/2022-10-19-09-29-12.gh-issue-97928.xj3im7.rst b/Misc/NEWS.d/next/Library/2022-10-19-09-29-12.gh-issue-97928.xj3im7.rst new file mode 100644 index 000000000000..cf33db7548f6 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-19-09-29-12.gh-issue-97928.xj3im7.rst @@ -0,0 +1,2 @@ +:meth:`tkinter.Text.count` raises now an exception for options starting with +"-" instead of silently ignoring them. From webhook-mailer at python.org Wed Oct 19 05:57:51 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 19 Oct 2022 09:57:51 -0000 Subject: [Python-checkins] gh-97928: Fix handling options starting with "-" in tkinter.Text.count() (GH-98436) Message-ID: https://github.com/python/cpython/commit/30b9c4d7842d97abbc49d57e031671d60704723b commit: 30b9c4d7842d97abbc49d57e031671d60704723b branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-19T02:57:27-07:00 summary: gh-97928: Fix handling options starting with "-" in tkinter.Text.count() (GH-98436) Previously they were silently ignored. Now they are errors. (cherry picked from commit e4ec8de6fa6f0a07e64f6a3e3f894926b4b0652d) Co-authored-by: Serhiy Storchaka files: A Misc/NEWS.d/next/Library/2022-10-19-09-29-12.gh-issue-97928.xj3im7.rst M Lib/tkinter/__init__.py M Lib/tkinter/test/test_tkinter/test_text.py diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index 356446911e0a..a8e7bf490ad4 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -3648,7 +3648,7 @@ def count(self, index1, index2, *args): # new in Tk 8.5 "lines", "xpixels" and "ypixels". There is an additional possible option "update", which if given then all subsequent options ensure that any possible out of date information is recalculated.""" - args = ['-%s' % arg for arg in args if not arg.startswith('-')] + args = ['-%s' % arg for arg in args] args += [index1, index2] res = self.tk.call(self._w, 'count', *args) or None if res is not None and len(args) <= 3: diff --git a/Lib/tkinter/test/test_tkinter/test_text.py b/Lib/tkinter/test/test_tkinter/test_text.py index f0b101b5803b..ea557586c770 100644 --- a/Lib/tkinter/test/test_tkinter/test_text.py +++ b/Lib/tkinter/test/test_tkinter/test_text.py @@ -76,9 +76,7 @@ def test_count(self): self.assertEqual(text.count('1.0', 'end'), (124,) # 'indices' by default if self.wantobjects else ('124',)) self.assertRaises(tkinter.TclError, text.count, '1.0', 'end', 'spam') - # '-lines' is ignored, 'indices' is used by default - self.assertEqual(text.count('1.0', 'end', '-lines'), (124,) - if self.wantobjects else ('124',)) + self.assertRaises(tkinter.TclError, text.count, '1.0', 'end', '-lines') self.assertIsInstance(text.count('1.3', '1.5', 'ypixels'), tuple) self.assertIsInstance(text.count('1.3', '1.5', 'update', 'ypixels'), int diff --git a/Misc/NEWS.d/next/Library/2022-10-19-09-29-12.gh-issue-97928.xj3im7.rst b/Misc/NEWS.d/next/Library/2022-10-19-09-29-12.gh-issue-97928.xj3im7.rst new file mode 100644 index 000000000000..cf33db7548f6 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-19-09-29-12.gh-issue-97928.xj3im7.rst @@ -0,0 +1,2 @@ +:meth:`tkinter.Text.count` raises now an exception for options starting with +"-" instead of silently ignoring them. From webhook-mailer at python.org Wed Oct 19 06:05:17 2022 From: webhook-mailer at python.org (iritkatriel) Date: Wed, 19 Oct 2022 10:05:17 -0000 Subject: [Python-checkins] gh-92886: Fix tests that fail when running with optimizations (`-O`) in `test_py_compile.py` (GH-93235) Message-ID: https://github.com/python/cpython/commit/602ea40d8936812367db2ffed5226ca25a607f46 commit: 602ea40d8936812367db2ffed5226ca25a607f46 branch: main author: Jack Hindmarch <1750152+jackh-ncl at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2022-10-19T11:05:08+01:00 summary: gh-92886: Fix tests that fail when running with optimizations (`-O`) in `test_py_compile.py` (GH-93235) files: A Misc/NEWS.d/next/Tests/2022-05-25-22-53-30.gh-issue-92886.mIfdtz.rst M Lib/test/test_py_compile.py diff --git a/Lib/test/test_py_compile.py b/Lib/test/test_py_compile.py index a4a52b180dbb..5e0a44ad9691 100644 --- a/Lib/test/test_py_compile.py +++ b/Lib/test/test_py_compile.py @@ -235,11 +235,12 @@ def pycompilecmd(self, *args, **kwargs): # assert_python_* helpers don't return proc object. We'll just use # subprocess.run() instead of spawn_python() and its friends to test # stdin support of the CLI. + opts = '-m' if __debug__ else '-Om' if args and args[0] == '-' and 'input' in kwargs: - return subprocess.run([sys.executable, '-m', 'py_compile', '-'], + return subprocess.run([sys.executable, opts, 'py_compile', '-'], input=kwargs['input'].encode(), capture_output=True) - return script_helper.assert_python_ok('-m', 'py_compile', *args, **kwargs) + return script_helper.assert_python_ok(opts, 'py_compile', *args, **kwargs) def pycompilecmd_failure(self, *args): return script_helper.assert_python_failure('-m', 'py_compile', *args) diff --git a/Misc/NEWS.d/next/Tests/2022-05-25-22-53-30.gh-issue-92886.mIfdtz.rst b/Misc/NEWS.d/next/Tests/2022-05-25-22-53-30.gh-issue-92886.mIfdtz.rst new file mode 100644 index 000000000000..014e9e614cca --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2022-05-25-22-53-30.gh-issue-92886.mIfdtz.rst @@ -0,0 +1 @@ +Fixing tests that fail when running with optimizations (``-O``) in ``test_py_compile.py`` From webhook-mailer at python.org Wed Oct 19 06:07:13 2022 From: webhook-mailer at python.org (iritkatriel) Date: Wed, 19 Oct 2022 10:07:13 -0000 Subject: [Python-checkins] gh-92886: Fix tests that fail when running with optimizations (`-O`) in `_test_multiprocessing.py` (GH-93233) Message-ID: https://github.com/python/cpython/commit/a3be8743348464364db9d513b22bcdd39a2c5fb5 commit: a3be8743348464364db9d513b22bcdd39a2c5fb5 branch: main author: Jack Hindmarch <1750152+jackh-ncl at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2022-10-19T11:07:07+01:00 summary: gh-92886: Fix tests that fail when running with optimizations (`-O`) in `_test_multiprocessing.py` (GH-93233) files: A Misc/NEWS.d/next/Tests/2022-05-25-22-34-10.gh-issue-92886.1Lkt8S.rst M Lib/test/_test_multiprocessing.py diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index f74d8d7fbd72..a66f4f5b897c 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -5698,45 +5698,48 @@ def test_joinable_queue(self): @classmethod def _test_list(cls, obj): - assert obj[0] == 5 - assert obj.count(5) == 1 - assert obj.index(5) == 0 + case = unittest.TestCase() + case.assertEqual(obj[0], 5) + case.assertEqual(obj.count(5), 1) + case.assertEqual(obj.index(5), 0) obj.sort() obj.reverse() for x in obj: pass - assert len(obj) == 1 - assert obj.pop(0) == 5 + case.assertEqual(len(obj), 1) + case.assertEqual(obj.pop(0), 5) def test_list(self): o = self.manager.list() o.append(5) self.run_worker(self._test_list, o) - assert not o + self.assertIsNotNone(o) self.assertEqual(len(o), 0) @classmethod def _test_dict(cls, obj): - assert len(obj) == 1 - assert obj['foo'] == 5 - assert obj.get('foo') == 5 - assert list(obj.items()) == [('foo', 5)] - assert list(obj.keys()) == ['foo'] - assert list(obj.values()) == [5] - assert obj.copy() == {'foo': 5} - assert obj.popitem() == ('foo', 5) + case = unittest.TestCase() + case.assertEqual(len(obj), 1) + case.assertEqual(obj['foo'], 5) + case.assertEqual(obj.get('foo'), 5) + case.assertListEqual(list(obj.items()), [('foo', 5)]) + case.assertListEqual(list(obj.keys()), ['foo']) + case.assertListEqual(list(obj.values()), [5]) + case.assertDictEqual(obj.copy(), {'foo': 5}) + case.assertTupleEqual(obj.popitem(), ('foo', 5)) def test_dict(self): o = self.manager.dict() o['foo'] = 5 self.run_worker(self._test_dict, o) - assert not o + self.assertIsNotNone(o) self.assertEqual(len(o), 0) @classmethod def _test_value(cls, obj): - assert obj.value == 1 - assert obj.get() == 1 + case = unittest.TestCase() + case.assertEqual(obj.value, 1) + case.assertEqual(obj.get(), 1) obj.set(2) def test_value(self): @@ -5747,10 +5750,11 @@ def test_value(self): @classmethod def _test_array(cls, obj): - assert obj[0] == 0 - assert obj[1] == 1 - assert len(obj) == 2 - assert list(obj) == [0, 1] + case = unittest.TestCase() + case.assertEqual(obj[0], 0) + case.assertEqual(obj[1], 1) + case.assertEqual(len(obj), 2) + case.assertListEqual(list(obj), [0, 1]) def test_array(self): o = self.manager.Array('i', [0, 1]) @@ -5758,8 +5762,9 @@ def test_array(self): @classmethod def _test_namespace(cls, obj): - assert obj.x == 0 - assert obj.y == 1 + case = unittest.TestCase() + case.assertEqual(obj.x, 0) + case.assertEqual(obj.y, 1) def test_namespace(self): o = self.manager.Namespace() diff --git a/Misc/NEWS.d/next/Tests/2022-05-25-22-34-10.gh-issue-92886.1Lkt8S.rst b/Misc/NEWS.d/next/Tests/2022-05-25-22-34-10.gh-issue-92886.1Lkt8S.rst new file mode 100644 index 000000000000..2b9c1b4d2dd4 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2022-05-25-22-34-10.gh-issue-92886.1Lkt8S.rst @@ -0,0 +1 @@ +Fixing tests that fail when running with optimizations (``-O``) in ``_test_multiprocessing.py`` From webhook-mailer at python.org Wed Oct 19 06:39:05 2022 From: webhook-mailer at python.org (iritkatriel) Date: Wed, 19 Oct 2022 10:39:05 -0000 Subject: [Python-checkins] gh-92886: Replace assertion statements in `handlers.BaseHandler` to support running with optimizations (`-O`) (GH-93231) Message-ID: https://github.com/python/cpython/commit/b6e59d76c0e1214ca2c927be35f165ecd1f763df commit: b6e59d76c0e1214ca2c927be35f165ecd1f763df branch: main author: Jack Hindmarch <1750152+jackh-ncl at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2022-10-19T11:38:59+01:00 summary: gh-92886: Replace assertion statements in `handlers.BaseHandler` to support running with optimizations (`-O`) (GH-93231) files: A Misc/NEWS.d/next/Library/2022-05-25-22-09-38.gh-issue-92886.ylwDSc.rst M Lib/wsgiref/handlers.py diff --git a/Lib/wsgiref/handlers.py b/Lib/wsgiref/handlers.py index 6623b700537c..cd0916dc5553 100644 --- a/Lib/wsgiref/handlers.py +++ b/Lib/wsgiref/handlers.py @@ -237,9 +237,7 @@ def start_response(self, status, headers,exc_info=None): self.status = status self.headers = self.headers_class(headers) status = self._convert_string_type(status, "Status") - assert len(status)>=4,"Status must be at least 4 characters" - assert status[:3].isdigit(), "Status message must begin w/3-digit code" - assert status[3]==" ", "Status message must have a space after code" + self._validate_status(status) if __debug__: for name, val in headers: @@ -250,6 +248,14 @@ def start_response(self, status, headers,exc_info=None): return self.write + def _validate_status(self, status): + if len(status) < 4: + raise AssertionError("Status must be at least 4 characters") + if not status[:3].isdigit(): + raise AssertionError("Status message must begin w/3-digit code") + if status[3] != " ": + raise AssertionError("Status message must have a space after code") + def _convert_string_type(self, value, title): """Convert/check value type.""" if type(value) is str: diff --git a/Misc/NEWS.d/next/Library/2022-05-25-22-09-38.gh-issue-92886.ylwDSc.rst b/Misc/NEWS.d/next/Library/2022-05-25-22-09-38.gh-issue-92886.ylwDSc.rst new file mode 100644 index 000000000000..7854381de30f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-05-25-22-09-38.gh-issue-92886.ylwDSc.rst @@ -0,0 +1 @@ +Replace ``assert`` statements with ``raise AssertionError()`` in :class:`~wsgiref.BaseHandler` so that the tested behaviour is maintained running with optimizations ``(-O)``. From webhook-mailer at python.org Wed Oct 19 08:00:34 2022 From: webhook-mailer at python.org (ezio-melotti) Date: Wed, 19 Oct 2022 12:00:34 -0000 Subject: [Python-checkins] Docs: Bump sphinx-lint and fix unbalanced inline literal markup (#98441) Message-ID: https://github.com/python/cpython/commit/50553004fe12dcaed3aa9a96b356eb84f247c8fd commit: 50553004fe12dcaed3aa9a96b356eb84f247c8fd branch: main author: Hugo van Kemenade committer: ezio-melotti date: 2022-10-19T14:00:28+02:00 summary: Docs: Bump sphinx-lint and fix unbalanced inline literal markup (#98441) Bump sphinx-lint and fix unbalanced inline literal markup files: M Doc/requirements.txt M Misc/NEWS.d/next/C API/2022-07-12-17-39-32.gh-issue-94731.9CPJNU.rst diff --git a/Doc/requirements.txt b/Doc/requirements.txt index 32c53e95917e..958665db69e2 100644 --- a/Doc/requirements.txt +++ b/Doc/requirements.txt @@ -7,10 +7,7 @@ sphinx==4.5.0 blurb -# sphinx-lint 0.6.2 yields many default role errors due to the new regular -# expression used for default role detection, so we don't use the version -# until the errors are fixed. -sphinx-lint==0.6.5 +sphinx-lint==0.6.7 # The theme used by the documentation is stored separately, so we need # to install that as well. diff --git a/Misc/NEWS.d/next/C API/2022-07-12-17-39-32.gh-issue-94731.9CPJNU.rst b/Misc/NEWS.d/next/C API/2022-07-12-17-39-32.gh-issue-94731.9CPJNU.rst index b7816d28215e..a96b002915c2 100644 --- a/Misc/NEWS.d/next/C API/2022-07-12-17-39-32.gh-issue-94731.9CPJNU.rst +++ b/Misc/NEWS.d/next/C API/2022-07-12-17-39-32.gh-issue-94731.9CPJNU.rst @@ -1,3 +1,3 @@ Python again uses C-style casts for most casting operations when compiled with C++. This may trigger compiler warnings, if they are enabled with e.g. -``-Wold-style-cast `` or ``-Wzero-as-null-pointer-constant`` options for ``g++``. +``-Wold-style-cast`` or ``-Wzero-as-null-pointer-constant`` options for ``g++``. From webhook-mailer at python.org Wed Oct 19 10:21:53 2022 From: webhook-mailer at python.org (rhettinger) Date: Wed, 19 Oct 2022 14:21:53 -0000 Subject: [Python-checkins] [3.11] Sync the batched() recipe with the 3.12 implementation (GH-98446) Message-ID: https://github.com/python/cpython/commit/07cc997e00507e5cd7d242ff881ff7d7837cd817 commit: 07cc997e00507e5cd7d242ff881ff7d7837cd817 branch: 3.11 author: Raymond Hettinger committer: rhettinger date: 2022-10-19T09:21:14-05:00 summary: [3.11] Sync the batched() recipe with the 3.12 implementation (GH-98446) files: M Doc/library/itertools.rst diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 0f295741e655..eb4c8088c771 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -887,6 +887,8 @@ which incur interpreter overhead. def batched(iterable, n): "Batch data into lists of length n. The last batch may be shorter." # batched('ABCDEFG', 3) --> ABC DEF G + if n < 1: + raise ValueError('n must be at least one') it = iter(iterable) while (batch := list(islice(it, n))): yield batch @@ -1272,12 +1274,6 @@ which incur interpreter overhead. [['A', 'B'], ['C', 'D'], ['E', 'F'], ['G']] >>> list(batched('ABCDEFG', 1)) [['A'], ['B'], ['C'], ['D'], ['E'], ['F'], ['G']] - >>> list(batched('ABCDEFG', 0)) - [] - >>> list(batched('ABCDEFG', -1)) - Traceback (most recent call last): - ... - ValueError: Stop argument for islice() must be None or an integer: 0 <= x <= sys.maxsize. >>> s = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' >>> all(list(flatten(batched(s[:n], 5))) == list(s[:n]) for n in range(len(s))) True From webhook-mailer at python.org Wed Oct 19 10:49:40 2022 From: webhook-mailer at python.org (vsajip) Date: Wed, 19 Oct 2022 14:49:40 -0000 Subject: [Python-checkins] [doc] Refresh the venv introduction documentation, and correct the statement about VIRTUAL_ENV (GH-98350) Message-ID: https://github.com/python/cpython/commit/1a6bacb31f7b49c244a6cc3ff0fa7f71a82412ef commit: 1a6bacb31f7b49c244a6cc3ff0fa7f71a82412ef branch: main author: Phil Elson committer: vsajip date: 2022-10-19T15:49:34+01:00 summary: [doc] Refresh the venv introduction documentation, and correct the statement about VIRTUAL_ENV (GH-98350) Co-authored-by: C.A.M. Gerlach files: M Doc/library/venv.rst M Doc/using/venv-create.inc diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst index 40eccdec16b3..adc6cd339ac1 100644 --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -15,14 +15,22 @@ -------------- -The :mod:`venv` module provides support for creating lightweight "virtual -environments" with their own site directories, optionally isolated from system -site directories. Each virtual environment has its own Python binary (which -matches the version of the binary that was used to create this environment) and -can have its own independent set of installed Python packages in its site -directories. +.. _venv-def: +.. _venv-intro: + +The :mod:`!venv` module supports creating lightweight "virtual environments", +each with their own independent set of Python packages installed in +their :mod:`site` directories. +A virtual environment is created on top of an existing +Python installation, known as the virtual environment's "base" Python, and may +optionally be isolated from the packages in the base environment, +so only those explicitly installed in the virtual environment are available. -See :pep:`405` for more information about Python virtual environments. +When used from within a virtual environment, common installation tools such as +`pip`_ will install Python packages into a virtual environment +without needing to be told to do so explicitly. + +See :pep:`405` for more background on Python virtual environments. .. seealso:: @@ -36,54 +44,72 @@ Creating virtual environments .. include:: /using/venv-create.inc +.. _venv-explanation: -.. _venv-def: +How venvs work +-------------- -.. note:: A virtual environment is a Python environment such that the Python - interpreter, libraries and scripts installed into it are isolated from those - installed in other virtual environments, and (by default) any libraries - installed in a "system" Python, i.e., one which is installed as part of your - operating system. - - A virtual environment is a directory tree which contains Python executable - files and other files which indicate that it is a virtual environment. - - Common installation tools such as setuptools_ and pip_ work as - expected with virtual environments. In other words, when a virtual - environment is active, they install Python packages into the virtual - environment without needing to be told to do so explicitly. - - When a virtual environment is active (i.e., the virtual environment's Python - interpreter is running), the attributes :attr:`sys.prefix` and - :attr:`sys.exec_prefix` point to the base directory of the virtual - environment, whereas :attr:`sys.base_prefix` and - :attr:`sys.base_exec_prefix` point to the non-virtual environment Python - installation which was used to create the virtual environment. If a virtual - environment is not active, then :attr:`sys.prefix` is the same as - :attr:`sys.base_prefix` and :attr:`sys.exec_prefix` is the same as - :attr:`sys.base_exec_prefix` (they all point to a non-virtual environment - Python installation). - - When a virtual environment is active, any options that change the - installation path will be ignored from all ``setuptools`` configuration - files to prevent projects being inadvertently installed outside of the - virtual environment. - - When working in a command shell, users can make a virtual environment active - by running an ``activate`` script in the virtual environment's executables - directory (the precise filename and command to use the file is - shell-dependent), which prepends the virtual environment's directory for - executables to the ``PATH`` environment variable for the running shell. There - should be no need in other circumstances to activate a virtual - environment; scripts installed into virtual environments have a "shebang" - line which points to the virtual environment's Python interpreter. This means - that the script will run with that interpreter regardless of the value of - ``PATH``. On Windows, "shebang" line processing is supported if you have the - Python Launcher for Windows installed (this was added to Python in 3.3 - see - :pep:`397` for more details). Thus, double-clicking an installed script in a - Windows Explorer window should run the script with the correct interpreter - without there needing to be any reference to its virtual environment in - ``PATH``. +When a Python interpreter is running from a virtual environment, +:data:`sys.prefix` and :data:`sys.exec_prefix` +point to the directories of the virtual environment, +whereas :data:`sys.base_prefix` and :data:`sys.base_exec_prefix` +point to those of the base Python used to create the environment. +It is sufficient to check +``sys.prefix == sys.base_prefix`` to determine if the current interpreter is +running from a virtual environment. + +A virtual environment may be "activated" using a script in its binary directory +(``bin`` on POSIX; ``Scripts`` on Windows). +This will prepend that directory to your :envvar:`!PATH`, so that running +:program:`!python` will invoke the environment's Python interpreter +and you can run installed scripts without having to use their full path. +The invocation of the activation script is platform-specific +(:samp:`{}` must be replaced by the path to the directory +containing the virtual environment): + ++-------------+------------+--------------------------------------------------+ +| Platform | Shell | Command to activate virtual environment | ++=============+============+==================================================+ +| POSIX | bash/zsh | :samp:`$ source {}/bin/activate` | +| +------------+--------------------------------------------------+ +| | fish | :samp:`$ source {}/bin/activate.fish` | +| +------------+--------------------------------------------------+ +| | csh/tcsh | :samp:`$ source {}/bin/activate.csh` | +| +------------+--------------------------------------------------+ +| | PowerShell | :samp:`$ {}/bin/Activate.ps1` | ++-------------+------------+--------------------------------------------------+ +| Windows | cmd.exe | :samp:`C:\\> {}\\Scripts\\activate.bat` | +| +------------+--------------------------------------------------+ +| | PowerShell | :samp:`PS C:\\> {}\\Scripts\\Activate.ps1` | ++-------------+------------+--------------------------------------------------+ + +.. versionadded:: 3.4 + :program:`!fish` and :program:`!csh` activation scripts. + +.. versionadded:: 3.8 + PowerShell activation scripts installed under POSIX for PowerShell Core + support. + +You don't specifically *need* to activate a virtual environment, +as you can just specify the full path to that environment's +Python interpreter when invoking Python. +Furthermore, all scripts installed in the environment +should be runnable without activating it. + +In order to achieve this, scripts installed into virtual environments have +a "shebang" line which points to the environment's Python interpreter, +i.e. :samp:`#!/{}/bin/python`. +This means that the script will run with that interpreter regardless of the +value of :envvar:`!PATH`. On Windows, "shebang" line processing is supported if +you have the :ref:`launcher` installed. Thus, double-clicking an installed +script in a Windows Explorer window should run it with the correct interpreter +without the environment needing to be activated or on the :envvar:`!PATH`. + +When a virtual environment has been activated, the :envvar:`!VIRTUAL_ENV` +environment variable is set to the path of the environment. +Since explicitly activating a virtual environment is not required to use it, +:envvar:`!VIRTUAL_ENV` cannot be relied upon to determine +whether a virtual environment is being used. .. warning:: Because scripts installed in environments should not expect the environment to be activated, their shebang lines contain the absolute paths @@ -99,6 +125,11 @@ Creating virtual environments environment in its new location. Otherwise, software installed into the environment may not work as expected. +You can deactivate a virtual environment by typing ``deactivate`` in your shell. +The exact mechanism is platform-specific and is an internal implementation +detail (typically, a script or shell function will be used). + + .. _venv-api: API diff --git a/Doc/using/venv-create.inc b/Doc/using/venv-create.inc index c2a9f521a148..fd8cc019b4d1 100644 --- a/Doc/using/venv-create.inc +++ b/Doc/using/venv-create.inc @@ -105,45 +105,3 @@ Multiple paths can be given to ``venv``, in which case an identical virtual environment will be created, according to the given options, at each provided path. -Once a virtual environment has been created, it can be "activated" using a -script in the virtual environment's binary directory. The invocation of the -script is platform-specific (`` must be replaced by the path of the -directory containing the virtual environment): - -+-------------+-----------------+-----------------------------------------+ -| Platform | Shell | Command to activate virtual environment | -+=============+=================+=========================================+ -| POSIX | bash/zsh | $ source /bin/activate | -+-------------+-----------------+-----------------------------------------+ -| | fish | $ source /bin/activate.fish | -+-------------+-----------------+-----------------------------------------+ -| | csh/tcsh | $ source /bin/activate.csh | -+-------------+-----------------+-----------------------------------------+ -| | PowerShell Core | $ /bin/Activate.ps1 | -+-------------+-----------------+-----------------------------------------+ -| Windows | cmd.exe | C:\\> \\Scripts\\activate.bat | -+-------------+-----------------+-----------------------------------------+ -| | PowerShell | PS C:\\> \\Scripts\\Activate.ps1 | -+-------------+-----------------+-----------------------------------------+ - -When a virtual environment is active, the :envvar:`VIRTUAL_ENV` environment -variable is set to the path of the virtual environment. This can be used to -check if one is running inside a virtual environment. - -You don't specifically *need* to activate an environment; activation just -prepends the virtual environment's binary directory to your path, so that -"python" invokes the virtual environment's Python interpreter and you can run -installed scripts without having to use their full path. However, all scripts -installed in a virtual environment should be runnable without activating it, -and run with the virtual environment's Python automatically. - -You can deactivate a virtual environment by typing "deactivate" in your shell. -The exact mechanism is platform-specific and is an internal implementation -detail (typically a script or shell function will be used). - -.. versionadded:: 3.4 - ``fish`` and ``csh`` activation scripts. - -.. versionadded:: 3.8 - PowerShell activation scripts installed under POSIX for PowerShell Core - support. From webhook-mailer at python.org Wed Oct 19 11:36:20 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Wed, 19 Oct 2022 15:36:20 -0000 Subject: [Python-checkins] Doc: Remove title text from internal links (#98409) Message-ID: https://github.com/python/cpython/commit/52fcba651288ac1c0f9b1fb71379f1dad54ee1da commit: 52fcba651288ac1c0f9b1fb71379f1dad54ee1da branch: main author: Rafael Fontenelle committer: JelleZijlstra date: 2022-10-19T08:36:07-07:00 summary: Doc: Remove title text from internal links (#98409) Rely on the title of the linked internal page instead of putting the title. Sphinx will render with the title correctly, and this will reduce work for translators files: M Doc/whatsnew/3.10.rst diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index 8beb8b19463f..2389b1a63b1c 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -2152,8 +2152,7 @@ Porting to Python 3.10 * The ``PY_SSIZE_T_CLEAN`` macro must now be defined to use :c:func:`PyArg_ParseTuple` and :c:func:`Py_BuildValue` formats which use ``#``: ``es#``, ``et#``, ``s#``, ``u#``, ``y#``, ``z#``, ``U#`` and ``Z#``. - See :ref:`Parsing arguments and building values - ` and the :pep:`353`. + See :ref:`arg-parsing` and :pep:`353`. (Contributed by Victor Stinner in :issue:`40943`.) * Since :c:func:`Py_REFCNT()` is changed to the inline static function, @@ -2184,8 +2183,7 @@ Porting to Python 3.10 :c:func:`Py_GetProgramFullPath`, :c:func:`Py_GetPythonHome` and :c:func:`Py_GetProgramName` functions now return ``NULL`` if called before :c:func:`Py_Initialize` (before Python is initialized). Use the new - :ref:`Python Initialization Configuration API ` to get the - :ref:`Python Path Configuration. `. + :ref:`init-config` API to get the :ref:`init-path-config`. (Contributed by Victor Stinner in :issue:`42260`.) * :c:func:`PyList_SET_ITEM`, :c:func:`PyTuple_SET_ITEM` and @@ -2199,7 +2197,7 @@ Porting to Python 3.10 ``picklebufobject.h``, ``pyarena.h``, ``pyctype.h``, ``pydebug.h``, ``pyfpe.h``, and ``pytime.h`` have been moved to the ``Include/cpython`` directory. These files must not be included directly, as they are already - included in ``Python.h``: :ref:`Include Files `. If they have + included in ``Python.h``; see :ref:`api-includes`. If they have been included directly, consider including ``Python.h`` instead. (Contributed by Nicholas Sim in :issue:`35134`.) From webhook-mailer at python.org Wed Oct 19 11:44:11 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 19 Oct 2022 15:44:11 -0000 Subject: [Python-checkins] Doc: Remove title text from internal links (GH-98409) Message-ID: https://github.com/python/cpython/commit/f0c0d309c34f074eaa88c701b3c3c6ca97d54c72 commit: f0c0d309c34f074eaa88c701b3c3c6ca97d54c72 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-19T08:44:05-07:00 summary: Doc: Remove title text from internal links (GH-98409) Rely on the title of the linked internal page instead of putting the title. Sphinx will render with the title correctly, and this will reduce work for translators (cherry picked from commit 52fcba651288ac1c0f9b1fb71379f1dad54ee1da) Co-authored-by: Rafael Fontenelle files: M Doc/whatsnew/3.10.rst diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index 24d5bba66e33..549fdda3aa4e 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -2151,8 +2151,7 @@ Porting to Python 3.10 * The ``PY_SSIZE_T_CLEAN`` macro must now be defined to use :c:func:`PyArg_ParseTuple` and :c:func:`Py_BuildValue` formats which use ``#``: ``es#``, ``et#``, ``s#``, ``u#``, ``y#``, ``z#``, ``U#`` and ``Z#``. - See :ref:`Parsing arguments and building values - ` and the :pep:`353`. + See :ref:`arg-parsing` and :pep:`353`. (Contributed by Victor Stinner in :issue:`40943`.) * Since :c:func:`Py_REFCNT()` is changed to the inline static function, @@ -2183,8 +2182,7 @@ Porting to Python 3.10 :c:func:`Py_GetProgramFullPath`, :c:func:`Py_GetPythonHome` and :c:func:`Py_GetProgramName` functions now return ``NULL`` if called before :c:func:`Py_Initialize` (before Python is initialized). Use the new - :ref:`Python Initialization Configuration API ` to get the - :ref:`Python Path Configuration. `. + :ref:`init-config` API to get the :ref:`init-path-config`. (Contributed by Victor Stinner in :issue:`42260`.) * :c:func:`PyList_SET_ITEM`, :c:func:`PyTuple_SET_ITEM` and @@ -2198,7 +2196,7 @@ Porting to Python 3.10 ``picklebufobject.h``, ``pyarena.h``, ``pyctype.h``, ``pydebug.h``, ``pyfpe.h``, and ``pytime.h`` have been moved to the ``Include/cpython`` directory. These files must not be included directly, as they are already - included in ``Python.h``: :ref:`Include Files `. If they have + included in ``Python.h``; see :ref:`api-includes`. If they have been included directly, consider including ``Python.h`` instead. (Contributed by Nicholas Sim in :issue:`35134`.) From webhook-mailer at python.org Wed Oct 19 11:45:32 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 19 Oct 2022 15:45:32 -0000 Subject: [Python-checkins] Doc: Remove title text from internal links (GH-98409) Message-ID: https://github.com/python/cpython/commit/ac2e7bec08a82f124435b93d89bd48e835e809ba commit: ac2e7bec08a82f124435b93d89bd48e835e809ba branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-19T08:45:25-07:00 summary: Doc: Remove title text from internal links (GH-98409) Rely on the title of the linked internal page instead of putting the title. Sphinx will render with the title correctly, and this will reduce work for translators (cherry picked from commit 52fcba651288ac1c0f9b1fb71379f1dad54ee1da) Co-authored-by: Rafael Fontenelle files: M Doc/whatsnew/3.10.rst diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index 8434de2fbe55..ae5fe3f85dbe 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -2147,8 +2147,7 @@ Porting to Python 3.10 * The ``PY_SSIZE_T_CLEAN`` macro must now be defined to use :c:func:`PyArg_ParseTuple` and :c:func:`Py_BuildValue` formats which use ``#``: ``es#``, ``et#``, ``s#``, ``u#``, ``y#``, ``z#``, ``U#`` and ``Z#``. - See :ref:`Parsing arguments and building values - ` and the :pep:`353`. + See :ref:`arg-parsing` and :pep:`353`. (Contributed by Victor Stinner in :issue:`40943`.) * Since :c:func:`Py_REFCNT()` is changed to the inline static function, @@ -2179,8 +2178,7 @@ Porting to Python 3.10 :c:func:`Py_GetProgramFullPath`, :c:func:`Py_GetPythonHome` and :c:func:`Py_GetProgramName` functions now return ``NULL`` if called before :c:func:`Py_Initialize` (before Python is initialized). Use the new - :ref:`Python Initialization Configuration API ` to get the - :ref:`Python Path Configuration. `. + :ref:`init-config` API to get the :ref:`init-path-config`. (Contributed by Victor Stinner in :issue:`42260`.) * :c:func:`PyList_SET_ITEM`, :c:func:`PyTuple_SET_ITEM` and @@ -2194,7 +2192,7 @@ Porting to Python 3.10 ``picklebufobject.h``, ``pyarena.h``, ``pyctype.h``, ``pydebug.h``, ``pyfpe.h``, and ``pytime.h`` have been moved to the ``Include/cpython`` directory. These files must not be included directly, as they are already - included in ``Python.h``: :ref:`Include Files `. If they have + included in ``Python.h``; see :ref:`api-includes`. If they have been included directly, consider including ``Python.h`` instead. (Contributed by Nicholas Sim in :issue:`35134`.) From webhook-mailer at python.org Wed Oct 19 16:27:51 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 19 Oct 2022 20:27:51 -0000 Subject: [Python-checkins] gh-98417: Store int_max_str_digits on the Interpreter State (GH-98418) Message-ID: https://github.com/python/cpython/commit/9c8dde0fa5309ae9f83a4faa07f062fcd84df4cf commit: 9c8dde0fa5309ae9f83a4faa07f062fcd84df4cf branch: main author: Eric Snow committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-19T13:27:46-07:00 summary: gh-98417: Store int_max_str_digits on the Interpreter State (GH-98418) files: M Include/internal/pycore_interp.h M Objects/longobject.c M Python/pylifecycle.c M Python/sysmodule.c diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index c11e897305d4..e643c7e9e4ed 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -69,6 +69,11 @@ struct atexit_state { }; +struct _Py_long_state { + int max_str_digits; +}; + + /* interpreter state */ /* PyInterpreterState holds the global state for one of the runtime's @@ -164,6 +169,7 @@ struct _is { struct _Py_unicode_state unicode; struct _Py_float_state float_state; + struct _Py_long_state long_state; /* Using a cache is very effective since typically only a single slice is created and then deleted again. */ PySliceObject *slice_cache; diff --git a/Objects/longobject.c b/Objects/longobject.c index 8b13df4181ec..304fabfad744 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -1767,7 +1767,7 @@ long_to_decimal_string_internal(PyObject *aa, if (size_a >= 10 * _PY_LONG_MAX_STR_DIGITS_THRESHOLD / (3 * PyLong_SHIFT) + 2) { PyInterpreterState *interp = _PyInterpreterState_GET(); - int max_str_digits = interp->config.int_max_str_digits; + int max_str_digits = interp->long_state.max_str_digits; if ((max_str_digits > 0) && (max_str_digits / (3 * PyLong_SHIFT) <= (size_a - 11) / 10)) { PyErr_Format(PyExc_ValueError, _MAX_STR_DIGITS_ERROR_FMT_TO_STR, @@ -1837,7 +1837,7 @@ long_to_decimal_string_internal(PyObject *aa, } if (strlen > _PY_LONG_MAX_STR_DIGITS_THRESHOLD) { PyInterpreterState *interp = _PyInterpreterState_GET(); - int max_str_digits = interp->config.int_max_str_digits; + int max_str_digits = interp->long_state.max_str_digits; Py_ssize_t strlen_nosign = strlen - negative; if ((max_str_digits > 0) && (strlen_nosign > max_str_digits)) { Py_DECREF(scratch); @@ -2578,7 +2578,7 @@ long_from_string_base(const char **str, int base, PyLongObject **res) * quadratic algorithm. */ if (digits > _PY_LONG_MAX_STR_DIGITS_THRESHOLD) { PyInterpreterState *interp = _PyInterpreterState_GET(); - int max_str_digits = interp->config.int_max_str_digits; + int max_str_digits = interp->long_state.max_str_digits; if ((max_str_digits > 0) && (digits > max_str_digits)) { PyErr_Format(PyExc_ValueError, _MAX_STR_DIGITS_ERROR_FMT_TO_INT, max_str_digits, digits); diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index c550f13bc148..4195a9dbca81 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -480,6 +480,8 @@ interpreter_update_config(PyThreadState *tstate, int only_update_path_config) } } + tstate->interp->long_state.max_str_digits = config->int_max_str_digits; + // Update the sys module for the new configuration if (_PySys_UpdateConfig(tstate) < 0) { return -1; diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 2c66415ee3d3..708145651812 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1717,7 +1717,7 @@ sys_get_int_max_str_digits_impl(PyObject *module) /*[clinic end generated code: output=0042f5e8ae0e8631 input=8dab13e2023e60d5]*/ { PyInterpreterState *interp = _PyInterpreterState_GET(); - return PyLong_FromLong(interp->config.int_max_str_digits); + return PyLong_FromLong(interp->long_state.max_str_digits); } /*[clinic input] @@ -1734,7 +1734,7 @@ sys_set_int_max_str_digits_impl(PyObject *module, int maxdigits) { PyThreadState *tstate = _PyThreadState_GET(); if ((!maxdigits) || (maxdigits >= _PY_LONG_MAX_STR_DIGITS_THRESHOLD)) { - tstate->interp->config.int_max_str_digits = maxdigits; + tstate->interp->long_state.max_str_digits = maxdigits; Py_RETURN_NONE; } else { PyErr_Format( From webhook-mailer at python.org Wed Oct 19 17:28:30 2022 From: webhook-mailer at python.org (vsajip) Date: Wed, 19 Oct 2022 21:28:30 -0000 Subject: [Python-checkins] =?utf-8?b?WzMuMTFdIFtkb2NdIFJlZnJlc2ggdGhlIHZl?= =?utf-8?q?nv_introduction_documentation=2C_and_correct_the_st=E2=80=A6_?= =?utf-8?q?=28GH-98465=29?= Message-ID: https://github.com/python/cpython/commit/3b7e0204bf9ccb44f4e3412b5752cb11b3f18a8f commit: 3b7e0204bf9ccb44f4e3412b5752cb11b3f18a8f branch: 3.11 author: Vinay Sajip committer: vsajip date: 2022-10-19T22:28:24+01:00 summary: [3.11] [doc] Refresh the venv introduction documentation, and correct the st? (GH-98465) Co-authored-by: C.A.M. Gerlach Co-authored-by: Phil Elson files: M Doc/library/venv.rst M Doc/using/venv-create.inc diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst index 3bed25645a92..adc6cd339ac1 100644 --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -15,14 +15,22 @@ -------------- -The :mod:`venv` module provides support for creating lightweight "virtual -environments" with their own site directories, optionally isolated from system -site directories. Each virtual environment has its own Python binary (which -matches the version of the binary that was used to create this environment) and -can have its own independent set of installed Python packages in its site -directories. +.. _venv-def: +.. _venv-intro: + +The :mod:`!venv` module supports creating lightweight "virtual environments", +each with their own independent set of Python packages installed in +their :mod:`site` directories. +A virtual environment is created on top of an existing +Python installation, known as the virtual environment's "base" Python, and may +optionally be isolated from the packages in the base environment, +so only those explicitly installed in the virtual environment are available. + +When used from within a virtual environment, common installation tools such as +`pip`_ will install Python packages into a virtual environment +without needing to be told to do so explicitly. -See :pep:`405` for more information about Python virtual environments. +See :pep:`405` for more background on Python virtual environments. .. seealso:: @@ -36,54 +44,72 @@ Creating virtual environments .. include:: /using/venv-create.inc +.. _venv-explanation: -.. _venv-def: +How venvs work +-------------- -.. note:: A virtual environment is a Python environment such that the Python - interpreter, libraries and scripts installed into it are isolated from those - installed in other virtual environments, and (by default) any libraries - installed in a "system" Python, i.e., one which is installed as part of your - operating system. - - A virtual environment is a directory tree which contains Python executable - files and other files which indicate that it is a virtual environment. - - Common installation tools such as setuptools_ and pip_ work as - expected with virtual environments. In other words, when a virtual - environment is active, they install Python packages into the virtual - environment without needing to be told to do so explicitly. - - When a virtual environment is active (i.e., the virtual environment's Python - interpreter is running), the attributes :attr:`sys.prefix` and - :attr:`sys.exec_prefix` point to the base directory of the virtual - environment, whereas :attr:`sys.base_prefix` and - :attr:`sys.base_exec_prefix` point to the non-virtual environment Python - installation which was used to create the virtual environment. If a virtual - environment is not active, then :attr:`sys.prefix` is the same as - :attr:`sys.base_prefix` and :attr:`sys.exec_prefix` is the same as - :attr:`sys.base_exec_prefix` (they all point to a non-virtual environment - Python installation). - - When a virtual environment is active, any options that change the - installation path will be ignored from all :mod:`distutils` configuration - files to prevent projects being inadvertently installed outside of the - virtual environment. - - When working in a command shell, users can make a virtual environment active - by running an ``activate`` script in the virtual environment's executables - directory (the precise filename and command to use the file is - shell-dependent), which prepends the virtual environment's directory for - executables to the ``PATH`` environment variable for the running shell. There - should be no need in other circumstances to activate a virtual - environment; scripts installed into virtual environments have a "shebang" - line which points to the virtual environment's Python interpreter. This means - that the script will run with that interpreter regardless of the value of - ``PATH``. On Windows, "shebang" line processing is supported if you have the - Python Launcher for Windows installed (this was added to Python in 3.3 - see - :pep:`397` for more details). Thus, double-clicking an installed script in a - Windows Explorer window should run the script with the correct interpreter - without there needing to be any reference to its virtual environment in - ``PATH``. +When a Python interpreter is running from a virtual environment, +:data:`sys.prefix` and :data:`sys.exec_prefix` +point to the directories of the virtual environment, +whereas :data:`sys.base_prefix` and :data:`sys.base_exec_prefix` +point to those of the base Python used to create the environment. +It is sufficient to check +``sys.prefix == sys.base_prefix`` to determine if the current interpreter is +running from a virtual environment. + +A virtual environment may be "activated" using a script in its binary directory +(``bin`` on POSIX; ``Scripts`` on Windows). +This will prepend that directory to your :envvar:`!PATH`, so that running +:program:`!python` will invoke the environment's Python interpreter +and you can run installed scripts without having to use their full path. +The invocation of the activation script is platform-specific +(:samp:`{}` must be replaced by the path to the directory +containing the virtual environment): + ++-------------+------------+--------------------------------------------------+ +| Platform | Shell | Command to activate virtual environment | ++=============+============+==================================================+ +| POSIX | bash/zsh | :samp:`$ source {}/bin/activate` | +| +------------+--------------------------------------------------+ +| | fish | :samp:`$ source {}/bin/activate.fish` | +| +------------+--------------------------------------------------+ +| | csh/tcsh | :samp:`$ source {}/bin/activate.csh` | +| +------------+--------------------------------------------------+ +| | PowerShell | :samp:`$ {}/bin/Activate.ps1` | ++-------------+------------+--------------------------------------------------+ +| Windows | cmd.exe | :samp:`C:\\> {}\\Scripts\\activate.bat` | +| +------------+--------------------------------------------------+ +| | PowerShell | :samp:`PS C:\\> {}\\Scripts\\Activate.ps1` | ++-------------+------------+--------------------------------------------------+ + +.. versionadded:: 3.4 + :program:`!fish` and :program:`!csh` activation scripts. + +.. versionadded:: 3.8 + PowerShell activation scripts installed under POSIX for PowerShell Core + support. + +You don't specifically *need* to activate a virtual environment, +as you can just specify the full path to that environment's +Python interpreter when invoking Python. +Furthermore, all scripts installed in the environment +should be runnable without activating it. + +In order to achieve this, scripts installed into virtual environments have +a "shebang" line which points to the environment's Python interpreter, +i.e. :samp:`#!/{}/bin/python`. +This means that the script will run with that interpreter regardless of the +value of :envvar:`!PATH`. On Windows, "shebang" line processing is supported if +you have the :ref:`launcher` installed. Thus, double-clicking an installed +script in a Windows Explorer window should run it with the correct interpreter +without the environment needing to be activated or on the :envvar:`!PATH`. + +When a virtual environment has been activated, the :envvar:`!VIRTUAL_ENV` +environment variable is set to the path of the environment. +Since explicitly activating a virtual environment is not required to use it, +:envvar:`!VIRTUAL_ENV` cannot be relied upon to determine +whether a virtual environment is being used. .. warning:: Because scripts installed in environments should not expect the environment to be activated, their shebang lines contain the absolute paths @@ -99,6 +125,11 @@ Creating virtual environments environment in its new location. Otherwise, software installed into the environment may not work as expected. +You can deactivate a virtual environment by typing ``deactivate`` in your shell. +The exact mechanism is platform-specific and is an internal implementation +detail (typically, a script or shell function will be used). + + .. _venv-api: API @@ -191,6 +222,45 @@ creation according to their needs, the :class:`EnvBuilder` class. ``clear=True``, contents of the environment directory will be cleared and then all necessary subdirectories will be recreated. + The returned context object is a :class:`types.SimpleNamespace` with the + following attributes: + + * ``env_dir`` - The location of the virtual environment. Used for + ``__VENV_DIR__`` in activation scripts (see :meth:`install_scripts`). + + * ``env_name`` - The name of the virtual environment. Used for + ``__VENV_NAME__`` in activation scripts (see :meth:`install_scripts`). + + * ``prompt`` - The prompt to be used by the activation scripts. Used for + ``__VENV_PROMPT__`` in activation scripts (see :meth:`install_scripts`). + + * ``executable`` - The underlying Python executable used by the virtual + environment. This takes into account the case where a virtual environment + is created from another virtual environment. + + * ``inc_path`` - The include path for the virtual environment. + + * ``lib_path`` - The purelib path for the virtual environment. + + * ``bin_path`` - The script path for the virtual environment. + + * ``bin_name`` - The name of the script path relative to the virtual + environment location. Used for ``__VENV_BIN_NAME__`` in activation + scripts (see :meth:`install_scripts`). + + * ``env_exe`` - The name of the Python interpreter in the virtual + environment. Used for ``__VENV_PYTHON__`` in activation scripts + (see :meth:`install_scripts`). + + * ``env_exec_cmd`` - The name of the Python interpreter, taking into + account filesystem redirections. This can be used to run Python in + the virtual environment. + + + .. versionchanged:: 3.12 + The attribute ``lib_path`` was added to the context, and the context + object was documented. + .. versionchanged:: 3.11 The *venv* :ref:`sysconfig installation scheme ` diff --git a/Doc/using/venv-create.inc b/Doc/using/venv-create.inc index b9785832864e..b929705648c5 100644 --- a/Doc/using/venv-create.inc +++ b/Doc/using/venv-create.inc @@ -105,45 +105,3 @@ Multiple paths can be given to ``venv``, in which case an identical virtual environment will be created, according to the given options, at each provided path. -Once a virtual environment has been created, it can be "activated" using a -script in the virtual environment's binary directory. The invocation of the -script is platform-specific (`` must be replaced by the path of the -directory containing the virtual environment): - -+-------------+-----------------+-----------------------------------------+ -| Platform | Shell | Command to activate virtual environment | -+=============+=================+=========================================+ -| POSIX | bash/zsh | $ source /bin/activate | -+-------------+-----------------+-----------------------------------------+ -| | fish | $ source /bin/activate.fish | -+-------------+-----------------+-----------------------------------------+ -| | csh/tcsh | $ source /bin/activate.csh | -+-------------+-----------------+-----------------------------------------+ -| | PowerShell Core | $ /bin/Activate.ps1 | -+-------------+-----------------+-----------------------------------------+ -| Windows | cmd.exe | C:\\> \\Scripts\\activate.bat | -+-------------+-----------------+-----------------------------------------+ -| | PowerShell | PS C:\\> \\Scripts\\Activate.ps1 | -+-------------+-----------------+-----------------------------------------+ - -When a virtual environment is active, the :envvar:`VIRTUAL_ENV` environment -variable is set to the path of the virtual environment. This can be used to -check if one is running inside a virtual environment. - -You don't specifically *need* to activate an environment; activation just -prepends the virtual environment's binary directory to your path, so that -"python" invokes the virtual environment's Python interpreter and you can run -installed scripts without having to use their full path. However, all scripts -installed in a virtual environment should be runnable without activating it, -and run with the virtual environment's Python automatically. - -You can deactivate a virtual environment by typing "deactivate" in your shell. -The exact mechanism is platform-specific and is an internal implementation -detail (typically a script or shell function will be used). - -.. versionadded:: 3.4 - ``fish`` and ``csh`` activation scripts. - -.. versionadded:: 3.8 - PowerShell activation scripts installed under POSIX for PowerShell Core - support. From webhook-mailer at python.org Wed Oct 19 17:56:40 2022 From: webhook-mailer at python.org (vsajip) Date: Wed, 19 Oct 2022 21:56:40 -0000 Subject: [Python-checkins] =?utf-8?b?WzMuMTBdIFtkb2NdIFJlZnJlc2ggdGhlIHZl?= =?utf-8?q?nv_introduction_documentation=2C_and_correct=E2=80=A6_=28GH-984?= =?utf-8?b?NjYp?= Message-ID: https://github.com/python/cpython/commit/dddbbd9e3e4e12ed5a805dd4e08953e3332a15ea commit: dddbbd9e3e4e12ed5a805dd4e08953e3332a15ea branch: 3.10 author: Vinay Sajip committer: vsajip date: 2022-10-19T22:56:26+01:00 summary: [3.10] [doc] Refresh the venv introduction documentation, and correct? (GH-98466) Co-authored-by: C.A.M. Gerlach Co-authored-by: Phil Elson files: M Doc/library/venv.rst M Doc/using/venv-create.inc diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst index fe5e4c0c9cb5..3ab83a23cf24 100644 --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -15,74 +15,99 @@ -------------- -The :mod:`venv` module provides support for creating lightweight "virtual -environments" with their own site directories, optionally isolated from system -site directories. Each virtual environment has its own Python binary (which -matches the version of the binary that was used to create this environment) and -can have its own independent set of installed Python packages in its site -directories. +.. _venv-def: +.. _venv-intro: + +The :mod:`!venv` module supports creating lightweight "virtual environments", +each with their own independent set of Python packages installed in +their :mod:`site` directories. +A virtual environment is created on top of an existing +Python installation, known as the virtual environment's "base" Python, and may +optionally be isolated from the packages in the base environment, +so only those explicitly installed in the virtual environment are available. + +When used from within a virtual environment, common installation tools such as +`pip`_ will install Python packages into a virtual environment +without needing to be told to do so explicitly. -See :pep:`405` for more information about Python virtual environments. +See :pep:`405` for more background on Python virtual environments. .. seealso:: `Python Packaging User Guide: Creating and using virtual environments `__ - Creating virtual environments ----------------------------- .. include:: /using/venv-create.inc +.. _venv-explanation: -.. _venv-def: +How venvs work +-------------- -.. note:: A virtual environment is a Python environment such that the Python - interpreter, libraries and scripts installed into it are isolated from those - installed in other virtual environments, and (by default) any libraries - installed in a "system" Python, i.e., one which is installed as part of your - operating system. - - A virtual environment is a directory tree which contains Python executable - files and other files which indicate that it is a virtual environment. - - Common installation tools such as setuptools_ and pip_ work as - expected with virtual environments. In other words, when a virtual - environment is active, they install Python packages into the virtual - environment without needing to be told to do so explicitly. - - When a virtual environment is active (i.e., the virtual environment's Python - interpreter is running), the attributes :attr:`sys.prefix` and - :attr:`sys.exec_prefix` point to the base directory of the virtual - environment, whereas :attr:`sys.base_prefix` and - :attr:`sys.base_exec_prefix` point to the non-virtual environment Python - installation which was used to create the virtual environment. If a virtual - environment is not active, then :attr:`sys.prefix` is the same as - :attr:`sys.base_prefix` and :attr:`sys.exec_prefix` is the same as - :attr:`sys.base_exec_prefix` (they all point to a non-virtual environment - Python installation). - - When a virtual environment is active, any options that change the - installation path will be ignored from all :mod:`distutils` configuration - files to prevent projects being inadvertently installed outside of the - virtual environment. - - When working in a command shell, users can make a virtual environment active - by running an ``activate`` script in the virtual environment's executables - directory (the precise filename and command to use the file is - shell-dependent), which prepends the virtual environment's directory for - executables to the ``PATH`` environment variable for the running shell. There - should be no need in other circumstances to activate a virtual - environment; scripts installed into virtual environments have a "shebang" - line which points to the virtual environment's Python interpreter. This means - that the script will run with that interpreter regardless of the value of - ``PATH``. On Windows, "shebang" line processing is supported if you have the - Python Launcher for Windows installed (this was added to Python in 3.3 - see - :pep:`397` for more details). Thus, double-clicking an installed script in a - Windows Explorer window should run the script with the correct interpreter - without there needing to be any reference to its virtual environment in - ``PATH``. +When a Python interpreter is running from a virtual environment, +:data:`sys.prefix` and :data:`sys.exec_prefix` +point to the directories of the virtual environment, +whereas :data:`sys.base_prefix` and :data:`sys.base_exec_prefix` +point to those of the base Python used to create the environment. +It is sufficient to check +``sys.prefix == sys.base_prefix`` to determine if the current interpreter is +running from a virtual environment. + +A virtual environment may be "activated" using a script in its binary directory +(``bin`` on POSIX; ``Scripts`` on Windows). +This will prepend that directory to your :envvar:`!PATH`, so that running +:program:`!python` will invoke the environment's Python interpreter +and you can run installed scripts without having to use their full path. +The invocation of the activation script is platform-specific +(:samp:`{}` must be replaced by the path to the directory +containing the virtual environment): + ++-------------+------------+--------------------------------------------------+ +| Platform | Shell | Command to activate virtual environment | ++=============+============+==================================================+ +| POSIX | bash/zsh | :samp:`$ source {}/bin/activate` | +| +------------+--------------------------------------------------+ +| | fish | :samp:`$ source {}/bin/activate.fish` | +| +------------+--------------------------------------------------+ +| | csh/tcsh | :samp:`$ source {}/bin/activate.csh` | +| +------------+--------------------------------------------------+ +| | PowerShell | :samp:`$ {}/bin/Activate.ps1` | ++-------------+------------+--------------------------------------------------+ +| Windows | cmd.exe | :samp:`C:\\> {}\\Scripts\\activate.bat` | +| +------------+--------------------------------------------------+ +| | PowerShell | :samp:`PS C:\\> {}\\Scripts\\Activate.ps1` | ++-------------+------------+--------------------------------------------------+ + +.. versionadded:: 3.4 + :program:`!fish` and :program:`!csh` activation scripts. + +.. versionadded:: 3.8 + PowerShell activation scripts installed under POSIX for PowerShell Core + support. + +You don't specifically *need* to activate a virtual environment, +as you can just specify the full path to that environment's +Python interpreter when invoking Python. +Furthermore, all scripts installed in the environment +should be runnable without activating it. + +In order to achieve this, scripts installed into virtual environments have +a "shebang" line which points to the environment's Python interpreter, +i.e. :samp:`#!/{}/bin/python`. +This means that the script will run with that interpreter regardless of the +value of :envvar:`!PATH`. On Windows, "shebang" line processing is supported if +you have the :ref:`launcher` installed. Thus, double-clicking an installed +script in a Windows Explorer window should run it with the correct interpreter +without the environment needing to be activated or on the :envvar:`!PATH`. + +When a virtual environment has been activated, the :envvar:`!VIRTUAL_ENV` +environment variable is set to the path of the environment. +Since explicitly activating a virtual environment is not required to use it, +:envvar:`!VIRTUAL_ENV` cannot be relied upon to determine +whether a virtual environment is being used. .. warning:: Because scripts installed in environments should not expect the environment to be activated, their shebang lines contain the absolute paths @@ -98,6 +123,11 @@ Creating virtual environments environment in its new location. Otherwise, software installed into the environment may not work as expected. +You can deactivate a virtual environment by typing ``deactivate`` in your shell. +The exact mechanism is platform-specific and is an internal implementation +detail (typically, a script or shell function will be used). + + .. _venv-api: API @@ -183,11 +213,56 @@ creation according to their needs, the :class:`EnvBuilder` class. .. method:: ensure_directories(env_dir) - Creates the environment directory and all necessary directories, and - returns a context object. This is just a holder for attributes (such as - paths), for use by the other methods. The directories are allowed to - exist already, as long as either ``clear`` or ``upgrade`` were - specified to allow operating on an existing environment directory. + Creates the environment directory and all necessary subdirectories that + don't already exist, and returns a context object. This context object + is just a holder for attributes (such as paths) for use by the other + methods. If the :class:`EnvBuilder` is created with the arg + ``clear=True``, contents of the environment directory will be cleared + and then all necessary subdirectories will be recreated. + + The returned context object is a :class:`types.SimpleNamespace` with the + following attributes: + + * ``env_dir`` - The location of the virtual environment. Used for + ``__VENV_DIR__`` in activation scripts (see :meth:`install_scripts`). + + * ``env_name`` - The name of the virtual environment. Used for + ``__VENV_NAME__`` in activation scripts (see :meth:`install_scripts`). + + * ``prompt`` - The prompt to be used by the activation scripts. Used for + ``__VENV_PROMPT__`` in activation scripts (see :meth:`install_scripts`). + + * ``executable`` - The underlying Python executable used by the virtual + environment. This takes into account the case where a virtual environment + is created from another virtual environment. + + * ``inc_path`` - The include path for the virtual environment. + + * ``lib_path`` - The purelib path for the virtual environment. + + * ``bin_path`` - The script path for the virtual environment. + + * ``bin_name`` - The name of the script path relative to the virtual + environment location. Used for ``__VENV_BIN_NAME__`` in activation + scripts (see :meth:`install_scripts`). + + * ``env_exe`` - The name of the Python interpreter in the virtual + environment. Used for ``__VENV_PYTHON__`` in activation scripts + (see :meth:`install_scripts`). + + * ``env_exec_cmd`` - The name of the Python interpreter, taking into + account filesystem redirections. This can be used to run Python in + the virtual environment. + + + .. versionchanged:: 3.12 + The attribute ``lib_path`` was added to the context, and the context + object was documented. + + .. versionchanged:: 3.11 + The *venv* + :ref:`sysconfig installation scheme ` + is used to construct the paths of the created directories. .. method:: create_configuration(context) diff --git a/Doc/using/venv-create.inc b/Doc/using/venv-create.inc index b9785832864e..b929705648c5 100644 --- a/Doc/using/venv-create.inc +++ b/Doc/using/venv-create.inc @@ -105,45 +105,3 @@ Multiple paths can be given to ``venv``, in which case an identical virtual environment will be created, according to the given options, at each provided path. -Once a virtual environment has been created, it can be "activated" using a -script in the virtual environment's binary directory. The invocation of the -script is platform-specific (`` must be replaced by the path of the -directory containing the virtual environment): - -+-------------+-----------------+-----------------------------------------+ -| Platform | Shell | Command to activate virtual environment | -+=============+=================+=========================================+ -| POSIX | bash/zsh | $ source /bin/activate | -+-------------+-----------------+-----------------------------------------+ -| | fish | $ source /bin/activate.fish | -+-------------+-----------------+-----------------------------------------+ -| | csh/tcsh | $ source /bin/activate.csh | -+-------------+-----------------+-----------------------------------------+ -| | PowerShell Core | $ /bin/Activate.ps1 | -+-------------+-----------------+-----------------------------------------+ -| Windows | cmd.exe | C:\\> \\Scripts\\activate.bat | -+-------------+-----------------+-----------------------------------------+ -| | PowerShell | PS C:\\> \\Scripts\\Activate.ps1 | -+-------------+-----------------+-----------------------------------------+ - -When a virtual environment is active, the :envvar:`VIRTUAL_ENV` environment -variable is set to the path of the virtual environment. This can be used to -check if one is running inside a virtual environment. - -You don't specifically *need* to activate an environment; activation just -prepends the virtual environment's binary directory to your path, so that -"python" invokes the virtual environment's Python interpreter and you can run -installed scripts without having to use their full path. However, all scripts -installed in a virtual environment should be runnable without activating it, -and run with the virtual environment's Python automatically. - -You can deactivate a virtual environment by typing "deactivate" in your shell. -The exact mechanism is platform-specific and is an internal implementation -detail (typically a script or shell function will be used). - -.. versionadded:: 3.4 - ``fish`` and ``csh`` activation scripts. - -.. versionadded:: 3.8 - PowerShell activation scripts installed under POSIX for PowerShell Core - support. From webhook-mailer at python.org Wed Oct 19 18:00:15 2022 From: webhook-mailer at python.org (zooba) Date: Wed, 19 Oct 2022 22:00:15 -0000 Subject: [Python-checkins] gh-98414: py.exe launcher does not use defaults for -V:company/ option (GH-98460) Message-ID: https://github.com/python/cpython/commit/4bd63f66cd4f6e8d549f88ae0f4b0106d522b6bb commit: 4bd63f66cd4f6e8d549f88ae0f4b0106d522b6bb branch: main author: Steve Dower committer: zooba date: 2022-10-19T23:00:09+01:00 summary: gh-98414: py.exe launcher does not use defaults for -V:company/ option (GH-98460) files: A Misc/NEWS.d/next/Windows/2022-10-19-19-35-37.gh-issue-98414.FbHZuS.rst M Lib/test/test_launcher.py M PC/launcher2.c diff --git a/Lib/test/test_launcher.py b/Lib/test/test_launcher.py index be0cd90c7906..432a44622b5f 100644 --- a/Lib/test/test_launcher.py +++ b/Lib/test/test_launcher.py @@ -369,6 +369,13 @@ def test_filter_to_company(self): self.assertEqual(company, data["env.company"]) self.assertEqual("3.100", data["env.tag"]) + def test_filter_to_company_with_default(self): + company = "PythonTestSuite" + data = self.run_py([f"-V:{company}/"], env=dict(PY_PYTHON="3.0")) + self.assertEqual("X.Y.exe", data["LaunchCommand"]) + self.assertEqual(company, data["env.company"]) + self.assertEqual("3.100", data["env.tag"]) + def test_filter_to_tag(self): company = "PythonTestSuite" data = self.run_py([f"-V:3.100"]) diff --git a/Misc/NEWS.d/next/Windows/2022-10-19-19-35-37.gh-issue-98414.FbHZuS.rst b/Misc/NEWS.d/next/Windows/2022-10-19-19-35-37.gh-issue-98414.FbHZuS.rst new file mode 100644 index 000000000000..df07b7f547df --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2022-10-19-19-35-37.gh-issue-98414.FbHZuS.rst @@ -0,0 +1,3 @@ +Fix :file:`py.exe` launcher handling of ``-V:/`` option when +default preferences have been set in environment variables or configuration +files. diff --git a/PC/launcher2.c b/PC/launcher2.c index 23eaa19dde38..1f6f97b82092 100644 --- a/PC/launcher2.c +++ b/PC/launcher2.c @@ -653,6 +653,7 @@ parseCommandLine(SearchInfo *search) search->tag = argStart; } search->tagLength = (int)(tail - search->tag); + search->allowDefaults = false; search->restOfCmdLine = tail; } else if (MATCHES(L"0") || MATCHES(L"-list")) { search->list = true; From webhook-mailer at python.org Wed Oct 19 18:31:58 2022 From: webhook-mailer at python.org (vstinner) Date: Wed, 19 Oct 2022 22:31:58 -0000 Subject: [Python-checkins] gh-98257: Make _PyEval_SetTrace() reentrant (#98258) Message-ID: https://github.com/python/cpython/commit/a8fe4bbd6b78517f640e25697338b9448c4675c1 commit: a8fe4bbd6b78517f640e25697338b9448c4675c1 branch: main author: Victor Stinner committer: vstinner date: 2022-10-20T00:31:47+02:00 summary: gh-98257: Make _PyEval_SetTrace() reentrant (#98258) Make sys.setprofile() and sys.settrace() functions reentrant. They can no long fail with: RuntimeError("Cannot install a trace function while another trace function is being installed"). Make _PyEval_SetTrace() and _PyEval_SetProfile() functions reentrant, rather than detecting and rejecting reentrant calls. Only delete the reference to function arguments once the new function is fully set, when a reentrant call is safe. Call also _PySys_Audit() earlier. files: A Misc/NEWS.d/next/Library/2022-10-14-12-29-05.gh-issue-98257.aMSMs2.rst M Lib/test/test_sys_setprofile.py M Lib/test/test_sys_settrace.py M Python/ceval.c diff --git a/Lib/test/test_sys_setprofile.py b/Lib/test/test_sys_setprofile.py index 4c3053a1e3e9..acae433cd0a5 100644 --- a/Lib/test/test_sys_setprofile.py +++ b/Lib/test/test_sys_setprofile.py @@ -437,12 +437,8 @@ def __del__(self): sys.setprofile(bar) sys.setprofile(A()) - with support.catch_unraisable_exception() as cm: - sys.setprofile(foo) - self.assertEqual(cm.unraisable.object, A.__del__) - self.assertIsInstance(cm.unraisable.exc_value, RuntimeError) - - self.assertEqual(sys.getprofile(), foo) + sys.setprofile(foo) + self.assertEqual(sys.getprofile(), bar) def test_same_object(self): diff --git a/Lib/test/test_sys_settrace.py b/Lib/test/test_sys_settrace.py index 4f577c2ea5da..a448f80449ca 100644 --- a/Lib/test/test_sys_settrace.py +++ b/Lib/test/test_sys_settrace.py @@ -2796,12 +2796,8 @@ def __del__(self): sys.settrace(bar) sys.settrace(A()) - with support.catch_unraisable_exception() as cm: - sys.settrace(foo) - self.assertEqual(cm.unraisable.object, A.__del__) - self.assertIsInstance(cm.unraisable.exc_value, RuntimeError) - - self.assertEqual(sys.gettrace(), foo) + sys.settrace(foo) + self.assertEqual(sys.gettrace(), bar) def test_same_object(self): diff --git a/Misc/NEWS.d/next/Library/2022-10-14-12-29-05.gh-issue-98257.aMSMs2.rst b/Misc/NEWS.d/next/Library/2022-10-14-12-29-05.gh-issue-98257.aMSMs2.rst new file mode 100644 index 000000000000..67f6cb4dbc19 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-14-12-29-05.gh-issue-98257.aMSMs2.rst @@ -0,0 +1,3 @@ +Make :func:`sys.setprofile` and :func:`sys.settrace` functions reentrant. They +can no long fail with: ``RuntimeError("Cannot install a trace function while +another trace function is being installed")``. Patch by Victor Stinner. diff --git a/Python/ceval.c b/Python/ceval.c index a112f8bebb5a..fb8dd4811628 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -6343,38 +6343,23 @@ _PyEval_SetProfile(PyThreadState *tstate, Py_tracefunc func, PyObject *arg) /* The caller must hold the GIL */ assert(PyGILState_Check()); - static int reentrant = 0; - if (reentrant) { - _PyErr_SetString(tstate, PyExc_RuntimeError, "Cannot install a profile function " - "while another profile function is being installed"); - reentrant = 0; - return -1; - } - reentrant = 1; - /* Call _PySys_Audit() in the context of the current thread state, even if tstate is not the current thread state. */ PyThreadState *current_tstate = _PyThreadState_GET(); if (_PySys_Audit(current_tstate, "sys.setprofile", NULL) < 0) { - reentrant = 0; return -1; } - PyObject *profileobj = tstate->c_profileobj; - - tstate->c_profilefunc = NULL; - tstate->c_profileobj = NULL; - /* Must make sure that tracing is not ignored if 'profileobj' is freed */ - _PyThreadState_UpdateTracingState(tstate); - Py_XDECREF(profileobj); - - Py_XINCREF(arg); - tstate->c_profileobj = arg; tstate->c_profilefunc = func; - + PyObject *old_profileobj = tstate->c_profileobj; + tstate->c_profileobj = Py_XNewRef(arg); /* Flag that tracing or profiling is turned on */ _PyThreadState_UpdateTracingState(tstate); - reentrant = 0; + + // gh-98257: Only call Py_XDECREF() once the new profile function is fully + // set, so it's safe to call sys.setprofile() again (reentrant call). + Py_XDECREF(old_profileobj); + return 0; } @@ -6416,39 +6401,23 @@ _PyEval_SetTrace(PyThreadState *tstate, Py_tracefunc func, PyObject *arg) /* The caller must hold the GIL */ assert(PyGILState_Check()); - static int reentrant = 0; - - if (reentrant) { - _PyErr_SetString(tstate, PyExc_RuntimeError, "Cannot install a trace function " - "while another trace function is being installed"); - reentrant = 0; - return -1; - } - reentrant = 1; - /* Call _PySys_Audit() in the context of the current thread state, even if tstate is not the current thread state. */ PyThreadState *current_tstate = _PyThreadState_GET(); if (_PySys_Audit(current_tstate, "sys.settrace", NULL) < 0) { - reentrant = 0; return -1; } - PyObject *traceobj = tstate->c_traceobj; - - tstate->c_tracefunc = NULL; - tstate->c_traceobj = NULL; - /* Must make sure that profiling is not ignored if 'traceobj' is freed */ - _PyThreadState_UpdateTracingState(tstate); - Py_XINCREF(arg); - Py_XDECREF(traceobj); - tstate->c_traceobj = arg; tstate->c_tracefunc = func; - + PyObject *old_traceobj = tstate->c_traceobj; + tstate->c_traceobj = Py_XNewRef(arg); /* Flag that tracing or profiling is turned on */ _PyThreadState_UpdateTracingState(tstate); - reentrant = 0; + // gh-98257: Only call Py_XDECREF() once the new trace function is fully + // set, so it's safe to call sys.settrace() again (reentrant call). + Py_XDECREF(old_traceobj); + return 0; } From webhook-mailer at python.org Wed Oct 19 18:41:35 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 19 Oct 2022 22:41:35 -0000 Subject: [Python-checkins] gh-98414: py.exe launcher does not use defaults for -V:company/ option (GH-98460) Message-ID: https://github.com/python/cpython/commit/0b71dad9b8dce1aa2ce04328e9906274f381ca76 commit: 0b71dad9b8dce1aa2ce04328e9906274f381ca76 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-19T15:41:28-07:00 summary: gh-98414: py.exe launcher does not use defaults for -V:company/ option (GH-98460) (cherry picked from commit 4bd63f66cd4f6e8d549f88ae0f4b0106d522b6bb) Co-authored-by: Steve Dower files: A Misc/NEWS.d/next/Windows/2022-10-19-19-35-37.gh-issue-98414.FbHZuS.rst M Lib/test/test_launcher.py M PC/launcher2.c diff --git a/Lib/test/test_launcher.py b/Lib/test/test_launcher.py index 97686e6ce982..ba6856b3e246 100644 --- a/Lib/test/test_launcher.py +++ b/Lib/test/test_launcher.py @@ -370,6 +370,13 @@ def test_filter_to_company(self): self.assertEqual(company, data["env.company"]) self.assertEqual("3.100", data["env.tag"]) + def test_filter_to_company_with_default(self): + company = "PythonTestSuite" + data = self.run_py([f"-V:{company}/"], env=dict(PY_PYTHON="3.0")) + self.assertEqual("X.Y.exe", data["LaunchCommand"]) + self.assertEqual(company, data["env.company"]) + self.assertEqual("3.100", data["env.tag"]) + def test_filter_to_tag(self): company = "PythonTestSuite" data = self.run_py([f"-V:3.100"]) diff --git a/Misc/NEWS.d/next/Windows/2022-10-19-19-35-37.gh-issue-98414.FbHZuS.rst b/Misc/NEWS.d/next/Windows/2022-10-19-19-35-37.gh-issue-98414.FbHZuS.rst new file mode 100644 index 000000000000..df07b7f547df --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2022-10-19-19-35-37.gh-issue-98414.FbHZuS.rst @@ -0,0 +1,3 @@ +Fix :file:`py.exe` launcher handling of ``-V:/`` option when +default preferences have been set in environment variables or configuration +files. diff --git a/PC/launcher2.c b/PC/launcher2.c index 23eaa19dde38..1f6f97b82092 100644 --- a/PC/launcher2.c +++ b/PC/launcher2.c @@ -653,6 +653,7 @@ parseCommandLine(SearchInfo *search) search->tag = argStart; } search->tagLength = (int)(tail - search->tag); + search->allowDefaults = false; search->restOfCmdLine = tail; } else if (MATCHES(L"0") || MATCHES(L"-list")) { search->list = true; From webhook-mailer at python.org Wed Oct 19 20:25:16 2022 From: webhook-mailer at python.org (miss-islington) Date: Thu, 20 Oct 2022 00:25:16 -0000 Subject: [Python-checkins] gh-98354: Add unicode check for 'name' attribute in _imp_create_builtin (GH-98412) Message-ID: https://github.com/python/cpython/commit/1f369ad07ff44b1fd6db75b33298e20ad604efc8 commit: 1f369ad07ff44b1fd6db75b33298e20ad604efc8 branch: main author: chgnrdv <52372310+chgnrdv at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-19T17:25:10-07:00 summary: gh-98354: Add unicode check for 'name' attribute in _imp_create_builtin (GH-98412) Fixes #98354 files: A Misc/NEWS.d/next/Core and Builtins/2022-10-19-18-03-28.gh-issue-98354.GRGta3.rst M Lib/test/test_imp.py M Python/import.c diff --git a/Lib/test/test_imp.py b/Lib/test/test_imp.py index 35b6afa91ebd..446e913e5bf3 100644 --- a/Lib/test/test_imp.py +++ b/Lib/test/test_imp.py @@ -378,6 +378,40 @@ def test_find_and_load_checked_pyc(self): mod = imp.load_module('mymod', file, path, description) self.assertEqual(mod.x, 42) + def test_issue98354(self): + # _imp.create_builtin should raise TypeError + # if 'name' attribute of 'spec' argument is not a 'str' instance + + create_builtin = support.get_attribute(_imp, "create_builtin") + + class FakeSpec: + def __init__(self, name): + self.name = self + spec = FakeSpec("time") + with self.assertRaises(TypeError): + create_builtin(spec) + + class FakeSpec2: + name = [1, 2, 3, 4] + spec = FakeSpec2() + with self.assertRaises(TypeError): + create_builtin(spec) + + import builtins + class UnicodeSubclass(str): + pass + class GoodSpec: + name = UnicodeSubclass("builtins") + spec = GoodSpec() + bltin = create_builtin(spec) + self.assertEqual(bltin, builtins) + + class UnicodeSubclassFakeSpec(str): + def __init__(self, name): + self.name = self + spec = UnicodeSubclassFakeSpec("builtins") + bltin = create_builtin(spec) + self.assertEqual(bltin, builtins) class ReloadTests(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-19-18-03-28.gh-issue-98354.GRGta3.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-19-18-03-28.gh-issue-98354.GRGta3.rst new file mode 100644 index 000000000000..a600f3e927a3 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-19-18-03-28.gh-issue-98354.GRGta3.rst @@ -0,0 +1 @@ +Added unicode check for ``name`` attribute of ``spec`` argument passed in :func:`_imp.create_builtin` function. diff --git a/Python/import.c b/Python/import.c index 698ef37ce0a1..9d35d2617742 100644 --- a/Python/import.c +++ b/Python/import.c @@ -1021,6 +1021,14 @@ _imp_create_builtin(PyObject *module, PyObject *spec) return NULL; } + if (!PyUnicode_Check(name)) { + PyErr_Format(PyExc_TypeError, + "name must be string, not %.200s", + Py_TYPE(name)->tp_name); + Py_DECREF(name); + return NULL; + } + PyObject *mod = create_builtin(tstate, name, spec); Py_DECREF(name); return mod; From webhook-mailer at python.org Wed Oct 19 20:53:44 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Thu, 20 Oct 2022 00:53:44 -0000 Subject: [Python-checkins] typing tests: `_overload_dummy` raises `NotImplementedError`, not `RuntimeError` (#98351) Message-ID: https://github.com/python/cpython/commit/1ca6647f22794f0a0c982ecb03e764db76d51087 commit: 1ca6647f22794f0a0c982ecb03e764db76d51087 branch: main author: Nikita Sobolev committer: JelleZijlstra date: 2022-10-19T17:53:36-07:00 summary: typing tests: `_overload_dummy` raises `NotImplementedError`, not `RuntimeError` (#98351) files: M Lib/test/test_typing.py diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index e4cf3c7d53b6..ab8e71735c4d 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -4398,7 +4398,7 @@ def method(self): ... class OverloadTests(BaseTestCase): def test_overload_fails(self): - with self.assertRaises(RuntimeError): + with self.assertRaises(NotImplementedError): @overload def blah(): From webhook-mailer at python.org Wed Oct 19 20:53:56 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Thu, 20 Oct 2022 00:53:56 -0000 Subject: [Python-checkins] [3.11] gh-94808: Cover `str.rsplit` for UCS1, UCS2 or UCS4 (GH-98228) (#98291) Message-ID: https://github.com/python/cpython/commit/df4aaff0e60e907225370755bb9881b08fb2b0ea commit: df4aaff0e60e907225370755bb9881b08fb2b0ea branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: JelleZijlstra date: 2022-10-19T17:53:50-07:00 summary: [3.11] gh-94808: Cover `str.rsplit` for UCS1, UCS2 or UCS4 (GH-98228) (#98291) gh-94808: Cover `str.rsplit` for UCS1, UCS2 or UCS4 (GH-98228) (cherry picked from commit b7dd2cad186e44e2b481f4518be62f34c682ea59) Co-authored-by: Nikita Sobolev files: M Lib/test/string_tests.py M Lib/test/test_unicode.py diff --git a/Lib/test/string_tests.py b/Lib/test/string_tests.py index 0d4c7ecf4a04..d69edd7bf458 100644 --- a/Lib/test/string_tests.py +++ b/Lib/test/string_tests.py @@ -469,6 +469,11 @@ def test_split(self): self.checkraises(ValueError, 'hello', 'split', '', 0) def test_rsplit(self): + # without arg + self.checkequal(['a', 'b', 'c', 'd'], 'a b c d', 'rsplit') + self.checkequal(['a', 'b', 'c', 'd'], 'a b c d', 'rsplit') + self.checkequal([], '', 'rsplit') + # by a char self.checkequal(['a', 'b', 'c', 'd'], 'a|b|c|d', 'rsplit', '|') self.checkequal(['a|b|c', 'd'], 'a|b|c|d', 'rsplit', '|', 1) @@ -522,6 +527,9 @@ def test_rsplit(self): # with keyword args self.checkequal(['a', 'b', 'c', 'd'], 'a|b|c|d', 'rsplit', sep='|') + self.checkequal(['a', 'b', 'c', 'd'], 'a b c d', 'rsplit', sep=None) + self.checkequal(['a b c', 'd'], + 'a b c d', 'rsplit', sep=None, maxsplit=1) self.checkequal(['a|b|c', 'd'], 'a|b|c|d', 'rsplit', '|', maxsplit=1) self.checkequal(['a|b|c', 'd'], diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py index 9b0e4b230506..60e5b1902cf6 100644 --- a/Lib/test/test_unicode.py +++ b/Lib/test/test_unicode.py @@ -441,10 +441,10 @@ def test_split(self): def test_rsplit(self): string_tests.CommonTest.test_rsplit(self) # test mixed kinds - for left, right in ('ba', '\u0101\u0100', '\U00010301\U00010300'): + for left, right in ('ba', '??', '\u0101\u0100', '\U00010301\U00010300'): left *= 9 right *= 9 - for delim in ('c', '\u0102', '\U00010302'): + for delim in ('c', '?', '\u0102', '\U00010302'): self.checkequal([left + right], left + right, 'rsplit', delim) self.checkequal([left, right], @@ -454,6 +454,10 @@ def test_rsplit(self): self.checkequal([left, right], left + delim * 2 + right, 'rsplit', delim *2) + # Check `None` as well: + self.checkequal([left + right], + left + right, 'rsplit', None) + def test_partition(self): string_tests.MixinStrUnicodeUserStringTest.test_partition(self) # test mixed kinds From webhook-mailer at python.org Wed Oct 19 21:23:58 2022 From: webhook-mailer at python.org (miss-islington) Date: Thu, 20 Oct 2022 01:23:58 -0000 Subject: [Python-checkins] typing tests: `_overload_dummy` raises `NotImplementedError`, not `RuntimeError` (GH-98351) Message-ID: https://github.com/python/cpython/commit/5f5fa4ca4b959f5e86fe141e297fd8b93eaeabff commit: 5f5fa4ca4b959f5e86fe141e297fd8b93eaeabff branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-19T18:23:40-07:00 summary: typing tests: `_overload_dummy` raises `NotImplementedError`, not `RuntimeError` (GH-98351) (cherry picked from commit 1ca6647f22794f0a0c982ecb03e764db76d51087) Co-authored-by: Nikita Sobolev files: M Lib/test/test_typing.py diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 71590449dc56..298e374e4cfa 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -4367,7 +4367,7 @@ def method(self): ... class OverloadTests(BaseTestCase): def test_overload_fails(self): - with self.assertRaises(RuntimeError): + with self.assertRaises(NotImplementedError): @overload def blah(): From webhook-mailer at python.org Wed Oct 19 21:56:28 2022 From: webhook-mailer at python.org (corona10) Date: Thu, 20 Oct 2022 01:56:28 -0000 Subject: [Python-checkins] gh-98374: Suppress ImportError for invalid query for help() command. (gh-98450) Message-ID: https://github.com/python/cpython/commit/4156b2fc1378531bdd9459cd131fb9fa25a5af34 commit: 4156b2fc1378531bdd9459cd131fb9fa25a5af34 branch: main author: Dong-hee Na committer: corona10 date: 2022-10-20T10:56:21+09:00 summary: gh-98374: Suppress ImportError for invalid query for help() command. (gh-98450) files: A Misc/NEWS.d/next/Core and Builtins/2022-10-19-23-48-46.gh-issue-98374.eOBh8M.rst M Lib/pydoc.py diff --git a/Lib/pydoc.py b/Lib/pydoc.py index a4dc910c8a8e..c79ec77a8c09 100755 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -1997,7 +1997,10 @@ def __repr__(self): _GoInteractive = object() def __call__(self, request=_GoInteractive): if request is not self._GoInteractive: - self.help(request) + try: + self.help(request) + except ImportError as e: + self.output.write(f'{e}\n') else: self.intro() self.interact() diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-19-23-48-46.gh-issue-98374.eOBh8M.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-19-23-48-46.gh-issue-98374.eOBh8M.rst new file mode 100644 index 000000000000..56a41e3883d1 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-19-23-48-46.gh-issue-98374.eOBh8M.rst @@ -0,0 +1,2 @@ +Suppress ImportError for invalid query for help() command. Patch by Dong-hee +Na. From webhook-mailer at python.org Wed Oct 19 22:43:27 2022 From: webhook-mailer at python.org (corona10) Date: Thu, 20 Oct 2022 02:43:27 -0000 Subject: [Python-checkins] =?utf-8?q?=5B3=2E11=5D_gh-98374=3A_Suppress_Im?= =?utf-8?q?portError_for_invalid_query_for_help=28=29_co=E2=80=A6_=28gh-98?= =?utf-8?q?472=29?= Message-ID: https://github.com/python/cpython/commit/e2af980e19794adb36647396c74a7e5aa96ba90e commit: e2af980e19794adb36647396c74a7e5aa96ba90e branch: 3.11 author: Dong-hee Na committer: corona10 date: 2022-10-20T11:43:21+09:00 summary: [3.11] gh-98374: Suppress ImportError for invalid query for help() co? (gh-98472) files: A Misc/NEWS.d/next/Core and Builtins/2022-10-19-23-48-46.gh-issue-98374.eOBh8M.rst M Lib/pydoc.py diff --git a/Lib/pydoc.py b/Lib/pydoc.py index 434316635d48..088a3ba8817c 100755 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -1998,7 +1998,10 @@ def __repr__(self): _GoInteractive = object() def __call__(self, request=_GoInteractive): if request is not self._GoInteractive: - self.help(request) + try: + self.help(request) + except ImportError as e: + self.output.write(f'{e}\n') else: self.intro() self.interact() diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-19-23-48-46.gh-issue-98374.eOBh8M.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-19-23-48-46.gh-issue-98374.eOBh8M.rst new file mode 100644 index 000000000000..56a41e3883d1 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-19-23-48-46.gh-issue-98374.eOBh8M.rst @@ -0,0 +1,2 @@ +Suppress ImportError for invalid query for help() command. Patch by Dong-hee +Na. From webhook-mailer at python.org Thu Oct 20 03:28:28 2022 From: webhook-mailer at python.org (rhettinger) Date: Thu, 20 Oct 2022 07:28:28 -0000 Subject: [Python-checkins] GH-98363: Presize the list for batched() (GH-98419) Message-ID: https://github.com/python/cpython/commit/c1e02d4e4e09dfc9d57c4d36eca1bbf312d4162d commit: c1e02d4e4e09dfc9d57c4d36eca1bbf312d4162d branch: main author: Raymond Hettinger committer: rhettinger date: 2022-10-20T02:28:17-05:00 summary: GH-98363: Presize the list for batched() (GH-98419) files: M Modules/itertoolsmodule.c diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index a5bbba14c280..868e8a8b384f 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -142,6 +142,7 @@ static PyObject * batched_next(batchedobject *bo) { Py_ssize_t i; + Py_ssize_t n = bo->batch_size; PyObject *it = bo->it; PyObject *item; PyObject *result; @@ -149,28 +150,27 @@ batched_next(batchedobject *bo) if (it == NULL) { return NULL; } - result = PyList_New(0); + result = PyList_New(n); if (result == NULL) { return NULL; } - for (i=0 ; i < bo->batch_size ; i++) { + for (i=0 ; i < n ; i++) { item = PyIter_Next(it); if (item == NULL) { break; } - if (PyList_Append(result, item) < 0) { - Py_DECREF(item); - Py_DECREF(result); - return NULL; - } - Py_DECREF(item); + PyList_SET_ITEM(result, i, item); } - if (PyList_GET_SIZE(result) > 0) { - return result; + if (i == 0) { + Py_CLEAR(bo->it); + Py_DECREF(result); + return NULL; } - Py_CLEAR(bo->it); - Py_DECREF(result); - return NULL; + if (i < n) { + PyObject *short_list = PyList_GetSlice(result, 0, i); + Py_SETREF(result, short_list); + } + return result; } static PyTypeObject batched_type = { From webhook-mailer at python.org Thu Oct 20 05:09:37 2022 From: webhook-mailer at python.org (vstinner) Date: Thu, 20 Oct 2022 09:09:37 -0000 Subject: [Python-checkins] gh-95023: Added os.setns and os.unshare functions (#95046) Message-ID: https://github.com/python/cpython/commit/a371a7e03e43e08cae70235a71904989c0f57a5e commit: a371a7e03e43e08cae70235a71904989c0f57a5e branch: main author: Noam Cohen committer: vstinner date: 2022-10-20T11:08:54+02:00 summary: gh-95023: Added os.setns and os.unshare functions (#95046) Added os.setns and os.unshare to easily switch between namespaces on Linux. Co-authored-by: Christian Heimes Co-authored-by: CAM Gerlach Co-authored-by: Victor Stinner files: A Misc/NEWS.d/next/Core and Builtins/2022-07-20-09-04-55.gh-issue-95023.bs-xd7.rst M Doc/library/os.rst M Include/internal/pycore_global_strings.h M Include/internal/pycore_runtime_init_generated.h M Lib/test/test_posix.py M Misc/ACKS M Modules/clinic/posixmodule.c.h M Modules/posixmodule.c M configure M configure.ac M pyconfig.h.in diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 43066fa1e13d..0f0fb55e315c 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -590,6 +590,44 @@ process and user. See the documentation for :func:`getgroups` for cases where it may not return the same group list set by calling setgroups(). +.. function:: setns(fd, nstype=0) + + Reassociate the current thread with a Linux namespace. + See the :manpage:`setns(2)` and :manpage:`namespaces(7)` man pages for more + details. + + If *fd* refers to a :file:`/proc/{pid}/ns/` link, ``setns()`` reassociates the + calling thread with the namespace associated with that link, + and *nstype* may be set to one of the + :ref:`CLONE_NEW* constants ` + to impose constraints on the operation + (``0`` means no constraints). + + Since Linux 5.8, *fd* may refer to a PID file descriptor obtained from + :func:`~os.pidfd_open`. In this case, ``setns()`` reassociates the calling thread + into one or more of the same namespaces as the thread referred to by *fd*. + This is subject to any constraints imposed by *nstype*, + which is a bit mask combining one or more of the + :ref:`CLONE_NEW* constants `, + e.g. ``setns(fd, os.CLONE_NEWUTS | os.CLONE_NEWPID)``. + The caller's memberships in unspecified namespaces are left unchanged. + + *fd* can be any object with a :meth:`~io.IOBase.fileno` method, or a raw file descriptor. + + This example reassociates the thread with the ``init`` process's network namespace:: + + fd = os.open("/proc/1/ns/net", os.O_RDONLY) + os.setns(fd, os.CLONE_NEWNET) + os.close(fd) + + .. availability:: Linux >= 3.0 with glibc >= 2.14. + + .. versionadded:: 3.12 + + .. seealso:: + + The :func:`~os.unshare` function. + .. function:: setpgrp() Call the system call :c:func:`setpgrp` or ``setpgrp(0, 0)`` depending on @@ -756,6 +794,49 @@ process and user. The function is now always available and is also available on Windows. +.. function:: unshare(flags) + + Disassociate parts of the process execution context, and move them into a + newly created namespace. + See the :manpage:`unshare(2)` + man page for more details. + The *flags* argument is a bit mask, combining zero or more of the + :ref:`CLONE_* constants `, + that specifies which parts of the execution context should be + unshared from their existing associations and moved to a new namespace. + If the *flags* argument is ``0``, no changes are made to the calling process's + execution context. + + .. availability:: Linux >= 2.6.16. + + .. versionadded:: 3.12 + + .. seealso:: + + The :func:`~os.setns` function. + +.. _os-unshare-clone-flags: + +Flags to the :func:`unshare` function, if the implementation supports them. +See :manpage:`unshare(2)` in the Linux manual +for their exact effect and availability. + +.. data:: CLONE_FILES + CLONE_FS + CLONE_NEWCGROUP + CLONE_NEWIPC + CLONE_NEWNET + CLONE_NEWNS + CLONE_NEWPID + CLONE_NEWTIME + CLONE_NEWUSER + CLONE_NEWUTS + CLONE_SIGHAND + CLONE_SYSVSEM + CLONE_THREAD + CLONE_VM + + .. _os-newstreams: File Object Creation diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 811cfc147fcf..9c716a3012f4 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -489,6 +489,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(node_depth) STRUCT_FOR_ID(node_offset) STRUCT_FOR_ID(ns) + STRUCT_FOR_ID(nstype) STRUCT_FOR_ID(number) STRUCT_FOR_ID(obj) STRUCT_FOR_ID(object) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index 8ce95884ccdd..55c7c9e3194c 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -998,6 +998,7 @@ extern "C" { INIT_ID(node_depth), \ INIT_ID(node_offset), \ INIT_ID(ns), \ + INIT_ID(nstype), \ INIT_ID(number), \ INIT_ID(obj), \ INIT_ID(object), \ @@ -2307,6 +2308,8 @@ _PyUnicode_InitStaticStrings(void) { PyUnicode_InternInPlace(&string); string = &_Py_ID(ns); PyUnicode_InternInPlace(&string); + string = &_Py_ID(nstype); + PyUnicode_InternInPlace(&string); string = &_Py_ID(number); PyUnicode_InternInPlace(&string); string = &_Py_ID(obj); @@ -6546,6 +6549,10 @@ _PyStaticObjects_CheckRefcnt(void) { _PyObject_Dump((PyObject *)&_Py_ID(ns)); Py_FatalError("immortal object has less refcnt than expected _PyObject_IMMORTAL_REFCNT"); }; + if (Py_REFCNT((PyObject *)&_Py_ID(nstype)) < _PyObject_IMMORTAL_REFCNT) { + _PyObject_Dump((PyObject *)&_Py_ID(nstype)); + Py_FatalError("immortal object has less refcnt than expected _PyObject_IMMORTAL_REFCNT"); + }; if (Py_REFCNT((PyObject *)&_Py_ID(number)) < _PyObject_IMMORTAL_REFCNT) { _PyObject_Dump((PyObject *)&_Py_ID(number)); Py_FatalError("immortal object has less refcnt than expected _PyObject_IMMORTAL_REFCNT"); diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py index be561afc4cff..442dec8b2806 100644 --- a/Lib/test/test_posix.py +++ b/Lib/test/test_posix.py @@ -2191,6 +2191,53 @@ def test_utime(self): os.utime("path", dir_fd=0) +class NamespacesTests(unittest.TestCase): + """Tests for os.unshare() and os.setns().""" + + @unittest.skipUnless(hasattr(os, 'unshare'), 'needs os.unshare()') + @unittest.skipUnless(hasattr(os, 'setns'), 'needs os.setns()') + @unittest.skipUnless(os.path.exists('/proc/self/ns/uts'), 'need /proc/self/ns/uts') + @support.requires_linux_version(3, 0, 0) + def test_unshare_setns(self): + code = """if 1: + import errno + import os + import sys + fd = os.open('/proc/self/ns/uts', os.O_RDONLY) + try: + original = os.readlink('/proc/self/ns/uts') + try: + os.unshare(os.CLONE_NEWUTS) + except OSError as e: + if e.errno == errno.ENOSPC: + # skip test if limit is exceeded + sys.exit() + raise + new = os.readlink('/proc/self/ns/uts') + if original == new: + raise Exception('os.unshare failed') + os.setns(fd, os.CLONE_NEWUTS) + restored = os.readlink('/proc/self/ns/uts') + if original != restored: + raise Exception('os.setns failed') + except PermissionError: + # The calling process did not have the required privileges + # for this operation + pass + except OSError as e: + # Skip the test on these errors: + # - ENOSYS: syscall not available + # - EINVAL: kernel was not configured with the CONFIG_UTS_NS option + # - ENOMEM: not enough memory + if e.errno not in (errno.ENOSYS, errno.EINVAL, errno.ENOMEM): + raise + finally: + os.close(fd) + """ + + assert_python_ok("-c", code) + + def tearDownModule(): support.reap_children() diff --git a/Misc/ACKS b/Misc/ACKS index ec5e326847b8..985314851573 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -344,6 +344,7 @@ Herv? Coatanhay Riccardo Coccioli Nick Coghlan Josh Cogliati +Noam Cohen Dave Cole Terrence Cole Benjamin Collar diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-07-20-09-04-55.gh-issue-95023.bs-xd7.rst b/Misc/NEWS.d/next/Core and Builtins/2022-07-20-09-04-55.gh-issue-95023.bs-xd7.rst new file mode 100644 index 000000000000..bf0558ba79c7 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-07-20-09-04-55.gh-issue-95023.bs-xd7.rst @@ -0,0 +1 @@ +Implement :func:`os.setns` and :func:`os.unshare` for Linux. Patch by Noam Cohen. diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h index 31bd01d1c3c1..1ad96ea296ea 100644 --- a/Modules/clinic/posixmodule.c.h +++ b/Modules/clinic/posixmodule.c.h @@ -5211,6 +5211,147 @@ os_pidfd_open(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObjec #endif /* (defined(__linux__) && defined(__NR_pidfd_open)) */ +#if defined(HAVE_SETNS) + +PyDoc_STRVAR(os_setns__doc__, +"setns($module, /, fd, nstype=0)\n" +"--\n" +"\n" +"Move the calling thread into different namespaces.\n" +"\n" +" fd\n" +" A file descriptor to a namespace.\n" +" nstype\n" +" Type of namespace."); + +#define OS_SETNS_METHODDEF \ + {"setns", _PyCFunction_CAST(os_setns), METH_FASTCALL|METH_KEYWORDS, os_setns__doc__}, + +static PyObject * +os_setns_impl(PyObject *module, int fd, int nstype); + +static PyObject * +os_setns(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(fd), &_Py_ID(nstype), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"fd", "nstype", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "setns", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; + int fd; + int nstype = 0; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 2, 0, argsbuf); + if (!args) { + goto exit; + } + if (!_PyLong_FileDescriptor_Converter(args[0], &fd)) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + nstype = _PyLong_AsInt(args[1]); + if (nstype == -1 && PyErr_Occurred()) { + goto exit; + } +skip_optional_pos: + return_value = os_setns_impl(module, fd, nstype); + +exit: + return return_value; +} + +#endif /* defined(HAVE_SETNS) */ + +#if defined(HAVE_UNSHARE) + +PyDoc_STRVAR(os_unshare__doc__, +"unshare($module, /, flags)\n" +"--\n" +"\n" +"Disassociate parts of a process (or thread) execution context.\n" +"\n" +" flags\n" +" Namespaces to be unshared."); + +#define OS_UNSHARE_METHODDEF \ + {"unshare", _PyCFunction_CAST(os_unshare), METH_FASTCALL|METH_KEYWORDS, os_unshare__doc__}, + +static PyObject * +os_unshare_impl(PyObject *module, int flags); + +static PyObject * +os_unshare(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(flags), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"flags", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "unshare", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + int flags; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + flags = _PyLong_AsInt(args[0]); + if (flags == -1 && PyErr_Occurred()) { + goto exit; + } + return_value = os_unshare_impl(module, flags); + +exit: + return return_value; +} + +#endif /* defined(HAVE_UNSHARE) */ + #if (defined(HAVE_READLINK) || defined(MS_WINDOWS)) PyDoc_STRVAR(os_readlink__doc__, @@ -11085,6 +11226,14 @@ os_waitstatus_to_exitcode(PyObject *module, PyObject *const *args, Py_ssize_t na #define OS_PIDFD_OPEN_METHODDEF #endif /* !defined(OS_PIDFD_OPEN_METHODDEF) */ +#ifndef OS_SETNS_METHODDEF + #define OS_SETNS_METHODDEF +#endif /* !defined(OS_SETNS_METHODDEF) */ + +#ifndef OS_UNSHARE_METHODDEF + #define OS_UNSHARE_METHODDEF +#endif /* !defined(OS_UNSHARE_METHODDEF) */ + #ifndef OS_READLINK_METHODDEF #define OS_READLINK_METHODDEF #endif /* !defined(OS_READLINK_METHODDEF) */ @@ -11368,4 +11517,4 @@ os_waitstatus_to_exitcode(PyObject *module, PyObject *const *args, Py_ssize_t na #ifndef OS_WAITSTATUS_TO_EXITCODE_METHODDEF #define OS_WAITSTATUS_TO_EXITCODE_METHODDEF #endif /* !defined(OS_WAITSTATUS_TO_EXITCODE_METHODDEF) */ -/*[clinic end generated code: output=471ab8f2ad3d46b0 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=90f5e6995114e5ca input=a9049054013a1b77]*/ diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 39198cb7ddcd..56ea319ecb3a 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -8581,6 +8581,64 @@ os_pidfd_open_impl(PyObject *module, pid_t pid, unsigned int flags) #endif +#ifdef HAVE_SETNS +/*[clinic input] +os.setns + fd: fildes + A file descriptor to a namespace. + nstype: int = 0 + Type of namespace. + +Move the calling thread into different namespaces. +[clinic start generated code]*/ + +static PyObject * +os_setns_impl(PyObject *module, int fd, int nstype) +/*[clinic end generated code: output=5dbd055bfb66ecd0 input=42787871226bf3ee]*/ +{ + int res; + + Py_BEGIN_ALLOW_THREADS + res = setns(fd, nstype); + Py_END_ALLOW_THREADS + + if (res != 0) { + return posix_error(); + } + + Py_RETURN_NONE; +} +#endif + + +#ifdef HAVE_UNSHARE +/*[clinic input] +os.unshare + flags: int + Namespaces to be unshared. + +Disassociate parts of a process (or thread) execution context. +[clinic start generated code]*/ + +static PyObject * +os_unshare_impl(PyObject *module, int flags) +/*[clinic end generated code: output=1b3177906dd237ee input=9e065db3232b8b1b]*/ +{ + int res; + + Py_BEGIN_ALLOW_THREADS + res = unshare(flags); + Py_END_ALLOW_THREADS + + if (res != 0) { + return posix_error(); + } + + Py_RETURN_NONE; +} +#endif + + #if defined(HAVE_READLINK) || defined(MS_WINDOWS) /*[clinic input] os.readlink @@ -14945,6 +15003,8 @@ static PyMethodDef posix_methods[] = { OS__ADD_DLL_DIRECTORY_METHODDEF OS__REMOVE_DLL_DIRECTORY_METHODDEF OS_WAITSTATUS_TO_EXITCODE_METHODDEF + OS_SETNS_METHODDEF + OS_UNSHARE_METHODDEF {NULL, NULL} /* Sentinel */ }; @@ -15390,6 +15450,53 @@ all_ins(PyObject *m) #ifdef SCHED_FX if (PyModule_AddIntConstant(m, "SCHED_FX", SCHED_FSS)) return -1; #endif + +/* constants for namespaces */ +#if defined(HAVE_SETNS) || defined(HAVE_UNSHARE) +#ifdef CLONE_FS + if (PyModule_AddIntMacro(m, CLONE_FS)) return -1; +#endif +#ifdef CLONE_FILES + if (PyModule_AddIntMacro(m, CLONE_FILES)) return -1; +#endif +#ifdef CLONE_NEWNS + if (PyModule_AddIntMacro(m, CLONE_NEWNS)) return -1; +#endif +#ifdef CLONE_NEWCGROUP + if (PyModule_AddIntMacro(m, CLONE_NEWCGROUP)) return -1; +#endif +#ifdef CLONE_NEWUTS + if (PyModule_AddIntMacro(m, CLONE_NEWUTS)) return -1; +#endif +#ifdef CLONE_NEWIPC + if (PyModule_AddIntMacro(m, CLONE_NEWIPC)) return -1; +#endif +#ifdef CLONE_NEWUSER + if (PyModule_AddIntMacro(m, CLONE_NEWUSER)) return -1; +#endif +#ifdef CLONE_NEWPID + if (PyModule_AddIntMacro(m, CLONE_NEWPID)) return -1; +#endif +#ifdef CLONE_NEWNET + if (PyModule_AddIntMacro(m, CLONE_NEWNET)) return -1; +#endif +#ifdef CLONE_NEWTIME + if (PyModule_AddIntMacro(m, CLONE_NEWTIME)) return -1; +#endif +#ifdef CLONE_SYSVSEM + if (PyModule_AddIntMacro(m, CLONE_SYSVSEM)) return -1; +#endif +#ifdef CLONE_THREAD + if (PyModule_AddIntMacro(m, CLONE_THREAD)) return -1; +#endif +#ifdef CLONE_SIGHAND + if (PyModule_AddIntMacro(m, CLONE_SIGHAND)) return -1; +#endif +#ifdef CLONE_VM + if (PyModule_AddIntMacro(m, CLONE_VM)) return -1; +#endif +#endif + #endif #ifdef USE_XATTRS diff --git a/configure b/configure index 0e9f72faa7b1..15d97963742f 100755 --- a/configure +++ b/configure @@ -19111,6 +19111,20 @@ fi done +# check for namespace functions +for ac_func in setns unshare +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + diff --git a/configure.ac b/configure.ac index a4f3b0ab8466..c7945aaf8505 100644 --- a/configure.ac +++ b/configure.ac @@ -5083,6 +5083,9 @@ AC_CHECK_FUNCS(setpgrp, []) ) +# check for namespace functions +AC_CHECK_FUNCS([setns unshare]) + dnl We search for both crypt and crypt_r as one or the other may be defined dnl libxcrypt provides and libcrypt with crypt_r() since dnl at least 3.1.1 from 2015. diff --git a/pyconfig.h.in b/pyconfig.h.in index 1ce09855f555..0d3c851a1af9 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -1067,6 +1067,9 @@ /* Define to 1 if you have the `setlocale' function. */ #undef HAVE_SETLOCALE +/* Define to 1 if you have the `setns' function. */ +#undef HAVE_SETNS + /* Define to 1 if you have the `setpgid' function. */ #undef HAVE_SETPGID @@ -1437,6 +1440,9 @@ /* Define to 1 if you have the `unlinkat' function. */ #undef HAVE_UNLINKAT +/* Define to 1 if you have the `unshare' function. */ +#undef HAVE_UNSHARE + /* Define if you have a useable wchar_t type defined in wchar.h; useable means wchar_t must be an unsigned type with at least 16 bits. (see Include/unicodeobject.h). */ From webhook-mailer at python.org Thu Oct 20 06:43:41 2022 From: webhook-mailer at python.org (serhiy-storchaka) Date: Thu, 20 Oct 2022 10:43:41 -0000 Subject: [Python-checkins] Add more tkinter.Canvas tests (GH-98475) Message-ID: https://github.com/python/cpython/commit/ff173ed2f6b07f38ec18f854daba6451bf1a9000 commit: ff173ed2f6b07f38ec18f854daba6451bf1a9000 branch: main author: Serhiy Storchaka committer: serhiy-storchaka date: 2022-10-20T13:43:12+03:00 summary: Add more tkinter.Canvas tests (GH-98475) It is a prerequisite for #94473. Add tests for the coords() method and for creation of some Canvas items. files: M Lib/test/test_tkinter/test_widgets.py diff --git a/Lib/test/test_tkinter/test_widgets.py b/Lib/test/test_tkinter/test_widgets.py index 6cde1ccdbfcd..6fde93cbecc7 100644 --- a/Lib/test/test_tkinter/test_widgets.py +++ b/Lib/test/test_tkinter/test_widgets.py @@ -759,6 +759,164 @@ def test_configure_yscrollincrement(self): self.checkPixelsParam(widget, 'yscrollincrement', 10, 0, 11.2, 13.6, -10, '0.1i') + def _test_option_joinstyle(self, c, factory): + for joinstyle in 'bevel', 'miter', 'round': + i = factory(joinstyle=joinstyle) + self.assertEqual(c.itemcget(i, 'joinstyle'), joinstyle) + self.assertRaises(TclError, factory, joinstyle='spam') + + def _test_option_smooth(self, c, factory): + for smooth in 1, True, '1', 'true', 'yes', 'on': + i = factory(smooth=smooth) + self.assertEqual(c.itemcget(i, 'smooth'), 'true') + for smooth in 0, False, '0', 'false', 'no', 'off': + i = factory(smooth=smooth) + self.assertEqual(c.itemcget(i, 'smooth'), '0') + i = factory(smooth=True, splinestep=30) + self.assertEqual(c.itemcget(i, 'smooth'), 'true') + self.assertEqual(c.itemcget(i, 'splinestep'), '30') + i = factory(smooth='raw', splinestep=30) + self.assertEqual(c.itemcget(i, 'smooth'), 'raw') + self.assertEqual(c.itemcget(i, 'splinestep'), '30') + self.assertRaises(TclError, factory, smooth='spam') + + def test_create_rectangle(self): + c = self.create() + i1 = c.create_rectangle(20, 30, 60, 10) + self.assertEqual(c.coords(i1), [20.0, 10.0, 60.0, 30.0]) + self.assertEqual(c.bbox(i1), (19, 9, 61, 31)) + + i2 = c.create_rectangle([21, 31, 61, 11]) + self.assertEqual(c.coords(i2), [21.0, 11.0, 61.0, 31.0]) + self.assertEqual(c.bbox(i2), (20, 10, 62, 32)) + + i3 = c.create_rectangle((22, 32), (62, 12)) + self.assertEqual(c.coords(i3), [22.0, 12.0, 62.0, 32.0]) + self.assertEqual(c.bbox(i3), (21, 11, 63, 33)) + + i4 = c.create_rectangle([(23, 33), (63, 13)]) + self.assertEqual(c.coords(i4), [23.0, 13.0, 63.0, 33.0]) + self.assertEqual(c.bbox(i4), (22, 12, 64, 34)) + + self.assertRaises(TclError, c.create_rectangle, 20, 30, 60) + self.assertRaises(TclError, c.create_rectangle, [20, 30, 60]) + self.assertRaises(TclError, c.create_rectangle, 20, 30, 40, 50, 60, 10) + self.assertRaises(TclError, c.create_rectangle, [20, 30, 40, 50, 60, 10]) + self.assertRaises(TclError, c.create_rectangle, 20, 30) + self.assertRaises(TclError, c.create_rectangle, [20, 30]) + self.assertRaises(IndexError, c.create_rectangle) + self.assertRaises(IndexError, c.create_rectangle, []) + + def test_create_line(self): + c = self.create() + i1 = c.create_line(20, 30, 40, 50, 60, 10) + self.assertEqual(c.coords(i1), [20.0, 30.0, 40.0, 50.0, 60.0, 10.0]) + self.assertEqual(c.bbox(i1), (18, 8, 62, 52)) + self.assertEqual(c.itemcget(i1, 'arrow'), 'none') + self.assertEqual(c.itemcget(i1, 'arrowshape'), '8 10 3') + self.assertEqual(c.itemcget(i1, 'capstyle'), 'butt') + self.assertEqual(c.itemcget(i1, 'joinstyle'), 'round') + self.assertEqual(c.itemcget(i1, 'smooth'), '0') + self.assertEqual(c.itemcget(i1, 'splinestep'), '12') + + i2 = c.create_line([21, 31, 41, 51, 61, 11]) + self.assertEqual(c.coords(i2), [21.0, 31.0, 41.0, 51.0, 61.0, 11.0]) + self.assertEqual(c.bbox(i2), (19, 9, 63, 53)) + + i3 = c.create_line((22, 32), (42, 52), (62, 12)) + self.assertEqual(c.coords(i3), [22.0, 32.0, 42.0, 52.0, 62.0, 12.0]) + self.assertEqual(c.bbox(i3), (20, 10, 64, 54)) + + i4 = c.create_line([(23, 33), (43, 53), (63, 13)]) + self.assertEqual(c.coords(i4), [23.0, 33.0, 43.0, 53.0, 63.0, 13.0]) + self.assertEqual(c.bbox(i4), (21, 11, 65, 55)) + + self.assertRaises(TclError, c.create_line, 20, 30, 60) + self.assertRaises(TclError, c.create_line, [20, 30, 60]) + self.assertRaises(TclError, c.create_line, 20, 30) + self.assertRaises(TclError, c.create_line, [20, 30]) + self.assertRaises(IndexError, c.create_line) + self.assertRaises(IndexError, c.create_line, []) + + for arrow in 'none', 'first', 'last', 'both': + i = c.create_line(20, 30, 60, 10, arrow=arrow) + self.assertEqual(c.itemcget(i, 'arrow'), arrow) + i = c.create_line(20, 30, 60, 10, arrow='first', arrowshape=[10, 15, 5]) + self.assertEqual(c.itemcget(i, 'arrowshape'), '10 15 5') + self.assertRaises(TclError, c.create_line, 20, 30, 60, 10, arrow='spam') + + for capstyle in 'butt', 'projecting', 'round': + i = c.create_line(20, 30, 60, 10, capstyle=capstyle) + self.assertEqual(c.itemcget(i, 'capstyle'), capstyle) + self.assertRaises(TclError, c.create_line, 20, 30, 60, 10, capstyle='spam') + + self._test_option_joinstyle(c, + lambda **kwargs: c.create_line(20, 30, 40, 50, 60, 10, **kwargs)) + self._test_option_smooth(c, + lambda **kwargs: c.create_line(20, 30, 60, 10, **kwargs)) + + def test_create_polygon(self): + c = self.create() + i1 = c.create_polygon(20, 30, 40, 50, 60, 10) + self.assertEqual(c.coords(i1), [20.0, 30.0, 40.0, 50.0, 60.0, 10.0]) + self.assertEqual(c.bbox(i1), (19, 9, 61, 51)) + self.assertEqual(c.itemcget(i1, 'joinstyle'), 'round') + self.assertEqual(c.itemcget(i1, 'smooth'), '0') + self.assertEqual(c.itemcget(i1, 'splinestep'), '12') + + i2 = c.create_polygon([21, 31, 41, 51, 61, 11]) + self.assertEqual(c.coords(i2), [21.0, 31.0, 41.0, 51.0, 61.0, 11.0]) + self.assertEqual(c.bbox(i2), (20, 10, 62, 52)) + + i3 = c.create_polygon((22, 32), (42, 52), (62, 12)) + self.assertEqual(c.coords(i3), [22.0, 32.0, 42.0, 52.0, 62.0, 12.0]) + self.assertEqual(c.bbox(i3), (21, 11, 63, 53)) + + i4 = c.create_polygon([(23, 33), (43, 53), (63, 13)]) + self.assertEqual(c.coords(i4), [23.0, 33.0, 43.0, 53.0, 63.0, 13.0]) + self.assertEqual(c.bbox(i4), (22, 12, 64, 54)) + + self.assertRaises(TclError, c.create_polygon, 20, 30, 60) + self.assertRaises(TclError, c.create_polygon, [20, 30, 60]) + self.assertRaises(IndexError, c.create_polygon) + self.assertRaises(IndexError, c.create_polygon, []) + + self._test_option_joinstyle(c, + lambda **kwargs: c.create_polygon(20, 30, 40, 50, 60, 10, **kwargs)) + self._test_option_smooth(c, + lambda **kwargs: c.create_polygon(20, 30, 40, 50, 60, 10, **kwargs)) + + def test_coords(self): + c = self.create() + i = c.create_line(20, 30, 40, 50, 60, 10, tags='x') + self.assertEqual(c.coords(i), [20.0, 30.0, 40.0, 50.0, 60.0, 10.0]) + self.assertEqual(c.coords('x'), [20.0, 30.0, 40.0, 50.0, 60.0, 10.0]) + self.assertEqual(c.bbox(i), (18, 8, 62, 52)) + + c.coords(i, 50, 60, 70, 80, 90, 40) + self.assertEqual(c.coords(i), [50.0, 60.0, 70.0, 80.0, 90.0, 40.0]) + self.assertEqual(c.bbox(i), (48, 38, 92, 82)) + + c.coords(i, [21, 31, 41, 51, 61, 11]) + self.assertEqual(c.coords(i), [21.0, 31.0, 41.0, 51.0, 61.0, 11.0]) + + c.coords(i, 20, 30, 60, 10) + self.assertEqual(c.coords(i), [20.0, 30.0, 60.0, 10.0]) + self.assertEqual(c.bbox(i), (18, 8, 62, 32)) + + self.assertRaises(TclError, c.coords, i, 20, 30, 60) + self.assertRaises(TclError, c.coords, i, [20, 30, 60]) + self.assertRaises(TclError, c.coords, i, 20, 30) + self.assertRaises(TclError, c.coords, i, [20, 30]) + + c.coords(i, '20', '30c', '60i', '10p') + coords = c.coords(i) + self.assertIsInstance(coords, list) + self.assertEqual(len(coords), 4) + self.assertEqual(coords[0], 20) + for i in range(4): + self.assertIsInstance(coords[i], float) + @requires_tcl(8, 6) def test_moveto(self): widget = self.create() From webhook-mailer at python.org Thu Oct 20 07:04:51 2022 From: webhook-mailer at python.org (miss-islington) Date: Thu, 20 Oct 2022 11:04:51 -0000 Subject: [Python-checkins] Add more tkinter.Canvas tests (GH-98475) Message-ID: https://github.com/python/cpython/commit/05111d0a645c064390bfb65234fc395e380bb179 commit: 05111d0a645c064390bfb65234fc395e380bb179 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-20T04:04:45-07:00 summary: Add more tkinter.Canvas tests (GH-98475) It is a prerequisite for GH-94473. Add tests for the coords() method and for creation of some Canvas items. (cherry picked from commit ff173ed2f6b07f38ec18f854daba6451bf1a9000) Co-authored-by: Serhiy Storchaka files: M Lib/tkinter/test/test_tkinter/test_widgets.py diff --git a/Lib/tkinter/test/test_tkinter/test_widgets.py b/Lib/tkinter/test/test_tkinter/test_widgets.py index 995bed2ecf60..da321a1daedb 100644 --- a/Lib/tkinter/test/test_tkinter/test_widgets.py +++ b/Lib/tkinter/test/test_tkinter/test_widgets.py @@ -759,6 +759,164 @@ def test_configure_yscrollincrement(self): self.checkPixelsParam(widget, 'yscrollincrement', 10, 0, 11.2, 13.6, -10, '0.1i') + def _test_option_joinstyle(self, c, factory): + for joinstyle in 'bevel', 'miter', 'round': + i = factory(joinstyle=joinstyle) + self.assertEqual(c.itemcget(i, 'joinstyle'), joinstyle) + self.assertRaises(TclError, factory, joinstyle='spam') + + def _test_option_smooth(self, c, factory): + for smooth in 1, True, '1', 'true', 'yes', 'on': + i = factory(smooth=smooth) + self.assertEqual(c.itemcget(i, 'smooth'), 'true') + for smooth in 0, False, '0', 'false', 'no', 'off': + i = factory(smooth=smooth) + self.assertEqual(c.itemcget(i, 'smooth'), '0') + i = factory(smooth=True, splinestep=30) + self.assertEqual(c.itemcget(i, 'smooth'), 'true') + self.assertEqual(c.itemcget(i, 'splinestep'), '30') + i = factory(smooth='raw', splinestep=30) + self.assertEqual(c.itemcget(i, 'smooth'), 'raw') + self.assertEqual(c.itemcget(i, 'splinestep'), '30') + self.assertRaises(TclError, factory, smooth='spam') + + def test_create_rectangle(self): + c = self.create() + i1 = c.create_rectangle(20, 30, 60, 10) + self.assertEqual(c.coords(i1), [20.0, 10.0, 60.0, 30.0]) + self.assertEqual(c.bbox(i1), (19, 9, 61, 31)) + + i2 = c.create_rectangle([21, 31, 61, 11]) + self.assertEqual(c.coords(i2), [21.0, 11.0, 61.0, 31.0]) + self.assertEqual(c.bbox(i2), (20, 10, 62, 32)) + + i3 = c.create_rectangle((22, 32), (62, 12)) + self.assertEqual(c.coords(i3), [22.0, 12.0, 62.0, 32.0]) + self.assertEqual(c.bbox(i3), (21, 11, 63, 33)) + + i4 = c.create_rectangle([(23, 33), (63, 13)]) + self.assertEqual(c.coords(i4), [23.0, 13.0, 63.0, 33.0]) + self.assertEqual(c.bbox(i4), (22, 12, 64, 34)) + + self.assertRaises(TclError, c.create_rectangle, 20, 30, 60) + self.assertRaises(TclError, c.create_rectangle, [20, 30, 60]) + self.assertRaises(TclError, c.create_rectangle, 20, 30, 40, 50, 60, 10) + self.assertRaises(TclError, c.create_rectangle, [20, 30, 40, 50, 60, 10]) + self.assertRaises(TclError, c.create_rectangle, 20, 30) + self.assertRaises(TclError, c.create_rectangle, [20, 30]) + self.assertRaises(IndexError, c.create_rectangle) + self.assertRaises(IndexError, c.create_rectangle, []) + + def test_create_line(self): + c = self.create() + i1 = c.create_line(20, 30, 40, 50, 60, 10) + self.assertEqual(c.coords(i1), [20.0, 30.0, 40.0, 50.0, 60.0, 10.0]) + self.assertEqual(c.bbox(i1), (18, 8, 62, 52)) + self.assertEqual(c.itemcget(i1, 'arrow'), 'none') + self.assertEqual(c.itemcget(i1, 'arrowshape'), '8 10 3') + self.assertEqual(c.itemcget(i1, 'capstyle'), 'butt') + self.assertEqual(c.itemcget(i1, 'joinstyle'), 'round') + self.assertEqual(c.itemcget(i1, 'smooth'), '0') + self.assertEqual(c.itemcget(i1, 'splinestep'), '12') + + i2 = c.create_line([21, 31, 41, 51, 61, 11]) + self.assertEqual(c.coords(i2), [21.0, 31.0, 41.0, 51.0, 61.0, 11.0]) + self.assertEqual(c.bbox(i2), (19, 9, 63, 53)) + + i3 = c.create_line((22, 32), (42, 52), (62, 12)) + self.assertEqual(c.coords(i3), [22.0, 32.0, 42.0, 52.0, 62.0, 12.0]) + self.assertEqual(c.bbox(i3), (20, 10, 64, 54)) + + i4 = c.create_line([(23, 33), (43, 53), (63, 13)]) + self.assertEqual(c.coords(i4), [23.0, 33.0, 43.0, 53.0, 63.0, 13.0]) + self.assertEqual(c.bbox(i4), (21, 11, 65, 55)) + + self.assertRaises(TclError, c.create_line, 20, 30, 60) + self.assertRaises(TclError, c.create_line, [20, 30, 60]) + self.assertRaises(TclError, c.create_line, 20, 30) + self.assertRaises(TclError, c.create_line, [20, 30]) + self.assertRaises(IndexError, c.create_line) + self.assertRaises(IndexError, c.create_line, []) + + for arrow in 'none', 'first', 'last', 'both': + i = c.create_line(20, 30, 60, 10, arrow=arrow) + self.assertEqual(c.itemcget(i, 'arrow'), arrow) + i = c.create_line(20, 30, 60, 10, arrow='first', arrowshape=[10, 15, 5]) + self.assertEqual(c.itemcget(i, 'arrowshape'), '10 15 5') + self.assertRaises(TclError, c.create_line, 20, 30, 60, 10, arrow='spam') + + for capstyle in 'butt', 'projecting', 'round': + i = c.create_line(20, 30, 60, 10, capstyle=capstyle) + self.assertEqual(c.itemcget(i, 'capstyle'), capstyle) + self.assertRaises(TclError, c.create_line, 20, 30, 60, 10, capstyle='spam') + + self._test_option_joinstyle(c, + lambda **kwargs: c.create_line(20, 30, 40, 50, 60, 10, **kwargs)) + self._test_option_smooth(c, + lambda **kwargs: c.create_line(20, 30, 60, 10, **kwargs)) + + def test_create_polygon(self): + c = self.create() + i1 = c.create_polygon(20, 30, 40, 50, 60, 10) + self.assertEqual(c.coords(i1), [20.0, 30.0, 40.0, 50.0, 60.0, 10.0]) + self.assertEqual(c.bbox(i1), (19, 9, 61, 51)) + self.assertEqual(c.itemcget(i1, 'joinstyle'), 'round') + self.assertEqual(c.itemcget(i1, 'smooth'), '0') + self.assertEqual(c.itemcget(i1, 'splinestep'), '12') + + i2 = c.create_polygon([21, 31, 41, 51, 61, 11]) + self.assertEqual(c.coords(i2), [21.0, 31.0, 41.0, 51.0, 61.0, 11.0]) + self.assertEqual(c.bbox(i2), (20, 10, 62, 52)) + + i3 = c.create_polygon((22, 32), (42, 52), (62, 12)) + self.assertEqual(c.coords(i3), [22.0, 32.0, 42.0, 52.0, 62.0, 12.0]) + self.assertEqual(c.bbox(i3), (21, 11, 63, 53)) + + i4 = c.create_polygon([(23, 33), (43, 53), (63, 13)]) + self.assertEqual(c.coords(i4), [23.0, 33.0, 43.0, 53.0, 63.0, 13.0]) + self.assertEqual(c.bbox(i4), (22, 12, 64, 54)) + + self.assertRaises(TclError, c.create_polygon, 20, 30, 60) + self.assertRaises(TclError, c.create_polygon, [20, 30, 60]) + self.assertRaises(IndexError, c.create_polygon) + self.assertRaises(IndexError, c.create_polygon, []) + + self._test_option_joinstyle(c, + lambda **kwargs: c.create_polygon(20, 30, 40, 50, 60, 10, **kwargs)) + self._test_option_smooth(c, + lambda **kwargs: c.create_polygon(20, 30, 40, 50, 60, 10, **kwargs)) + + def test_coords(self): + c = self.create() + i = c.create_line(20, 30, 40, 50, 60, 10, tags='x') + self.assertEqual(c.coords(i), [20.0, 30.0, 40.0, 50.0, 60.0, 10.0]) + self.assertEqual(c.coords('x'), [20.0, 30.0, 40.0, 50.0, 60.0, 10.0]) + self.assertEqual(c.bbox(i), (18, 8, 62, 52)) + + c.coords(i, 50, 60, 70, 80, 90, 40) + self.assertEqual(c.coords(i), [50.0, 60.0, 70.0, 80.0, 90.0, 40.0]) + self.assertEqual(c.bbox(i), (48, 38, 92, 82)) + + c.coords(i, [21, 31, 41, 51, 61, 11]) + self.assertEqual(c.coords(i), [21.0, 31.0, 41.0, 51.0, 61.0, 11.0]) + + c.coords(i, 20, 30, 60, 10) + self.assertEqual(c.coords(i), [20.0, 30.0, 60.0, 10.0]) + self.assertEqual(c.bbox(i), (18, 8, 62, 32)) + + self.assertRaises(TclError, c.coords, i, 20, 30, 60) + self.assertRaises(TclError, c.coords, i, [20, 30, 60]) + self.assertRaises(TclError, c.coords, i, 20, 30) + self.assertRaises(TclError, c.coords, i, [20, 30]) + + c.coords(i, '20', '30c', '60i', '10p') + coords = c.coords(i) + self.assertIsInstance(coords, list) + self.assertEqual(len(coords), 4) + self.assertEqual(coords[0], 20) + for i in range(4): + self.assertIsInstance(coords[i], float) + @requires_tcl(8, 6) def test_moveto(self): widget = self.create() From webhook-mailer at python.org Thu Oct 20 07:46:08 2022 From: webhook-mailer at python.org (vsajip) Date: Thu, 20 Oct 2022 11:46:08 -0000 Subject: [Python-checkins] [doc] Improve logging cookbook example. (GH-98481) Message-ID: https://github.com/python/cpython/commit/a956c2fd556da8d00ee6e43f0597ba2fa6cead33 commit: a956c2fd556da8d00ee6e43f0597ba2fa6cead33 branch: main author: Vinay Sajip committer: vsajip date: 2022-10-20T12:46:03+01:00 summary: [doc] Improve logging cookbook example. (GH-98481) files: M Doc/howto/logging-cookbook.rst diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst index eac34aaab3aa..ae101e3cdf25 100644 --- a/Doc/howto/logging-cookbook.rst +++ b/Doc/howto/logging-cookbook.rst @@ -3712,6 +3712,71 @@ Of course, the examples above show output according to the format used by :func:`~logging.basicConfig`, but you can use a different formatter when you configure logging. +Note that with the above scheme, you are somewhat at the mercy of buffering and +the sequence of write calls which you are intercepting. For example, with the +definition of ``LoggerWriter`` above, if you have the snippet + +.. code-block:: python + + sys.stderr = LoggerWriter(logger, logging.WARNING) + 1 / 0 + +then running the script results in + +.. code-block:: text + + WARNING:demo:Traceback (most recent call last): + + WARNING:demo: File "/home/runner/cookbook-loggerwriter/test.py", line 53, in + + WARNING:demo: + WARNING:demo:main() + WARNING:demo: File "/home/runner/cookbook-loggerwriter/test.py", line 49, in main + + WARNING:demo: + WARNING:demo:1 / 0 + WARNING:demo:ZeroDivisionError + WARNING:demo:: + WARNING:demo:division by zero + +As you can see, this output isn't ideal. That's because the underlying code +which writes to ``sys.stderr`` makes mutiple writes, each of which results in a +separate logged line (for example, the last three lines above). To get around +this problem, you need to buffer things and only output log lines when newlines +are seen. Let's use a slghtly better implementation of ``LoggerWriter``: + +.. code-block:: python + + class BufferingLoggerWriter(LoggerWriter): + def __init__(self, logger, level): + super().__init__(logger, level) + self.buffer = '' + + def write(self, message): + if '\n' not in message: + self.buffer += message + else: + parts = message.split('\n') + if self.buffer: + s = self.buffer + parts.pop(0) + self.logger.log(self.level, s) + self.buffer = parts.pop() + for part in parts: + self.logger.log(self.level, part) + +This just buffers up stuff until a newline is seen, and then logs complete +lines. With this approach, you get better output: + +.. code-block:: text + + WARNING:demo:Traceback (most recent call last): + WARNING:demo: File "/home/runner/cookbook-loggerwriter/main.py", line 55, in + WARNING:demo: main() + WARNING:demo: File "/home/runner/cookbook-loggerwriter/main.py", line 52, in main + WARNING:demo: 1/0 + WARNING:demo:ZeroDivisionError: division by zero + + .. patterns-to-avoid: Patterns to avoid From webhook-mailer at python.org Thu Oct 20 07:53:58 2022 From: webhook-mailer at python.org (vsajip) Date: Thu, 20 Oct 2022 11:53:58 -0000 Subject: [Python-checkins] [3.10] [doc] Improve logging cookbook example. (GH-98481) (GH-98482) Message-ID: https://github.com/python/cpython/commit/3f040bc8e4edef0940c71e4609bd9785b02d0f9e commit: 3f040bc8e4edef0940c71e4609bd9785b02d0f9e branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: vsajip date: 2022-10-20T12:53:53+01:00 summary: [3.10] [doc] Improve logging cookbook example. (GH-98481) (GH-98482) Co-authored-by: Vinay Sajip files: M Doc/howto/logging-cookbook.rst diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst index d9a19420db7b..22f7aa943acb 100644 --- a/Doc/howto/logging-cookbook.rst +++ b/Doc/howto/logging-cookbook.rst @@ -3712,6 +3712,71 @@ Of course, these above examples show output according to the format used by :func:`~logging.basicConfig`, but you can use a different formatter when you configure logging. +Note that with the above scheme, you are somewhat at the mercy of buffering and +the sequence of write calls which you are intercepting. For example, with the +definition of ``LoggerWriter`` above, if you have the snippet + +.. code-block:: python + + sys.stderr = LoggerWriter(logger, logging.WARNING) + 1 / 0 + +then running the script results in + +.. code-block:: text + + WARNING:demo:Traceback (most recent call last): + + WARNING:demo: File "/home/runner/cookbook-loggerwriter/test.py", line 53, in + + WARNING:demo: + WARNING:demo:main() + WARNING:demo: File "/home/runner/cookbook-loggerwriter/test.py", line 49, in main + + WARNING:demo: + WARNING:demo:1 / 0 + WARNING:demo:ZeroDivisionError + WARNING:demo:: + WARNING:demo:division by zero + +As you can see, this output isn't ideal. That's because the underlying code +which writes to ``sys.stderr`` makes mutiple writes, each of which results in a +separate logged line (for example, the last three lines above). To get around +this problem, you need to buffer things and only output log lines when newlines +are seen. Let's use a slghtly better implementation of ``LoggerWriter``: + +.. code-block:: python + + class BufferingLoggerWriter(LoggerWriter): + def __init__(self, logger, level): + super().__init__(logger, level) + self.buffer = '' + + def write(self, message): + if '\n' not in message: + self.buffer += message + else: + parts = message.split('\n') + if self.buffer: + s = self.buffer + parts.pop(0) + self.logger.log(self.level, s) + self.buffer = parts.pop() + for part in parts: + self.logger.log(self.level, part) + +This just buffers up stuff until a newline is seen, and then logs complete +lines. With this approach, you get better output: + +.. code-block:: text + + WARNING:demo:Traceback (most recent call last): + WARNING:demo: File "/home/runner/cookbook-loggerwriter/main.py", line 55, in + WARNING:demo: main() + WARNING:demo: File "/home/runner/cookbook-loggerwriter/main.py", line 52, in main + WARNING:demo: 1/0 + WARNING:demo:ZeroDivisionError: division by zero + + .. patterns-to-avoid: Patterns to avoid From webhook-mailer at python.org Thu Oct 20 07:54:58 2022 From: webhook-mailer at python.org (vsajip) Date: Thu, 20 Oct 2022 11:54:58 -0000 Subject: [Python-checkins] [3.11] [doc] Improve logging cookbook example. (GH-98481) (GH-98483) Message-ID: https://github.com/python/cpython/commit/860efa3534b097debdd939fd135883992da48c15 commit: 860efa3534b097debdd939fd135883992da48c15 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: vsajip date: 2022-10-20T12:54:52+01:00 summary: [3.11] [doc] Improve logging cookbook example. (GH-98481) (GH-98483) Co-authored-by: Vinay Sajip files: M Doc/howto/logging-cookbook.rst diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst index eac34aaab3aa..ae101e3cdf25 100644 --- a/Doc/howto/logging-cookbook.rst +++ b/Doc/howto/logging-cookbook.rst @@ -3712,6 +3712,71 @@ Of course, the examples above show output according to the format used by :func:`~logging.basicConfig`, but you can use a different formatter when you configure logging. +Note that with the above scheme, you are somewhat at the mercy of buffering and +the sequence of write calls which you are intercepting. For example, with the +definition of ``LoggerWriter`` above, if you have the snippet + +.. code-block:: python + + sys.stderr = LoggerWriter(logger, logging.WARNING) + 1 / 0 + +then running the script results in + +.. code-block:: text + + WARNING:demo:Traceback (most recent call last): + + WARNING:demo: File "/home/runner/cookbook-loggerwriter/test.py", line 53, in + + WARNING:demo: + WARNING:demo:main() + WARNING:demo: File "/home/runner/cookbook-loggerwriter/test.py", line 49, in main + + WARNING:demo: + WARNING:demo:1 / 0 + WARNING:demo:ZeroDivisionError + WARNING:demo:: + WARNING:demo:division by zero + +As you can see, this output isn't ideal. That's because the underlying code +which writes to ``sys.stderr`` makes mutiple writes, each of which results in a +separate logged line (for example, the last three lines above). To get around +this problem, you need to buffer things and only output log lines when newlines +are seen. Let's use a slghtly better implementation of ``LoggerWriter``: + +.. code-block:: python + + class BufferingLoggerWriter(LoggerWriter): + def __init__(self, logger, level): + super().__init__(logger, level) + self.buffer = '' + + def write(self, message): + if '\n' not in message: + self.buffer += message + else: + parts = message.split('\n') + if self.buffer: + s = self.buffer + parts.pop(0) + self.logger.log(self.level, s) + self.buffer = parts.pop() + for part in parts: + self.logger.log(self.level, part) + +This just buffers up stuff until a newline is seen, and then logs complete +lines. With this approach, you get better output: + +.. code-block:: text + + WARNING:demo:Traceback (most recent call last): + WARNING:demo: File "/home/runner/cookbook-loggerwriter/main.py", line 55, in + WARNING:demo: main() + WARNING:demo: File "/home/runner/cookbook-loggerwriter/main.py", line 52, in main + WARNING:demo: 1/0 + WARNING:demo:ZeroDivisionError: division by zero + + .. patterns-to-avoid: Patterns to avoid From webhook-mailer at python.org Thu Oct 20 09:08:12 2022 From: webhook-mailer at python.org (ezio-melotti) Date: Thu, 20 Oct 2022 13:08:12 -0000 Subject: [Python-checkins] [3.11] Docs: Bump sphinx-lint and use double backticks for inline literals (GH-98441) (#98445) Message-ID: https://github.com/python/cpython/commit/095e06f4ca8715e117182b34cd668d77de9857e4 commit: 095e06f4ca8715e117182b34cd668d77de9857e4 branch: 3.11 author: Hugo van Kemenade committer: ezio-melotti date: 2022-10-20T06:07:33-07:00 summary: [3.11] Docs: Bump sphinx-lint and use double backticks for inline literals (GH-98441) (#98445) Bump sphinx-lint and use double backticks for inline literals files: M Doc/c-api/init.rst M Doc/library/asyncio-api-index.rst M Doc/library/pathlib.rst M Doc/library/subprocess.rst M Doc/requirements.txt diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index 511d24da4fb7..55c05096ae91 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -1800,7 +1800,7 @@ is not possible due to its implementation being opaque at build time. .. note:: A freed key becomes a dangling pointer. You should reset the key to - `NULL`. + ``NULL``. Methods diff --git a/Doc/library/asyncio-api-index.rst b/Doc/library/asyncio-api-index.rst index 54c1cd6582e4..ad475150fe7d 100644 --- a/Doc/library/asyncio-api-index.rst +++ b/Doc/library/asyncio-api-index.rst @@ -57,7 +57,7 @@ await on multiple things with timeouts. - Monitor for completion. * - :func:`timeout` - - Run with a timeout. Useful in cases when `wait_for` is not suitable. + - Run with a timeout. Useful in cases when ``wait_for`` is not suitable. * - :func:`to_thread` - Asynchronously run a function in a separate OS thread. diff --git a/Doc/library/pathlib.rst b/Doc/library/pathlib.rst index 5012150b86ce..843513c5fc54 100644 --- a/Doc/library/pathlib.rst +++ b/Doc/library/pathlib.rst @@ -391,7 +391,7 @@ Pure paths provide the following methods and properties: If you want to walk an arbitrary filesystem path upwards, it is recommended to first call :meth:`Path.resolve` so as to resolve - symlinks and eliminate `".."` components. + symlinks and eliminate ``".."`` components. .. data:: PurePath.name diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst index dee5bd879db5..51b9e38b7b6c 100644 --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -829,7 +829,7 @@ Instances of the :class:`Popen` class have the following methods: On Windows, SIGTERM is an alias for :meth:`terminate`. CTRL_C_EVENT and CTRL_BREAK_EVENT can be sent to processes started with a *creationflags* - parameter which includes `CREATE_NEW_PROCESS_GROUP`. + parameter which includes ``CREATE_NEW_PROCESS_GROUP``. .. method:: Popen.terminate() diff --git a/Doc/requirements.txt b/Doc/requirements.txt index 7f82dc32113a..958665db69e2 100644 --- a/Doc/requirements.txt +++ b/Doc/requirements.txt @@ -7,10 +7,7 @@ sphinx==4.5.0 blurb -# sphinx-lint 0.6.2 yields many default role errors due to the new regular -# expression used for default role detection, so we don't use the version -# until the errors are fixed. -sphinx-lint==0.6.4 +sphinx-lint==0.6.7 # The theme used by the documentation is stored separately, so we need # to install that as well. From webhook-mailer at python.org Thu Oct 20 09:45:41 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Thu, 20 Oct 2022 13:45:41 -0000 Subject: [Python-checkins] CODEOWNERS: Become a typing code owner (#98480) Message-ID: https://github.com/python/cpython/commit/cb93b4aee5eb12dc6c4b2dccc81a2e5ace3ea4de commit: cb93b4aee5eb12dc6c4b2dccc81a2e5ace3ea4de branch: main author: Alex Waygood committer: JelleZijlstra date: 2022-10-20T06:45:34-07:00 summary: CODEOWNERS: Become a typing code owner (#98480) files: M .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 2fd933a22f3c..74081b2ef2e8 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -135,7 +135,7 @@ Lib/ast.py @isidentical **/*idlelib* @terryjreedy -**/*typing* @gvanrossum @Fidget-Spinner @JelleZijlstra +**/*typing* @gvanrossum @Fidget-Spinner @JelleZijlstra @AlexWaygood **/*asyncore @giampaolo **/*asynchat @giampaolo From webhook-mailer at python.org Thu Oct 20 09:53:46 2022 From: webhook-mailer at python.org (zooba) Date: Thu, 20 Oct 2022 13:53:46 -0000 Subject: [Python-checkins] gh-98360: multiprocessing now spawns children on Windows with correct argv[0] in virtual environments (GH-98462) Message-ID: https://github.com/python/cpython/commit/e48f9b2b7e73f4a89a9b9c287f3b93dc13a60460 commit: e48f9b2b7e73f4a89a9b9c287f3b93dc13a60460 branch: main author: Steve Dower committer: zooba date: 2022-10-20T14:53:38+01:00 summary: gh-98360: multiprocessing now spawns children on Windows with correct argv[0] in virtual environments (GH-98462) files: A Lib/test/_test_venv_multiprocessing.py A Misc/NEWS.d/next/Windows/2022-10-19-20-00-28.gh-issue-98360.O2m6YG.rst M Lib/multiprocessing/popen_spawn_win32.py M Lib/test/test_venv.py diff --git a/Lib/multiprocessing/popen_spawn_win32.py b/Lib/multiprocessing/popen_spawn_win32.py index 9c4098d0fa4f..4d60ffc030be 100644 --- a/Lib/multiprocessing/popen_spawn_win32.py +++ b/Lib/multiprocessing/popen_spawn_win32.py @@ -54,19 +54,20 @@ def __init__(self, process_obj): wfd = msvcrt.open_osfhandle(whandle, 0) cmd = spawn.get_command_line(parent_pid=os.getpid(), pipe_handle=rhandle) - cmd = ' '.join('"%s"' % x for x in cmd) python_exe = spawn.get_executable() # bpo-35797: When running in a venv, we bypass the redirect # executor and launch our base Python. if WINENV and _path_eq(python_exe, sys.executable): - python_exe = sys._base_executable + cmd[0] = python_exe = sys._base_executable env = os.environ.copy() env["__PYVENV_LAUNCHER__"] = sys.executable else: env = None + cmd = ' '.join('"%s"' % x for x in cmd) + with open(wfd, 'wb', closefd=True) as to_child: # start process try: diff --git a/Lib/test/_test_venv_multiprocessing.py b/Lib/test/_test_venv_multiprocessing.py new file mode 100644 index 000000000000..af72e915ba52 --- /dev/null +++ b/Lib/test/_test_venv_multiprocessing.py @@ -0,0 +1,40 @@ +import multiprocessing +import random +import sys +import time + +def fill_queue(queue, code): + queue.put(code) + + +def drain_queue(queue, code): + if code != queue.get(): + sys.exit(1) + + +def test_func(): + code = random.randrange(0, 1000) + queue = multiprocessing.Queue() + fill_pool = multiprocessing.Process( + target=fill_queue, + args=(queue, code) + ) + drain_pool = multiprocessing.Process( + target=drain_queue, + args=(queue, code) + ) + drain_pool.start() + fill_pool.start() + fill_pool.join() + drain_pool.join() + + +def main(): + test_pool = multiprocessing.Process(target=test_func) + test_pool.start() + test_pool.join() + sys.exit(test_pool.exitcode) + + +if __name__ == "__main__": + main() diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py index b355b0050cd5..5ce86cffd248 100644 --- a/Lib/test/test_venv.py +++ b/Lib/test/test_venv.py @@ -20,7 +20,7 @@ from test.support import (captured_stdout, captured_stderr, skip_if_broken_multiprocessing_synchronize, verbose, requires_subprocess, is_emscripten, is_wasi, - requires_venv_with_pip) + requires_venv_with_pip, TEST_HOME_DIR) from test.support.os_helper import (can_symlink, EnvironmentVarGuard, rmtree) import unittest import venv @@ -482,6 +482,20 @@ def test_multiprocessing(self): 'pool.terminate()']) self.assertEqual(out.strip(), "python".encode()) + @requireVenvCreate + def test_multiprocessing_recursion(self): + """ + Test that the multiprocessing is able to spawn itself + """ + skip_if_broken_multiprocessing_synchronize() + + rmtree(self.env_dir) + self.run_with_capture(venv.create, self.env_dir) + envpy = os.path.join(os.path.realpath(self.env_dir), + self.bindir, self.exe) + script = os.path.join(TEST_HOME_DIR, '_test_venv_multiprocessing.py') + subprocess.check_call([envpy, script]) + @unittest.skipIf(os.name == 'nt', 'not relevant on Windows') def test_deactivate_with_strict_bash_opts(self): bash = shutil.which("bash") diff --git a/Misc/NEWS.d/next/Windows/2022-10-19-20-00-28.gh-issue-98360.O2m6YG.rst b/Misc/NEWS.d/next/Windows/2022-10-19-20-00-28.gh-issue-98360.O2m6YG.rst new file mode 100644 index 000000000000..61c1e5e837fe --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2022-10-19-20-00-28.gh-issue-98360.O2m6YG.rst @@ -0,0 +1,4 @@ +Fixes :mod:`multiprocessing` spawning child processes on Windows from a +virtual environment to ensure that child processes that also use +:mod:`multiprocessing` to spawn more children will recognize that they are +in a virtual environment. From webhook-mailer at python.org Thu Oct 20 09:59:17 2022 From: webhook-mailer at python.org (encukou) Date: Thu, 20 Oct 2022 13:59:17 -0000 Subject: [Python-checkins] gh-98421: Clean Up PyObject_Print (GH-98422) Message-ID: https://github.com/python/cpython/commit/c60b3b3cca9cab5f5dab7217660c45ebfdb1d7b8 commit: c60b3b3cca9cab5f5dab7217660c45ebfdb1d7b8 branch: main author: MonadChains committer: encukou date: 2022-10-20T15:59:10+02:00 summary: gh-98421: Clean Up PyObject_Print (GH-98422) Work on test coverage for `PyObject_Print` made it clear that some lines can't get executed. Simplify the function by excluding the checks for non-string types. Also eliminate creating a temporary bytes object. files: M Objects/object.c diff --git a/Objects/object.c b/Objects/object.c index 26cdcef59ddd..837f0a1a578c 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -282,31 +282,22 @@ PyObject_Print(PyObject *op, FILE *fp, int flags) s = PyObject_Str(op); else s = PyObject_Repr(op); - if (s == NULL) + if (s == NULL) { ret = -1; - else if (PyBytes_Check(s)) { - fwrite(PyBytes_AS_STRING(s), 1, - PyBytes_GET_SIZE(s), fp); } - else if (PyUnicode_Check(s)) { - PyObject *t; - t = PyUnicode_AsEncodedString(s, "utf-8", "backslashreplace"); + else { + assert(PyUnicode_Check(s)); + const char *t; + Py_ssize_t len; + t = PyUnicode_AsUTF8AndSize(s, &len); if (t == NULL) { ret = -1; } else { - fwrite(PyBytes_AS_STRING(t), 1, - PyBytes_GET_SIZE(t), fp); - Py_DECREF(t); + fwrite(t, 1, len, fp); } + Py_DECREF(s); } - else { - PyErr_Format(PyExc_TypeError, - "str() or repr() returned '%.100s'", - Py_TYPE(s)->tp_name); - ret = -1; - } - Py_XDECREF(s); } } if (ret == 0) { From webhook-mailer at python.org Thu Oct 20 10:18:31 2022 From: webhook-mailer at python.org (miss-islington) Date: Thu, 20 Oct 2022 14:18:31 -0000 Subject: [Python-checkins] CODEOWNERS: Become a typing code owner (GH-98480) Message-ID: https://github.com/python/cpython/commit/ba6492e2a705ebbe140fdf8734114156e55b3c9a commit: ba6492e2a705ebbe140fdf8734114156e55b3c9a branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-20T07:18:09-07:00 summary: CODEOWNERS: Become a typing code owner (GH-98480) (cherry picked from commit cb93b4aee5eb12dc6c4b2dccc81a2e5ace3ea4de) Co-authored-by: Alex Waygood files: M .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 3c4e8697f807..6b53266f1227 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -131,7 +131,7 @@ Lib/ast.py @isidentical **/*idlelib* @terryjreedy -**/*typing* @gvanrossum @Fidget-Spinner @JelleZijlstra +**/*typing* @gvanrossum @Fidget-Spinner @JelleZijlstra @AlexWaygood **/*asyncore @giampaolo **/*asynchat @giampaolo From webhook-mailer at python.org Thu Oct 20 10:19:42 2022 From: webhook-mailer at python.org (miss-islington) Date: Thu, 20 Oct 2022 14:19:42 -0000 Subject: [Python-checkins] CODEOWNERS: Become a typing code owner (GH-98480) Message-ID: https://github.com/python/cpython/commit/49d79938837ce6f59035073c3978a60e22199613 commit: 49d79938837ce6f59035073c3978a60e22199613 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-20T07:19:35-07:00 summary: CODEOWNERS: Become a typing code owner (GH-98480) (cherry picked from commit cb93b4aee5eb12dc6c4b2dccc81a2e5ace3ea4de) Co-authored-by: Alex Waygood files: M .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 227fd2bc7702..3d39e0c4ef04 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -133,7 +133,7 @@ Lib/ast.py @isidentical **/*idlelib* @terryjreedy -**/*typing* @gvanrossum @Fidget-Spinner @JelleZijlstra +**/*typing* @gvanrossum @Fidget-Spinner @JelleZijlstra @AlexWaygood **/*asyncore @giampaolo **/*asynchat @giampaolo From webhook-mailer at python.org Thu Oct 20 10:33:24 2022 From: webhook-mailer at python.org (miss-islington) Date: Thu, 20 Oct 2022 14:33:24 -0000 Subject: [Python-checkins] gh-98360: multiprocessing now spawns children on Windows with correct argv[0] in virtual environments (GH-98462) Message-ID: https://github.com/python/cpython/commit/ace6611de602906414d612b5649c13b9d8115a1e commit: ace6611de602906414d612b5649c13b9d8115a1e branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-20T07:33:12-07:00 summary: gh-98360: multiprocessing now spawns children on Windows with correct argv[0] in virtual environments (GH-98462) (cherry picked from commit e48f9b2b7e73f4a89a9b9c287f3b93dc13a60460) Co-authored-by: Steve Dower files: A Lib/test/_test_venv_multiprocessing.py A Misc/NEWS.d/next/Windows/2022-10-19-20-00-28.gh-issue-98360.O2m6YG.rst M Lib/multiprocessing/popen_spawn_win32.py M Lib/test/test_venv.py diff --git a/Lib/multiprocessing/popen_spawn_win32.py b/Lib/multiprocessing/popen_spawn_win32.py index 9c4098d0fa4f..4d60ffc030be 100644 --- a/Lib/multiprocessing/popen_spawn_win32.py +++ b/Lib/multiprocessing/popen_spawn_win32.py @@ -54,19 +54,20 @@ def __init__(self, process_obj): wfd = msvcrt.open_osfhandle(whandle, 0) cmd = spawn.get_command_line(parent_pid=os.getpid(), pipe_handle=rhandle) - cmd = ' '.join('"%s"' % x for x in cmd) python_exe = spawn.get_executable() # bpo-35797: When running in a venv, we bypass the redirect # executor and launch our base Python. if WINENV and _path_eq(python_exe, sys.executable): - python_exe = sys._base_executable + cmd[0] = python_exe = sys._base_executable env = os.environ.copy() env["__PYVENV_LAUNCHER__"] = sys.executable else: env = None + cmd = ' '.join('"%s"' % x for x in cmd) + with open(wfd, 'wb', closefd=True) as to_child: # start process try: diff --git a/Lib/test/_test_venv_multiprocessing.py b/Lib/test/_test_venv_multiprocessing.py new file mode 100644 index 000000000000..af72e915ba52 --- /dev/null +++ b/Lib/test/_test_venv_multiprocessing.py @@ -0,0 +1,40 @@ +import multiprocessing +import random +import sys +import time + +def fill_queue(queue, code): + queue.put(code) + + +def drain_queue(queue, code): + if code != queue.get(): + sys.exit(1) + + +def test_func(): + code = random.randrange(0, 1000) + queue = multiprocessing.Queue() + fill_pool = multiprocessing.Process( + target=fill_queue, + args=(queue, code) + ) + drain_pool = multiprocessing.Process( + target=drain_queue, + args=(queue, code) + ) + drain_pool.start() + fill_pool.start() + fill_pool.join() + drain_pool.join() + + +def main(): + test_pool = multiprocessing.Process(target=test_func) + test_pool.start() + test_pool.join() + sys.exit(test_pool.exitcode) + + +if __name__ == "__main__": + main() diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py index b0a86ee4abc5..c88df1795fda 100644 --- a/Lib/test/test_venv.py +++ b/Lib/test/test_venv.py @@ -20,7 +20,7 @@ from test.support import (captured_stdout, captured_stderr, requires_zlib, skip_if_broken_multiprocessing_synchronize, verbose, requires_subprocess, is_emscripten, is_wasi, - requires_venv_with_pip) + requires_venv_with_pip, TEST_HOME_DIR) from test.support.os_helper import (can_symlink, EnvironmentVarGuard, rmtree) import unittest import venv @@ -482,6 +482,20 @@ def test_multiprocessing(self): 'pool.terminate()']) self.assertEqual(out.strip(), "python".encode()) + @requireVenvCreate + def test_multiprocessing_recursion(self): + """ + Test that the multiprocessing is able to spawn itself + """ + skip_if_broken_multiprocessing_synchronize() + + rmtree(self.env_dir) + self.run_with_capture(venv.create, self.env_dir) + envpy = os.path.join(os.path.realpath(self.env_dir), + self.bindir, self.exe) + script = os.path.join(TEST_HOME_DIR, '_test_venv_multiprocessing.py') + subprocess.check_call([envpy, script]) + @unittest.skipIf(os.name == 'nt', 'not relevant on Windows') def test_deactivate_with_strict_bash_opts(self): bash = shutil.which("bash") diff --git a/Misc/NEWS.d/next/Windows/2022-10-19-20-00-28.gh-issue-98360.O2m6YG.rst b/Misc/NEWS.d/next/Windows/2022-10-19-20-00-28.gh-issue-98360.O2m6YG.rst new file mode 100644 index 000000000000..61c1e5e837fe --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2022-10-19-20-00-28.gh-issue-98360.O2m6YG.rst @@ -0,0 +1,4 @@ +Fixes :mod:`multiprocessing` spawning child processes on Windows from a +virtual environment to ensure that child processes that also use +:mod:`multiprocessing` to spawn more children will recognize that they are +in a virtual environment. From webhook-mailer at python.org Thu Oct 20 11:58:44 2022 From: webhook-mailer at python.org (iritkatriel) Date: Thu, 20 Oct 2022 15:58:44 -0000 Subject: [Python-checkins] gh-98461: Fix source location in comprehensions bytecode (GH-98464) Message-ID: https://github.com/python/cpython/commit/4ec9ed8fde8e285a3eea97c199f7bbf7c95c8881 commit: 4ec9ed8fde8e285a3eea97c199f7bbf7c95c8881 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2022-10-20T16:58:37+01:00 summary: gh-98461: Fix source location in comprehensions bytecode (GH-98464) files: A Misc/NEWS.d/next/Core and Builtins/2022-10-19-20-53-38.gh-issue-98461.iNmPDV.rst M Lib/test/test_compile.py M Python/compile.c diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index 85f05a8dd257..a59d692876b6 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -1249,6 +1249,165 @@ def test_multiline_assert(self): self.assertOpcodeSourcePositionIs(compiled_code, 'RAISE_VARARGS', line=1, end_line=3, column=0, end_column=30, occurrence=1) + def test_multiline_generator_expression(self): + snippet = """\ +((x, + 2*x) + for x + in [1,2,3] if (x > 0 + and x < 100 + and x != 50)) +""" + compiled_code, _ = self.check_positions_against_ast(snippet) + compiled_code = compiled_code.co_consts[0] + self.assertIsInstance(compiled_code, types.CodeType) + self.assertOpcodeSourcePositionIs(compiled_code, 'YIELD_VALUE', + line=1, end_line=2, column=1, end_column=8, occurrence=1) + self.assertOpcodeSourcePositionIs(compiled_code, 'JUMP_BACKWARD', + line=1, end_line=2, column=1, end_column=8, occurrence=1) + self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_VALUE', + line=1, end_line=6, column=0, end_column=32, occurrence=1) + + def test_multiline_async_generator_expression(self): + snippet = """\ +((x, + 2*x) + async for x + in [1,2,3] if (x > 0 + and x < 100 + and x != 50)) +""" + compiled_code, _ = self.check_positions_against_ast(snippet) + compiled_code = compiled_code.co_consts[0] + self.assertIsInstance(compiled_code, types.CodeType) + self.assertOpcodeSourcePositionIs(compiled_code, 'YIELD_VALUE', + line=1, end_line=2, column=1, end_column=8, occurrence=2) + self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_VALUE', + line=6, end_line=6, column=23, end_column=30, occurrence=1) + + def test_multiline_list_comprehension(self): + snippet = """\ +[(x, + 2*x) + for x + in [1,2,3] if (x > 0 + and x < 100 + and x != 50)] +""" + compiled_code, _ = self.check_positions_against_ast(snippet) + compiled_code = compiled_code.co_consts[0] + self.assertIsInstance(compiled_code, types.CodeType) + self.assertOpcodeSourcePositionIs(compiled_code, 'LIST_APPEND', + line=1, end_line=2, column=1, end_column=8, occurrence=1) + self.assertOpcodeSourcePositionIs(compiled_code, 'JUMP_BACKWARD', + line=1, end_line=2, column=1, end_column=8, occurrence=1) + self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_VALUE', + line=1, end_line=6, column=0, end_column=32, occurrence=1) + + def test_multiline_async_list_comprehension(self): + snippet = """\ +async def f(): + [(x, + 2*x) + async for x + in [1,2,3] if (x > 0 + and x < 100 + and x != 50)] +""" + compiled_code, _ = self.check_positions_against_ast(snippet) + g = {} + eval(compiled_code, g) + compiled_code = g['f'].__code__.co_consts[1] + self.assertIsInstance(compiled_code, types.CodeType) + self.assertOpcodeSourcePositionIs(compiled_code, 'LIST_APPEND', + line=2, end_line=3, column=5, end_column=12, occurrence=1) + self.assertOpcodeSourcePositionIs(compiled_code, 'JUMP_BACKWARD', + line=2, end_line=3, column=5, end_column=12, occurrence=1) + self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_VALUE', + line=2, end_line=7, column=4, end_column=36, occurrence=1) + + def test_multiline_set_comprehension(self): + snippet = """\ +{(x, + 2*x) + for x + in [1,2,3] if (x > 0 + and x < 100 + and x != 50)} +""" + compiled_code, _ = self.check_positions_against_ast(snippet) + compiled_code = compiled_code.co_consts[0] + self.assertIsInstance(compiled_code, types.CodeType) + self.assertOpcodeSourcePositionIs(compiled_code, 'SET_ADD', + line=1, end_line=2, column=1, end_column=8, occurrence=1) + self.assertOpcodeSourcePositionIs(compiled_code, 'JUMP_BACKWARD', + line=1, end_line=2, column=1, end_column=8, occurrence=1) + self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_VALUE', + line=1, end_line=6, column=0, end_column=32, occurrence=1) + + def test_multiline_async_set_comprehension(self): + snippet = """\ +async def f(): + {(x, + 2*x) + async for x + in [1,2,3] if (x > 0 + and x < 100 + and x != 50)} +""" + compiled_code, _ = self.check_positions_against_ast(snippet) + g = {} + eval(compiled_code, g) + compiled_code = g['f'].__code__.co_consts[1] + self.assertIsInstance(compiled_code, types.CodeType) + self.assertOpcodeSourcePositionIs(compiled_code, 'SET_ADD', + line=2, end_line=3, column=5, end_column=12, occurrence=1) + self.assertOpcodeSourcePositionIs(compiled_code, 'JUMP_BACKWARD', + line=2, end_line=3, column=5, end_column=12, occurrence=1) + self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_VALUE', + line=2, end_line=7, column=4, end_column=36, occurrence=1) + + def test_multiline_dict_comprehension(self): + snippet = """\ +{x: + 2*x + for x + in [1,2,3] if (x > 0 + and x < 100 + and x != 50)} +""" + compiled_code, _ = self.check_positions_against_ast(snippet) + compiled_code = compiled_code.co_consts[0] + self.assertIsInstance(compiled_code, types.CodeType) + self.assertOpcodeSourcePositionIs(compiled_code, 'MAP_ADD', + line=1, end_line=2, column=1, end_column=7, occurrence=1) + self.assertOpcodeSourcePositionIs(compiled_code, 'JUMP_BACKWARD', + line=1, end_line=2, column=1, end_column=7, occurrence=1) + self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_VALUE', + line=1, end_line=6, column=0, end_column=32, occurrence=1) + + def test_multiline_async_dict_comprehension(self): + snippet = """\ +async def f(): + {x: + 2*x + async for x + in [1,2,3] if (x > 0 + and x < 100 + and x != 50)} +""" + compiled_code, _ = self.check_positions_against_ast(snippet) + g = {} + eval(compiled_code, g) + compiled_code = g['f'].__code__.co_consts[1] + self.assertIsInstance(compiled_code, types.CodeType) + self.assertOpcodeSourcePositionIs(compiled_code, 'MAP_ADD', + line=2, end_line=3, column=5, end_column=11, occurrence=1) + self.assertOpcodeSourcePositionIs(compiled_code, 'JUMP_BACKWARD', + line=2, end_line=3, column=5, end_column=11, occurrence=1) + self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_VALUE', + line=2, end_line=7, column=4, end_column=36, occurrence=1) + def test_very_long_line_end_offset(self): # Make sure we get the correct column offset for offsets # too large to store in a byte. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-19-20-53-38.gh-issue-98461.iNmPDV.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-19-20-53-38.gh-issue-98461.iNmPDV.rst new file mode 100644 index 000000000000..6289f208609e --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-19-20-53-38.gh-issue-98461.iNmPDV.rst @@ -0,0 +1 @@ +Fix source location in bytecode for list, set and dict comprehensions as well as generator expressions. diff --git a/Python/compile.c b/Python/compile.c index c888f4064c79..70f38d4d0cda 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -482,13 +482,13 @@ static int compiler_try_star_except(struct compiler *, stmt_ty); static int compiler_set_qualname(struct compiler *); static int compiler_sync_comprehension_generator( - struct compiler *c, location *ploc, + struct compiler *c, location loc, asdl_comprehension_seq *generators, int gen_index, int depth, expr_ty elt, expr_ty val, int type); static int compiler_async_comprehension_generator( - struct compiler *c, location *ploc, + struct compiler *c, location loc, asdl_comprehension_seq *generators, int gen_index, int depth, expr_ty elt, expr_ty val, int type); @@ -5190,7 +5190,7 @@ compiler_call_helper(struct compiler *c, location loc, static int -compiler_comprehension_generator(struct compiler *c, location *ploc, +compiler_comprehension_generator(struct compiler *c, location loc, asdl_comprehension_seq *generators, int gen_index, int depth, expr_ty elt, expr_ty val, int type) @@ -5199,35 +5199,33 @@ compiler_comprehension_generator(struct compiler *c, location *ploc, gen = (comprehension_ty)asdl_seq_GET(generators, gen_index); if (gen->is_async) { return compiler_async_comprehension_generator( - c, ploc, generators, gen_index, depth, elt, val, type); + c, loc, generators, gen_index, depth, elt, val, type); } else { return compiler_sync_comprehension_generator( - c, ploc, generators, gen_index, depth, elt, val, type); + c, loc, generators, gen_index, depth, elt, val, type); } } static int -compiler_sync_comprehension_generator(struct compiler *c, location *ploc, - asdl_comprehension_seq *generators, int gen_index, - int depth, +compiler_sync_comprehension_generator(struct compiler *c, location loc, + asdl_comprehension_seq *generators, + int gen_index, int depth, expr_ty elt, expr_ty val, int type) { /* generate code for the iterator, then each of the ifs, and then write to the element */ - comprehension_ty gen; - Py_ssize_t i, n; - NEW_JUMP_TARGET_LABEL(c, start); NEW_JUMP_TARGET_LABEL(c, if_cleanup); NEW_JUMP_TARGET_LABEL(c, anchor); - gen = (comprehension_ty)asdl_seq_GET(generators, gen_index); + comprehension_ty gen = (comprehension_ty)asdl_seq_GET(generators, + gen_index); if (gen_index == 0) { /* Receive outermost iter as an implicit argument */ c->u->u_argcount = 1; - ADDOP_I(c, *ploc, LOAD_FAST, 0); + ADDOP_I(c, loc, LOAD_FAST, 0); } else { /* Sub-iter - calculate on the fly */ @@ -5254,29 +5252,34 @@ compiler_sync_comprehension_generator(struct compiler *c, location *ploc, } if (IS_LABEL(start)) { VISIT(c, expr, gen->iter); - ADDOP(c, *ploc, GET_ITER); + ADDOP(c, loc, GET_ITER); } } if (IS_LABEL(start)) { depth++; USE_LABEL(c, start); - ADDOP_JUMP(c, *ploc, FOR_ITER, anchor); + ADDOP_JUMP(c, loc, FOR_ITER, anchor); } VISIT(c, expr, gen->target); /* XXX this needs to be cleaned up...a lot! */ - n = asdl_seq_LEN(gen->ifs); - for (i = 0; i < n; i++) { + Py_ssize_t n = asdl_seq_LEN(gen->ifs); + for (Py_ssize_t i = 0; i < n; i++) { expr_ty e = (expr_ty)asdl_seq_GET(gen->ifs, i); - if (!compiler_jump_if(c, ploc, e, if_cleanup, 0)) + if (!compiler_jump_if(c, &loc, e, if_cleanup, 0)) { return 0; + } } - if (++gen_index < asdl_seq_LEN(generators)) - if (!compiler_comprehension_generator(c, ploc, + if (++gen_index < asdl_seq_LEN(generators)) { + if (!compiler_comprehension_generator(c, loc, generators, gen_index, depth, - elt, val, type)) - return 0; + elt, val, type)) { + return 0; + } + } + + location elt_loc = LOC(elt); /* only append after the last for generator */ if (gen_index >= asdl_seq_LEN(generators)) { @@ -5284,23 +5287,27 @@ compiler_sync_comprehension_generator(struct compiler *c, location *ploc, switch (type) { case COMP_GENEXP: VISIT(c, expr, elt); - ADDOP_YIELD(c, *ploc); - ADDOP(c, *ploc, POP_TOP); + ADDOP_YIELD(c, elt_loc); + ADDOP(c, elt_loc, POP_TOP); break; case COMP_LISTCOMP: VISIT(c, expr, elt); - ADDOP_I(c, *ploc, LIST_APPEND, depth + 1); + ADDOP_I(c, elt_loc, LIST_APPEND, depth + 1); break; case COMP_SETCOMP: VISIT(c, expr, elt); - ADDOP_I(c, *ploc, SET_ADD, depth + 1); + ADDOP_I(c, elt_loc, SET_ADD, depth + 1); break; case COMP_DICTCOMP: /* With '{k: v}', k is evaluated before v, so we do the same. */ VISIT(c, expr, elt); VISIT(c, expr, val); - ADDOP_I(c, *ploc, MAP_ADD, depth + 1); + elt_loc = LOCATION(elt->lineno, + val->end_lineno, + elt->col_offset, + val->end_col_offset); + ADDOP_I(c, elt_loc, MAP_ADD, depth + 1); break; default: return 0; @@ -5309,7 +5316,7 @@ compiler_sync_comprehension_generator(struct compiler *c, location *ploc, USE_LABEL(c, if_cleanup); if (IS_LABEL(start)) { - ADDOP_JUMP(c, *ploc, JUMP, start); + ADDOP_JUMP(c, elt_loc, JUMP, start); USE_LABEL(c, anchor); } @@ -5318,81 +5325,88 @@ compiler_sync_comprehension_generator(struct compiler *c, location *ploc, } static int -compiler_async_comprehension_generator(struct compiler *c, location *ploc, - asdl_comprehension_seq *generators, int gen_index, - int depth, +compiler_async_comprehension_generator(struct compiler *c, location loc, + asdl_comprehension_seq *generators, + int gen_index, int depth, expr_ty elt, expr_ty val, int type) { - comprehension_ty gen; - Py_ssize_t i, n; NEW_JUMP_TARGET_LABEL(c, start); NEW_JUMP_TARGET_LABEL(c, except); NEW_JUMP_TARGET_LABEL(c, if_cleanup); - gen = (comprehension_ty)asdl_seq_GET(generators, gen_index); + comprehension_ty gen = (comprehension_ty)asdl_seq_GET(generators, + gen_index); if (gen_index == 0) { /* Receive outermost iter as an implicit argument */ c->u->u_argcount = 1; - ADDOP_I(c, *ploc, LOAD_FAST, 0); + ADDOP_I(c, loc, LOAD_FAST, 0); } else { /* Sub-iter - calculate on the fly */ VISIT(c, expr, gen->iter); - ADDOP(c, *ploc, GET_AITER); + ADDOP(c, loc, GET_AITER); } USE_LABEL(c, start); /* Runtime will push a block here, so we need to account for that */ - if (!compiler_push_fblock(c, *ploc, ASYNC_COMPREHENSION_GENERATOR, + if (!compiler_push_fblock(c, loc, ASYNC_COMPREHENSION_GENERATOR, start, NO_LABEL, NULL)) { return 0; } - ADDOP_JUMP(c, *ploc, SETUP_FINALLY, except); - ADDOP(c, *ploc, GET_ANEXT); - ADDOP_LOAD_CONST(c, *ploc, Py_None); - ADD_YIELD_FROM(c, *ploc, 1); - ADDOP(c, *ploc, POP_BLOCK); + ADDOP_JUMP(c, loc, SETUP_FINALLY, except); + ADDOP(c, loc, GET_ANEXT); + ADDOP_LOAD_CONST(c, loc, Py_None); + ADD_YIELD_FROM(c, loc, 1); + ADDOP(c, loc, POP_BLOCK); VISIT(c, expr, gen->target); - n = asdl_seq_LEN(gen->ifs); - for (i = 0; i < n; i++) { + Py_ssize_t n = asdl_seq_LEN(gen->ifs); + for (Py_ssize_t i = 0; i < n; i++) { expr_ty e = (expr_ty)asdl_seq_GET(gen->ifs, i); - if (!compiler_jump_if(c, ploc, e, if_cleanup, 0)) + if (!compiler_jump_if(c, &loc, e, if_cleanup, 0)) { return 0; + } } depth++; - if (++gen_index < asdl_seq_LEN(generators)) - if (!compiler_comprehension_generator(c, ploc, + if (++gen_index < asdl_seq_LEN(generators)) { + if (!compiler_comprehension_generator(c, loc, generators, gen_index, depth, - elt, val, type)) - return 0; + elt, val, type)) { + return 0; + } + } + location elt_loc = LOC(elt); /* only append after the last for generator */ if (gen_index >= asdl_seq_LEN(generators)) { /* comprehension specific code */ switch (type) { case COMP_GENEXP: VISIT(c, expr, elt); - ADDOP_YIELD(c, *ploc); - ADDOP(c, *ploc, POP_TOP); + ADDOP_YIELD(c, elt_loc); + ADDOP(c, elt_loc, POP_TOP); break; case COMP_LISTCOMP: VISIT(c, expr, elt); - ADDOP_I(c, *ploc, LIST_APPEND, depth + 1); + ADDOP_I(c, elt_loc, LIST_APPEND, depth + 1); break; case COMP_SETCOMP: VISIT(c, expr, elt); - ADDOP_I(c, *ploc, SET_ADD, depth + 1); + ADDOP_I(c, elt_loc, SET_ADD, depth + 1); break; case COMP_DICTCOMP: /* With '{k: v}', k is evaluated before v, so we do the same. */ VISIT(c, expr, elt); VISIT(c, expr, val); - ADDOP_I(c, *ploc, MAP_ADD, depth + 1); + elt_loc = LOCATION(elt->lineno, + val->end_lineno, + elt->col_offset, + val->end_col_offset); + ADDOP_I(c, elt_loc, MAP_ADD, depth + 1); break; default: return 0; @@ -5400,14 +5414,13 @@ compiler_async_comprehension_generator(struct compiler *c, location *ploc, } USE_LABEL(c, if_cleanup); - ADDOP_JUMP(c, *ploc, JUMP, start); + ADDOP_JUMP(c, elt_loc, JUMP, start); compiler_pop_fblock(c, ASYNC_COMPREHENSION_GENERATOR, start); USE_LABEL(c, except); - //UNSET_LOC(c); - ADDOP(c, *ploc, END_ASYNC_FOR); + ADDOP(c, loc, END_ASYNC_FOR); return 1; } @@ -5466,12 +5479,13 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, ADDOP_I(c, loc, op, 0); } - if (!compiler_comprehension_generator(c, &loc, generators, 0, 0, - elt, val, type)) + if (!compiler_comprehension_generator(c, loc, generators, 0, 0, + elt, val, type)) { goto error_in_scope; + } if (type != COMP_GENEXP) { - ADDOP(c, loc, RETURN_VALUE); + ADDOP(c, LOC(e), RETURN_VALUE); } co = assemble(c, 1); From webhook-mailer at python.org Thu Oct 20 17:01:02 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Thu, 20 Oct 2022 21:01:02 -0000 Subject: [Python-checkins] gh-96035: Make urllib.parse.urlparse reject non-numeric ports (#98273) Message-ID: https://github.com/python/cpython/commit/6f15ca8c7afa23e1adc87f2b66b958b721f9acab commit: 6f15ca8c7afa23e1adc87f2b66b958b721f9acab branch: main author: Ben Kallus <49924171+kenballus at users.noreply.github.com> committer: JelleZijlstra date: 2022-10-20T14:00:56-07:00 summary: gh-96035: Make urllib.parse.urlparse reject non-numeric ports (#98273) Co-authored-by: Jelle Zijlstra files: A Misc/NEWS.d/next/Library/2022-10-14-19-57-37.gh-issue-96035.0xcX-p.rst M Lib/test/test_urlparse.py M Lib/urllib/parse.py diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py index 81d6018bd1a4..59a601d9e85b 100644 --- a/Lib/test/test_urlparse.py +++ b/Lib/test/test_urlparse.py @@ -653,13 +653,16 @@ def test_attributes_bad_port(self): """Check handling of invalid ports.""" for bytes in (False, True): for parse in (urllib.parse.urlsplit, urllib.parse.urlparse): - for port in ("foo", "1.5", "-1", "0x10"): + for port in ("foo", "1.5", "-1", "0x10", "-0", "1_1", " 1", "1 ", "?"): with self.subTest(bytes=bytes, parse=parse, port=port): netloc = "www.example.net:" + port url = "http://" + netloc if bytes: - netloc = netloc.encode("ascii") - url = url.encode("ascii") + if netloc.isascii() and port.isascii(): + netloc = netloc.encode("ascii") + url = url.encode("ascii") + else: + continue p = parse(url) self.assertEqual(p.netloc, netloc) with self.assertRaises(ValueError): @@ -1199,6 +1202,7 @@ def test_splitnport(self): self.assertEqual(splitnport('127.0.0.1', 55), ('127.0.0.1', 55)) self.assertEqual(splitnport('parrot:cheese'), ('parrot', None)) self.assertEqual(splitnport('parrot:cheese', 55), ('parrot', None)) + self.assertEqual(splitnport('parrot: +1_0 '), ('parrot', None)) def test_splitquery(self): # Normal cases are exercised by other tests; ensure that we also diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py index 3734c73948c6..9a3102afd63b 100644 --- a/Lib/urllib/parse.py +++ b/Lib/urllib/parse.py @@ -167,12 +167,11 @@ def hostname(self): def port(self): port = self._hostinfo[1] if port is not None: - try: - port = int(port, 10) - except ValueError: - message = f'Port could not be cast to integer value as {port!r}' - raise ValueError(message) from None - if not ( 0 <= port <= 65535): + if port.isdigit() and port.isascii(): + port = int(port) + else: + raise ValueError(f"Port could not be cast to integer value as {port!r}") + if not (0 <= port <= 65535): raise ValueError("Port out of range 0-65535") return port @@ -1132,15 +1131,15 @@ def splitnport(host, defport=-1): def _splitnport(host, defport=-1): """Split host and port, returning numeric port. Return given default port if no ':' found; defaults to -1. - Return numerical port if a valid number are found after ':'. + Return numerical port if a valid number is found after ':'. Return None if ':' but not a valid number.""" host, delim, port = host.rpartition(':') if not delim: host = port elif port: - try: + if port.isdigit() and port.isascii(): nport = int(port) - except ValueError: + else: nport = None return host, nport return host, defport diff --git a/Misc/NEWS.d/next/Library/2022-10-14-19-57-37.gh-issue-96035.0xcX-p.rst b/Misc/NEWS.d/next/Library/2022-10-14-19-57-37.gh-issue-96035.0xcX-p.rst new file mode 100644 index 000000000000..f04a0fd0915e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-14-19-57-37.gh-issue-96035.0xcX-p.rst @@ -0,0 +1,3 @@ +Fix bug in :func:`urllib.parse.urlparse` that causes certain port numbers +containing whitespace, underscores, plus and minus signs, or non-ASCII digits to be +incorrectly accepted. From webhook-mailer at python.org Thu Oct 20 17:28:42 2022 From: webhook-mailer at python.org (miss-islington) Date: Thu, 20 Oct 2022 21:28:42 -0000 Subject: [Python-checkins] gh-96035: Make urllib.parse.urlparse reject non-numeric ports (GH-98273) Message-ID: https://github.com/python/cpython/commit/1520f4e45bc9d968a98d062ca6880387a0d98c08 commit: 1520f4e45bc9d968a98d062ca6880387a0d98c08 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-20T14:28:36-07:00 summary: gh-96035: Make urllib.parse.urlparse reject non-numeric ports (GH-98273) Co-authored-by: Jelle Zijlstra (cherry picked from commit 6f15ca8c7afa23e1adc87f2b66b958b721f9acab) Co-authored-by: Ben Kallus <49924171+kenballus at users.noreply.github.com> files: A Misc/NEWS.d/next/Library/2022-10-14-19-57-37.gh-issue-96035.0xcX-p.rst M Lib/test/test_urlparse.py M Lib/urllib/parse.py diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py index 2f629c72ae78..4d28646d5fff 100644 --- a/Lib/test/test_urlparse.py +++ b/Lib/test/test_urlparse.py @@ -653,13 +653,16 @@ def test_attributes_bad_port(self): """Check handling of invalid ports.""" for bytes in (False, True): for parse in (urllib.parse.urlsplit, urllib.parse.urlparse): - for port in ("foo", "1.5", "-1", "0x10"): + for port in ("foo", "1.5", "-1", "0x10", "-0", "1_1", " 1", "1 ", "?"): with self.subTest(bytes=bytes, parse=parse, port=port): netloc = "www.example.net:" + port url = "http://" + netloc if bytes: - netloc = netloc.encode("ascii") - url = url.encode("ascii") + if netloc.isascii() and port.isascii(): + netloc = netloc.encode("ascii") + url = url.encode("ascii") + else: + continue p = parse(url) self.assertEqual(p.netloc, netloc) with self.assertRaises(ValueError): @@ -1195,6 +1198,7 @@ def test_splitnport(self): self.assertEqual(splitnport('127.0.0.1', 55), ('127.0.0.1', 55)) self.assertEqual(splitnport('parrot:cheese'), ('parrot', None)) self.assertEqual(splitnport('parrot:cheese', 55), ('parrot', None)) + self.assertEqual(splitnport('parrot: +1_0 '), ('parrot', None)) def test_splitquery(self): # Normal cases are exercised by other tests; ensure that we also diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py index d70a6943f0a7..12fe0112e4fe 100644 --- a/Lib/urllib/parse.py +++ b/Lib/urllib/parse.py @@ -167,12 +167,11 @@ def hostname(self): def port(self): port = self._hostinfo[1] if port is not None: - try: - port = int(port, 10) - except ValueError: - message = f'Port could not be cast to integer value as {port!r}' - raise ValueError(message) from None - if not ( 0 <= port <= 65535): + if port.isdigit() and port.isascii(): + port = int(port) + else: + raise ValueError(f"Port could not be cast to integer value as {port!r}") + if not (0 <= port <= 65535): raise ValueError("Port out of range 0-65535") return port @@ -1125,15 +1124,15 @@ def splitnport(host, defport=-1): def _splitnport(host, defport=-1): """Split host and port, returning numeric port. Return given default port if no ':' found; defaults to -1. - Return numerical port if a valid number are found after ':'. + Return numerical port if a valid number is found after ':'. Return None if ':' but not a valid number.""" host, delim, port = host.rpartition(':') if not delim: host = port elif port: - try: + if port.isdigit() and port.isascii(): nport = int(port) - except ValueError: + else: nport = None return host, nport return host, defport diff --git a/Misc/NEWS.d/next/Library/2022-10-14-19-57-37.gh-issue-96035.0xcX-p.rst b/Misc/NEWS.d/next/Library/2022-10-14-19-57-37.gh-issue-96035.0xcX-p.rst new file mode 100644 index 000000000000..f04a0fd0915e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-14-19-57-37.gh-issue-96035.0xcX-p.rst @@ -0,0 +1,3 @@ +Fix bug in :func:`urllib.parse.urlparse` that causes certain port numbers +containing whitespace, underscores, plus and minus signs, or non-ASCII digits to be +incorrectly accepted. From webhook-mailer at python.org Thu Oct 20 17:29:27 2022 From: webhook-mailer at python.org (miss-islington) Date: Thu, 20 Oct 2022 21:29:27 -0000 Subject: [Python-checkins] gh-96035: Make urllib.parse.urlparse reject non-numeric ports (GH-98273) Message-ID: https://github.com/python/cpython/commit/0db4c5990c7b994e0272b7812e2692d110ab2aec commit: 0db4c5990c7b994e0272b7812e2692d110ab2aec branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-20T14:29:21-07:00 summary: gh-96035: Make urllib.parse.urlparse reject non-numeric ports (GH-98273) Co-authored-by: Jelle Zijlstra (cherry picked from commit 6f15ca8c7afa23e1adc87f2b66b958b721f9acab) Co-authored-by: Ben Kallus <49924171+kenballus at users.noreply.github.com> files: A Misc/NEWS.d/next/Library/2022-10-14-19-57-37.gh-issue-96035.0xcX-p.rst M Lib/test/test_urlparse.py M Lib/urllib/parse.py diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py index 31943f357f49..ca37c3c403e3 100644 --- a/Lib/test/test_urlparse.py +++ b/Lib/test/test_urlparse.py @@ -653,13 +653,16 @@ def test_attributes_bad_port(self): """Check handling of invalid ports.""" for bytes in (False, True): for parse in (urllib.parse.urlsplit, urllib.parse.urlparse): - for port in ("foo", "1.5", "-1", "0x10"): + for port in ("foo", "1.5", "-1", "0x10", "-0", "1_1", " 1", "1 ", "?"): with self.subTest(bytes=bytes, parse=parse, port=port): netloc = "www.example.net:" + port url = "http://" + netloc if bytes: - netloc = netloc.encode("ascii") - url = url.encode("ascii") + if netloc.isascii() and port.isascii(): + netloc = netloc.encode("ascii") + url = url.encode("ascii") + else: + continue p = parse(url) self.assertEqual(p.netloc, netloc) with self.assertRaises(ValueError): @@ -1186,6 +1189,7 @@ def test_splitnport(self): self.assertEqual(splitnport('127.0.0.1', 55), ('127.0.0.1', 55)) self.assertEqual(splitnport('parrot:cheese'), ('parrot', None)) self.assertEqual(splitnport('parrot:cheese', 55), ('parrot', None)) + self.assertEqual(splitnport('parrot: +1_0 '), ('parrot', None)) def test_splitquery(self): # Normal cases are exercised by other tests; ensure that we also diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py index b35997bc00ce..26ddf307485d 100644 --- a/Lib/urllib/parse.py +++ b/Lib/urllib/parse.py @@ -171,12 +171,11 @@ def hostname(self): def port(self): port = self._hostinfo[1] if port is not None: - try: - port = int(port, 10) - except ValueError: - message = f'Port could not be cast to integer value as {port!r}' - raise ValueError(message) from None - if not ( 0 <= port <= 65535): + if port.isdigit() and port.isascii(): + port = int(port) + else: + raise ValueError(f"Port could not be cast to integer value as {port!r}") + if not (0 <= port <= 65535): raise ValueError("Port out of range 0-65535") return port @@ -1125,15 +1124,15 @@ def splitnport(host, defport=-1): def _splitnport(host, defport=-1): """Split host and port, returning numeric port. Return given default port if no ':' found; defaults to -1. - Return numerical port if a valid number are found after ':'. + Return numerical port if a valid number is found after ':'. Return None if ':' but not a valid number.""" host, delim, port = host.rpartition(':') if not delim: host = port elif port: - try: + if port.isdigit() and port.isascii(): nport = int(port) - except ValueError: + else: nport = None return host, nport return host, defport diff --git a/Misc/NEWS.d/next/Library/2022-10-14-19-57-37.gh-issue-96035.0xcX-p.rst b/Misc/NEWS.d/next/Library/2022-10-14-19-57-37.gh-issue-96035.0xcX-p.rst new file mode 100644 index 000000000000..f04a0fd0915e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-14-19-57-37.gh-issue-96035.0xcX-p.rst @@ -0,0 +1,3 @@ +Fix bug in :func:`urllib.parse.urlparse` that causes certain port numbers +containing whitespace, underscores, plus and minus signs, or non-ASCII digits to be +incorrectly accepted. From webhook-mailer at python.org Thu Oct 20 18:27:59 2022 From: webhook-mailer at python.org (sweeneyde) Date: Thu, 20 Oct 2022 22:27:59 -0000 Subject: [Python-checkins] gh-97912: Avoid quadratic behavior when adding LOAD_FAST_CHECK (GH-97952) Message-ID: https://github.com/python/cpython/commit/39bc70e267929600057d62103739b7160e69dc8b commit: 39bc70e267929600057d62103739b7160e69dc8b branch: main author: Dennis Sweeney <36520290+sweeneyde at users.noreply.github.com> committer: sweeneyde <36520290+sweeneyde at users.noreply.github.com> date: 2022-10-20T18:27:41-04:00 summary: gh-97912: Avoid quadratic behavior when adding LOAD_FAST_CHECK (GH-97952) * The compiler analyzes the usage of the first 64 local variables all at once using bit masks. * Local variables beyond the first 64 are only partially analyzed, achieving linear time. files: A Misc/NEWS.d/next/Core and Builtins/2022-10-06-06-36-29.gh-issue-97912.jGRJpa.rst M Lib/test/test_peepholer.py M Python/compile.c diff --git a/Lib/test/test_peepholer.py b/Lib/test/test_peepholer.py index ab45e3c52a03..7363452f5e13 100644 --- a/Lib/test/test_peepholer.py +++ b/Lib/test/test_peepholer.py @@ -776,6 +776,45 @@ def f(): self.assertInBytecode(f, 'LOAD_FAST_CHECK') self.assertNotInBytecode(f, 'LOAD_FAST') + def test_load_fast_too_many_locals(self): + # When there get to be too many locals to analyze completely, + # later locals are all converted to LOAD_FAST_CHECK, except + # when a store or prior load occurred in the same basicblock. + def f(): + a00 = a01 = a02 = a03 = a04 = a05 = a06 = a07 = a08 = a09 = 1 + a10 = a11 = a12 = a13 = a14 = a15 = a16 = a17 = a18 = a19 = 1 + a20 = a21 = a22 = a23 = a24 = a25 = a26 = a27 = a28 = a29 = 1 + a30 = a31 = a32 = a33 = a34 = a35 = a36 = a37 = a38 = a39 = 1 + a40 = a41 = a42 = a43 = a44 = a45 = a46 = a47 = a48 = a49 = 1 + a50 = a51 = a52 = a53 = a54 = a55 = a56 = a57 = a58 = a59 = 1 + a60 = a61 = a62 = a63 = a64 = a65 = a66 = a67 = a68 = a69 = 1 + a70 = a71 = a72 = a73 = a74 = a75 = a76 = a77 = a78 = a79 = 1 + del a72, a73 + print(a73) + print(a70, a71, a72, a73) + while True: + print(a00, a01, a62, a63) + print(a64, a65, a78, a79) + + for i in 0, 1, 62, 63: + # First 64 locals: analyze completely + self.assertInBytecode(f, 'LOAD_FAST', f"a{i:02}") + self.assertNotInBytecode(f, 'LOAD_FAST_CHECK', f"a{i:02}") + for i in 64, 65, 78, 79: + # Locals >=64 not in the same basicblock + self.assertInBytecode(f, 'LOAD_FAST_CHECK', f"a{i:02}") + self.assertNotInBytecode(f, 'LOAD_FAST', f"a{i:02}") + for i in 70, 71: + # Locals >=64 in the same basicblock + self.assertInBytecode(f, 'LOAD_FAST', f"a{i:02}") + self.assertNotInBytecode(f, 'LOAD_FAST_CHECK', f"a{i:02}") + # del statements should invalidate within basicblocks. + self.assertInBytecode(f, 'LOAD_FAST_CHECK', "a72") + self.assertNotInBytecode(f, 'LOAD_FAST', "a72") + # previous checked loads within a basicblock enable unchecked loads + self.assertInBytecode(f, 'LOAD_FAST_CHECK', "a73") + self.assertInBytecode(f, 'LOAD_FAST', "a73") + def test_setting_lineno_adds_check(self): code = textwrap.dedent("""\ def f(): diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-06-06-36-29.gh-issue-97912.jGRJpa.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-06-06-36-29.gh-issue-97912.jGRJpa.rst new file mode 100644 index 000000000000..bd3d221252b2 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-06-06-36-29.gh-issue-97912.jGRJpa.rst @@ -0,0 +1 @@ +The compiler now avoids quadratic behavior when finding which instructions should use the :opcode:`LOAD_FAST_CHECK` opcode. diff --git a/Python/compile.c b/Python/compile.c index 70f38d4d0cda..676558b0f409 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -114,6 +114,13 @@ (opcode) == RAISE_VARARGS || \ (opcode) == RERAISE) +#define IS_SUPERINSTRUCTION_OPCODE(opcode) \ + ((opcode) == LOAD_FAST__LOAD_FAST || \ + (opcode) == LOAD_FAST__LOAD_CONST || \ + (opcode) == LOAD_CONST__LOAD_FAST || \ + (opcode) == STORE_FAST__LOAD_FAST || \ + (opcode) == STORE_FAST__STORE_FAST) + #define IS_TOP_LEVEL_AWAIT(c) ( \ (c->c_flags->cf_flags & PyCF_ALLOW_TOP_LEVEL_AWAIT) \ && (c->u->u_ste->ste_type == ModuleBlock)) @@ -258,6 +265,8 @@ typedef struct basicblock_ { int b_iused; /* length of instruction array (b_instr) */ int b_ialloc; + /* Used by add_checks_for_loads_of_unknown_variables */ + uint64_t b_unsafe_locals_mask; /* Number of predecessors that a block has. */ int b_predecessors; /* depth of stack upon entry of block, computed by stackdepth() */ @@ -8052,103 +8061,165 @@ assemble_jump_offsets(basicblock *entryblock) } -// Ensure each basicblock is only put onto the stack once. -#define MAYBE_PUSH(B) do { \ - if ((B)->b_visited == 0) { \ - *(*stack_top)++ = (B); \ - (B)->b_visited = 1; \ - } \ - } while (0) +// helper functions for add_checks_for_loads_of_unknown_variables +static inline void +maybe_push(basicblock *b, uint64_t unsafe_mask, basicblock ***sp) +{ + // Push b if the unsafe mask is giving us any new information. + // To avoid overflowing the stack, only allow each block once. + // Use b->b_visited=1 to mean that b is currently on the stack. + uint64_t both = b->b_unsafe_locals_mask | unsafe_mask; + if (b->b_unsafe_locals_mask != both) { + b->b_unsafe_locals_mask = both; + // More work left to do. + if (!b->b_visited) { + // not on the stack, so push it. + *(*sp)++ = b; + b->b_visited = 1; + } + } +} static void -scan_block_for_local(int target, basicblock *b, bool unsafe_to_start, - basicblock ***stack_top) +scan_block_for_locals(basicblock *b, basicblock ***sp) { - bool unsafe = unsafe_to_start; + // bit i is set if local i is potentially uninitialized + uint64_t unsafe_mask = b->b_unsafe_locals_mask; for (int i = 0; i < b->b_iused; i++) { struct instr *instr = &b->b_instr[i]; assert(instr->i_opcode != EXTENDED_ARG); assert(instr->i_opcode != EXTENDED_ARG_QUICK); - assert(instr->i_opcode != LOAD_FAST__LOAD_FAST); - assert(instr->i_opcode != STORE_FAST__LOAD_FAST); - assert(instr->i_opcode != LOAD_CONST__LOAD_FAST); - assert(instr->i_opcode != STORE_FAST__STORE_FAST); - assert(instr->i_opcode != LOAD_FAST__LOAD_CONST); - if (unsafe && instr->i_except != NULL) { - MAYBE_PUSH(instr->i_except); - } - if (instr->i_oparg != target) { + assert(!IS_SUPERINSTRUCTION_OPCODE(instr->i_opcode)); + if (instr->i_except != NULL) { + maybe_push(instr->i_except, unsafe_mask, sp); + } + if (instr->i_oparg >= 64) { continue; } + assert(instr->i_oparg >= 0); + uint64_t bit = (uint64_t)1 << instr->i_oparg; switch (instr->i_opcode) { + case DELETE_FAST: + unsafe_mask |= bit; + break; + case STORE_FAST: + unsafe_mask &= ~bit; + break; case LOAD_FAST_CHECK: - // if this doesn't raise, then var is defined - unsafe = false; + // If this doesn't raise, then the local is defined. + unsafe_mask &= ~bit; break; case LOAD_FAST: - if (unsafe) { + if (unsafe_mask & bit) { instr->i_opcode = LOAD_FAST_CHECK; } - unsafe = false; - break; - case STORE_FAST: - unsafe = false; - break; - case DELETE_FAST: - unsafe = true; + unsafe_mask &= ~bit; break; } } - if (unsafe) { - // unsafe at end of this block, - // so unsafe at start of next blocks - if (b->b_next && BB_HAS_FALLTHROUGH(b)) { - MAYBE_PUSH(b->b_next); - } - struct instr *last = basicblock_last_instr(b); - if (last != NULL) { - if (is_jump(last)) { - assert(last->i_target != NULL); - MAYBE_PUSH(last->i_target); + if (b->b_next && BB_HAS_FALLTHROUGH(b)) { + maybe_push(b->b_next, unsafe_mask, sp); + } + struct instr *last = basicblock_last_instr(b); + if (last && is_jump(last)) { + assert(last->i_target != NULL); + maybe_push(last->i_target, unsafe_mask, sp); + } +} + +static int +fast_scan_many_locals(basicblock *entryblock, int nlocals) +{ + assert(nlocals > 64); + Py_ssize_t *states = PyMem_Calloc(nlocals - 64, sizeof(Py_ssize_t)); + if (states == NULL) { + PyErr_NoMemory(); + return -1; + } + Py_ssize_t blocknum = 0; + // state[i - 64] == blocknum if local i is guaranteed to + // be initialized, i.e., if it has had a previous LOAD_FAST or + // STORE_FAST within that basicblock (not followed by DELETE_FAST). + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { + blocknum++; + for (int i = 0; i < b->b_iused; i++) { + struct instr *instr = &b->b_instr[i]; + assert(instr->i_opcode != EXTENDED_ARG); + assert(instr->i_opcode != EXTENDED_ARG_QUICK); + assert(!IS_SUPERINSTRUCTION_OPCODE(instr->i_opcode)); + int arg = instr->i_oparg; + if (arg < 64) { + continue; + } + assert(arg >= 0); + switch (instr->i_opcode) { + case DELETE_FAST: + states[arg - 64] = blocknum - 1; + break; + case STORE_FAST: + states[arg - 64] = blocknum; + break; + case LOAD_FAST: + if (states[arg - 64] != blocknum) { + instr->i_opcode = LOAD_FAST_CHECK; + } + states[arg - 64] = blocknum; + break; + case LOAD_FAST_CHECK: + Py_UNREACHABLE(); } } } + PyMem_Free(states); + return 0; } -#undef MAYBE_PUSH static int add_checks_for_loads_of_uninitialized_variables(basicblock *entryblock, struct compiler *c) { + int nlocals = (int)PyDict_GET_SIZE(c->u->u_varnames); + if (nlocals == 0) { + return 0; + } + if (nlocals > 64) { + // To avoid O(nlocals**2) compilation, locals beyond the first + // 64 are only analyzed one basicblock at a time: initialization + // info is not passed between basicblocks. + if (fast_scan_many_locals(entryblock, nlocals) < 0) { + return -1; + } + nlocals = 64; + } basicblock **stack = make_cfg_traversal_stack(entryblock); if (stack == NULL) { return -1; } - Py_ssize_t nparams = PyList_GET_SIZE(c->u->u_ste->ste_varnames); - int nlocals = (int)PyDict_GET_SIZE(c->u->u_varnames); - for (int target = 0; target < nlocals; target++) { - for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - b->b_visited = 0; - } - basicblock **stack_top = stack; + basicblock **sp = stack; - // First pass: find the relevant DFS starting points: - // the places where "being uninitialized" originates, - // which are the entry block and any DELETE_FAST statements. - if (target >= nparams) { - // only non-parameter locals start out uninitialized. - *(stack_top++) = entryblock; - entryblock->b_visited = 1; - } - for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - scan_block_for_local(target, b, false, &stack_top); - } + // First origin of being uninitialized: + // The non-parameter locals in the entry block. + int nparams = (int)PyList_GET_SIZE(c->u->u_ste->ste_varnames); + uint64_t start_mask = 0; + for (int i = nparams; i < nlocals; i++) { + start_mask |= (uint64_t)1 << i; + } + maybe_push(entryblock, start_mask, &sp); - // Second pass: Depth-first search to propagate uncertainty - while (stack_top > stack) { - basicblock *b = *--stack_top; - scan_block_for_local(target, b, true, &stack_top); - } + // Second origin of being uninitialized: + // There could be DELETE_FAST somewhere, so + // be sure to scan each basicblock at least once. + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { + scan_block_for_locals(b, &sp); + } + + // Now propagate the uncertainty from the origins we found: Use + // LOAD_FAST_CHECK for any LOAD_FAST where the local could be undefined. + while (sp > stack) { + basicblock *b = *--sp; + // mark as no longer on stack + b->b_visited = 0; + scan_block_for_locals(b, &sp); } PyMem_Free(stack); return 0; From webhook-mailer at python.org Thu Oct 20 18:30:15 2022 From: webhook-mailer at python.org (Yhg1s) Date: Thu, 20 Oct 2022 22:30:15 -0000 Subject: [Python-checkins] gh-97514: Don't use Linux abstract sockets for multiprocessing (#98501) Message-ID: https://github.com/python/cpython/commit/49f61068f49747164988ffc5a442d2a63874fc17 commit: 49f61068f49747164988ffc5a442d2a63874fc17 branch: main author: Gregory P. Smith committer: Yhg1s date: 2022-10-20T15:30:09-07:00 summary: gh-97514: Don't use Linux abstract sockets for multiprocessing (#98501) Linux abstract sockets are insecure as they lack any form of filesystem permissions so their use allows anyone on the system to inject code into the process. This removes the default preference for abstract sockets in multiprocessing introduced in Python 3.9+ via https://github.com/python/cpython/pull/18866 while fixing https://github.com/python/cpython/issues/84031. Explicit use of an abstract socket by a user now generates a RuntimeWarning. If we choose to keep this warning, it should be backported to the 3.7 and 3.8 branches. files: A Misc/NEWS.d/next/Security/2022-09-07-10-42-00.gh-issue-97514.Yggdsl.rst M Lib/multiprocessing/connection.py diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py index 65303d29f51f..b08144f7a1a1 100644 --- a/Lib/multiprocessing/connection.py +++ b/Lib/multiprocessing/connection.py @@ -73,11 +73,6 @@ def arbitrary_address(family): if family == 'AF_INET': return ('localhost', 0) elif family == 'AF_UNIX': - # Prefer abstract sockets if possible to avoid problems with the address - # size. When coding portable applications, some implementations have - # sun_path as short as 92 bytes in the sockaddr_un struct. - if util.abstract_sockets_supported: - return f"\0listener-{os.getpid()}-{next(_mmap_counter)}" return tempfile.mktemp(prefix='listener-', dir=util.get_temp_dir()) elif family == 'AF_PIPE': return tempfile.mktemp(prefix=r'\\.\pipe\pyc-%d-%d-' % diff --git a/Misc/NEWS.d/next/Security/2022-09-07-10-42-00.gh-issue-97514.Yggdsl.rst b/Misc/NEWS.d/next/Security/2022-09-07-10-42-00.gh-issue-97514.Yggdsl.rst new file mode 100644 index 000000000000..02d95b570520 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2022-09-07-10-42-00.gh-issue-97514.Yggdsl.rst @@ -0,0 +1,15 @@ +On Linux the :mod:`multiprocessing` module returns to using filesystem backed +unix domain sockets for communication with the *forkserver* process instead of +the Linux abstract socket namespace. Only code that chooses to use the +:ref:`"forkserver" start method ` is affected. + +Abstract sockets have no permissions and could allow any user on the system in +the same `network namespace +`_ (often the +whole system) to inject code into the multiprocessing *forkserver* process. +This was a potential privilege escalation. Filesystem based socket permissions +restrict this to the *forkserver* process user as was the default in Python 3.8 +and earlier. + +This prevents Linux `CVE-2022-42919 +`_. From webhook-mailer at python.org Thu Oct 20 19:56:22 2022 From: webhook-mailer at python.org (miss-islington) Date: Thu, 20 Oct 2022 23:56:22 -0000 Subject: [Python-checkins] [3.10] gh-97514: Don't use Linux abstract sockets for multiprocessing (GH-98501) (GH-98503) Message-ID: https://github.com/python/cpython/commit/eae692eed18892309bcc25a2c0f8980038305ea2 commit: eae692eed18892309bcc25a2c0f8980038305ea2 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-20T16:55:51-07:00 summary: [3.10] gh-97514: Don't use Linux abstract sockets for multiprocessing (GH-98501) (GH-98503) Linux abstract sockets are insecure as they lack any form of filesystem permissions so their use allows anyone on the system to inject code into the process. This removes the default preference for abstract sockets in multiprocessing introduced in Python 3.9+ via https://github.com/python/cpython/pull/18866 while fixing https://github.com/python/cpython/issues/84031. Explicit use of an abstract socket by a user now generates a RuntimeWarning. If we choose to keep this warning, it should be backported to the 3.7 and 3.8 branches. (cherry picked from commit 49f61068f49747164988ffc5a442d2a63874fc17) Co-authored-by: Gregory P. Smith Automerge-Triggered-By: GH:gpshead files: A Misc/NEWS.d/next/Security/2022-09-07-10-42-00.gh-issue-97514.Yggdsl.rst M Lib/multiprocessing/connection.py diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py index 510e4b5aba44..8e2facf92a94 100644 --- a/Lib/multiprocessing/connection.py +++ b/Lib/multiprocessing/connection.py @@ -73,11 +73,6 @@ def arbitrary_address(family): if family == 'AF_INET': return ('localhost', 0) elif family == 'AF_UNIX': - # Prefer abstract sockets if possible to avoid problems with the address - # size. When coding portable applications, some implementations have - # sun_path as short as 92 bytes in the sockaddr_un struct. - if util.abstract_sockets_supported: - return f"\0listener-{os.getpid()}-{next(_mmap_counter)}" return tempfile.mktemp(prefix='listener-', dir=util.get_temp_dir()) elif family == 'AF_PIPE': return tempfile.mktemp(prefix=r'\\.\pipe\pyc-%d-%d-' % diff --git a/Misc/NEWS.d/next/Security/2022-09-07-10-42-00.gh-issue-97514.Yggdsl.rst b/Misc/NEWS.d/next/Security/2022-09-07-10-42-00.gh-issue-97514.Yggdsl.rst new file mode 100644 index 000000000000..02d95b570520 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2022-09-07-10-42-00.gh-issue-97514.Yggdsl.rst @@ -0,0 +1,15 @@ +On Linux the :mod:`multiprocessing` module returns to using filesystem backed +unix domain sockets for communication with the *forkserver* process instead of +the Linux abstract socket namespace. Only code that chooses to use the +:ref:`"forkserver" start method ` is affected. + +Abstract sockets have no permissions and could allow any user on the system in +the same `network namespace +`_ (often the +whole system) to inject code into the multiprocessing *forkserver* process. +This was a potential privilege escalation. Filesystem based socket permissions +restrict this to the *forkserver* process user as was the default in Python 3.8 +and earlier. + +This prevents Linux `CVE-2022-42919 +`_. From webhook-mailer at python.org Thu Oct 20 19:56:22 2022 From: webhook-mailer at python.org (miss-islington) Date: Thu, 20 Oct 2022 23:56:22 -0000 Subject: [Python-checkins] [3.11] gh-97514: Don't use Linux abstract sockets for multiprocessing (GH-98501) (GH-98502) Message-ID: https://github.com/python/cpython/commit/4686d77a04570a663164c03193d9def23c89b122 commit: 4686d77a04570a663164c03193d9def23c89b122 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-20T16:55:37-07:00 summary: [3.11] gh-97514: Don't use Linux abstract sockets for multiprocessing (GH-98501) (GH-98502) Linux abstract sockets are insecure as they lack any form of filesystem permissions so their use allows anyone on the system to inject code into the process. This removes the default preference for abstract sockets in multiprocessing introduced in Python 3.9+ via https://github.com/python/cpython/pull/18866 while fixing https://github.com/python/cpython/issues/84031. Explicit use of an abstract socket by a user now generates a RuntimeWarning. If we choose to keep this warning, it should be backported to the 3.7 and 3.8 branches. (cherry picked from commit 49f61068f49747164988ffc5a442d2a63874fc17) Co-authored-by: Gregory P. Smith Automerge-Triggered-By: GH:gpshead files: A Misc/NEWS.d/next/Security/2022-09-07-10-42-00.gh-issue-97514.Yggdsl.rst M Lib/multiprocessing/connection.py diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py index 65303d29f51f..b08144f7a1a1 100644 --- a/Lib/multiprocessing/connection.py +++ b/Lib/multiprocessing/connection.py @@ -73,11 +73,6 @@ def arbitrary_address(family): if family == 'AF_INET': return ('localhost', 0) elif family == 'AF_UNIX': - # Prefer abstract sockets if possible to avoid problems with the address - # size. When coding portable applications, some implementations have - # sun_path as short as 92 bytes in the sockaddr_un struct. - if util.abstract_sockets_supported: - return f"\0listener-{os.getpid()}-{next(_mmap_counter)}" return tempfile.mktemp(prefix='listener-', dir=util.get_temp_dir()) elif family == 'AF_PIPE': return tempfile.mktemp(prefix=r'\\.\pipe\pyc-%d-%d-' % diff --git a/Misc/NEWS.d/next/Security/2022-09-07-10-42-00.gh-issue-97514.Yggdsl.rst b/Misc/NEWS.d/next/Security/2022-09-07-10-42-00.gh-issue-97514.Yggdsl.rst new file mode 100644 index 000000000000..02d95b570520 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2022-09-07-10-42-00.gh-issue-97514.Yggdsl.rst @@ -0,0 +1,15 @@ +On Linux the :mod:`multiprocessing` module returns to using filesystem backed +unix domain sockets for communication with the *forkserver* process instead of +the Linux abstract socket namespace. Only code that chooses to use the +:ref:`"forkserver" start method ` is affected. + +Abstract sockets have no permissions and could allow any user on the system in +the same `network namespace +`_ (often the +whole system) to inject code into the multiprocessing *forkserver* process. +This was a potential privilege escalation. Filesystem based socket permissions +restrict this to the *forkserver* process user as was the default in Python 3.8 +and earlier. + +This prevents Linux `CVE-2022-42919 +`_. From webhook-mailer at python.org Fri Oct 21 06:35:28 2022 From: webhook-mailer at python.org (iritkatriel) Date: Fri, 21 Oct 2022 10:35:28 -0000 Subject: [Python-checkins] gh-98172: [doc] mention that except* handles naked exceptions (GH-98496) Message-ID: https://github.com/python/cpython/commit/8367ca136ed7616cb1f71bd9f1ec98dbcfd35d98 commit: 8367ca136ed7616cb1f71bd9f1ec98dbcfd35d98 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2022-10-21T11:35:20+01:00 summary: gh-98172: [doc] mention that except* handles naked exceptions (GH-98496) files: M Doc/reference/compound_stmts.rst diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index 896348183643..c3c78119958e 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -343,7 +343,7 @@ the case of :keyword:`except`, but in the case of exception groups we can have partial matches when the type matches some of the exceptions in the group. This means that multiple :keyword:`!except*` clauses can execute, each handling part of the exception group. -Each clause executes once and handles an exception group +Each clause executes at most once and handles an exception group of all matching exceptions. Each exception in the group is handled by at most one :keyword:`!except*` clause, the first that matches it. :: @@ -364,10 +364,22 @@ one :keyword:`!except*` clause, the first that matches it. :: | ValueError: 1 +------------------------------------ + Any remaining exceptions that were not handled by any :keyword:`!except*` clause are re-raised at the end, combined into an exception group along with all exceptions that were raised from within :keyword:`!except*` clauses. +If the raised exception is not an exception group and its type matches +one of the :keyword:`!except*` clauses, it is caught and wrapped by an +exception group with an empty message string. :: + + >>> try: + ... raise BlockingIOError + ... except* BlockingIOError as e: + ... print(repr(e)) + ... + ExceptionGroup('', (BlockingIOError())) + An :keyword:`!except*` clause must have a matching type, and this type cannot be a subclass of :exc:`BaseExceptionGroup`. It is not possible to mix :keyword:`except` and :keyword:`!except*` From webhook-mailer at python.org Fri Oct 21 06:44:08 2022 From: webhook-mailer at python.org (miss-islington) Date: Fri, 21 Oct 2022 10:44:08 -0000 Subject: [Python-checkins] gh-98172: [doc] mention that except* handles naked exceptions (GH-98496) Message-ID: https://github.com/python/cpython/commit/0bc2cf9915c65a6a91fadc0c1d411caba57db494 commit: 0bc2cf9915c65a6a91fadc0c1d411caba57db494 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-21T03:43:56-07:00 summary: gh-98172: [doc] mention that except* handles naked exceptions (GH-98496) (cherry picked from commit 8367ca136ed7616cb1f71bd9f1ec98dbcfd35d98) Co-authored-by: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> files: M Doc/reference/compound_stmts.rst diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index 896348183643..c3c78119958e 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -343,7 +343,7 @@ the case of :keyword:`except`, but in the case of exception groups we can have partial matches when the type matches some of the exceptions in the group. This means that multiple :keyword:`!except*` clauses can execute, each handling part of the exception group. -Each clause executes once and handles an exception group +Each clause executes at most once and handles an exception group of all matching exceptions. Each exception in the group is handled by at most one :keyword:`!except*` clause, the first that matches it. :: @@ -364,10 +364,22 @@ one :keyword:`!except*` clause, the first that matches it. :: | ValueError: 1 +------------------------------------ + Any remaining exceptions that were not handled by any :keyword:`!except*` clause are re-raised at the end, combined into an exception group along with all exceptions that were raised from within :keyword:`!except*` clauses. +If the raised exception is not an exception group and its type matches +one of the :keyword:`!except*` clauses, it is caught and wrapped by an +exception group with an empty message string. :: + + >>> try: + ... raise BlockingIOError + ... except* BlockingIOError as e: + ... print(repr(e)) + ... + ExceptionGroup('', (BlockingIOError())) + An :keyword:`!except*` clause must have a matching type, and this type cannot be a subclass of :exc:`BaseExceptionGroup`. It is not possible to mix :keyword:`except` and :keyword:`!except*` From webhook-mailer at python.org Fri Oct 21 09:42:11 2022 From: webhook-mailer at python.org (markshannon) Date: Fri, 21 Oct 2022 13:42:11 -0000 Subject: [Python-checkins] gh-91051: allow setting a callback hook on PyType_Modified (GH-97875) Message-ID: https://github.com/python/cpython/commit/82ccbf69a842db25d8117f1c41b47aa5b4ed96ab commit: 82ccbf69a842db25d8117f1c41b47aa5b4ed96ab branch: main author: Carl Meyer committer: markshannon date: 2022-10-21T14:41:51+01:00 summary: gh-91051: allow setting a callback hook on PyType_Modified (GH-97875) files: A Misc/NEWS.d/next/C API/2022-10-05-10-43-32.gh-issue-91051.ODDRsQ.rst M Doc/c-api/type.rst M Doc/whatsnew/3.12.rst M Include/cpython/object.h M Include/internal/pycore_interp.h M Lib/test/test_capi.py M Lib/test/test_sys.py M Modules/_testcapimodule.c M Objects/typeobject.c diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst index 1dc05001adfa..7b5d1fac40ed 100644 --- a/Doc/c-api/type.rst +++ b/Doc/c-api/type.rst @@ -57,6 +57,55 @@ Type Objects modification of the attributes or base classes of the type. +.. c:function:: int PyType_AddWatcher(PyType_WatchCallback callback) + + Register *callback* as a type watcher. Return a non-negative integer ID + which must be passed to future calls to :c:func:`PyType_Watch`. In case of + error (e.g. no more watcher IDs available), return ``-1`` and set an + exception. + + .. versionadded:: 3.12 + + +.. c:function:: int PyType_ClearWatcher(int watcher_id) + + Clear watcher identified by *watcher_id* (previously returned from + :c:func:`PyType_AddWatcher`). Return ``0`` on success, ``-1`` on error (e.g. + if *watcher_id* was never registered.) + + An extension should never call ``PyType_ClearWatcher`` with a *watcher_id* + that was not returned to it by a previous call to + :c:func:`PyType_AddWatcher`. + + .. versionadded:: 3.12 + + +.. c:function:: int PyType_Watch(int watcher_id, PyObject *type) + + Mark *type* as watched. The callback granted *watcher_id* by + :c:func:`PyType_AddWatcher` will be called whenever + :c:func:`PyType_Modified` reports a change to *type*. (The callback may be + called only once for a series of consecutive modifications to *type*, if + :c:func:`PyType_Lookup` is not called on *type* between the modifications; + this is an implementation detail and subject to change.) + + An extension should never call ``PyType_Watch`` with a *watcher_id* that was + not returned to it by a previous call to :c:func:`PyType_AddWatcher`. + + .. versionadded:: 3.12 + + +.. c:type:: int (*PyType_WatchCallback)(PyObject *type) + + Type of a type-watcher callback function. + + The callback must not modify *type* or cause :c:func:`PyType_Modified` to be + called on *type* or any type in its MRO; violating this rule could cause + infinite recursion. + + .. versionadded:: 3.12 + + .. c:function:: int PyType_HasFeature(PyTypeObject *o, int feature) Return non-zero if the type object *o* sets the feature *feature*. diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 525efc405c85..3e0b106c4a04 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -587,6 +587,12 @@ New Features :c:func:`PyDict_AddWatch` and related APIs to be called whenever a dictionary is modified. This is intended for use by optimizing interpreters, JIT compilers, or debuggers. + (Contributed by Carl Meyer in :gh:`91052`.) + +* Added :c:func:`PyType_AddWatcher` and :c:func:`PyType_Watch` API to register + callbacks to receive notification on changes to a type. + (Contributed by Carl Meyer in :gh:`91051`.) + Porting to Python 3.12 ---------------------- diff --git a/Include/cpython/object.h b/Include/cpython/object.h index c80fc1df0e0b..900b52321dff 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -224,6 +224,9 @@ struct _typeobject { destructor tp_finalize; vectorcallfunc tp_vectorcall; + + /* bitset of which type-watchers care about this type */ + char tp_watched; }; /* This struct is used by the specializer @@ -510,3 +513,11 @@ Py_DEPRECATED(3.11) typedef int UsingDeprecatedTrashcanMacro; PyAPI_FUNC(int) _PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg); PyAPI_FUNC(void) _PyObject_ClearManagedDict(PyObject *obj); + +#define TYPE_MAX_WATCHERS 8 + +typedef int(*PyType_WatchCallback)(PyTypeObject *); +PyAPI_FUNC(int) PyType_AddWatcher(PyType_WatchCallback callback); +PyAPI_FUNC(int) PyType_ClearWatcher(int watcher_id); +PyAPI_FUNC(int) PyType_Watch(int watcher_id, PyObject *type); +PyAPI_FUNC(int) PyType_Unwatch(int watcher_id, PyObject *type); diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index e643c7e9e4ed..9017e84e15af 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -166,6 +166,7 @@ struct _is { struct atexit_state atexit; PyObject *audit_hooks; + PyType_WatchCallback type_watchers[TYPE_MAX_WATCHERS]; struct _Py_unicode_state unicode; struct _Py_float_state float_state; diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py index a2183cfb0fdf..364c607b3c18 100644 --- a/Lib/test/test_capi.py +++ b/Lib/test/test_capi.py @@ -2,7 +2,7 @@ # these are all functions _testcapi exports whose name begins with 'test_'. from collections import OrderedDict -from contextlib import contextmanager +from contextlib import contextmanager, ExitStack import _thread import importlib.machinery import importlib.util @@ -1606,5 +1606,172 @@ def test_clear_unassigned_watcher_id(self): self.clear_watcher(1) +class TestTypeWatchers(unittest.TestCase): + # types of watchers testcapimodule can add: + TYPES = 0 # appends modified types to global event list + ERROR = 1 # unconditionally sets and signals a RuntimeException + WRAP = 2 # appends modified type wrapped in list to global event list + + # duplicating the C constant + TYPE_MAX_WATCHERS = 8 + + def add_watcher(self, kind=TYPES): + return _testcapi.add_type_watcher(kind) + + def clear_watcher(self, watcher_id): + _testcapi.clear_type_watcher(watcher_id) + + @contextmanager + def watcher(self, kind=TYPES): + wid = self.add_watcher(kind) + try: + yield wid + finally: + self.clear_watcher(wid) + + def assert_events(self, expected): + actual = _testcapi.get_type_modified_events() + self.assertEqual(actual, expected) + + def watch(self, wid, t): + _testcapi.watch_type(wid, t) + + def unwatch(self, wid, t): + _testcapi.unwatch_type(wid, t) + + def test_watch_type(self): + class C: pass + with self.watcher() as wid: + self.watch(wid, C) + C.foo = "bar" + self.assert_events([C]) + + def test_event_aggregation(self): + class C: pass + with self.watcher() as wid: + self.watch(wid, C) + C.foo = "bar" + C.bar = "baz" + # only one event registered for both modifications + self.assert_events([C]) + + def test_lookup_resets_aggregation(self): + class C: pass + with self.watcher() as wid: + self.watch(wid, C) + C.foo = "bar" + # lookup resets type version tag + self.assertEqual(C.foo, "bar") + C.bar = "baz" + # both events registered + self.assert_events([C, C]) + + def test_unwatch_type(self): + class C: pass + with self.watcher() as wid: + self.watch(wid, C) + C.foo = "bar" + self.assertEqual(C.foo, "bar") + self.assert_events([C]) + self.unwatch(wid, C) + C.bar = "baz" + self.assert_events([C]) + + def test_clear_watcher(self): + class C: pass + # outer watcher is unused, it's just to keep events list alive + with self.watcher() as _: + with self.watcher() as wid: + self.watch(wid, C) + C.foo = "bar" + self.assertEqual(C.foo, "bar") + self.assert_events([C]) + C.bar = "baz" + # Watcher on C has been cleared, no new event + self.assert_events([C]) + + def test_watch_type_subclass(self): + class C: pass + class D(C): pass + with self.watcher() as wid: + self.watch(wid, D) + C.foo = "bar" + self.assert_events([D]) + + def test_error(self): + class C: pass + with self.watcher(kind=self.ERROR) as wid: + self.watch(wid, C) + with catch_unraisable_exception() as cm: + C.foo = "bar" + self.assertIs(cm.unraisable.object, C) + self.assertEqual(str(cm.unraisable.exc_value), "boom!") + self.assert_events([]) + + def test_two_watchers(self): + class C1: pass + class C2: pass + with self.watcher() as wid1: + with self.watcher(kind=self.WRAP) as wid2: + self.assertNotEqual(wid1, wid2) + self.watch(wid1, C1) + self.watch(wid2, C2) + C1.foo = "bar" + C2.hmm = "baz" + self.assert_events([C1, [C2]]) + + def test_watch_non_type(self): + with self.watcher() as wid: + with self.assertRaisesRegex(ValueError, r"Cannot watch non-type"): + self.watch(wid, 1) + + def test_watch_out_of_range_watcher_id(self): + class C: pass + with self.assertRaisesRegex(ValueError, r"Invalid type watcher ID -1"): + self.watch(-1, C) + with self.assertRaisesRegex(ValueError, r"Invalid type watcher ID 8"): + self.watch(self.TYPE_MAX_WATCHERS, C) + + def test_watch_unassigned_watcher_id(self): + class C: pass + with self.assertRaisesRegex(ValueError, r"No type watcher set for ID 1"): + self.watch(1, C) + + def test_unwatch_non_type(self): + with self.watcher() as wid: + with self.assertRaisesRegex(ValueError, r"Cannot watch non-type"): + self.unwatch(wid, 1) + + def test_unwatch_out_of_range_watcher_id(self): + class C: pass + with self.assertRaisesRegex(ValueError, r"Invalid type watcher ID -1"): + self.unwatch(-1, C) + with self.assertRaisesRegex(ValueError, r"Invalid type watcher ID 8"): + self.unwatch(self.TYPE_MAX_WATCHERS, C) + + def test_unwatch_unassigned_watcher_id(self): + class C: pass + with self.assertRaisesRegex(ValueError, r"No type watcher set for ID 1"): + self.unwatch(1, C) + + def test_clear_out_of_range_watcher_id(self): + with self.assertRaisesRegex(ValueError, r"Invalid type watcher ID -1"): + self.clear_watcher(-1) + with self.assertRaisesRegex(ValueError, r"Invalid type watcher ID 8"): + self.clear_watcher(self.TYPE_MAX_WATCHERS) + + def test_clear_unassigned_watcher_id(self): + with self.assertRaisesRegex(ValueError, r"No type watcher set for ID 1"): + self.clear_watcher(1) + + def test_no_more_ids_available(self): + contexts = [self.watcher() for i in range(self.TYPE_MAX_WATCHERS)] + with ExitStack() as stack: + for ctx in contexts: + stack.enter_context(ctx) + with self.assertRaisesRegex(RuntimeError, r"no more type watcher IDs"): + self.add_watcher() + + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 41482734872e..9184e9a42f19 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -1521,7 +1521,7 @@ def delx(self): del self.__x check((1,2,3), vsize('') + 3*self.P) # type # static type: PyTypeObject - fmt = 'P2nPI13Pl4Pn9Pn12PIP' + fmt = 'P2nPI13Pl4Pn9Pn12PIPc' s = vsize('2P' + fmt) check(int, s) # class diff --git a/Misc/NEWS.d/next/C API/2022-10-05-10-43-32.gh-issue-91051.ODDRsQ.rst b/Misc/NEWS.d/next/C API/2022-10-05-10-43-32.gh-issue-91051.ODDRsQ.rst new file mode 100644 index 000000000000..c18e2d61f397 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2022-10-05-10-43-32.gh-issue-91051.ODDRsQ.rst @@ -0,0 +1,2 @@ +Add :c:func:`PyType_Watch` and related APIs to allow callbacks on +:c:func:`PyType_Modified`. diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 624e878b20d8..194b2de2f0d6 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -5695,6 +5695,128 @@ function_get_module(PyObject *self, PyObject *func) } +// type watchers + +static PyObject *g_type_modified_events; +static int g_type_watchers_installed; + +static int +type_modified_callback(PyTypeObject *type) +{ + assert(PyList_Check(g_type_modified_events)); + if(PyList_Append(g_type_modified_events, (PyObject *)type) < 0) { + return -1; + } + return 0; +} + +static int +type_modified_callback_wrap(PyTypeObject *type) +{ + assert(PyList_Check(g_type_modified_events)); + PyObject *list = PyList_New(0); + if (!list) { + return -1; + } + if (PyList_Append(list, (PyObject *)type) < 0) { + Py_DECREF(list); + return -1; + } + if (PyList_Append(g_type_modified_events, list) < 0) { + Py_DECREF(list); + return -1; + } + Py_DECREF(list); + return 0; +} + +static int +type_modified_callback_error(PyTypeObject *type) +{ + PyErr_SetString(PyExc_RuntimeError, "boom!"); + return -1; +} + +static PyObject * +add_type_watcher(PyObject *self, PyObject *kind) +{ + int watcher_id; + assert(PyLong_Check(kind)); + long kind_l = PyLong_AsLong(kind); + if (kind_l == 2) { + watcher_id = PyType_AddWatcher(type_modified_callback_wrap); + } else if (kind_l == 1) { + watcher_id = PyType_AddWatcher(type_modified_callback_error); + } else { + watcher_id = PyType_AddWatcher(type_modified_callback); + } + if (watcher_id < 0) { + return NULL; + } + if (!g_type_watchers_installed) { + assert(!g_type_modified_events); + if (!(g_type_modified_events = PyList_New(0))) { + return NULL; + } + } + g_type_watchers_installed++; + return PyLong_FromLong(watcher_id); +} + +static PyObject * +clear_type_watcher(PyObject *self, PyObject *watcher_id) +{ + if (PyType_ClearWatcher(PyLong_AsLong(watcher_id))) { + return NULL; + } + g_type_watchers_installed--; + if (!g_type_watchers_installed) { + assert(g_type_modified_events); + Py_CLEAR(g_type_modified_events); + } + Py_RETURN_NONE; +} + +static PyObject * +get_type_modified_events(PyObject *self, PyObject *Py_UNUSED(args)) +{ + if (!g_type_modified_events) { + PyErr_SetString(PyExc_RuntimeError, "no watchers active"); + return NULL; + } + Py_INCREF(g_type_modified_events); + return g_type_modified_events; +} + +static PyObject * +watch_type(PyObject *self, PyObject *args) +{ + PyObject *type; + int watcher_id; + if (!PyArg_ParseTuple(args, "iO", &watcher_id, &type)) { + return NULL; + } + if (PyType_Watch(watcher_id, type)) { + return NULL; + } + Py_RETURN_NONE; +} + +static PyObject * +unwatch_type(PyObject *self, PyObject *args) +{ + PyObject *type; + int watcher_id; + if (!PyArg_ParseTuple(args, "iO", &watcher_id, &type)) { + return NULL; + } + if (PyType_Unwatch(watcher_id, type)) { + return NULL; + } + Py_RETURN_NONE; +} + + static PyObject *test_buildvalue_issue38913(PyObject *, PyObject *); static PyObject *getargs_s_hash_int(PyObject *, PyObject *, PyObject*); static PyObject *getargs_s_hash_int2(PyObject *, PyObject *, PyObject*); @@ -5981,6 +6103,11 @@ static PyMethodDef TestMethods[] = { {"function_get_code", function_get_code, METH_O, NULL}, {"function_get_globals", function_get_globals, METH_O, NULL}, {"function_get_module", function_get_module, METH_O, NULL}, + {"add_type_watcher", add_type_watcher, METH_O, NULL}, + {"clear_type_watcher", clear_type_watcher, METH_O, NULL}, + {"watch_type", watch_type, METH_VARARGS, NULL}, + {"unwatch_type", unwatch_type, METH_VARARGS, NULL}, + {"get_type_modified_events", get_type_modified_events, METH_NOARGS, NULL}, {NULL, NULL} /* sentinel */ }; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 196a6aee4993..7f8f2c7846eb 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -372,6 +372,83 @@ _PyTypes_Fini(PyInterpreterState *interp) static PyObject * lookup_subclasses(PyTypeObject *); +int +PyType_AddWatcher(PyType_WatchCallback callback) +{ + PyInterpreterState *interp = _PyInterpreterState_GET(); + + for (int i = 0; i < TYPE_MAX_WATCHERS; i++) { + if (!interp->type_watchers[i]) { + interp->type_watchers[i] = callback; + return i; + } + } + + PyErr_SetString(PyExc_RuntimeError, "no more type watcher IDs available"); + return -1; +} + +static inline int +validate_watcher_id(PyInterpreterState *interp, int watcher_id) +{ + if (watcher_id < 0 || watcher_id >= TYPE_MAX_WATCHERS) { + PyErr_Format(PyExc_ValueError, "Invalid type watcher ID %d", watcher_id); + return -1; + } + if (!interp->type_watchers[watcher_id]) { + PyErr_Format(PyExc_ValueError, "No type watcher set for ID %d", watcher_id); + return -1; + } + return 0; +} + +int +PyType_ClearWatcher(int watcher_id) +{ + PyInterpreterState *interp = _PyInterpreterState_GET(); + if (validate_watcher_id(interp, watcher_id) < 0) { + return -1; + } + interp->type_watchers[watcher_id] = NULL; + return 0; +} + +static int assign_version_tag(PyTypeObject *type); + +int +PyType_Watch(int watcher_id, PyObject* obj) +{ + if (!PyType_Check(obj)) { + PyErr_SetString(PyExc_ValueError, "Cannot watch non-type"); + return -1; + } + PyTypeObject *type = (PyTypeObject *)obj; + PyInterpreterState *interp = _PyInterpreterState_GET(); + if (validate_watcher_id(interp, watcher_id) < 0) { + return -1; + } + // ensure we will get a callback on the next modification + assign_version_tag(type); + type->tp_watched |= (1 << watcher_id); + return 0; +} + +int +PyType_Unwatch(int watcher_id, PyObject* obj) +{ + if (!PyType_Check(obj)) { + PyErr_SetString(PyExc_ValueError, "Cannot watch non-type"); + return -1; + } + PyTypeObject *type = (PyTypeObject *)obj; + PyInterpreterState *interp = _PyInterpreterState_GET(); + if (validate_watcher_id(interp, watcher_id)) { + return -1; + } + type->tp_watched &= ~(1 << watcher_id); + return 0; +} + void PyType_Modified(PyTypeObject *type) { @@ -409,6 +486,23 @@ PyType_Modified(PyTypeObject *type) } } + if (type->tp_watched) { + PyInterpreterState *interp = _PyInterpreterState_GET(); + int bits = type->tp_watched; + int i = 0; + while(bits && i < TYPE_MAX_WATCHERS) { + if (bits & 1) { + PyType_WatchCallback cb = interp->type_watchers[i]; + if (cb && (cb(type) < 0)) { + PyErr_WriteUnraisable((PyObject *)type); + } + } + i += 1; + bits >>= 1; + } + } + + type->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG; type->tp_version_tag = 0; /* 0 is not a valid version tag */ } @@ -467,7 +561,7 @@ type_mro_modified(PyTypeObject *type, PyObject *bases) { } static int -assign_version_tag(struct type_cache *cache, PyTypeObject *type) +assign_version_tag(PyTypeObject *type) { /* Ensure that the tp_version_tag is valid and set Py_TPFLAGS_VALID_VERSION_TAG. To respect the invariant, this @@ -492,7 +586,7 @@ assign_version_tag(struct type_cache *cache, PyTypeObject *type) Py_ssize_t n = PyTuple_GET_SIZE(bases); for (Py_ssize_t i = 0; i < n; i++) { PyObject *b = PyTuple_GET_ITEM(bases, i); - if (!assign_version_tag(cache, _PyType_CAST(b))) + if (!assign_version_tag(_PyType_CAST(b))) return 0; } type->tp_flags |= Py_TPFLAGS_VALID_VERSION_TAG; @@ -4111,7 +4205,7 @@ _PyType_Lookup(PyTypeObject *type, PyObject *name) return NULL; } - if (MCACHE_CACHEABLE_NAME(name) && assign_version_tag(cache, type)) { + if (MCACHE_CACHEABLE_NAME(name) && assign_version_tag(type)) { h = MCACHE_HASH_METHOD(type, name); struct type_cache_entry *entry = &cache->hashtable[h]; entry->version = type->tp_version_tag; From webhook-mailer at python.org Fri Oct 21 10:21:45 2022 From: webhook-mailer at python.org (vstinner) Date: Fri, 21 Oct 2022 14:21:45 -0000 Subject: [Python-checkins] gh-95027: Fix regrtest stdout encoding on Windows (#98492) Message-ID: https://github.com/python/cpython/commit/ec1f6f5f139868dc2c1116a7c7c878c38c668d53 commit: ec1f6f5f139868dc2c1116a7c7c878c38c668d53 branch: main author: Victor Stinner committer: vstinner date: 2022-10-21T16:21:36+02:00 summary: gh-95027: Fix regrtest stdout encoding on Windows (#98492) On Windows, when the Python test suite is run with the -jN option, the ANSI code page is now used as the encoding for the stdout temporary file, rather than using UTF-8 which can lead to decoding errors. files: A Misc/NEWS.d/next/Tests/2022-10-20-17-49-50.gh-issue-95027.viRpJB.rst M Lib/test/libregrtest/runtest_mp.py diff --git a/Lib/test/libregrtest/runtest_mp.py b/Lib/test/libregrtest/runtest_mp.py index a4d3e5c3146a..a12fcb46e0fd 100644 --- a/Lib/test/libregrtest/runtest_mp.py +++ b/Lib/test/libregrtest/runtest_mp.py @@ -22,6 +22,9 @@ from test.libregrtest.setup import setup_tests from test.libregrtest.utils import format_duration, print_warning +if sys.platform == 'win32': + import locale + # Display the running tests if nothing happened last N seconds PROGRESS_UPDATE = 30.0 # seconds @@ -267,11 +270,16 @@ def _run_process(self, test_name: str, tmp_dir: str, stdout_fh: TextIO) -> int: self.current_test_name = None def _runtest(self, test_name: str) -> MultiprocessResult: + if sys.platform == 'win32': + # gh-95027: When stdout is not a TTY, Python uses the ANSI code + # page for the sys.stdout encoding. If the main process runs in a + # terminal, sys.stdout uses WindowsConsoleIO with UTF-8 encoding. + encoding = locale.getencoding() + else: + encoding = sys.stdout.encoding # gh-94026: Write stdout+stderr to a tempfile as workaround for # non-blocking pipes on Emscripten with NodeJS. - with tempfile.TemporaryFile( - 'w+', encoding=sys.stdout.encoding - ) as stdout_fh: + with tempfile.TemporaryFile('w+', encoding=encoding) as stdout_fh: # gh-93353: Check for leaked temporary files in the parent process, # since the deletion of temporary files can happen late during # Python finalization: too late for libregrtest. diff --git a/Misc/NEWS.d/next/Tests/2022-10-20-17-49-50.gh-issue-95027.viRpJB.rst b/Misc/NEWS.d/next/Tests/2022-10-20-17-49-50.gh-issue-95027.viRpJB.rst new file mode 100644 index 000000000000..8bf1a9d33573 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2022-10-20-17-49-50.gh-issue-95027.viRpJB.rst @@ -0,0 +1,4 @@ +On Windows, when the Python test suite is run with the ``-jN`` option, the +ANSI code page is now used as the encoding for the stdout temporary file, +rather than using UTF-8 which can lead to decoding errors. Patch by Victor +Stinner. From webhook-mailer at python.org Fri Oct 21 10:52:23 2022 From: webhook-mailer at python.org (miss-islington) Date: Fri, 21 Oct 2022 14:52:23 -0000 Subject: [Python-checkins] gh-95027: Fix regrtest stdout encoding on Windows (GH-98492) Message-ID: https://github.com/python/cpython/commit/b2aa28eec56d07b9c6777b02b7247cf21839de9f commit: b2aa28eec56d07b9c6777b02b7247cf21839de9f branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-21T07:52:17-07:00 summary: gh-95027: Fix regrtest stdout encoding on Windows (GH-98492) On Windows, when the Python test suite is run with the -jN option, the ANSI code page is now used as the encoding for the stdout temporary file, rather than using UTF-8 which can lead to decoding errors. (cherry picked from commit ec1f6f5f139868dc2c1116a7c7c878c38c668d53) Co-authored-by: Victor Stinner files: A Misc/NEWS.d/next/Tests/2022-10-20-17-49-50.gh-issue-95027.viRpJB.rst M Lib/test/libregrtest/runtest_mp.py diff --git a/Lib/test/libregrtest/runtest_mp.py b/Lib/test/libregrtest/runtest_mp.py index 13649ce10b3a..c6a4dae2df86 100644 --- a/Lib/test/libregrtest/runtest_mp.py +++ b/Lib/test/libregrtest/runtest_mp.py @@ -21,6 +21,9 @@ from test.libregrtest.setup import setup_tests from test.libregrtest.utils import format_duration, print_warning +if sys.platform == 'win32': + import locale + # Display the running tests if nothing happened last N seconds PROGRESS_UPDATE = 30.0 # seconds @@ -259,11 +262,16 @@ def _run_process(self, test_name: str, stdout_fh: TextIO) -> int: self.current_test_name = None def _runtest(self, test_name: str) -> MultiprocessResult: + if sys.platform == 'win32': + # gh-95027: When stdout is not a TTY, Python uses the ANSI code + # page for the sys.stdout encoding. If the main process runs in a + # terminal, sys.stdout uses WindowsConsoleIO with UTF-8 encoding. + encoding = locale.getencoding() + else: + encoding = sys.stdout.encoding # gh-94026: Write stdout+stderr to a tempfile as workaround for # non-blocking pipes on Emscripten with NodeJS. - with tempfile.TemporaryFile( - 'w+', encoding=sys.stdout.encoding - ) as stdout_fh: + with tempfile.TemporaryFile('w+', encoding=encoding) as stdout_fh: # gh-93353: Check for leaked temporary files in the parent process, # since the deletion of temporary files can happen late during # Python finalization: too late for libregrtest. diff --git a/Misc/NEWS.d/next/Tests/2022-10-20-17-49-50.gh-issue-95027.viRpJB.rst b/Misc/NEWS.d/next/Tests/2022-10-20-17-49-50.gh-issue-95027.viRpJB.rst new file mode 100644 index 000000000000..8bf1a9d33573 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2022-10-20-17-49-50.gh-issue-95027.viRpJB.rst @@ -0,0 +1,4 @@ +On Windows, when the Python test suite is run with the ``-jN`` option, the +ANSI code page is now used as the encoding for the stdout temporary file, +rather than using UTF-8 which can lead to decoding errors. Patch by Victor +Stinner. From webhook-mailer at python.org Fri Oct 21 13:32:22 2022 From: webhook-mailer at python.org (rhettinger) Date: Fri, 21 Oct 2022 17:32:22 -0000 Subject: [Python-checkins] GH-98363: Fix exception handling in batched() (GH-98523) Message-ID: https://github.com/python/cpython/commit/a5ff80c8bc96210bace3ffb683b01fbd7f4ab76d commit: a5ff80c8bc96210bace3ffb683b01fbd7f4ab76d branch: main author: Raymond Hettinger committer: rhettinger date: 2022-10-21T12:31:52-05:00 summary: GH-98363: Fix exception handling in batched() (GH-98523) files: M Lib/test/test_itertools.py M Modules/itertoolsmodule.c diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py index c0e35711a2b3..a0a740fba8e8 100644 --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -2012,6 +2012,20 @@ def __iter__(self): def __next__(self): 3 // 0 +class E2: + 'Test propagation of exceptions after two iterations' + def __init__(self, seqn): + self.seqn = seqn + self.i = 0 + def __iter__(self): + return self + def __next__(self): + if self.i == 2: + raise ZeroDivisionError + v = self.seqn[self.i] + self.i += 1 + return v + class S: 'Test immediate stop' def __init__(self, seqn): @@ -2050,6 +2064,7 @@ def test_batched(self): self.assertRaises(TypeError, batched, X(s), 2) self.assertRaises(TypeError, batched, N(s), 2) self.assertRaises(ZeroDivisionError, list, batched(E(s), 2)) + self.assertRaises(ZeroDivisionError, list, batched(E2(s), 4)) def test_chain(self): for s in ("123", "", range(1000), ('do', 1.2), range(2000,2200,5)): diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index 868e8a8b384f..627e698fc6b9 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -154,23 +154,36 @@ batched_next(batchedobject *bo) if (result == NULL) { return NULL; } + iternextfunc iternext = *Py_TYPE(it)->tp_iternext; + PyObject **items = PySequence_Fast_ITEMS(result); for (i=0 ; i < n ; i++) { - item = PyIter_Next(it); + item = iternext(it); if (item == NULL) { - break; + goto null_item; + } + items[i] = item; + } + return result; + + null_item: + if (PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_StopIteration)) { + PyErr_Clear(); + } else { + /* input raised an exception other than StopIteration */ + Py_CLEAR(bo->it); + Py_DECREF(result); + return NULL; } - PyList_SET_ITEM(result, i, item); } if (i == 0) { Py_CLEAR(bo->it); Py_DECREF(result); return NULL; } - if (i < n) { - PyObject *short_list = PyList_GetSlice(result, 0, i); - Py_SETREF(result, short_list); - } - return result; + PyObject *short_list = PyList_GetSlice(result, 0, i); + Py_DECREF(result); + return short_list; } static PyTypeObject batched_type = { From webhook-mailer at python.org Fri Oct 21 15:26:09 2022 From: webhook-mailer at python.org (gpshead) Date: Fri, 21 Oct 2022 19:26:09 -0000 Subject: [Python-checkins] [3.10] gh-98517: Fix buffer overflows in _sha3 module (#98519) Message-ID: https://github.com/python/cpython/commit/0e4e058602d93b88256ff90bbef501ba20be9dd3 commit: 0e4e058602d93b88256ff90bbef501ba20be9dd3 branch: 3.10 author: Theo Buehler committer: gpshead date: 2022-10-21T12:26:01-07:00 summary: [3.10] gh-98517: Fix buffer overflows in _sha3 module (#98519) This is a port of the applicable part of XKCP's fix [1] for CVE-2022-37454 and avoids the segmentation fault and the infinite loop in the test cases published in [2]. [1]: https://github.com/XKCP/XKCP/commit/fdc6fef075f4e81d6b1bc38364248975e08e340a [2]: https://mouha.be/sha-3-buffer-overflow/ Regression test added by: Gregory P. Smith [Google LLC] files: A Misc/NEWS.d/next/Security/2022-10-21-13-31-47.gh-issue-98517.SXXGfV.rst M Lib/test/test_hashlib.py M Modules/_sha3/kcp/KeccakSponge.inc diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py index 535f4aa3e04c..9aa6c1f0a3b6 100644 --- a/Lib/test/test_hashlib.py +++ b/Lib/test/test_hashlib.py @@ -495,6 +495,15 @@ def test_case_md5_huge(self, size): def test_case_md5_uintmax(self, size): self.check('md5', b'A'*size, '28138d306ff1b8281f1a9067e1a1a2b3') + @unittest.skipIf(sys.maxsize < _4G - 1, 'test cannot run on 32-bit systems') + @bigmemtest(size=_4G - 1, memuse=1, dry_run=False) + def test_sha3_update_overflow(self, size): + """Regression test for gh-98517 CVE-2022-37454.""" + h = hashlib.sha3_224() + h.update(b'\x01') + h.update(b'\x01'*0xffff_ffff) + self.assertEqual(h.hexdigest(), '80762e8ce6700f114fec0f621fd97c4b9c00147fa052215294cceeed') + # use the three examples from Federal Information Processing Standards # Publication 180-1, Secure Hash Standard, 1995 April 17 # http://www.itl.nist.gov/div897/pubs/fip180-1.htm diff --git a/Misc/NEWS.d/next/Security/2022-10-21-13-31-47.gh-issue-98517.SXXGfV.rst b/Misc/NEWS.d/next/Security/2022-10-21-13-31-47.gh-issue-98517.SXXGfV.rst new file mode 100644 index 000000000000..2d23a6ad93c7 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2022-10-21-13-31-47.gh-issue-98517.SXXGfV.rst @@ -0,0 +1 @@ +Port XKCP's fix for the buffer overflows in SHA-3 (CVE-2022-37454). diff --git a/Modules/_sha3/kcp/KeccakSponge.inc b/Modules/_sha3/kcp/KeccakSponge.inc index e10739deafa8..cf92e4db4d36 100644 --- a/Modules/_sha3/kcp/KeccakSponge.inc +++ b/Modules/_sha3/kcp/KeccakSponge.inc @@ -171,7 +171,7 @@ int SpongeAbsorb(SpongeInstance *instance, const unsigned char *data, size_t dat i = 0; curData = data; while(i < dataByteLen) { - if ((instance->byteIOIndex == 0) && (dataByteLen >= (i + rateInBytes))) { + if ((instance->byteIOIndex == 0) && (dataByteLen-i >= rateInBytes)) { #ifdef SnP_FastLoop_Absorb /* processing full blocks first */ @@ -199,10 +199,10 @@ int SpongeAbsorb(SpongeInstance *instance, const unsigned char *data, size_t dat } else { /* normal lane: using the message queue */ - - partialBlock = (unsigned int)(dataByteLen - i); - if (partialBlock+instance->byteIOIndex > rateInBytes) + if (dataByteLen-i > rateInBytes-instance->byteIOIndex) partialBlock = rateInBytes-instance->byteIOIndex; + else + partialBlock = (unsigned int)(dataByteLen - i); #ifdef KeccakReference displayBytes(1, "Block to be absorbed (part)", curData, partialBlock); #endif @@ -281,7 +281,7 @@ int SpongeSqueeze(SpongeInstance *instance, unsigned char *data, size_t dataByte i = 0; curData = data; while(i < dataByteLen) { - if ((instance->byteIOIndex == rateInBytes) && (dataByteLen >= (i + rateInBytes))) { + if ((instance->byteIOIndex == rateInBytes) && (dataByteLen-i >= rateInBytes)) { for(j=dataByteLen-i; j>=rateInBytes; j-=rateInBytes) { SnP_Permute(instance->state); SnP_ExtractBytes(instance->state, curData, 0, rateInBytes); @@ -299,9 +299,10 @@ int SpongeSqueeze(SpongeInstance *instance, unsigned char *data, size_t dataByte SnP_Permute(instance->state); instance->byteIOIndex = 0; } - partialBlock = (unsigned int)(dataByteLen - i); - if (partialBlock+instance->byteIOIndex > rateInBytes) + if (dataByteLen-i > rateInBytes-instance->byteIOIndex) partialBlock = rateInBytes-instance->byteIOIndex; + else + partialBlock = (unsigned int)(dataByteLen - i); i += partialBlock; SnP_ExtractBytes(instance->state, curData, instance->byteIOIndex, partialBlock); From webhook-mailer at python.org Fri Oct 21 18:36:49 2022 From: webhook-mailer at python.org (ethanfurman) Date: Fri, 21 Oct 2022 22:36:49 -0000 Subject: [Python-checkins] gh-98298: [Enum] document ReprEnum, global_enum, and show_flag_values (GH-98455) Message-ID: https://github.com/python/cpython/commit/3e95ffc7aefb970bfd23e488381eab0dc71532e5 commit: 3e95ffc7aefb970bfd23e488381eab0dc71532e5 branch: main author: Ethan Furman committer: ethanfurman date: 2022-10-21T15:36:41-07:00 summary: gh-98298: [Enum] document ReprEnum, global_enum, and show_flag_values (GH-98455) Co-authored-by: C.A.M. Gerlach files: M Doc/library/enum.rst diff --git a/Doc/library/enum.rst b/Doc/library/enum.rst index a30a7a4ca343..1f317b9013d8 100644 --- a/Doc/library/enum.rst +++ b/Doc/library/enum.rst @@ -92,6 +92,11 @@ Module Contents the bitwise operators without losing their :class:`IntFlag` membership. :class:`IntFlag` members are also subclasses of :class:`int`. (`Notes`_) + :class:`ReprEnum` + + Used by :class:`IntEnum`, :class:`StrEnum`, and :class:`IntFlag` + to keep the :class:`str() ` of the mixed-in type. + :class:`EnumCheck` An enumeration with the values ``CONTINUOUS``, ``NAMED_FLAGS``, and @@ -132,9 +137,20 @@ Module Contents Do not make ``obj`` a member. Can be used as a decorator. + :func:`global_enum` + + Modify the :class:`str() ` and :func:`repr` of an enum + to show its members as belonging to the module instead of its class. + Should only be used if the enum members will be exported to the + module global namespace. + + :func:`show_flag_values` + + Return a list of all power-of-two integers contained in a flag. + .. versionadded:: 3.6 ``Flag``, ``IntFlag``, ``auto`` -.. versionadded:: 3.11 ``StrEnum``, ``EnumCheck``, ``FlagBoundary``, ``property``, ``member``, ``nonmember`` +.. versionadded:: 3.11 ``StrEnum``, ``EnumCheck``, ``ReprEnum``, ``FlagBoundary``, ``property``, ``member``, ``nonmember``, ``global_enum``, ``show_flag_values`` --------------- @@ -573,6 +589,20 @@ Data Types better support the *replacement of existing constants* use-case. :meth:`__format__` was already :func:`int.__format__` for that same reason. +.. class:: ReprEnum + + :class:`!ReprEum` uses the :meth:`repr() ` of :class:`Enum`, + but the :class:`str() ` of the mixed-in data type: + + * :meth:`!int.__str__` for :class:`IntEnum` and :class:`IntFlag` + * :meth:`!str.__str__` for :class:`StrEnum` + + Inherit from :class:`!ReprEnum` to keep the :class:`str() / :func:`format` + of the mixed-in data type instead of using the + :class:`Enum`-default :meth:`str() `. + + + .. versionadded:: 3.11 .. class:: EnumCheck @@ -808,6 +838,22 @@ Utilities and Decorators .. versionadded:: 3.11 +.. decorator:: global_enum + + A decorator to change the :class:`str() ` and :func:`repr` of an enum + to show its members as belonging to the module instead of its class. + Should only be used when the enum members are exported + to the module global namespace (see :class:`re.RegexFlag` for an example). + + + .. versionadded:: 3.11 + +.. function:: show_flag_values(value) + + Return a list of all power-of-two integers contained in a flag *value*. + + .. versionadded:: 3.11 + --------------- Notes From webhook-mailer at python.org Fri Oct 21 18:43:25 2022 From: webhook-mailer at python.org (brettcannon) Date: Fri, 21 Oct 2022 22:43:25 -0000 Subject: [Python-checkins] bpo-2716: add license for audioop module (#19972) Message-ID: https://github.com/python/cpython/commit/4c1145bb3796c550d477c8c154ff980d566fe4a2 commit: 4c1145bb3796c550d477c8c154ff980d566fe4a2 branch: main author: Furkan Onder committer: brettcannon date: 2022-10-21T15:43:20-07:00 summary: bpo-2716: add license for audioop module (#19972) files: M Doc/license.rst M Modules/audioop.c diff --git a/Doc/license.rst b/Doc/license.rst index 54643744dcf9..92059b91effd 100644 --- a/Doc/license.rst +++ b/Doc/license.rst @@ -987,3 +987,28 @@ https://www.w3.org/TR/xml-c14n2-testcases/ and is distributed under the THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Audioop +------- +The audioop module uses the code base in g771.c file of the SoX project:: + Programming the AdLib/Sound Blaster + FM Music Chips + Version 2.0 (24 Feb 1992) + Copyright (c) 1991, 1992 by Jeffrey S. Lee + jlee at smylex.uucp + Warranty and Copyright Policy + This document is provided on an "as-is" basis, and its author makes + no warranty or representation, express or implied, with respect to + its quality performance or fitness for a particular purpose. In no + event will the author of this document be liable for direct, indirect, + special, incidental, or consequential damages arising out of the use + or inability to use the information contained within. Use of this + document is at your own risk. + This file may be used and copied freely so long as the applicable + copyright notices are retained, and no modifications are made to the + text of the document. No money shall be charged for its distribution + beyond reasonable shipping, handling and duplication costs, nor shall + proprietary changes be made to this document so that it cannot be + distributed freely. This document may not be included in published + material or commercial packages without the written consent of its + author. diff --git a/Modules/audioop.c b/Modules/audioop.c index c29a3e8df409..6d484e8bba3e 100644 --- a/Modules/audioop.c +++ b/Modules/audioop.c @@ -1,3 +1,33 @@ +/* The audioop module uses the code base in g777.c file of the Sox project. + * Source: https://web.archive.org/web/19970716121258/http://www.spies.com/Sox/Archive/soxgamma.tar.gz + * Programming the AdLib/Sound Blaster + * FM Music Chips + * Version 2.0 (24 Feb 1992) + * + * Copyright (c) 1991, 1992 by Jeffrey S. Lee + * + * jlee at smylex.uucp + * + * + * + * Warranty and Copyright Policy + * + * This document is provided on an "as-is" basis, and its author makes + * no warranty or representation, express or implied, with respect to + * its quality performance or fitness for a particular purpose. In no + * event will the author of this document be liable for direct, indirect, + * special, incidental, or consequential damages arising out of the use + * or inability to use the information contained within. Use of this + * document is at your own risk. + * + * This file may be used and copied freely so long as the applicable + * copyright notices are retained, and no modifications are made to the + * text of the document. No money shall be charged for its distribution + * beyond reasonable shipping, handling and duplication costs, nor shall + * proprietary changes be made to this document so that it cannot be + * distributed freely. This document may not be included in published + * material or commercial packages without the written consent of its + * author. */ /* audioopmodule - Module to detect peak values in arrays */ @@ -28,20 +58,6 @@ fbound(double val, double minval, double maxval) } -/* Code shamelessly stolen from sox, 12.17.7, g711.c -** (c) Craig Reese, Joe Campbell and Jeff Poskanzer 1989 */ - -/* From g711.c: - * - * December 30, 1994: - * Functions linear2alaw, linear2ulaw have been updated to correctly - * convert unquantized 16 bit values. - * Tables for direct u- to A-law and A- to u-law conversions have been - * corrected. - * Borge Lindberg, Center for PersonKommunikation, Aalborg University. - * bli at cpk.auc.dk - * - */ #define BIAS 0x84 /* define the add-in bias for 16 bit samples */ #define CLIP 32635 #define SIGN_BIT (0x80) /* Sign bit for an A-law byte. */ From webhook-mailer at python.org Fri Oct 21 18:43:29 2022 From: webhook-mailer at python.org (miss-islington) Date: Fri, 21 Oct 2022 22:43:29 -0000 Subject: [Python-checkins] gh-98298: [Enum] document ReprEnum, global_enum, and show_flag_values (GH-98455) Message-ID: https://github.com/python/cpython/commit/31d23ae894d78be11bfc6333469dab25a83c6d46 commit: 31d23ae894d78be11bfc6333469dab25a83c6d46 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-21T15:43:23-07:00 summary: gh-98298: [Enum] document ReprEnum, global_enum, and show_flag_values (GH-98455) Co-authored-by: C.A.M. Gerlach (cherry picked from commit 3e95ffc7aefb970bfd23e488381eab0dc71532e5) Co-authored-by: Ethan Furman files: M Doc/library/enum.rst diff --git a/Doc/library/enum.rst b/Doc/library/enum.rst index 241d19d3bfb3..1abd25dc50a7 100644 --- a/Doc/library/enum.rst +++ b/Doc/library/enum.rst @@ -92,6 +92,11 @@ Module Contents the bitwise operators without losing their :class:`IntFlag` membership. :class:`IntFlag` members are also subclasses of :class:`int`. (`Notes`_) + :class:`ReprEnum` + + Used by :class:`IntEnum`, :class:`StrEnum`, and :class:`IntFlag` + to keep the :class:`str() ` of the mixed-in type. + :class:`EnumCheck` An enumeration with the values ``CONTINUOUS``, ``NAMED_FLAGS``, and @@ -132,9 +137,20 @@ Module Contents Do not make ``obj`` a member. Can be used as a decorator. + :func:`global_enum` + + Modify the :class:`str() ` and :func:`repr` of an enum + to show its members as belonging to the module instead of its class. + Should only be used if the enum members will be exported to the + module global namespace. + + :func:`show_flag_values` + + Return a list of all power-of-two integers contained in a flag. + .. versionadded:: 3.6 ``Flag``, ``IntFlag``, ``auto`` -.. versionadded:: 3.11 ``StrEnum``, ``EnumCheck``, ``FlagBoundary``, ``property``, ``member``, ``nonmember`` +.. versionadded:: 3.11 ``StrEnum``, ``EnumCheck``, ``ReprEnum``, ``FlagBoundary``, ``property``, ``member``, ``nonmember``, ``global_enum``, ``show_flag_values`` --------------- @@ -580,6 +596,20 @@ Data Types better support the *replacement of existing constants* use-case. :meth:`__format__` was already :func:`int.__format__` for that same reason. +.. class:: ReprEnum + + :class:`!ReprEum` uses the :meth:`repr() ` of :class:`Enum`, + but the :class:`str() ` of the mixed-in data type: + + * :meth:`!int.__str__` for :class:`IntEnum` and :class:`IntFlag` + * :meth:`!str.__str__` for :class:`StrEnum` + + Inherit from :class:`!ReprEnum` to keep the :class:`str() / :func:`format` + of the mixed-in data type instead of using the + :class:`Enum`-default :meth:`str() `. + + + .. versionadded:: 3.11 .. class:: EnumCheck @@ -815,6 +845,22 @@ Utilities and Decorators .. versionadded:: 3.11 +.. decorator:: global_enum + + A decorator to change the :class:`str() ` and :func:`repr` of an enum + to show its members as belonging to the module instead of its class. + Should only be used when the enum members are exported + to the module global namespace (see :class:`re.RegexFlag` for an example). + + + .. versionadded:: 3.11 + +.. function:: show_flag_values(value) + + Return a list of all power-of-two integers contained in a flag *value*. + + .. versionadded:: 3.11 + --------------- Notes From webhook-mailer at python.org Fri Oct 21 19:01:14 2022 From: webhook-mailer at python.org (gvanrossum) Date: Fri, 21 Oct 2022 23:01:14 -0000 Subject: [Python-checkins] gh-51511: Note that codecs.open()'s encoding parameter affects automatic conversion to binary mode (#94370) Message-ID: https://github.com/python/cpython/commit/d9407b174c81fda33e6c09a6f988c9a7cb8368af commit: d9407b174c81fda33e6c09a6f988c9a7cb8368af branch: main author: Stanley <46876382+slateny at users.noreply.github.com> committer: gvanrossum date: 2022-10-21T16:01:05-07:00 summary: gh-51511: Note that codecs.open()'s encoding parameter affects automatic conversion to binary mode (#94370) files: M Doc/library/codecs.rst M Lib/codecs.py M Lib/test/test_codecs.py diff --git a/Doc/library/codecs.rst b/Doc/library/codecs.rst index 4a665f2254f8..8225236350d2 100644 --- a/Doc/library/codecs.rst +++ b/Doc/library/codecs.rst @@ -189,7 +189,8 @@ wider range of codecs when working with binary files: .. note:: - Underlying encoded files are always opened in binary mode. + If *encoding* is not ``None``, then the + underlying encoded files are always opened in binary mode. No automatic conversion of ``'\n'`` is done on reading and writing. The *mode* argument may be any binary mode acceptable to the built-in :func:`open` function; the ``'b'`` is automatically added. diff --git a/Lib/codecs.py b/Lib/codecs.py index 5a1e7ec80400..c1c55d8afef3 100644 --- a/Lib/codecs.py +++ b/Lib/codecs.py @@ -878,7 +878,8 @@ def open(filename, mode='r', encoding=None, errors='strict', buffering=-1): codecs. Output is also codec dependent and will usually be Unicode as well. - Underlying encoded files are always opened in binary mode. + If encoding is not None, then the + underlying encoded files are always opened in binary mode. The default file mode is 'r', meaning to open the file in read mode. encoding specifies the encoding which is to be used for the diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py index 57f3648eb701..32a704f4e97e 100644 --- a/Lib/test/test_codecs.py +++ b/Lib/test/test_codecs.py @@ -708,7 +708,8 @@ def test_decoder_state(self): "spamspam", self.spambe) def test_bug691291(self): - # Files are always opened in binary mode, even if no binary mode was + # If encoding is not None, then + # files are always opened in binary mode, even if no binary mode was # specified. This means that no automatic conversion of '\n' is done # on reading and writing. s1 = 'Hello\r\nworld\r\n' From webhook-mailer at python.org Fri Oct 21 19:07:36 2022 From: webhook-mailer at python.org (miss-islington) Date: Fri, 21 Oct 2022 23:07:36 -0000 Subject: [Python-checkins] bpo-2716: add license for audioop module (GH-19972) Message-ID: https://github.com/python/cpython/commit/68f25e261e8df51e357dc0b6660ca771eac1e87f commit: 68f25e261e8df51e357dc0b6660ca771eac1e87f branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-21T16:07:30-07:00 summary: bpo-2716: add license for audioop module (GH-19972) (cherry picked from commit 4c1145bb3796c550d477c8c154ff980d566fe4a2) Co-authored-by: Furkan Onder files: M Doc/license.rst M Modules/audioop.c diff --git a/Doc/license.rst b/Doc/license.rst index 00691b30ba6d..ea1edc432556 100644 --- a/Doc/license.rst +++ b/Doc/license.rst @@ -984,3 +984,28 @@ https://www.w3.org/TR/xml-c14n2-testcases/ and is distributed under the THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Audioop +------- +The audioop module uses the code base in g771.c file of the SoX project:: + Programming the AdLib/Sound Blaster + FM Music Chips + Version 2.0 (24 Feb 1992) + Copyright (c) 1991, 1992 by Jeffrey S. Lee + jlee at smylex.uucp + Warranty and Copyright Policy + This document is provided on an "as-is" basis, and its author makes + no warranty or representation, express or implied, with respect to + its quality performance or fitness for a particular purpose. In no + event will the author of this document be liable for direct, indirect, + special, incidental, or consequential damages arising out of the use + or inability to use the information contained within. Use of this + document is at your own risk. + This file may be used and copied freely so long as the applicable + copyright notices are retained, and no modifications are made to the + text of the document. No money shall be charged for its distribution + beyond reasonable shipping, handling and duplication costs, nor shall + proprietary changes be made to this document so that it cannot be + distributed freely. This document may not be included in published + material or commercial packages without the written consent of its + author. diff --git a/Modules/audioop.c b/Modules/audioop.c index d74e634ac448..b764dd97d535 100644 --- a/Modules/audioop.c +++ b/Modules/audioop.c @@ -1,3 +1,33 @@ +/* The audioop module uses the code base in g777.c file of the Sox project. + * Source: https://web.archive.org/web/19970716121258/http://www.spies.com/Sox/Archive/soxgamma.tar.gz + * Programming the AdLib/Sound Blaster + * FM Music Chips + * Version 2.0 (24 Feb 1992) + * + * Copyright (c) 1991, 1992 by Jeffrey S. Lee + * + * jlee at smylex.uucp + * + * + * + * Warranty and Copyright Policy + * + * This document is provided on an "as-is" basis, and its author makes + * no warranty or representation, express or implied, with respect to + * its quality performance or fitness for a particular purpose. In no + * event will the author of this document be liable for direct, indirect, + * special, incidental, or consequential damages arising out of the use + * or inability to use the information contained within. Use of this + * document is at your own risk. + * + * This file may be used and copied freely so long as the applicable + * copyright notices are retained, and no modifications are made to the + * text of the document. No money shall be charged for its distribution + * beyond reasonable shipping, handling and duplication costs, nor shall + * proprietary changes be made to this document so that it cannot be + * distributed freely. This document may not be included in published + * material or commercial packages without the written consent of its + * author. */ /* audioopmodule - Module to detect peak values in arrays */ @@ -28,20 +58,6 @@ fbound(double val, double minval, double maxval) } -/* Code shamelessly stolen from sox, 12.17.7, g711.c -** (c) Craig Reese, Joe Campbell and Jeff Poskanzer 1989 */ - -/* From g711.c: - * - * December 30, 1994: - * Functions linear2alaw, linear2ulaw have been updated to correctly - * convert unquantized 16 bit values. - * Tables for direct u- to A-law and A- to u-law conversions have been - * corrected. - * Borge Lindberg, Center for PersonKommunikation, Aalborg University. - * bli at cpk.auc.dk - * - */ #define BIAS 0x84 /* define the add-in bias for 16 bit samples */ #define CLIP 32635 #define SIGN_BIT (0x80) /* Sign bit for an A-law byte. */ From webhook-mailer at python.org Fri Oct 21 19:27:47 2022 From: webhook-mailer at python.org (miss-islington) Date: Fri, 21 Oct 2022 23:27:47 -0000 Subject: [Python-checkins] gh-51511: Note that codecs.open()'s encoding parameter affects automatic conversion to binary mode (GH-94370) Message-ID: https://github.com/python/cpython/commit/c835b97c5f9f057fd6346b661be32ff0b2c060e7 commit: c835b97c5f9f057fd6346b661be32ff0b2c060e7 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-21T16:27:41-07:00 summary: gh-51511: Note that codecs.open()'s encoding parameter affects automatic conversion to binary mode (GH-94370) (cherry picked from commit d9407b174c81fda33e6c09a6f988c9a7cb8368af) Co-authored-by: Stanley <46876382+slateny at users.noreply.github.com> files: M Doc/library/codecs.rst M Lib/codecs.py M Lib/test/test_codecs.py diff --git a/Doc/library/codecs.rst b/Doc/library/codecs.rst index 4a665f2254f8..8225236350d2 100644 --- a/Doc/library/codecs.rst +++ b/Doc/library/codecs.rst @@ -189,7 +189,8 @@ wider range of codecs when working with binary files: .. note:: - Underlying encoded files are always opened in binary mode. + If *encoding* is not ``None``, then the + underlying encoded files are always opened in binary mode. No automatic conversion of ``'\n'`` is done on reading and writing. The *mode* argument may be any binary mode acceptable to the built-in :func:`open` function; the ``'b'`` is automatically added. diff --git a/Lib/codecs.py b/Lib/codecs.py index e6ad6e3a0523..3b173b612101 100644 --- a/Lib/codecs.py +++ b/Lib/codecs.py @@ -878,7 +878,8 @@ def open(filename, mode='r', encoding=None, errors='strict', buffering=-1): codecs. Output is also codec dependent and will usually be Unicode as well. - Underlying encoded files are always opened in binary mode. + If encoding is not None, then the + underlying encoded files are always opened in binary mode. The default file mode is 'r', meaning to open the file in read mode. encoding specifies the encoding which is to be used for the diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py index 42c600dcb00d..7cabe6a83a2a 100644 --- a/Lib/test/test_codecs.py +++ b/Lib/test/test_codecs.py @@ -709,7 +709,8 @@ def test_decoder_state(self): "spamspam", self.spambe) def test_bug691291(self): - # Files are always opened in binary mode, even if no binary mode was + # If encoding is not None, then + # files are always opened in binary mode, even if no binary mode was # specified. This means that no automatic conversion of '\n' is done # on reading and writing. s1 = 'Hello\r\nworld\r\n' From webhook-mailer at python.org Fri Oct 21 19:28:31 2022 From: webhook-mailer at python.org (miss-islington) Date: Fri, 21 Oct 2022 23:28:31 -0000 Subject: [Python-checkins] gh-51511: Note that codecs.open()'s encoding parameter affects automatic conversion to binary mode (GH-94370) Message-ID: https://github.com/python/cpython/commit/dcb342b5f9d931b030ca310bf3e175bbc54df5aa commit: dcb342b5f9d931b030ca310bf3e175bbc54df5aa branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-21T16:28:25-07:00 summary: gh-51511: Note that codecs.open()'s encoding parameter affects automatic conversion to binary mode (GH-94370) (cherry picked from commit d9407b174c81fda33e6c09a6f988c9a7cb8368af) Co-authored-by: Stanley <46876382+slateny at users.noreply.github.com> files: M Doc/library/codecs.rst M Lib/codecs.py M Lib/test/test_codecs.py diff --git a/Doc/library/codecs.rst b/Doc/library/codecs.rst index 1c10462c1509..7d56327aad26 100644 --- a/Doc/library/codecs.rst +++ b/Doc/library/codecs.rst @@ -189,7 +189,8 @@ wider range of codecs when working with binary files: .. note:: - Underlying encoded files are always opened in binary mode. + If *encoding* is not ``None``, then the + underlying encoded files are always opened in binary mode. No automatic conversion of ``'\n'`` is done on reading and writing. The *mode* argument may be any binary mode acceptable to the built-in :func:`open` function; the ``'b'`` is automatically added. diff --git a/Lib/codecs.py b/Lib/codecs.py index e6ad6e3a0523..3b173b612101 100644 --- a/Lib/codecs.py +++ b/Lib/codecs.py @@ -878,7 +878,8 @@ def open(filename, mode='r', encoding=None, errors='strict', buffering=-1): codecs. Output is also codec dependent and will usually be Unicode as well. - Underlying encoded files are always opened in binary mode. + If encoding is not None, then the + underlying encoded files are always opened in binary mode. The default file mode is 'r', meaning to open the file in read mode. encoding specifies the encoding which is to be used for the diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py index a9c43d9554be..8edd5ac0633e 100644 --- a/Lib/test/test_codecs.py +++ b/Lib/test/test_codecs.py @@ -705,7 +705,8 @@ def test_decoder_state(self): "spamspam", self.spambe) def test_bug691291(self): - # Files are always opened in binary mode, even if no binary mode was + # If encoding is not None, then + # files are always opened in binary mode, even if no binary mode was # specified. This means that no automatic conversion of '\n' is done # on reading and writing. s1 = 'Hello\r\nworld\r\n' From webhook-mailer at python.org Fri Oct 21 19:44:54 2022 From: webhook-mailer at python.org (rhettinger) Date: Fri, 21 Oct 2022 23:44:54 -0000 Subject: [Python-checkins] GH-98363: Use better accessor macro (#98535) Message-ID: https://github.com/python/cpython/commit/8d574234d49acf3472f7151ee4296da0f297d6f2 commit: 8d574234d49acf3472f7151ee4296da0f297d6f2 branch: main author: Raymond Hettinger committer: rhettinger date: 2022-10-21T18:44:49-05:00 summary: GH-98363: Use better accessor macro (#98535) files: M Modules/itertoolsmodule.c diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index 627e698fc6b9..578c2d942885 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -155,7 +155,7 @@ batched_next(batchedobject *bo) return NULL; } iternextfunc iternext = *Py_TYPE(it)->tp_iternext; - PyObject **items = PySequence_Fast_ITEMS(result); + PyObject **items = _PyList_ITEMS(result); for (i=0 ; i < n ; i++) { item = iternext(it); if (item == NULL) { From webhook-mailer at python.org Fri Oct 21 23:38:28 2022 From: webhook-mailer at python.org (ned-deily) Date: Sat, 22 Oct 2022 03:38:28 -0000 Subject: [Python-checkins] [3.7] gh-98517: Fix buffer overflows in _sha3 module (GH-98519) (GH-98528) Message-ID: https://github.com/python/cpython/commit/8088c90044ba04cd5624b278340ebf934dbee4a5 commit: 8088c90044ba04cd5624b278340ebf934dbee4a5 branch: 3.7 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ned-deily date: 2022-10-21T23:37:54-04:00 summary: [3.7] gh-98517: Fix buffer overflows in _sha3 module (GH-98519) (GH-98528) This is a port of the applicable part of XKCP's fix [1] for CVE-2022-37454 and avoids the segmentation fault and the infinite loop in the test cases published in [2]. [1]: https://github.com/XKCP/XKCP/commit/fdc6fef075f4e81d6b1bc38364248975e08e340a [2]: https://mouha.be/sha-3-buffer-overflow/ Regression test added by: Gregory P. Smith [Google LLC] (cherry picked from commit 0e4e058602d93b88256ff90bbef501ba20be9dd3) Co-authored-by: Theo Buehler files: A Misc/NEWS.d/next/Security/2022-10-21-13-31-47.gh-issue-98517.SXXGfV.rst M Lib/test/test_hashlib.py M Modules/_sha3/kcp/KeccakSponge.inc diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py index fc0649d670d2..2bf96de4e0e7 100644 --- a/Lib/test/test_hashlib.py +++ b/Lib/test/test_hashlib.py @@ -415,6 +415,15 @@ def test_case_md5_huge(self, size): def test_case_md5_uintmax(self, size): self.check('md5', b'A'*size, '28138d306ff1b8281f1a9067e1a1a2b3') + @unittest.skipIf(sys.maxsize < _4G - 1, 'test cannot run on 32-bit systems') + @bigmemtest(size=_4G - 1, memuse=1, dry_run=False) + def test_sha3_update_overflow(self, size): + """Regression test for gh-98517 CVE-2022-37454.""" + h = hashlib.sha3_224() + h.update(b'\x01') + h.update(b'\x01'*0xffff_ffff) + self.assertEqual(h.hexdigest(), '80762e8ce6700f114fec0f621fd97c4b9c00147fa052215294cceeed') + # use the three examples from Federal Information Processing Standards # Publication 180-1, Secure Hash Standard, 1995 April 17 # http://www.itl.nist.gov/div897/pubs/fip180-1.htm diff --git a/Misc/NEWS.d/next/Security/2022-10-21-13-31-47.gh-issue-98517.SXXGfV.rst b/Misc/NEWS.d/next/Security/2022-10-21-13-31-47.gh-issue-98517.SXXGfV.rst new file mode 100644 index 000000000000..2d23a6ad93c7 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2022-10-21-13-31-47.gh-issue-98517.SXXGfV.rst @@ -0,0 +1 @@ +Port XKCP's fix for the buffer overflows in SHA-3 (CVE-2022-37454). diff --git a/Modules/_sha3/kcp/KeccakSponge.inc b/Modules/_sha3/kcp/KeccakSponge.inc index e10739deafa8..cf92e4db4d36 100644 --- a/Modules/_sha3/kcp/KeccakSponge.inc +++ b/Modules/_sha3/kcp/KeccakSponge.inc @@ -171,7 +171,7 @@ int SpongeAbsorb(SpongeInstance *instance, const unsigned char *data, size_t dat i = 0; curData = data; while(i < dataByteLen) { - if ((instance->byteIOIndex == 0) && (dataByteLen >= (i + rateInBytes))) { + if ((instance->byteIOIndex == 0) && (dataByteLen-i >= rateInBytes)) { #ifdef SnP_FastLoop_Absorb /* processing full blocks first */ @@ -199,10 +199,10 @@ int SpongeAbsorb(SpongeInstance *instance, const unsigned char *data, size_t dat } else { /* normal lane: using the message queue */ - - partialBlock = (unsigned int)(dataByteLen - i); - if (partialBlock+instance->byteIOIndex > rateInBytes) + if (dataByteLen-i > rateInBytes-instance->byteIOIndex) partialBlock = rateInBytes-instance->byteIOIndex; + else + partialBlock = (unsigned int)(dataByteLen - i); #ifdef KeccakReference displayBytes(1, "Block to be absorbed (part)", curData, partialBlock); #endif @@ -281,7 +281,7 @@ int SpongeSqueeze(SpongeInstance *instance, unsigned char *data, size_t dataByte i = 0; curData = data; while(i < dataByteLen) { - if ((instance->byteIOIndex == rateInBytes) && (dataByteLen >= (i + rateInBytes))) { + if ((instance->byteIOIndex == rateInBytes) && (dataByteLen-i >= rateInBytes)) { for(j=dataByteLen-i; j>=rateInBytes; j-=rateInBytes) { SnP_Permute(instance->state); SnP_ExtractBytes(instance->state, curData, 0, rateInBytes); @@ -299,9 +299,10 @@ int SpongeSqueeze(SpongeInstance *instance, unsigned char *data, size_t dataByte SnP_Permute(instance->state); instance->byteIOIndex = 0; } - partialBlock = (unsigned int)(dataByteLen - i); - if (partialBlock+instance->byteIOIndex > rateInBytes) + if (dataByteLen-i > rateInBytes-instance->byteIOIndex) partialBlock = rateInBytes-instance->byteIOIndex; + else + partialBlock = (unsigned int)(dataByteLen - i); i += partialBlock; SnP_ExtractBytes(instance->state, curData, instance->byteIOIndex, partialBlock); From webhook-mailer at python.org Sat Oct 22 07:29:10 2022 From: webhook-mailer at python.org (AlexWaygood) Date: Sat, 22 Oct 2022 11:29:10 -0000 Subject: [Python-checkins] [Enum docs]: fix order of arguments to isinstance() (#98542) Message-ID: https://github.com/python/cpython/commit/327fc1c6fa11b007213287cbf46380b7afed9be3 commit: 327fc1c6fa11b007213287cbf46380b7afed9be3 branch: main author: Cl?ment Robert committer: AlexWaygood date: 2022-10-22T12:29:00+01:00 summary: [Enum docs]: fix order of arguments to isinstance() (#98542) files: M Doc/library/enum.rst diff --git a/Doc/library/enum.rst b/Doc/library/enum.rst index 1f317b9013d8..dcced28b8508 100644 --- a/Doc/library/enum.rst +++ b/Doc/library/enum.rst @@ -427,7 +427,7 @@ Data Types .. note:: There are places in the stdlib that check for an exact :class:`str` instead of a :class:`str` subclass (i.e. ``type(unknown) == str`` - instead of ``isinstance(str, unknown)``), and in those locations you + instead of ``isinstance(unknown, str)``), and in those locations you will need to use ``str(StrEnum.member)``. .. note:: From webhook-mailer at python.org Sat Oct 22 07:36:07 2022 From: webhook-mailer at python.org (miss-islington) Date: Sat, 22 Oct 2022 11:36:07 -0000 Subject: [Python-checkins] [Enum docs]: fix order of arguments to isinstance() (GH-98542) Message-ID: https://github.com/python/cpython/commit/3cd39e9399796ebbf54fbc9402a21c98dfddb6a8 commit: 3cd39e9399796ebbf54fbc9402a21c98dfddb6a8 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-22T04:36:01-07:00 summary: [Enum docs]: fix order of arguments to isinstance() (GH-98542) (cherry picked from commit 327fc1c6fa11b007213287cbf46380b7afed9be3) Co-authored-by: Cl?ment Robert files: M Doc/library/enum.rst diff --git a/Doc/library/enum.rst b/Doc/library/enum.rst index 1abd25dc50a7..d666fa96e7cc 100644 --- a/Doc/library/enum.rst +++ b/Doc/library/enum.rst @@ -434,7 +434,7 @@ Data Types .. note:: There are places in the stdlib that check for an exact :class:`str` instead of a :class:`str` subclass (i.e. ``type(unknown) == str`` - instead of ``isinstance(str, unknown)``), and in those locations you + instead of ``isinstance(unknown, str)``), and in those locations you will need to use ``str(StrEnum.member)``. .. note:: From webhook-mailer at python.org Sat Oct 22 07:59:18 2022 From: webhook-mailer at python.org (AlexWaygood) Date: Sat, 22 Oct 2022 11:59:18 -0000 Subject: [Python-checkins] Fix typo in news entry (#98361) Message-ID: https://github.com/python/cpython/commit/f7f55a5b9e37d7172ec47030484865b8c585ff46 commit: f7f55a5b9e37d7172ec47030484865b8c585ff46 branch: main author: Ikko Ashimine committer: AlexWaygood date: 2022-10-22T12:59:12+01:00 summary: Fix typo in news entry (#98361) ouput -> output files: M Misc/NEWS.d/next/Windows/2022-08-30-12-01-51.gh-issue-94781.OxO-Gr.rst diff --git a/Misc/NEWS.d/next/Windows/2022-08-30-12-01-51.gh-issue-94781.OxO-Gr.rst b/Misc/NEWS.d/next/Windows/2022-08-30-12-01-51.gh-issue-94781.OxO-Gr.rst index d343173d40d6..2eaa83fa850d 100644 --- a/Misc/NEWS.d/next/Windows/2022-08-30-12-01-51.gh-issue-94781.OxO-Gr.rst +++ b/Misc/NEWS.d/next/Windows/2022-08-30-12-01-51.gh-issue-94781.OxO-Gr.rst @@ -1,2 +1,2 @@ -Fix :file:`pcbuild.proj` to clean previous instances of ouput files in ``Python\deepfreeze`` and +Fix :file:`pcbuild.proj` to clean previous instances of output files in ``Python\deepfreeze`` and ``Python\frozen_modules`` directories on Windows. Patch by Charlie Zhao. From webhook-mailer at python.org Sat Oct 22 08:00:32 2022 From: webhook-mailer at python.org (AlexWaygood) Date: Sat, 22 Oct 2022 12:00:32 -0000 Subject: [Python-checkins] [3.11] gh-98378: Add small format string example to strftime comments (GH-98379) (#98395) Message-ID: https://github.com/python/cpython/commit/9713cace26eac16c03e99c863079561ad7b8df1c commit: 9713cace26eac16c03e99c863079561ad7b8df1c branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: AlexWaygood date: 2022-10-22T13:00:26+01:00 summary: [3.11] gh-98378: Add small format string example to strftime comments (GH-98379) (#98395) gh-98378: Add small format string example to strftime comments (GH-98379) A small example of what a full date and time would look like would help a lot of developers who may not realize that they should investigate `time.h`'s `strftime`, run `man strftime`, or click through a series of docs on the python docs before they get to the actual [definition here](https://docs.python.org/3/library/datetime.htmlGH-strftime-and-strptime-format-codes) which still doesn't have an obvious copy-pastable example of "what the heck format does this thing actually expect?". Automerge-Triggered-By: GH:rhettinger (cherry picked from commit 6ccca69d0d313135b2fbb2aa92c69c315be779c6) Co-authored-by: Alex Zvorygin Co-authored-by: Alex Zvorygin Co-authored-by: Alex Waygood files: M Lib/datetime.py diff --git a/Lib/datetime.py b/Lib/datetime.py index 00ded32cc3e3..c3c2568f9865 100644 --- a/Lib/datetime.py +++ b/Lib/datetime.py @@ -1030,7 +1030,11 @@ def ctime(self): self._day, self._year) def strftime(self, fmt): - "Format using strftime()." + """ + Format using strftime(). + + Example: "%d/%m/%Y, %H:%M:%S" + """ return _wrap_strftime(self, fmt, self.timetuple()) def __format__(self, fmt): From webhook-mailer at python.org Sat Oct 22 08:21:14 2022 From: webhook-mailer at python.org (rhettinger) Date: Sat, 22 Oct 2022 12:21:14 -0000 Subject: [Python-checkins] GH-98363: Slicing isn't necessary. A size reduction will suffice. (GH-98538) Message-ID: https://github.com/python/cpython/commit/5871e19942fdcf83653924ae9a849941669c1143 commit: 5871e19942fdcf83653924ae9a849941669c1143 branch: main author: Raymond Hettinger committer: rhettinger date: 2022-10-22T07:21:06-05:00 summary: GH-98363: Slicing isn't necessary. A size reduction will suffice. (GH-98538) files: M Modules/itertoolsmodule.c diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index 578c2d942885..381ec3b31d52 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -167,23 +167,22 @@ batched_next(batchedobject *bo) null_item: if (PyErr_Occurred()) { - if (PyErr_ExceptionMatches(PyExc_StopIteration)) { - PyErr_Clear(); - } else { - /* input raised an exception other than StopIteration */ + if (!PyErr_ExceptionMatches(PyExc_StopIteration)) { + /* Input raised an exception other than StopIteration */ Py_CLEAR(bo->it); Py_DECREF(result); return NULL; } + PyErr_Clear(); } if (i == 0) { Py_CLEAR(bo->it); Py_DECREF(result); return NULL; } - PyObject *short_list = PyList_GetSlice(result, 0, i); - Py_DECREF(result); - return short_list; + /* Elements in result[i:] are still NULL */ + Py_SET_SIZE(result, i); + return result; } static PyTypeObject batched_type = { From webhook-mailer at python.org Sat Oct 22 12:05:16 2022 From: webhook-mailer at python.org (gvanrossum) Date: Sat, 22 Oct 2022 16:05:16 -0000 Subject: [Python-checkins] GH-98543: Fix `asyncio.TaskGroup` to not keep reference to errors after raising ExceptionGroup (#98544) Message-ID: https://github.com/python/cpython/commit/f4a14941e6e54b15012fca067f6a9b2ff29f201a commit: f4a14941e6e54b15012fca067f6a9b2ff29f201a branch: main author: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> committer: gvanrossum date: 2022-10-22T09:05:11-07:00 summary: GH-98543: Fix `asyncio.TaskGroup` to not keep reference to errors after raising ExceptionGroup (#98544) files: M Lib/asyncio/taskgroups.py diff --git a/Lib/asyncio/taskgroups.py b/Lib/asyncio/taskgroups.py index 5d5e2a8a85dd..911419e1769c 100644 --- a/Lib/asyncio/taskgroups.py +++ b/Lib/asyncio/taskgroups.py @@ -128,11 +128,11 @@ async def __aexit__(self, et, exc, tb): # Exceptions are heavy objects that can have object # cycles (bad for GC); let's not keep a reference to # a bunch of them. - errors = self._errors - self._errors = None - - me = BaseExceptionGroup('unhandled errors in a TaskGroup', errors) - raise me from None + try: + me = BaseExceptionGroup('unhandled errors in a TaskGroup', self._errors) + raise me from None + finally: + self._errors = None def create_task(self, coro, *, name=None, context=None): if not self._entered: From webhook-mailer at python.org Sat Oct 22 12:11:32 2022 From: webhook-mailer at python.org (gvanrossum) Date: Sat, 22 Oct 2022 16:11:32 -0000 Subject: [Python-checkins] GH-98539: fix ref cycle in `_SSLProtocolTransport` after close (#98540) Message-ID: https://github.com/python/cpython/commit/62bf5d8d0a36112619436a813ceefb7e4af52c24 commit: 62bf5d8d0a36112619436a813ceefb7e4af52c24 branch: main author: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> committer: gvanrossum date: 2022-10-22T09:11:27-07:00 summary: GH-98539: fix ref cycle in `_SSLProtocolTransport` after close (#98540) files: M Lib/asyncio/sslproto.py diff --git a/Lib/asyncio/sslproto.py b/Lib/asyncio/sslproto.py index de00953cc1d0..5cb5cd35883f 100644 --- a/Lib/asyncio/sslproto.py +++ b/Lib/asyncio/sslproto.py @@ -107,8 +107,11 @@ def close(self): protocol's connection_lost() method will (eventually) called with None as its argument. """ - self._closed = True - self._ssl_protocol._start_shutdown() + if not self._closed: + self._closed = True + self._ssl_protocol._start_shutdown() + else: + self._ssl_protocol = None def __del__(self, _warnings=warnings): if not self._closed: From webhook-mailer at python.org Sat Oct 22 15:12:11 2022 From: webhook-mailer at python.org (pablogsal) Date: Sat, 22 Oct 2022 19:12:11 -0000 Subject: [Python-checkins] gh-95913: Copyedit & xref FrameInfo in Whatsnew inspect section (#98304) Message-ID: https://github.com/python/cpython/commit/8f30267ab49e1ef3ac3165a102b2196336547c8a commit: 8f30267ab49e1ef3ac3165a102b2196336547c8a branch: main author: C.A.M. Gerlach committer: pablogsal date: 2022-10-22T20:12:04+01:00 summary: gh-95913: Copyedit & xref FrameInfo in Whatsnew inspect section (#98304) files: M Doc/library/inspect.rst M Doc/whatsnew/3.11.rst diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index 700cd9122cd3..44f1ae04c9e3 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -434,8 +434,10 @@ attributes: Return ``True`` if the type of object is a :class:`~types.MethodWrapperType`. - These are instances of :class:`~types.MethodWrapperType`, such as :meth:`~object().__str__`, - :meth:`~object().__eq__` and :meth:`~object().__repr__` + These are instances of :class:`~types.MethodWrapperType`, such as :meth:`~object.__str__`, + :meth:`~object.__eq__` and :meth:`~object.__repr__`. + + .. versionadded:: 3.11 .. function:: isroutine(object) @@ -1206,12 +1208,13 @@ is considered deprecated and may be removed in the future. number, start column offset, and end column offset associated with the instruction being executed by the frame this record corresponds to. -.. versionchanged:: 3.5 - Return a named tuple instead of a tuple. + .. versionchanged:: 3.5 + Return a :term:`named tuple` instead of a :class:`tuple`. + + .. versionchanged:: 3.11 + :class:`!FrameInfo` is now a class instance + (that is backwards compatible with the previous :term:`named tuple`). -.. versionchanged:: 3.11 - Changed the return object from a named tuple to a regular object (that is - backwards compatible with the previous named tuple). .. class:: Traceback @@ -1245,6 +1248,11 @@ is considered deprecated and may be removed in the future. the instruction being executed by the frame this traceback corresponds to. + .. versionchanged:: 3.11 + :class:`!Traceback` is now a class instance + (that is backwards compatible with the previous :term:`named tuple`). + + .. note:: Keeping references to frame objects, as found in the first element of the frame diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 46c5692c8449..5ce16ab5b5c0 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -775,22 +775,33 @@ IDLE and idlelib * Include prompts when saving Shell with inputs and outputs. (Contributed by Terry Jan Reedy in :gh:`95191`.) + +.. _whatsnew311-inspect: + inspect ------- -* Add :func:`inspect.getmembers_static`: return all members without + +* Add :func:`~inspect.getmembers_static` to return all members without triggering dynamic lookup via the descriptor protocol. (Contributed by Weipeng Hong in :issue:`30533`.) -* Add :func:`inspect.ismethodwrapper` for checking if the type of an object is a - :class:`~types.MethodWrapperType`. (Contributed by Hakan ?elik in :issue:`29418`.) +* Add :func:`~inspect.ismethodwrapper` + for checking if the type of an object is a :class:`~types.MethodWrapperType`. + (Contributed by Hakan ?elik in :issue:`29418`.) -* Change the frame-related functions in the :mod:`inspect` module to return a - regular object (that is backwards compatible with the old tuple-like - interface) that include the extended :pep:`657` position information (end +* Change the frame-related functions in the :mod:`inspect` module to return new + :class:`~inspect.FrameInfo` and :class:`~inspect.Traceback` class instances + (backwards compatible with the previous :term:`named tuple`-like interfaces) + that includes the extended :pep:`657` position information (end line number, column and end column). The affected functions are: - :func:`inspect.getframeinfo`, :func:`inspect.getouterframes`, :func:`inspect.getinnerframes`, - :func:`inspect.stack` and :func:`inspect.trace`. (Contributed by Pablo Galindo in - :gh:`88116`.) + + * :func:`inspect.getframeinfo` + * :func:`inspect.getouterframes` + * :func:`inspect.getinnerframes`, + * :func:`inspect.stack` + * :func:`inspect.trace` + + (Contributed by Pablo Galindo in :gh:`88116`.) locale ------ From webhook-mailer at python.org Sat Oct 22 15:14:16 2022 From: webhook-mailer at python.org (pablogsal) Date: Sat, 22 Oct 2022 19:14:16 -0000 Subject: [Python-checkins] gh-95913: Edit & expand Optimizations in 3.11 WhatsNew (#98426) Message-ID: https://github.com/python/cpython/commit/f58631be1148ee5436bb71d175d3993e3e6b4e1e commit: f58631be1148ee5436bb71d175d3993e3e6b4e1e branch: main author: C.A.M. Gerlach committer: pablogsal date: 2022-10-22T20:14:11+01:00 summary: gh-95913: Edit & expand Optimizations in 3.11 WhatsNew (#98426) files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 5ce16ab5b5c0..c143a418f3c5 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1171,33 +1171,52 @@ fcntl Optimizations ============= -* Compiler now optimizes simple C-style formatting with literal format - containing only format codes ``%s``, ``%r`` and ``%a`` and makes it as - fast as corresponding f-string expression. +This section covers specific optimizations independent of the +:ref:`whatsnew311-faster-cpython` project, which is covered in its own section. + +* The compiler now optimizes simple + :ref:`printf-style % formatting ` on string literals + containing only the format codes ``%s``, ``%r`` and ``%a`` and makes it as + fast as a corresponding :term:`f-string` expression. (Contributed by Serhiy Storchaka in :issue:`28307`.) -* "Zero-cost" exceptions are implemented. The cost of ``try`` statements is - almost eliminated when no exception is raised. - (Contributed by Mark Shannon in :issue:`40222`.) +* Integer division (``//``) is better tuned for optimization by compilers. + It is now around 20% faster on x86-64 when dividing an :class:`int` + by a value smaller than ``2**30``. + (Contributed by Gregory P. Smith and Tim Peters in :gh:`90564`.) -* Pure ASCII strings are now normalized in constant time by :func:`unicodedata.normalize`. - (Contributed by Dong-hee Na in :issue:`44987`.) +* :func:`sum` is now nearly 30% faster for integers smaller than ``2**30``. + (Contributed by Stefan Behnel in :gh:`68264`.) -* :mod:`math` functions :func:`~math.comb` and :func:`~math.perm` are now up - to 10 times or more faster for large arguments (the speed up is larger for - larger *k*). - (Contributed by Serhiy Storchaka in :issue:`37295`.) +* Resizing lists is streamlined for the common case, + speeding up :meth:`list.append` by ?15% + and simple :term:`list comprehension`\s by up to 20-30% + (Contributed by Dennis Sweeney in :gh:`91165`.) -* Dict don't store hash value when all inserted keys are Unicode objects. - This reduces dict size. For example, ``sys.getsizeof(dict.fromkeys("abcdefg"))`` - becomes 272 bytes from 352 bytes on 64bit platform. +* Dictionaries don't store hash values when all keys are Unicode objects, + decreasing :class:`dict` size. + For example, ``sys.getsizeof(dict.fromkeys("abcdefg"))`` + is reduced from 352 bytes to 272 bytes (23% smaller) on 64-bit platforms. (Contributed by Inada Naoki in :issue:`46845`.) -* :mod:`re`'s regular expression matching engine has been partially refactored, - and now uses computed gotos (or "threaded code") on supported platforms. As a - result, Python 3.11 executes the `pyperformance regular expression benchmarks - `_ up to 10% - faster than Python 3.10. +* Using :class:`asyncio.DatagramProtocol` is now orders of magnitude faster + when transferring large files over UDP, + with speeds over 100 times higher for a ?60 MiB file. + (Contributed by msoxzw in :gh:`91487`.) + +* :mod:`math` functions :func:`~math.comb` and :func:`~math.perm` are now + ?10 times faster for large arguments (with a larger speedup for larger *k*). + (Contributed by Serhiy Storchaka in :issue:`37295`.) + +* The :mod:`statistics` functions :func:`~statistics.mean`, + :func:`~statistics.variance` and :func:`~statistics.stdev` now consume + iterators in one pass rather than converting them to a :class:`list` first. + This is twice as fast and can save substantial memory. + (Contributed by Raymond Hettinger in :gh:`90415`.) + +* :func:`unicodedata.normalize` + now normalizes pure-ASCII strings in constant time. + (Contributed by Dong-hee Na in :issue:`44987`.) .. _whatsnew311-faster-cpython: From webhook-mailer at python.org Sat Oct 22 15:19:02 2022 From: webhook-mailer at python.org (pablogsal) Date: Sat, 22 Oct 2022 19:19:02 -0000 Subject: [Python-checkins] [3.11] gh-95913: Edit & expand Optimizations in 3.11 WhatsNew (GH-98426) (#98554) Message-ID: https://github.com/python/cpython/commit/24e8d0cf70dc0f6ca33cc41e82ffdfe4587b4cf3 commit: 24e8d0cf70dc0f6ca33cc41e82ffdfe4587b4cf3 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: pablogsal date: 2022-10-22T20:18:57+01:00 summary: [3.11] gh-95913: Edit & expand Optimizations in 3.11 WhatsNew (GH-98426) (#98554) gh-95913: Edit & expand Optimizations in 3.11 WhatsNew (GH-98426) (cherry picked from commit f58631be1148ee5436bb71d175d3993e3e6b4e1e) Co-authored-by: C.A.M. Gerlach Co-authored-by: C.A.M. Gerlach files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 46c5692c8449..507b06b8c568 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1160,33 +1160,52 @@ fcntl Optimizations ============= -* Compiler now optimizes simple C-style formatting with literal format - containing only format codes ``%s``, ``%r`` and ``%a`` and makes it as - fast as corresponding f-string expression. +This section covers specific optimizations independent of the +:ref:`whatsnew311-faster-cpython` project, which is covered in its own section. + +* The compiler now optimizes simple + :ref:`printf-style % formatting ` on string literals + containing only the format codes ``%s``, ``%r`` and ``%a`` and makes it as + fast as a corresponding :term:`f-string` expression. (Contributed by Serhiy Storchaka in :issue:`28307`.) -* "Zero-cost" exceptions are implemented. The cost of ``try`` statements is - almost eliminated when no exception is raised. - (Contributed by Mark Shannon in :issue:`40222`.) +* Integer division (``//``) is better tuned for optimization by compilers. + It is now around 20% faster on x86-64 when dividing an :class:`int` + by a value smaller than ``2**30``. + (Contributed by Gregory P. Smith and Tim Peters in :gh:`90564`.) -* Pure ASCII strings are now normalized in constant time by :func:`unicodedata.normalize`. - (Contributed by Dong-hee Na in :issue:`44987`.) +* :func:`sum` is now nearly 30% faster for integers smaller than ``2**30``. + (Contributed by Stefan Behnel in :gh:`68264`.) -* :mod:`math` functions :func:`~math.comb` and :func:`~math.perm` are now up - to 10 times or more faster for large arguments (the speed up is larger for - larger *k*). - (Contributed by Serhiy Storchaka in :issue:`37295`.) +* Resizing lists is streamlined for the common case, + speeding up :meth:`list.append` by ?15% + and simple :term:`list comprehension`\s by up to 20-30% + (Contributed by Dennis Sweeney in :gh:`91165`.) -* Dict don't store hash value when all inserted keys are Unicode objects. - This reduces dict size. For example, ``sys.getsizeof(dict.fromkeys("abcdefg"))`` - becomes 272 bytes from 352 bytes on 64bit platform. +* Dictionaries don't store hash values when all keys are Unicode objects, + decreasing :class:`dict` size. + For example, ``sys.getsizeof(dict.fromkeys("abcdefg"))`` + is reduced from 352 bytes to 272 bytes (23% smaller) on 64-bit platforms. (Contributed by Inada Naoki in :issue:`46845`.) -* :mod:`re`'s regular expression matching engine has been partially refactored, - and now uses computed gotos (or "threaded code") on supported platforms. As a - result, Python 3.11 executes the `pyperformance regular expression benchmarks - `_ up to 10% - faster than Python 3.10. +* Using :class:`asyncio.DatagramProtocol` is now orders of magnitude faster + when transferring large files over UDP, + with speeds over 100 times higher for a ?60 MiB file. + (Contributed by msoxzw in :gh:`91487`.) + +* :mod:`math` functions :func:`~math.comb` and :func:`~math.perm` are now + ?10 times faster for large arguments (with a larger speedup for larger *k*). + (Contributed by Serhiy Storchaka in :issue:`37295`.) + +* The :mod:`statistics` functions :func:`~statistics.mean`, + :func:`~statistics.variance` and :func:`~statistics.stdev` now consume + iterators in one pass rather than converting them to a :class:`list` first. + This is twice as fast and can save substantial memory. + (Contributed by Raymond Hettinger in :gh:`90415`.) + +* :func:`unicodedata.normalize` + now normalizes pure-ASCII strings in constant time. + (Contributed by Dong-hee Na in :issue:`44987`.) .. _whatsnew311-faster-cpython: From webhook-mailer at python.org Sat Oct 22 15:21:07 2022 From: webhook-mailer at python.org (miss-islington) Date: Sat, 22 Oct 2022 19:21:07 -0000 Subject: [Python-checkins] gh-95913: Copyedit & xref FrameInfo in Whatsnew inspect section (GH-98304) Message-ID: https://github.com/python/cpython/commit/519b56a5c79e00c9d97aadacefec893effdc396d commit: 519b56a5c79e00c9d97aadacefec893effdc396d branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-22T12:21:01-07:00 summary: gh-95913: Copyedit & xref FrameInfo in Whatsnew inspect section (GH-98304) (cherry picked from commit 8f30267ab49e1ef3ac3165a102b2196336547c8a) Co-authored-by: C.A.M. Gerlach files: M Doc/library/inspect.rst M Doc/whatsnew/3.11.rst diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index 700cd9122cd3..44f1ae04c9e3 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -434,8 +434,10 @@ attributes: Return ``True`` if the type of object is a :class:`~types.MethodWrapperType`. - These are instances of :class:`~types.MethodWrapperType`, such as :meth:`~object().__str__`, - :meth:`~object().__eq__` and :meth:`~object().__repr__` + These are instances of :class:`~types.MethodWrapperType`, such as :meth:`~object.__str__`, + :meth:`~object.__eq__` and :meth:`~object.__repr__`. + + .. versionadded:: 3.11 .. function:: isroutine(object) @@ -1206,12 +1208,13 @@ is considered deprecated and may be removed in the future. number, start column offset, and end column offset associated with the instruction being executed by the frame this record corresponds to. -.. versionchanged:: 3.5 - Return a named tuple instead of a tuple. + .. versionchanged:: 3.5 + Return a :term:`named tuple` instead of a :class:`tuple`. + + .. versionchanged:: 3.11 + :class:`!FrameInfo` is now a class instance + (that is backwards compatible with the previous :term:`named tuple`). -.. versionchanged:: 3.11 - Changed the return object from a named tuple to a regular object (that is - backwards compatible with the previous named tuple). .. class:: Traceback @@ -1245,6 +1248,11 @@ is considered deprecated and may be removed in the future. the instruction being executed by the frame this traceback corresponds to. + .. versionchanged:: 3.11 + :class:`!Traceback` is now a class instance + (that is backwards compatible with the previous :term:`named tuple`). + + .. note:: Keeping references to frame objects, as found in the first element of the frame diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 507b06b8c568..c143a418f3c5 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -775,22 +775,33 @@ IDLE and idlelib * Include prompts when saving Shell with inputs and outputs. (Contributed by Terry Jan Reedy in :gh:`95191`.) + +.. _whatsnew311-inspect: + inspect ------- -* Add :func:`inspect.getmembers_static`: return all members without + +* Add :func:`~inspect.getmembers_static` to return all members without triggering dynamic lookup via the descriptor protocol. (Contributed by Weipeng Hong in :issue:`30533`.) -* Add :func:`inspect.ismethodwrapper` for checking if the type of an object is a - :class:`~types.MethodWrapperType`. (Contributed by Hakan ?elik in :issue:`29418`.) +* Add :func:`~inspect.ismethodwrapper` + for checking if the type of an object is a :class:`~types.MethodWrapperType`. + (Contributed by Hakan ?elik in :issue:`29418`.) -* Change the frame-related functions in the :mod:`inspect` module to return a - regular object (that is backwards compatible with the old tuple-like - interface) that include the extended :pep:`657` position information (end +* Change the frame-related functions in the :mod:`inspect` module to return new + :class:`~inspect.FrameInfo` and :class:`~inspect.Traceback` class instances + (backwards compatible with the previous :term:`named tuple`-like interfaces) + that includes the extended :pep:`657` position information (end line number, column and end column). The affected functions are: - :func:`inspect.getframeinfo`, :func:`inspect.getouterframes`, :func:`inspect.getinnerframes`, - :func:`inspect.stack` and :func:`inspect.trace`. (Contributed by Pablo Galindo in - :gh:`88116`.) + + * :func:`inspect.getframeinfo` + * :func:`inspect.getouterframes` + * :func:`inspect.getinnerframes`, + * :func:`inspect.stack` + * :func:`inspect.trace` + + (Contributed by Pablo Galindo in :gh:`88116`.) locale ------ From webhook-mailer at python.org Sun Oct 23 01:24:12 2022 From: webhook-mailer at python.org (corona10) Date: Sun, 23 Oct 2022 05:24:12 -0000 Subject: [Python-checkins] gh-98456: Replace deprecated `set-output` with up-to-date version (gh-98457) Message-ID: https://github.com/python/cpython/commit/1db2a0cb20a1de5231a73fc7381056d725e90535 commit: 1db2a0cb20a1de5231a73fc7381056d725e90535 branch: main author: Noam Cohen committer: corona10 date: 2022-10-23T14:23:40+09:00 summary: gh-98456: Replace deprecated `set-output` with up-to-date version (gh-98457) files: M .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f782d394a57b..f0544c0962e1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -41,7 +41,7 @@ jobs: id: check run: | if [ -z "$GITHUB_BASE_REF" ]; then - echo '::set-output name=run_tests::true' + echo "run_tests=true" >> $GITHUB_OUTPUT else git fetch origin $GITHUB_BASE_REF --depth=1 # git diff "origin/$GITHUB_BASE_REF..." (3 dots) may be more @@ -57,7 +57,7 @@ jobs: # into the PR branch anyway. # # https://github.com/python/core-workflow/issues/373 - git diff --name-only origin/$GITHUB_BASE_REF.. | grep -qvE '(\.rst$|^Doc|^Misc)' && echo '::set-output name=run_tests::true' || true + git diff --name-only origin/$GITHUB_BASE_REF.. | grep -qvE '(\.rst$|^Doc|^Misc)' && echo "run_tests=true" >> $GITHUB_OUTPUT || true fi check_generated_files: From webhook-mailer at python.org Sun Oct 23 06:47:01 2022 From: webhook-mailer at python.org (corona10) Date: Sun, 23 Oct 2022 10:47:01 -0000 Subject: [Python-checkins] no-issue: typo fix in c-api/tuple.rst (gh-98560) Message-ID: https://github.com/python/cpython/commit/833f275840811a3f38c367df24bbc44caf00b26f commit: 833f275840811a3f38c367df24bbc44caf00b26f branch: main author: wim glenn committer: corona10 date: 2022-10-23T19:46:56+09:00 summary: no-issue: typo fix in c-api/tuple.rst (gh-98560) files: M Doc/c-api/tuple.rst diff --git a/Doc/c-api/tuple.rst b/Doc/c-api/tuple.rst index 0bfd4b308d93..5acddf7849aa 100644 --- a/Doc/c-api/tuple.rst +++ b/Doc/c-api/tuple.rst @@ -69,7 +69,7 @@ Tuple Objects Return the slice of the tuple pointed to by *p* between *low* and *high*, or ``NULL`` on failure. This is the equivalent of the Python expression - ``p[low:high]``. Indexing from the end of the list is not supported. + ``p[low:high]``. Indexing from the end of the tuple is not supported. .. c:function:: int PyTuple_SetItem(PyObject *p, Py_ssize_t pos, PyObject *o) From webhook-mailer at python.org Sun Oct 23 10:05:26 2022 From: webhook-mailer at python.org (Fidget-Spinner) Date: Sun, 23 Oct 2022 14:05:26 -0000 Subject: [Python-checkins] gh-98561: Fix a typo in typing (GH-98562) Message-ID: https://github.com/python/cpython/commit/b6d5d5b60afc61337c569c07a881003faaa791e7 commit: b6d5d5b60afc61337c569c07a881003faaa791e7 branch: main author: Omkaar <79257339+Infiniticity at users.noreply.github.com> committer: Fidget-Spinner date: 2022-10-23T22:05:08+08:00 summary: gh-98561: Fix a typo in typing (GH-98562) files: M Doc/library/typing.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index dc5696aff69b..ae7e22306996 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -319,7 +319,7 @@ single type parameter ``T`` . This also makes ``T`` valid as a type within the class body. The :class:`Generic` base class defines :meth:`~object.__class_getitem__` so -that ``LoggedVar[t]`` is valid as a type:: +that ``LoggedVar[T]`` is valid as a type:: from collections.abc import Iterable From webhook-mailer at python.org Sun Oct 23 10:11:34 2022 From: webhook-mailer at python.org (miss-islington) Date: Sun, 23 Oct 2022 14:11:34 -0000 Subject: [Python-checkins] gh-98561: Fix a typo in typing (GH-98562) Message-ID: https://github.com/python/cpython/commit/f3c23fc48cc9a72ec0ad447276bb07d1a85dd37f commit: f3c23fc48cc9a72ec0ad447276bb07d1a85dd37f branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-23T07:11:29-07:00 summary: gh-98561: Fix a typo in typing (GH-98562) (cherry picked from commit b6d5d5b60afc61337c569c07a881003faaa791e7) Co-authored-by: Omkaar <79257339+Infiniticity at users.noreply.github.com> files: M Doc/library/typing.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index cfe484b8e469..198bc880f9d7 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -305,7 +305,7 @@ single type parameter ``T`` . This also makes ``T`` valid as a type within the class body. The :class:`Generic` base class defines :meth:`~object.__class_getitem__` so -that ``LoggedVar[t]`` is valid as a type:: +that ``LoggedVar[T]`` is valid as a type:: from collections.abc import Iterable From webhook-mailer at python.org Sun Oct 23 10:13:30 2022 From: webhook-mailer at python.org (miss-islington) Date: Sun, 23 Oct 2022 14:13:30 -0000 Subject: [Python-checkins] gh-98561: Fix a typo in typing (GH-98562) Message-ID: https://github.com/python/cpython/commit/ae68a45daadb79af3888b084d502162d19aa4103 commit: ae68a45daadb79af3888b084d502162d19aa4103 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-23T07:13:25-07:00 summary: gh-98561: Fix a typo in typing (GH-98562) (cherry picked from commit b6d5d5b60afc61337c569c07a881003faaa791e7) Co-authored-by: Omkaar <79257339+Infiniticity at users.noreply.github.com> files: M Doc/library/typing.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 04f63f6f54bc..a9c71c466205 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -319,7 +319,7 @@ single type parameter ``T`` . This also makes ``T`` valid as a type within the class body. The :class:`Generic` base class defines :meth:`~object.__class_getitem__` so -that ``LoggedVar[t]`` is valid as a type:: +that ``LoggedVar[T]`` is valid as a type:: from collections.abc import Iterable From webhook-mailer at python.org Sun Oct 23 16:36:58 2022 From: webhook-mailer at python.org (ned-deily) Date: Sun, 23 Oct 2022 20:36:58 -0000 Subject: [Python-checkins] Update Mac installer messages to 3.12 alpha (GH-98575) Message-ID: https://github.com/python/cpython/commit/176b6c57be70fb70fd0563813a87822545eb4bbf commit: 176b6c57be70fb70fd0563813a87822545eb4bbf branch: main author: Ned Deily committer: ned-deily date: 2022-10-23T16:36:53-04:00 summary: Update Mac installer messages to 3.12 alpha (GH-98575) files: M Mac/BuildScript/resources/ReadMe.rtf M Mac/BuildScript/resources/Welcome.rtf diff --git a/Mac/BuildScript/resources/ReadMe.rtf b/Mac/BuildScript/resources/ReadMe.rtf index 8d699395f304..dbe8c520a7c7 100644 --- a/Mac/BuildScript/resources/ReadMe.rtf +++ b/Mac/BuildScript/resources/ReadMe.rtf @@ -1,4 +1,4 @@ -{\rtf1\ansi\ansicpg1252\cocoartf2580 +{\rtf1\ansi\ansicpg1252\cocoartf2639 \cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fswiss\fcharset0 Helvetica-Bold;\f2\fswiss\fcharset0 Helvetica-Oblique; \f3\fmodern\fcharset0 CourierNewPSMT;\f4\fmodern\fcharset0 Courier;} {\colortbl;\red255\green255\blue255;} @@ -11,7 +11,7 @@ \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\partightenfactor0 \f1\b \cf0 NOTE: -\f0\b0 This is an alpha preview of Python 3.11.0, the next feature release of Python 3. It is not intended for production use.\ +\f0\b0 This is an alpha preview of Python 3.12.0, the next feature release of Python 3. It is not intended for production use.\ \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0 \cf0 \ \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0 diff --git a/Mac/BuildScript/resources/Welcome.rtf b/Mac/BuildScript/resources/Welcome.rtf index e6ccfcb3fce9..7819241b618d 100644 --- a/Mac/BuildScript/resources/Welcome.rtf +++ b/Mac/BuildScript/resources/Welcome.rtf @@ -1,4 +1,4 @@ -{\rtf1\ansi\ansicpg1252\cocoartf2580 +{\rtf1\ansi\ansicpg1252\cocoartf2639 \cocoascreenfonts1\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fswiss\fcharset0 Helvetica-Bold;\f2\fmodern\fcharset0 CourierNewPSMT; } {\colortbl;\red255\green255\blue255;} @@ -26,5 +26,5 @@ At the end of this install, click on \ \f1\b NOTE: -\f0\b0 This is an alpha test preview of Python 3.11.0, the next feature release of Python 3. It is not intended for production use.\ +\f0\b0 This is an alpha test preview of Python 3.12.0, the next feature release of Python 3. It is not intended for production use.\ } \ No newline at end of file From webhook-mailer at python.org Sun Oct 23 18:57:36 2022 From: webhook-mailer at python.org (gpshead) Date: Sun, 23 Oct 2022 22:57:36 -0000 Subject: [Python-checkins] gh-91524: Speed up the regular expression substitution (#91525) Message-ID: https://github.com/python/cpython/commit/75a6fadf369315b27e12f670e6295cf2c2cf7d7e commit: 75a6fadf369315b27e12f670e6295cf2c2cf7d7e branch: main author: Serhiy Storchaka committer: gpshead date: 2022-10-23T15:57:30-07:00 summary: gh-91524: Speed up the regular expression substitution (#91525) Functions re.sub() and re.subn() and corresponding re.Pattern methods are now 2-3 times faster for replacement strings containing group references. Closes #91524 Primarily authored by serhiy-storchaka Serhiy Storchaka Minor-cleanups-by: Gregory P. Smith [Google] files: A Misc/NEWS.d/next/Library/2022-04-14-08-37-16.gh-issue-91524.g8PiIu.rst M Doc/whatsnew/3.12.rst M Lib/re/__init__.py M Lib/re/_constants.py M Lib/re/_parser.py M Modules/_sre/clinic/sre.c.h M Modules/_sre/sre.c M Modules/_sre/sre.h M Modules/_sre/sre_constants.h diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 3e0b106c4a04..8f8a99461510 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -205,6 +205,11 @@ Optimizations process, which improves performance by 1-5%. (Contributed by Kevin Modzelewski in :gh:`90536`.) +* Speed up the regular expression substitution (functions :func:`re.sub` and + :func:`re.subn` and corresponding :class:`re.Pattern` methods) for + replacement strings containing group references by 2--3 times. + (Contributed by Serhiy Storchaka in :gh:`91524`.) + CPython bytecode changes ======================== diff --git a/Lib/re/__init__.py b/Lib/re/__init__.py index 8d6a4ef3880f..4515650a721a 100644 --- a/Lib/re/__init__.py +++ b/Lib/re/__init__.py @@ -124,6 +124,7 @@ import enum from . import _compiler, _parser import functools +import _sre # public symbols @@ -230,7 +231,7 @@ def purge(): "Clear the regular expression caches" _cache.clear() _cache2.clear() - _compile_repl.cache_clear() + _compile_template.cache_clear() def template(pattern, flags=0): "Compile a template pattern, returning a Pattern object, deprecated" @@ -328,24 +329,9 @@ def _compile(pattern, flags): return p @functools.lru_cache(_MAXCACHE) -def _compile_repl(repl, pattern): +def _compile_template(pattern, repl): # internal: compile replacement pattern - return _parser.parse_template(repl, pattern) - -def _expand(pattern, match, template): - # internal: Match.expand implementation hook - template = _parser.parse_template(template, pattern) - return _parser.expand_template(template, match) - -def _subx(pattern, template): - # internal: Pattern.sub/subn implementation helper - template = _compile_repl(template, pattern) - if not template[0] and len(template[1]) == 1: - # literal replacement - return template[1][0] - def filter(match, template=template): - return _parser.expand_template(template, match) - return filter + return _sre.template(pattern, _parser.parse_template(repl, pattern)) # register myself for pickling diff --git a/Lib/re/_constants.py b/Lib/re/_constants.py index 10ee14bfab46..d8718d36075a 100644 --- a/Lib/re/_constants.py +++ b/Lib/re/_constants.py @@ -13,7 +13,7 @@ # update when constants are added or removed -MAGIC = 20220615 +MAGIC = 20221023 from _sre import MAXREPEAT, MAXGROUPS diff --git a/Lib/re/_parser.py b/Lib/re/_parser.py index 0d9cf632ea71..5709acb62672 100644 --- a/Lib/re/_parser.py +++ b/Lib/re/_parser.py @@ -984,24 +984,28 @@ def parse(str, flags=0, state=None): return p -def parse_template(source, state): +def parse_template(source, pattern): # parse 're' replacement string into list of literals and # group references s = Tokenizer(source) sget = s.get - groups = [] - literals = [] + result = [] literal = [] lappend = literal.append + def addliteral(): + if s.istext: + result.append(''.join(literal)) + else: + # The tokenizer implicitly decodes bytes objects as latin-1, we must + # therefore re-encode the final representation. + result.append(''.join(literal).encode('latin-1')) + del literal[:] def addgroup(index, pos): - if index > state.groups: + if index > pattern.groups: raise s.error("invalid group reference %d" % index, pos) - if literal: - literals.append(''.join(literal)) - del literal[:] - groups.append((len(literals), index)) - literals.append(None) - groupindex = state.groupindex + addliteral() + result.append(index) + groupindex = pattern.groupindex while True: this = sget() if this is None: @@ -1063,22 +1067,5 @@ def addgroup(index, pos): lappend(this) else: lappend(this) - if literal: - literals.append(''.join(literal)) - if not isinstance(source, str): - # The tokenizer implicitly decodes bytes objects as latin-1, we must - # therefore re-encode the final representation. - literals = [None if s is None else s.encode('latin-1') for s in literals] - return groups, literals - -def expand_template(template, match): - g = match.group - empty = match.string[:0] - groups, literals = template - literals = literals[:] - try: - for index, group in groups: - literals[index] = g(group) or empty - except IndexError: - raise error("invalid group reference %d" % index) from None - return empty.join(literals) + addliteral() + return result diff --git a/Misc/NEWS.d/next/Library/2022-04-14-08-37-16.gh-issue-91524.g8PiIu.rst b/Misc/NEWS.d/next/Library/2022-04-14-08-37-16.gh-issue-91524.g8PiIu.rst new file mode 100644 index 000000000000..b3f01755eaa3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-04-14-08-37-16.gh-issue-91524.g8PiIu.rst @@ -0,0 +1,3 @@ +Speed up the regular expression substitution (functions :func:`re.sub` and +:func:`re.subn` and corresponding :class:`re.Pattern` methods) for +replacement strings containing group references by 2--3 times. diff --git a/Modules/_sre/clinic/sre.c.h b/Modules/_sre/clinic/sre.c.h index 711e16a1190d..da641081ce9e 100644 --- a/Modules/_sre/clinic/sre.c.h +++ b/Modules/_sre/clinic/sre.c.h @@ -1068,6 +1068,45 @@ _sre_compile(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject return return_value; } +PyDoc_STRVAR(_sre_template__doc__, +"template($module, pattern, template, /)\n" +"--\n" +"\n" +"\n" +"\n" +" template\n" +" A list containing interleaved literal strings (str or bytes) and group\n" +" indices (int), as returned by re._parser.parse_template():\n" +" [literal1, group1, ..., literalN, groupN]"); + +#define _SRE_TEMPLATE_METHODDEF \ + {"template", _PyCFunction_CAST(_sre_template), METH_FASTCALL, _sre_template__doc__}, + +static PyObject * +_sre_template_impl(PyObject *module, PyObject *pattern, PyObject *template); + +static PyObject * +_sre_template(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *pattern; + PyObject *template; + + if (!_PyArg_CheckPositional("template", nargs, 2, 2)) { + goto exit; + } + pattern = args[0]; + if (!PyList_Check(args[1])) { + _PyArg_BadArgument("template", "argument 2", "list", args[1]); + goto exit; + } + template = args[1]; + return_value = _sre_template_impl(module, pattern, template); + +exit: + return return_value; +} + PyDoc_STRVAR(_sre_SRE_Match_expand__doc__, "expand($self, /, template)\n" "--\n" @@ -1421,4 +1460,4 @@ _sre_SRE_Scanner_search(ScannerObject *self, PyTypeObject *cls, PyObject *const } return _sre_SRE_Scanner_search_impl(self, cls); } -/*[clinic end generated code: output=14ea86f85c130a7b input=a9049054013a1b77]*/ +/*[clinic end generated code: output=e3ba72156dd71572 input=a9049054013a1b77]*/ diff --git a/Modules/_sre/sre.c b/Modules/_sre/sre.c index bcb30848d9a5..aae02652664f 100644 --- a/Modules/_sre/sre.c +++ b/Modules/_sre/sre.c @@ -51,13 +51,6 @@ static const char copyright[] = #include -/* name of this module, minus the leading underscore */ -#if !defined(SRE_MODULE) -#define SRE_MODULE "sre" -#endif - -#define SRE_PY_MODULE "re" - /* defining this one enables tracing */ #undef VERBOSE @@ -254,6 +247,8 @@ typedef struct { PyTypeObject *Pattern_Type; PyTypeObject *Match_Type; PyTypeObject *Scanner_Type; + PyTypeObject *Template_Type; + PyObject *compile_template; // reference to re._compile_template } _sremodulestate; static _sremodulestate * @@ -757,23 +752,6 @@ _sre_SRE_Pattern_search_impl(PatternObject *self, PyTypeObject *cls, return match; } -static PyObject* -call(const char* module, const char* function, PyObject* args) -{ - PyObject* func; - PyObject* result; - - if (!args) - return NULL; - func = _PyImport_GetModuleAttrString(module, function); - if (!func) - return NULL; - result = PyObject_CallObject(func, args); - Py_DECREF(func); - Py_DECREF(args); - return result; -} - /*[clinic input] _sre.SRE_Pattern.findall @@ -1036,6 +1014,57 @@ _sre_SRE_Pattern_split_impl(PatternObject *self, PyObject *string, } +static PyObject * +compile_template(_sremodulestate *module_state, + PatternObject *pattern, PyObject *template) +{ + /* delegate to Python code */ + PyObject *func = module_state->compile_template; + if (func == NULL) { + func = _PyImport_GetModuleAttrString("re", "_compile_template"); + if (func == NULL) { + return NULL; + } + Py_XSETREF(module_state->compile_template, func); + } + + PyObject *args[] = {(PyObject *)pattern, template}; + PyObject *result = PyObject_Vectorcall(func, args, 2, NULL); + + if (result == NULL && PyErr_ExceptionMatches(PyExc_TypeError)) { + /* If the replacement string is unhashable (e.g. bytearray), + * convert it to the basic type (str or bytes) and repeat. */ + if (PyUnicode_Check(template) && !PyUnicode_CheckExact(template)) { + PyErr_Clear(); + template = _PyUnicode_Copy(template); + } + else if (PyObject_CheckBuffer(template) && !PyBytes_CheckExact(template)) { + PyErr_Clear(); + template = PyBytes_FromObject(template); + } + else { + return NULL; + } + if (template == NULL) { + return NULL; + } + args[1] = template; + result = PyObject_Vectorcall(func, args, 2, NULL); + Py_DECREF(template); + } + + if (result != NULL && Py_TYPE(result) != module_state->Template_Type) { + PyErr_Format(PyExc_RuntimeError, + "the result of compiling a replacement string is %.200s", + Py_TYPE(result)->tp_name); + Py_DECREF(result); + return NULL; + } + return result; +} + +static PyObject *expand_template(TemplateObject *, MatchObject *); /* Forward */ + static PyObject* pattern_subx(_sremodulestate* module_state, PatternObject* self, @@ -1055,14 +1084,14 @@ pattern_subx(_sremodulestate* module_state, Py_ssize_t n; Py_ssize_t i, b, e; int isbytes, charsize; - int filter_is_callable; + enum {LITERAL, TEMPLATE, CALLABLE} filter_type; Py_buffer view; if (PyCallable_Check(ptemplate)) { /* sub/subn takes either a function or a template */ filter = ptemplate; Py_INCREF(filter); - filter_is_callable = 1; + filter_type = CALLABLE; } else { /* if not callable, check if it's a literal string */ int literal; @@ -1082,16 +1111,22 @@ pattern_subx(_sremodulestate* module_state, if (literal) { filter = ptemplate; Py_INCREF(filter); - filter_is_callable = 0; + filter_type = LITERAL; } else { /* not a literal; hand it over to the template compiler */ - filter = call( - SRE_PY_MODULE, "_subx", - PyTuple_Pack(2, self, ptemplate) - ); + filter = compile_template(module_state, self, ptemplate); if (!filter) return NULL; - filter_is_callable = PyCallable_Check(filter); + + assert(Py_TYPE(filter) == module_state->Template_Type); + if (Py_SIZE(filter) == 0) { + Py_INCREF(((TemplateObject *)filter)->literal); + Py_SETREF(filter, ((TemplateObject *)filter)->literal); + filter_type = LITERAL; + } + else { + filter_type = TEMPLATE; + } } } @@ -1142,12 +1177,19 @@ pattern_subx(_sremodulestate* module_state, } - if (filter_is_callable) { + if (filter_type != LITERAL) { /* pass match object through filter */ match = pattern_new_match(module_state, self, &state, 1); if (!match) goto error; - item = PyObject_CallOneArg(filter, match); + if (filter_type == TEMPLATE) { + item = expand_template((TemplateObject *)filter, + (MatchObject *)match); + } + else { + assert(filter_type == CALLABLE); + item = PyObject_CallOneArg(filter, match); + } Py_DECREF(match); if (!item) goto error; @@ -1482,6 +1524,69 @@ _sre_compile_impl(PyObject *module, PyObject *pattern, int flags, return (PyObject*) self; } +/*[clinic input] +_sre.template + + pattern: object + template: object(subclass_of="&PyList_Type") + A list containing interleaved literal strings (str or bytes) and group + indices (int), as returned by re._parser.parse_template(): + [literal1, group1, ..., literalN, groupN] + / + +[clinic start generated code]*/ + +static PyObject * +_sre_template_impl(PyObject *module, PyObject *pattern, PyObject *template) +/*[clinic end generated code: output=d51290e596ebca86 input=af55380b27f02942]*/ +{ + /* template is a list containing interleaved literal strings (str or bytes) + * and group indices (int), as returned by _parser.parse_template: + * [literal1, group1, literal2, ..., literalN]. + */ + _sremodulestate *module_state = get_sre_module_state(module); + TemplateObject *self = NULL; + Py_ssize_t n = PyList_GET_SIZE(template); + if ((n & 1) == 0 || n < 1) { + goto bad_template; + } + n /= 2; + self = PyObject_GC_NewVar(TemplateObject, module_state->Template_Type, n); + if (!self) + return NULL; + self->chunks = 1 + 2*n; + self->literal = PyList_GET_ITEM(template, 0); + Py_INCREF(self->literal); + for (Py_ssize_t i = 0; i < n; i++) { + Py_ssize_t index = PyLong_AsSsize_t(PyList_GET_ITEM(template, 2*i+1)); + if (index == -1 && PyErr_Occurred()) { + Py_DECREF(self); + return NULL; + } + if (index < 0) { + goto bad_template; + } + self->items[i].index = index; + + PyObject *literal = PyList_GET_ITEM(template, 2*i+2); + // Skip empty literals. + if ((PyUnicode_Check(literal) && !PyUnicode_GET_LENGTH(literal)) || + (PyBytes_Check(literal) && !PyBytes_GET_SIZE(literal))) + { + literal = NULL; + self->chunks--; + } + Py_XINCREF(literal); + self->items[i].literal = literal; + } + return (PyObject*) self; + +bad_template: + PyErr_SetString(PyExc_TypeError, "invalid template"); + Py_XDECREF(self); + return NULL; +} + /* -------------------------------------------------------------------- */ /* Code validation */ @@ -2096,11 +2201,14 @@ static PyObject * _sre_SRE_Match_expand_impl(MatchObject *self, PyObject *template) /*[clinic end generated code: output=931b58ccc323c3a1 input=4bfdb22c2f8b146a]*/ { - /* delegate to Python code */ - return call( - SRE_PY_MODULE, "_expand", - PyTuple_Pack(3, self->pattern, self, template) - ); + _sremodulestate *module_state = get_sre_module_state_by_class(Py_TYPE(self)); + PyObject *filter = compile_template(module_state, self->pattern, template); + if (filter == NULL) { + return NULL; + } + PyObject *result = expand_template((TemplateObject *)filter, self); + Py_DECREF(filter); + return result; } static PyObject* @@ -2685,6 +2793,112 @@ pattern_scanner(_sremodulestate *module_state, return (PyObject*) scanner; } +/* -------------------------------------------------------------------- */ +/* template methods */ + +static int +template_traverse(TemplateObject *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->literal); + for (Py_ssize_t i = 0, n = Py_SIZE(self); i < n; i++) { + Py_VISIT(self->items[i].literal); + } + return 0; +} + +static int +template_clear(TemplateObject *self) +{ + Py_CLEAR(self->literal); + for (Py_ssize_t i = 0, n = Py_SIZE(self); i < n; i++) { + Py_CLEAR(self->items[i].literal); + } + return 0; +} + +static void +template_dealloc(TemplateObject *self) +{ + PyTypeObject *tp = Py_TYPE(self); + + PyObject_GC_UnTrack(self); + (void)template_clear(self); + tp->tp_free(self); + Py_DECREF(tp); +} + +static PyObject * +expand_template(TemplateObject *self, MatchObject *match) +{ + if (Py_SIZE(self) == 0) { + Py_INCREF(self->literal); + return self->literal; + } + + PyObject *result = NULL; + Py_ssize_t count = 0; // the number of non-empty chunks + /* For small number of strings use a buffer allocated on the stack, + * otherwise use a list object. */ + PyObject *buffer[10]; + PyObject **out = buffer; + PyObject *list = NULL; + if (self->chunks > (int)Py_ARRAY_LENGTH(buffer) || + !PyUnicode_Check(self->literal)) + { + list = PyList_New(self->chunks); + if (!list) { + return NULL; + } + out = &PyList_GET_ITEM(list, 0); + } + + Py_INCREF(self->literal); + out[count++] = self->literal; + for (Py_ssize_t i = 0; i < Py_SIZE(self); i++) { + Py_ssize_t index = self->items[i].index; + if (index >= match->groups) { + PyErr_SetString(PyExc_IndexError, "no such group"); + goto cleanup; + } + PyObject *item = match_getslice_by_index(match, index, Py_None); + if (item == NULL) { + goto cleanup; + } + if (item != Py_None) { + Py_INCREF(item); + out[count++] = item; + } + Py_DECREF(item); + + PyObject *literal = self->items[i].literal; + if (literal != NULL) { + Py_INCREF(literal); + out[count++] = literal; + } + } + + if (PyUnicode_Check(self->literal)) { + result = _PyUnicode_JoinArray(&_Py_STR(empty), out, count); + } + else { + Py_SET_SIZE(list, count); + result = _PyBytes_Join((PyObject *)&_Py_SINGLETON(bytes_empty), list); + } + +cleanup: + if (list) { + Py_DECREF(list); + } + else { + for (Py_ssize_t i = 0; i < count; i++) { + Py_DECREF(out[i]); + } + } + return result; +} + + static Py_hash_t pattern_hash(PatternObject *self) { @@ -2907,15 +3121,32 @@ static PyType_Slot scanner_slots[] = { }; static PyType_Spec scanner_spec = { - .name = "_" SRE_MODULE ".SRE_Scanner", + .name = "_sre.SRE_Scanner", .basicsize = sizeof(ScannerObject), .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION | Py_TPFLAGS_HAVE_GC), .slots = scanner_slots, }; +static PyType_Slot template_slots[] = { + {Py_tp_dealloc, template_dealloc}, + {Py_tp_traverse, template_traverse}, + {Py_tp_clear, template_clear}, + {0, NULL}, +}; + +static PyType_Spec template_spec = { + .name = "_sre.SRE_Template", + .basicsize = sizeof(TemplateObject), + .itemsize = sizeof(((TemplateObject *)0)->items[0]), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE | + Py_TPFLAGS_DISALLOW_INSTANTIATION | Py_TPFLAGS_HAVE_GC), + .slots = template_slots, +}; + static PyMethodDef _functions[] = { _SRE_COMPILE_METHODDEF + _SRE_TEMPLATE_METHODDEF _SRE_GETCODESIZE_METHODDEF _SRE_ASCII_ISCASED_METHODDEF _SRE_UNICODE_ISCASED_METHODDEF @@ -2932,6 +3163,8 @@ sre_traverse(PyObject *module, visitproc visit, void *arg) Py_VISIT(state->Pattern_Type); Py_VISIT(state->Match_Type); Py_VISIT(state->Scanner_Type); + Py_VISIT(state->Template_Type); + Py_VISIT(state->compile_template); return 0; } @@ -2944,6 +3177,8 @@ sre_clear(PyObject *module) Py_CLEAR(state->Pattern_Type); Py_CLEAR(state->Match_Type); Py_CLEAR(state->Scanner_Type); + Py_CLEAR(state->Template_Type); + Py_CLEAR(state->compile_template); return 0; } @@ -2984,6 +3219,7 @@ sre_exec(PyObject *m) CREATE_TYPE(m, state->Pattern_Type, &pattern_spec); CREATE_TYPE(m, state->Match_Type, &match_spec); CREATE_TYPE(m, state->Scanner_Type, &scanner_spec); + CREATE_TYPE(m, state->Template_Type, &template_spec); if (PyModule_AddIntConstant(m, "MAGIC", SRE_MAGIC) < 0) { goto error; @@ -3013,7 +3249,7 @@ static PyModuleDef_Slot sre_slots[] = { static struct PyModuleDef sremodule = { .m_base = PyModuleDef_HEAD_INIT, - .m_name = "_" SRE_MODULE, + .m_name = "_sre", .m_size = sizeof(_sremodulestate), .m_methods = _functions, .m_slots = sre_slots, diff --git a/Modules/_sre/sre.h b/Modules/_sre/sre.h index 52ae3e11b5f7..d967d9ea04ba 100644 --- a/Modules/_sre/sre.h +++ b/Modules/_sre/sre.h @@ -52,6 +52,17 @@ typedef struct { Py_ssize_t mark[1]; } MatchObject; +typedef struct { + PyObject_VAR_HEAD + Py_ssize_t chunks; /* the number of group references and non-NULL literals + * self->chunks <= 2*Py_SIZE(self) + 1 */ + PyObject *literal; + struct { + Py_ssize_t index; + PyObject *literal; /* NULL if empty */ + } items[0]; +} TemplateObject; + typedef struct SRE_REPEAT_T { Py_ssize_t count; const SRE_CODE* pattern; /* points to REPEAT operator arguments */ diff --git a/Modules/_sre/sre_constants.h b/Modules/_sre/sre_constants.h index f030815c6c00..b5692292f652 100644 --- a/Modules/_sre/sre_constants.h +++ b/Modules/_sre/sre_constants.h @@ -11,7 +11,7 @@ * See the sre.c file for information on usage and redistribution. */ -#define SRE_MAGIC 20220615 +#define SRE_MAGIC 20221023 #define SRE_OP_FAILURE 0 #define SRE_OP_SUCCESS 1 #define SRE_OP_ANY 2 From webhook-mailer at python.org Mon Oct 24 08:33:37 2022 From: webhook-mailer at python.org (pablogsal) Date: Mon, 24 Oct 2022 12:33:37 -0000 Subject: [Python-checkins] gh-95913: Edit, xref & sort 3.11 WhatsNew Removed section (#98584) Message-ID: https://github.com/python/cpython/commit/8dbec4dbe57df30ec930c3035f86f8896764bc99 commit: 8dbec4dbe57df30ec930c3035f86f8896764bc99 branch: main author: C.A.M. Gerlach committer: pablogsal date: 2022-10-24T13:33:16+01:00 summary: gh-95913: Edit, xref & sort 3.11 WhatsNew Removed section (#98584) files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 710b6c888f61..a0622d37d953 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1734,95 +1734,98 @@ This section lists Python APIs that have been removed in Python 3.12. Removed C APIs are :ref:`listed separately `. -* :class:`smtpd.MailmanProxy` is now removed as it is unusable without - an external module, ``mailman``. (Contributed by Dong-hee Na in :issue:`35800`.) +* Removed the :func:`!@asyncio.coroutine` :term:`decorator` + enabling legacy generator-based coroutines to be compatible with + :keyword:`async` / :keyword:`await` code. + The function has been deprecated since Python 3.8 and the removal was + initially scheduled for Python 3.10. Use :keyword:`async def` instead. + (Contributed by Illia Volochii in :issue:`43216`.) + +* Removed :class:`!asyncio.coroutines.CoroWrapper` used for wrapping legacy + generator-based coroutine objects in the debug mode. + (Contributed by Illia Volochii in :issue:`43216`.) + +* Due to significant security concerns, the *reuse_address* parameter of + :meth:`asyncio.loop.create_datagram_endpoint`, disabled in Python 3.9, is + now entirely removed. This is because of the behavior of the socket option + ``SO_REUSEADDR`` in UDP. + (Contributed by Hugo van Kemenade in :issue:`45129`.) -* The ``binhex`` module, deprecated in Python 3.9, is now removed. - The following :mod:`binascii` functions, deprecated in Python 3.9, are now - also removed: +* Removed the :mod:`!binhex` module, deprecated in Python 3.9. + Also removed the related, similarly-deprecated :mod:`binascii` functions: - * ``a2b_hqx()``, ``b2a_hqx()``; - * ``rlecode_hqx()``, ``rledecode_hqx()``. + * :func:`!binascii.a2b_hqx` + * :func:`!binascii.b2a_hqx` + * :func:`!binascii.rlecode_hqx` + * :func:`!binascii.rldecode_hqx` The :func:`binascii.crc_hqx` function remains available. (Contributed by Victor Stinner in :issue:`45085`.) -* The distutils ``bdist_msi`` command, deprecated in Python 3.9, is now removed. +* Removed the :mod:`distutils` ``bdist_msi`` command deprecated in Python 3.9. Use ``bdist_wheel`` (wheel packages) instead. (Contributed by Hugo van Kemenade in :issue:`45124`.) -* Due to significant security concerns, the *reuse_address* parameter of - :meth:`asyncio.loop.create_datagram_endpoint`, disabled in Python 3.9, is - now entirely removed. This is because of the behavior of the socket option - ``SO_REUSEADDR`` in UDP. - (Contributed by Hugo van Kemenade in :issue:`45129`.) - -* Removed :meth:`__getitem__` methods of +* Removed the :meth:`~object.__getitem__` methods of :class:`xml.dom.pulldom.DOMEventStream`, :class:`wsgiref.util.FileWrapper` and :class:`fileinput.FileInput`, deprecated since Python 3.9. (Contributed by Hugo van Kemenade in :issue:`45132`.) -* The following deprecated functions and methods are removed in the :mod:`gettext` - module: :func:`~gettext.lgettext`, :func:`~gettext.ldgettext`, - :func:`~gettext.lngettext` and :func:`~gettext.ldngettext`. - - Function :func:`~gettext.bind_textdomain_codeset`, methods - :meth:`~gettext.NullTranslations.output_charset` and - :meth:`~gettext.NullTranslations.set_output_charset`, and the *codeset* - parameter of functions :func:`~gettext.translation` and - :func:`~gettext.install` are also removed, since they are only used for - the ``l*gettext()`` functions. +* Removed the deprecated :mod:`gettext` functions + :func:`!lgettext`, :func:`!ldgettext`, + :func:`!lngettext` and :func:`!ldngettext`. + Also removed the :func:`!bind_textdomain_codeset` function, + the :meth:`!NullTranslations.output_charset` and + :meth:`!NullTranslations.set_output_charset` methods, + and the *codeset* parameter of :func:`!translation` and :func:`!install`, + since they are only used for the :func:`!l*gettext` functions. (Contributed by Dong-hee Na and Serhiy Storchaka in :issue:`44235`.) -* The :func:`@asyncio.coroutine ` :term:`decorator` enabling - legacy generator-based coroutines to be compatible with async/await code. - The function has been deprecated since Python 3.8 and the removal was - initially scheduled for Python 3.10. Use :keyword:`async def` instead. - (Contributed by Illia Volochii in :issue:`43216`.) - -* :class:`asyncio.coroutines.CoroWrapper` used for wrapping legacy - generator-based coroutine objects in the debug mode. - (Contributed by Illia Volochii in :issue:`43216`.) - -* Removed the deprecated ``split()`` method of :class:`_tkinter.TkappType`. - (Contributed by Erlend E. Aasland in :issue:`38371`.) - * Removed from the :mod:`inspect` module: - * the ``getargspec`` function, deprecated since Python 3.0; + * The :func:`!getargspec` function, deprecated since Python 3.0; use :func:`inspect.signature` or :func:`inspect.getfullargspec` instead. - * the ``formatargspec`` function, deprecated since Python 3.5; - use the :func:`inspect.signature` function and :class:`Signature` object - directly. + * The :func:`!formatargspec` function, deprecated since Python 3.5; + use the :func:`inspect.signature` function + or the :class:`inspect.Signature` object directly. - * the undocumented ``Signature.from_builtin`` and ``Signature.from_function`` - functions, deprecated since Python 3.5; use the - :meth:`Signature.from_callable() ` method - instead. + * The undocumented :meth:`!Signature.from_builtin` + and :meth:`!Signature.from_function` methods, deprecated since Python 3.5; + use the :meth:`Signature.from_callable() ` + method instead. (Contributed by Hugo van Kemenade in :issue:`45320`.) -* Remove namespace package support from unittest discovery. It was introduced in - Python 3.4 but has been broken since Python 3.7. - (Contributed by Inada Naoki in :issue:`23882`.) - -* Remove ``__class_getitem__`` method from :class:`pathlib.PurePath`, +* Removed the :meth:`~object.__class_getitem__` method + from :class:`pathlib.PurePath`, because it was not used and added by mistake in previous versions. (Contributed by Nikita Sobolev in :issue:`46483`.) -* Remove the undocumented private ``float.__set_format__()`` method, previously - known as ``float.__setformat__()`` in Python 3.7. Its docstring said: "You - probably don't want to use this function. It exists mainly to be used in - Python's test suite." +* Removed the :class:`!MailmanProxy` class in the :mod:`smtpd` module, + as it is unusable without the external :mod:`!mailman` package. + (Contributed by Dong-hee Na in :issue:`35800`.) + +* Removed the deprecated :meth:`!split` method of :class:`!_tkinter.TkappType`. + (Contributed by Erlend E. Aasland in :issue:`38371`.) + +* Removed namespace package support from :mod:`unittest` discovery. + It was introduced in Python 3.4 but has been broken since Python 3.7. + (Contributed by Inada Naoki in :issue:`23882`.) + +* Removed the undocumented private :meth:`!float.__set_format__()` method, + previously known as :meth:`!float.__setformat__()` in Python 3.7. + Its docstring said: "You probably don't want to use this function. + It exists mainly to be used in Python's test suite." (Contributed by Victor Stinner in :issue:`46852`.) -* The ``--experimental-isolated-subinterpreters`` configure flag - (and corresponding ``EXPERIMENTAL_ISOLATED_SUBINTERPRETERS``) +* The :option:`!--experimental-isolated-subinterpreters` configure flag + (and corresponding :c:macro:`!EXPERIMENTAL_ISOLATED_SUBINTERPRETERS` macro) have been removed. -* Pynche --- The Pythonically Natural Color and Hue Editor --- has been moved out +* `Pynche `_ + --- The Pythonically Natural Color and Hue Editor --- has been moved out of ``Tools/scripts`` and is `being developed independently `_ from the Python source tree. From webhook-mailer at python.org Mon Oct 24 08:33:37 2022 From: webhook-mailer at python.org (pablogsal) Date: Mon, 24 Oct 2022 12:33:37 -0000 Subject: [Python-checkins] gh-95913 Add string section to Whatsnew with new Template methods (#98311) Message-ID: https://github.com/python/cpython/commit/e2dc223004a4230a9f820d2ff617770719a42cc6 commit: e2dc223004a4230a9f820d2ff617770719a42cc6 branch: main author: C.A.M. Gerlach committer: pablogsal date: 2022-10-24T13:33:04+01:00 summary: gh-95913 Add string section to Whatsnew with new Template methods (#98311) files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index c143a418f3c5..710b6c888f61 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -949,6 +949,18 @@ sqlite3 (Contributed by Aviv Palivoda and Erlend E. Aasland in :issue:`24905`.) +.. _whatsnew311-string: + +string +------ + +* Add :meth:`~string.Template.get_identifiers` + and :meth:`~string.Template.is_valid` to :class:`string.Template`, + which respectively return all valid placeholders, + and whether any invalid placeholders are present. + (Contributed by Ben Kehoe in :gh:`90465`.) + + sys --- From webhook-mailer at python.org Mon Oct 24 08:33:37 2022 From: webhook-mailer at python.org (pablogsal) Date: Mon, 24 Oct 2022 12:33:37 -0000 Subject: [Python-checkins] gh-95913: Edit, sort & expand 3.11 WhatsNew Porting section (#98585) Message-ID: https://github.com/python/cpython/commit/43bef54a32feef1eb6a4d63f00f89e2c5a39abd1 commit: 43bef54a32feef1eb6a4d63f00f89e2c5a39abd1 branch: main author: C.A.M. Gerlach committer: pablogsal date: 2022-10-24T13:33:31+01:00 summary: gh-95913: Edit, sort & expand 3.11 WhatsNew Porting section (#98585) files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index a0622d37d953..d8e8764aa338 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1842,22 +1842,23 @@ in the Python API that may require changes to your Python code. Porting notes for the C API are :ref:`listed separately `. -* Prohibited passing non-:class:`concurrent.futures.ThreadPoolExecutor` - executors to :meth:`loop.set_default_executor` following a deprecation in - Python 3.8. - (Contributed by Illia Volochii in :issue:`43234`.) - * :func:`open`, :func:`io.open`, :func:`codecs.open` and :class:`fileinput.FileInput` no longer accept ``'U'`` ("universal newline") - in the file mode. This flag was deprecated since Python 3.3. In Python 3, the - "universal newline" is used by default when a file is open in text mode. The - :ref:`newline parameter ` of :func:`open` controls - how universal newlines works. + in the file mode. In Python 3, "universal newline" mode is used by default + whenever a file is opened in text mode, + and the ``'U'`` flag has been deprecated since Python 3.3. + The :ref:`newline parameter ` + to these functions controls how universal newlines work. (Contributed by Victor Stinner in :issue:`37330`.) -* The :mod:`pdb` module now reads the :file:`.pdbrc` configuration file with - the ``'utf-8'`` encoding. - (Contributed by Srinivas Reddy Thatiparthy (?????????? ?????? ?????????) in :issue:`41137`.) +* :class:`ast.AST` node positions are now validated when provided to + :func:`compile` and other related functions. If invalid positions are detected, + a :exc:`ValueError` will be raised. (Contributed by Pablo Galindo in :gh:`93351`) + +* Prohibited passing non-:class:`concurrent.futures.ThreadPoolExecutor` + executors to :meth:`asyncio.loop.set_default_executor` + following a deprecation in Python 3.8. + (Contributed by Illia Volochii in :issue:`43234`.) * :mod:`calendar`: The :class:`calendar.LocaleTextCalendar` and :class:`calendar.LocaleHTMLCalendar` classes now use @@ -1865,29 +1866,29 @@ Porting notes for the C API are if no locale is specified. (Contributed by Victor Stinner in :issue:`46659`.) -* Global inline flags (e.g. ``(?i)``) can now only be used at the start of - the regular expressions. Using them not at the start of expression was - deprecated since Python 3.6. - (Contributed by Serhiy Storchaka in :issue:`47066`.) - -* :mod:`re` module: Fix a few long-standing bugs where, in rare cases, - capturing group could get wrong result. So the result may be different than - before. - (Contributed by Ma Lin in :issue:`35859`.) +* The :mod:`pdb` module now reads the :file:`.pdbrc` configuration file with + the ``'UTF-8'`` encoding. + (Contributed by Srinivas Reddy Thatiparthy (?????????? ?????? ?????????) in :issue:`41137`.) -* The *population* parameter of :func:`random.sample` must be a sequence. - Automatic conversion of sets to lists is no longer supported. If the sample size +* The *population* parameter of :func:`random.sample` must be a sequence, + and automatic conversion of :class:`set`\s to :class:`list`\s + is no longer supported. Also, if the sample size is larger than the population size, a :exc:`ValueError` is raised. (Contributed by Raymond Hettinger in :issue:`40465`.) -* :class:`ast.AST` node positions are now validated when provided to - :func:`compile` and other related functions. If invalid positions are detected, - a :exc:`ValueError` will be raised. (Contributed by Pablo Galindo in :gh:`93351`) +* The *random* optional parameter of :func:`random.shuffle` was removed. + It was previously an arbitrary random function to use for the shuffle; + now, :func:`random.random` (its previous default) will always be used. -* :c:member:`~PyTypeObject.tp_dictoffset` should be treated as write-only. - It can be set to describe C extension clases to the VM, but should be regarded - as meaningless when read. To get the pointer to the object's dictionary call - :c:func:`PyObject_GenericGetDict` instead. +* In :mod:`re` :ref:`re-syntax`, global inline flags (e.g. ``(?i)``) + can now only be used at the start of regular expressions. + Using them elsewhere has been deprecated since Python 3.6. + (Contributed by Serhiy Storchaka in :issue:`47066`.) + +* In the :mod:`re` module, several long-standing bugs where fixed that, + in rare cases, could cause capture groups to get the wrong result. + Therefore, this could change the captured output in these cases. + (Contributed by Ma Lin in :issue:`35859`.) .. _whatsnew311-build-changes: From webhook-mailer at python.org Mon Oct 24 08:34:10 2022 From: webhook-mailer at python.org (pablogsal) Date: Mon, 24 Oct 2022 12:34:10 -0000 Subject: [Python-checkins] gh-95913: Edit, link and sort 3.11 WhatsNew Build section (#98588) Message-ID: https://github.com/python/cpython/commit/e81fad6b8a2334903fac5799b43997623a2ed904 commit: e81fad6b8a2334903fac5799b43997623a2ed904 branch: main author: C.A.M. Gerlach committer: pablogsal date: 2022-10-24T13:34:05+01:00 summary: gh-95913: Edit, link and sort 3.11 WhatsNew Build section (#98588) files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index d8e8764aa338..8f3ef3ffc135 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1896,31 +1896,66 @@ Porting notes for the C API are Build Changes ============= -* Building Python now requires a C11 compiler. Optional C11 features are not - required. - (Contributed by Victor Stinner in :issue:`46656`.) - -* Building Python now requires support of IEEE 754 floating point numbers. - (Contributed by Victor Stinner in :issue:`46917`.) +* CPython now has :pep:`11` :pep:`Tier 3 support <11#tier-3>` for + cross compiling to the `WebAssembly `_ platforms + `Emscripten `_ + (``wasm32-unknown-emscripten``, i.e. Python in the browser) + and `WebAssembly System Interface (WASI) `_ + (``wasm32-unknown-wasi``). + The effort is inspired by previous work like `Pyodide `_. + These platforms provide a limited subset of POSIX APIs; Python standard + libraries features and modules related to networking, processes, threading, + signals, mmap, and users/groups are not available or don't work. + (Emscripten contributed by Christian Heimes and Ethan Smith in :gh:`84461` + and WASI contributed by Christian Heimes in :gh:`90473`; + platforms promoted in :gh:`95085`) + +* Building Python now requires: + + * A `C11 `_ compiler. + `Optional C11 features + `_ + are not required. + (Contributed by Victor Stinner in :issue:`46656`.) + + * Support for `IEEE 754 `_ + floating point numbers. + (Contributed by Victor Stinner in :issue:`46917`.) + + * Support for `floating point Not-a-Number (NaN) + `_, + as the :c:macro:`!Py_NO_NAN` macro has been removed. + (Contributed by Victor Stinner in :issue:`46656`.) + + * A `C99 `_ + ```` header file providing the + :c:func:`!copysign`, :c:func:`!hypot`, :c:func:`!isfinite`, + :c:func:`!isinf`, :c:func:`!isnan`, and :c:func:`!round` functions + (contributed by Victor Stinner in :issue:`45440`); + and a :c:data:`!NAN` constant or the :c:func:`!__builtin_nan` function + (Contributed by Victor Stinner in :issue:`46640`). + +* The :mod:`tkinter` package now requires `Tcl/Tk `_ + version 8.5.12 or newer. + (Contributed by Serhiy Storchaka in :issue:`46996`.) -* CPython can now be built with the ThinLTO option via ``--with-lto=thin``. - (Contributed by Dong-hee Na and Brett Holman in :issue:`44340`.) +* Build dependencies, compiler flags, and linker flags for most stdlib + extension modules are now detected by :program:`configure`. libffi, libnsl, + libsqlite3, zlib, bzip2, liblzma, libcrypt, Tcl/Tk, and uuid flags + are detected by `pkg-config + `_ (when available). + :mod:`tkinter` now requires a pkg-config command + to detect development settings for `Tcl/Tk`_ headers and libraries. + (Contributed by Christian Heimes and Erlend Egeberg Aasland in + :issue:`45847`, :issue:`45747`, and :issue:`45763`.) * libpython is no longer linked against libcrypt. (Contributed by Mike Gilbert in :issue:`45433`.) -* Building Python now requires a C99 ```` header file providing - the following functions: ``copysign()``, ``hypot()``, ``isfinite()``, - ``isinf()``, ``isnan()``, ``round()``. - (Contributed by Victor Stinner in :issue:`45440`.) - -* Building Python now requires a C99 ```` header file providing - a ``NAN`` constant, or the ``__builtin_nan()`` built-in function. - (Contributed by Victor Stinner in :issue:`46640`.) - -* Building Python now requires support for floating point Not-a-Number (NaN): - remove the ``Py_NO_NAN`` macro. - (Contributed by Victor Stinner in :issue:`46656`.) +* CPython can now be built with the + `ThinLTO `_ option + via passing ``thin`` to :option:`--with-lto`, i.e. ``--with-lto=thin``. + (Contributed by Dong-hee Na and Brett Holman in :issue:`44340`.) * Freelists for object structs can now be disabled. A new :program:`configure` option :option:`!--without-freelists` can be used to disable all freelists @@ -1929,55 +1964,30 @@ Build Changes * ``Modules/Setup`` and ``Modules/makesetup`` have been improved and tied up. Extension modules can now be built through ``makesetup``. All except some - test modules can be linked statically into main binary or library. + test modules can be linked statically into a main binary or library. (Contributed by Brett Cannon and Christian Heimes in :issue:`45548`, :issue:`45570`, :issue:`45571`, and :issue:`43974`.) -* Build dependencies, compiler flags, and linker flags for most stdlib - extension modules are now detected by :program:`configure`. libffi, libnsl, - libsqlite3, zlib, bzip2, liblzma, libcrypt, Tcl/Tk, and uuid flags - are detected by ``pkg-config`` (when available). :mod:`tkinter` now - requires ``pkg-config`` command to detect development settings for Tcl/Tk - headers and libraries. - (Contributed by Christian Heimes and Erlend Egeberg Aasland in - :issue:`45847`, :issue:`45747`, and :issue:`45763`.) - .. note:: - Use the environment variables :envvar:`TCLTK_CFLAGS` and - :envvar:`TCLTK_LIBS` to manually specify the location of Tcl/Tk headers - and libraries. The :program:`configure` options ``--with-tcltk-includes`` - and ``--with-tcltk-libs`` have been removed. + Use the environment variables :envvar:`!TCLTK_CFLAGS` and + :envvar:`!TCLTK_LIBS` to manually specify the location of Tcl/Tk headers + and libraries. The :program:`configure` options + :option:`!--with-tcltk-includes` and :option:`!--with-tcltk-libs` + have been removed. On RHEL 7 and CentOS 7 the development packages do not provide ``tcl.pc`` - and ``tk.pc``, use :envvar:`TCLTK_LIBS="-ltk8.5 -ltkstub8.5 -ltcl8.5"`. + and ``tk.pc``; use ``TCLTK_LIBS="-ltk8.5 -ltkstub8.5 -ltcl8.5"``. The directory ``Misc/rhel7`` contains ``.pc`` files and instructions - how to build Python with RHEL 7's and CentOS 7's Tcl/Tk and OpenSSL. - -* CPython now has :pep:`11` tier 3 support for cross compiling to WebAssembly - platform ``wasm32-unknown-emscripten`` (Python in the browser). The effort - is inspired by previous work like `Pyodide `_. - Emscripten provides a limited subset of POSIX APIs. Python standard - libraries features and modules related to networking, processes, threading, - signals, mmap, and users/groups are not available or don't work. - (Contributed by Christian Heimes and Ethan Smith in :gh:`84461`, - promoted in :gh:`95085`) - -* CPython now has :pep:`11` tier 3 support for cross compiling to WebAssembly - platform ``wasm32-unknown-wasi`` (WebAssembly System Interface). Like on - Emscripten, only a subset of Python's standard library is available on WASI. - (Contributed by Christian Heimes in :gh:`90473`, promoted in :gh:`95085`) + on how to build Python with RHEL 7's and CentOS 7's Tcl/Tk and OpenSSL. * CPython will now use 30-bit digits by default for the Python :class:`int` implementation. Previously, the default was to use 30-bit digits on platforms with ``SIZEOF_VOID_P >= 8``, and 15-bit digits otherwise. It's still possible to explicitly request use of 15-bit digits via either the - ``--enable-big-digits`` option to the configure script or (for Windows) the - ``PYLONG_BITS_IN_DIGIT`` variable in ``PC/pyconfig.h``, but this option may - be removed at some point in the future. (Contributed by Mark Dickinson in - :issue:`45569`.) - -* The :mod:`tkinter` package now requires Tcl/Tk version 8.5.12 or newer. - (Contributed by Serhiy Storchaka in :issue:`46996`.) + :option:`--enable-big-digits` option to the configure script + or (for Windows) the ``PYLONG_BITS_IN_DIGIT`` variable in ``PC/pyconfig.h``, + but this option may be removed at some point in the future. + (Contributed by Mark Dickinson in :issue:`45569`.) .. _whatsnew311-c-api: From webhook-mailer at python.org Mon Oct 24 08:41:06 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 24 Oct 2022 12:41:06 -0000 Subject: [Python-checkins] gh-95913: Edit, sort & expand 3.11 WhatsNew Porting section (GH-98585) Message-ID: https://github.com/python/cpython/commit/1beab508fb828b56c28d8008b823e1152bc52c0f commit: 1beab508fb828b56c28d8008b823e1152bc52c0f branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-24T05:41:00-07:00 summary: gh-95913: Edit, sort & expand 3.11 WhatsNew Porting section (GH-98585) (cherry picked from commit 43bef54a32feef1eb6a4d63f00f89e2c5a39abd1) Co-authored-by: C.A.M. Gerlach files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index c143a418f3c5..548812181792 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1827,22 +1827,23 @@ in the Python API that may require changes to your Python code. Porting notes for the C API are :ref:`listed separately `. -* Prohibited passing non-:class:`concurrent.futures.ThreadPoolExecutor` - executors to :meth:`loop.set_default_executor` following a deprecation in - Python 3.8. - (Contributed by Illia Volochii in :issue:`43234`.) - * :func:`open`, :func:`io.open`, :func:`codecs.open` and :class:`fileinput.FileInput` no longer accept ``'U'`` ("universal newline") - in the file mode. This flag was deprecated since Python 3.3. In Python 3, the - "universal newline" is used by default when a file is open in text mode. The - :ref:`newline parameter ` of :func:`open` controls - how universal newlines works. + in the file mode. In Python 3, "universal newline" mode is used by default + whenever a file is opened in text mode, + and the ``'U'`` flag has been deprecated since Python 3.3. + The :ref:`newline parameter ` + to these functions controls how universal newlines work. (Contributed by Victor Stinner in :issue:`37330`.) -* The :mod:`pdb` module now reads the :file:`.pdbrc` configuration file with - the ``'utf-8'`` encoding. - (Contributed by Srinivas Reddy Thatiparthy (?????????? ?????? ?????????) in :issue:`41137`.) +* :class:`ast.AST` node positions are now validated when provided to + :func:`compile` and other related functions. If invalid positions are detected, + a :exc:`ValueError` will be raised. (Contributed by Pablo Galindo in :gh:`93351`) + +* Prohibited passing non-:class:`concurrent.futures.ThreadPoolExecutor` + executors to :meth:`asyncio.loop.set_default_executor` + following a deprecation in Python 3.8. + (Contributed by Illia Volochii in :issue:`43234`.) * :mod:`calendar`: The :class:`calendar.LocaleTextCalendar` and :class:`calendar.LocaleHTMLCalendar` classes now use @@ -1850,29 +1851,29 @@ Porting notes for the C API are if no locale is specified. (Contributed by Victor Stinner in :issue:`46659`.) -* Global inline flags (e.g. ``(?i)``) can now only be used at the start of - the regular expressions. Using them not at the start of expression was - deprecated since Python 3.6. - (Contributed by Serhiy Storchaka in :issue:`47066`.) - -* :mod:`re` module: Fix a few long-standing bugs where, in rare cases, - capturing group could get wrong result. So the result may be different than - before. - (Contributed by Ma Lin in :issue:`35859`.) +* The :mod:`pdb` module now reads the :file:`.pdbrc` configuration file with + the ``'UTF-8'`` encoding. + (Contributed by Srinivas Reddy Thatiparthy (?????????? ?????? ?????????) in :issue:`41137`.) -* The *population* parameter of :func:`random.sample` must be a sequence. - Automatic conversion of sets to lists is no longer supported. If the sample size +* The *population* parameter of :func:`random.sample` must be a sequence, + and automatic conversion of :class:`set`\s to :class:`list`\s + is no longer supported. Also, if the sample size is larger than the population size, a :exc:`ValueError` is raised. (Contributed by Raymond Hettinger in :issue:`40465`.) -* :class:`ast.AST` node positions are now validated when provided to - :func:`compile` and other related functions. If invalid positions are detected, - a :exc:`ValueError` will be raised. (Contributed by Pablo Galindo in :gh:`93351`) +* The *random* optional parameter of :func:`random.shuffle` was removed. + It was previously an arbitrary random function to use for the shuffle; + now, :func:`random.random` (its previous default) will always be used. -* :c:member:`~PyTypeObject.tp_dictoffset` should be treated as write-only. - It can be set to describe C extension clases to the VM, but should be regarded - as meaningless when read. To get the pointer to the object's dictionary call - :c:func:`PyObject_GenericGetDict` instead. +* In :mod:`re` :ref:`re-syntax`, global inline flags (e.g. ``(?i)``) + can now only be used at the start of regular expressions. + Using them elsewhere has been deprecated since Python 3.6. + (Contributed by Serhiy Storchaka in :issue:`47066`.) + +* In the :mod:`re` module, several long-standing bugs where fixed that, + in rare cases, could cause capture groups to get the wrong result. + Therefore, this could change the captured output in these cases. + (Contributed by Ma Lin in :issue:`35859`.) .. _whatsnew311-build-changes: From webhook-mailer at python.org Mon Oct 24 08:41:12 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 24 Oct 2022 12:41:12 -0000 Subject: [Python-checkins] gh-95913: Edit, xref & sort 3.11 WhatsNew Removed section (GH-98584) Message-ID: https://github.com/python/cpython/commit/5288f66476b9aeb53bbc5718868579c60045c9ab commit: 5288f66476b9aeb53bbc5718868579c60045c9ab branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-24T05:41:07-07:00 summary: gh-95913: Edit, xref & sort 3.11 WhatsNew Removed section (GH-98584) (cherry picked from commit 8dbec4dbe57df30ec930c3035f86f8896764bc99) Co-authored-by: C.A.M. Gerlach files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 548812181792..b0b0b1791f74 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1722,95 +1722,98 @@ This section lists Python APIs that have been removed in Python 3.12. Removed C APIs are :ref:`listed separately `. -* :class:`smtpd.MailmanProxy` is now removed as it is unusable without - an external module, ``mailman``. (Contributed by Dong-hee Na in :issue:`35800`.) +* Removed the :func:`!@asyncio.coroutine` :term:`decorator` + enabling legacy generator-based coroutines to be compatible with + :keyword:`async` / :keyword:`await` code. + The function has been deprecated since Python 3.8 and the removal was + initially scheduled for Python 3.10. Use :keyword:`async def` instead. + (Contributed by Illia Volochii in :issue:`43216`.) + +* Removed :class:`!asyncio.coroutines.CoroWrapper` used for wrapping legacy + generator-based coroutine objects in the debug mode. + (Contributed by Illia Volochii in :issue:`43216`.) + +* Due to significant security concerns, the *reuse_address* parameter of + :meth:`asyncio.loop.create_datagram_endpoint`, disabled in Python 3.9, is + now entirely removed. This is because of the behavior of the socket option + ``SO_REUSEADDR`` in UDP. + (Contributed by Hugo van Kemenade in :issue:`45129`.) -* The ``binhex`` module, deprecated in Python 3.9, is now removed. - The following :mod:`binascii` functions, deprecated in Python 3.9, are now - also removed: +* Removed the :mod:`!binhex` module, deprecated in Python 3.9. + Also removed the related, similarly-deprecated :mod:`binascii` functions: - * ``a2b_hqx()``, ``b2a_hqx()``; - * ``rlecode_hqx()``, ``rledecode_hqx()``. + * :func:`!binascii.a2b_hqx` + * :func:`!binascii.b2a_hqx` + * :func:`!binascii.rlecode_hqx` + * :func:`!binascii.rldecode_hqx` The :func:`binascii.crc_hqx` function remains available. (Contributed by Victor Stinner in :issue:`45085`.) -* The distutils ``bdist_msi`` command, deprecated in Python 3.9, is now removed. +* Removed the :mod:`distutils` ``bdist_msi`` command deprecated in Python 3.9. Use ``bdist_wheel`` (wheel packages) instead. (Contributed by Hugo van Kemenade in :issue:`45124`.) -* Due to significant security concerns, the *reuse_address* parameter of - :meth:`asyncio.loop.create_datagram_endpoint`, disabled in Python 3.9, is - now entirely removed. This is because of the behavior of the socket option - ``SO_REUSEADDR`` in UDP. - (Contributed by Hugo van Kemenade in :issue:`45129`.) - -* Removed :meth:`__getitem__` methods of +* Removed the :meth:`~object.__getitem__` methods of :class:`xml.dom.pulldom.DOMEventStream`, :class:`wsgiref.util.FileWrapper` and :class:`fileinput.FileInput`, deprecated since Python 3.9. (Contributed by Hugo van Kemenade in :issue:`45132`.) -* The following deprecated functions and methods are removed in the :mod:`gettext` - module: :func:`~gettext.lgettext`, :func:`~gettext.ldgettext`, - :func:`~gettext.lngettext` and :func:`~gettext.ldngettext`. - - Function :func:`~gettext.bind_textdomain_codeset`, methods - :meth:`~gettext.NullTranslations.output_charset` and - :meth:`~gettext.NullTranslations.set_output_charset`, and the *codeset* - parameter of functions :func:`~gettext.translation` and - :func:`~gettext.install` are also removed, since they are only used for - the ``l*gettext()`` functions. +* Removed the deprecated :mod:`gettext` functions + :func:`!lgettext`, :func:`!ldgettext`, + :func:`!lngettext` and :func:`!ldngettext`. + Also removed the :func:`!bind_textdomain_codeset` function, + the :meth:`!NullTranslations.output_charset` and + :meth:`!NullTranslations.set_output_charset` methods, + and the *codeset* parameter of :func:`!translation` and :func:`!install`, + since they are only used for the :func:`!l*gettext` functions. (Contributed by Dong-hee Na and Serhiy Storchaka in :issue:`44235`.) -* The :func:`@asyncio.coroutine ` :term:`decorator` enabling - legacy generator-based coroutines to be compatible with async/await code. - The function has been deprecated since Python 3.8 and the removal was - initially scheduled for Python 3.10. Use :keyword:`async def` instead. - (Contributed by Illia Volochii in :issue:`43216`.) - -* :class:`asyncio.coroutines.CoroWrapper` used for wrapping legacy - generator-based coroutine objects in the debug mode. - (Contributed by Illia Volochii in :issue:`43216`.) - -* Removed the deprecated ``split()`` method of :class:`_tkinter.TkappType`. - (Contributed by Erlend E. Aasland in :issue:`38371`.) - * Removed from the :mod:`inspect` module: - * the ``getargspec`` function, deprecated since Python 3.0; + * The :func:`!getargspec` function, deprecated since Python 3.0; use :func:`inspect.signature` or :func:`inspect.getfullargspec` instead. - * the ``formatargspec`` function, deprecated since Python 3.5; - use the :func:`inspect.signature` function and :class:`Signature` object - directly. + * The :func:`!formatargspec` function, deprecated since Python 3.5; + use the :func:`inspect.signature` function + or the :class:`inspect.Signature` object directly. - * the undocumented ``Signature.from_builtin`` and ``Signature.from_function`` - functions, deprecated since Python 3.5; use the - :meth:`Signature.from_callable() ` method - instead. + * The undocumented :meth:`!Signature.from_builtin` + and :meth:`!Signature.from_function` methods, deprecated since Python 3.5; + use the :meth:`Signature.from_callable() ` + method instead. (Contributed by Hugo van Kemenade in :issue:`45320`.) -* Remove namespace package support from unittest discovery. It was introduced in - Python 3.4 but has been broken since Python 3.7. - (Contributed by Inada Naoki in :issue:`23882`.) - -* Remove ``__class_getitem__`` method from :class:`pathlib.PurePath`, +* Removed the :meth:`~object.__class_getitem__` method + from :class:`pathlib.PurePath`, because it was not used and added by mistake in previous versions. (Contributed by Nikita Sobolev in :issue:`46483`.) -* Remove the undocumented private ``float.__set_format__()`` method, previously - known as ``float.__setformat__()`` in Python 3.7. Its docstring said: "You - probably don't want to use this function. It exists mainly to be used in - Python's test suite." +* Removed the :class:`!MailmanProxy` class in the :mod:`smtpd` module, + as it is unusable without the external :mod:`!mailman` package. + (Contributed by Dong-hee Na in :issue:`35800`.) + +* Removed the deprecated :meth:`!split` method of :class:`!_tkinter.TkappType`. + (Contributed by Erlend E. Aasland in :issue:`38371`.) + +* Removed namespace package support from :mod:`unittest` discovery. + It was introduced in Python 3.4 but has been broken since Python 3.7. + (Contributed by Inada Naoki in :issue:`23882`.) + +* Removed the undocumented private :meth:`!float.__set_format__()` method, + previously known as :meth:`!float.__setformat__()` in Python 3.7. + Its docstring said: "You probably don't want to use this function. + It exists mainly to be used in Python's test suite." (Contributed by Victor Stinner in :issue:`46852`.) -* The ``--experimental-isolated-subinterpreters`` configure flag - (and corresponding ``EXPERIMENTAL_ISOLATED_SUBINTERPRETERS``) +* The :option:`!--experimental-isolated-subinterpreters` configure flag + (and corresponding :c:macro:`!EXPERIMENTAL_ISOLATED_SUBINTERPRETERS` macro) have been removed. -* Pynche --- The Pythonically Natural Color and Hue Editor --- has been moved out +* `Pynche `_ + --- The Pythonically Natural Color and Hue Editor --- has been moved out of ``Tools/scripts`` and is `being developed independently `_ from the Python source tree. From webhook-mailer at python.org Mon Oct 24 08:41:47 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 24 Oct 2022 12:41:47 -0000 Subject: [Python-checkins] gh-95913 Add string section to Whatsnew with new Template methods (GH-98311) Message-ID: https://github.com/python/cpython/commit/2af406666e7294aa78655edbc65ec9e87b8dc4bf commit: 2af406666e7294aa78655edbc65ec9e87b8dc4bf branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-24T05:41:42-07:00 summary: gh-95913 Add string section to Whatsnew with new Template methods (GH-98311) (cherry picked from commit e2dc223004a4230a9f820d2ff617770719a42cc6) Co-authored-by: C.A.M. Gerlach files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index b0b0b1791f74..d8e8764aa338 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -949,6 +949,18 @@ sqlite3 (Contributed by Aviv Palivoda and Erlend E. Aasland in :issue:`24905`.) +.. _whatsnew311-string: + +string +------ + +* Add :meth:`~string.Template.get_identifiers` + and :meth:`~string.Template.is_valid` to :class:`string.Template`, + which respectively return all valid placeholders, + and whether any invalid placeholders are present. + (Contributed by Ben Kehoe in :gh:`90465`.) + + sys --- From webhook-mailer at python.org Mon Oct 24 08:41:53 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 24 Oct 2022 12:41:53 -0000 Subject: [Python-checkins] gh-95913: Edit, link and sort 3.11 WhatsNew Build section (GH-98588) Message-ID: https://github.com/python/cpython/commit/3e41c16846601d51fa9c63e3dfef18b8f4e23142 commit: 3e41c16846601d51fa9c63e3dfef18b8f4e23142 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-24T05:41:47-07:00 summary: gh-95913: Edit, link and sort 3.11 WhatsNew Build section (GH-98588) (cherry picked from commit e81fad6b8a2334903fac5799b43997623a2ed904) Co-authored-by: C.A.M. Gerlach files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index d8e8764aa338..8f3ef3ffc135 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1896,31 +1896,66 @@ Porting notes for the C API are Build Changes ============= -* Building Python now requires a C11 compiler. Optional C11 features are not - required. - (Contributed by Victor Stinner in :issue:`46656`.) - -* Building Python now requires support of IEEE 754 floating point numbers. - (Contributed by Victor Stinner in :issue:`46917`.) +* CPython now has :pep:`11` :pep:`Tier 3 support <11#tier-3>` for + cross compiling to the `WebAssembly `_ platforms + `Emscripten `_ + (``wasm32-unknown-emscripten``, i.e. Python in the browser) + and `WebAssembly System Interface (WASI) `_ + (``wasm32-unknown-wasi``). + The effort is inspired by previous work like `Pyodide `_. + These platforms provide a limited subset of POSIX APIs; Python standard + libraries features and modules related to networking, processes, threading, + signals, mmap, and users/groups are not available or don't work. + (Emscripten contributed by Christian Heimes and Ethan Smith in :gh:`84461` + and WASI contributed by Christian Heimes in :gh:`90473`; + platforms promoted in :gh:`95085`) + +* Building Python now requires: + + * A `C11 `_ compiler. + `Optional C11 features + `_ + are not required. + (Contributed by Victor Stinner in :issue:`46656`.) + + * Support for `IEEE 754 `_ + floating point numbers. + (Contributed by Victor Stinner in :issue:`46917`.) + + * Support for `floating point Not-a-Number (NaN) + `_, + as the :c:macro:`!Py_NO_NAN` macro has been removed. + (Contributed by Victor Stinner in :issue:`46656`.) + + * A `C99 `_ + ```` header file providing the + :c:func:`!copysign`, :c:func:`!hypot`, :c:func:`!isfinite`, + :c:func:`!isinf`, :c:func:`!isnan`, and :c:func:`!round` functions + (contributed by Victor Stinner in :issue:`45440`); + and a :c:data:`!NAN` constant or the :c:func:`!__builtin_nan` function + (Contributed by Victor Stinner in :issue:`46640`). + +* The :mod:`tkinter` package now requires `Tcl/Tk `_ + version 8.5.12 or newer. + (Contributed by Serhiy Storchaka in :issue:`46996`.) -* CPython can now be built with the ThinLTO option via ``--with-lto=thin``. - (Contributed by Dong-hee Na and Brett Holman in :issue:`44340`.) +* Build dependencies, compiler flags, and linker flags for most stdlib + extension modules are now detected by :program:`configure`. libffi, libnsl, + libsqlite3, zlib, bzip2, liblzma, libcrypt, Tcl/Tk, and uuid flags + are detected by `pkg-config + `_ (when available). + :mod:`tkinter` now requires a pkg-config command + to detect development settings for `Tcl/Tk`_ headers and libraries. + (Contributed by Christian Heimes and Erlend Egeberg Aasland in + :issue:`45847`, :issue:`45747`, and :issue:`45763`.) * libpython is no longer linked against libcrypt. (Contributed by Mike Gilbert in :issue:`45433`.) -* Building Python now requires a C99 ```` header file providing - the following functions: ``copysign()``, ``hypot()``, ``isfinite()``, - ``isinf()``, ``isnan()``, ``round()``. - (Contributed by Victor Stinner in :issue:`45440`.) - -* Building Python now requires a C99 ```` header file providing - a ``NAN`` constant, or the ``__builtin_nan()`` built-in function. - (Contributed by Victor Stinner in :issue:`46640`.) - -* Building Python now requires support for floating point Not-a-Number (NaN): - remove the ``Py_NO_NAN`` macro. - (Contributed by Victor Stinner in :issue:`46656`.) +* CPython can now be built with the + `ThinLTO `_ option + via passing ``thin`` to :option:`--with-lto`, i.e. ``--with-lto=thin``. + (Contributed by Dong-hee Na and Brett Holman in :issue:`44340`.) * Freelists for object structs can now be disabled. A new :program:`configure` option :option:`!--without-freelists` can be used to disable all freelists @@ -1929,55 +1964,30 @@ Build Changes * ``Modules/Setup`` and ``Modules/makesetup`` have been improved and tied up. Extension modules can now be built through ``makesetup``. All except some - test modules can be linked statically into main binary or library. + test modules can be linked statically into a main binary or library. (Contributed by Brett Cannon and Christian Heimes in :issue:`45548`, :issue:`45570`, :issue:`45571`, and :issue:`43974`.) -* Build dependencies, compiler flags, and linker flags for most stdlib - extension modules are now detected by :program:`configure`. libffi, libnsl, - libsqlite3, zlib, bzip2, liblzma, libcrypt, Tcl/Tk, and uuid flags - are detected by ``pkg-config`` (when available). :mod:`tkinter` now - requires ``pkg-config`` command to detect development settings for Tcl/Tk - headers and libraries. - (Contributed by Christian Heimes and Erlend Egeberg Aasland in - :issue:`45847`, :issue:`45747`, and :issue:`45763`.) - .. note:: - Use the environment variables :envvar:`TCLTK_CFLAGS` and - :envvar:`TCLTK_LIBS` to manually specify the location of Tcl/Tk headers - and libraries. The :program:`configure` options ``--with-tcltk-includes`` - and ``--with-tcltk-libs`` have been removed. + Use the environment variables :envvar:`!TCLTK_CFLAGS` and + :envvar:`!TCLTK_LIBS` to manually specify the location of Tcl/Tk headers + and libraries. The :program:`configure` options + :option:`!--with-tcltk-includes` and :option:`!--with-tcltk-libs` + have been removed. On RHEL 7 and CentOS 7 the development packages do not provide ``tcl.pc`` - and ``tk.pc``, use :envvar:`TCLTK_LIBS="-ltk8.5 -ltkstub8.5 -ltcl8.5"`. + and ``tk.pc``; use ``TCLTK_LIBS="-ltk8.5 -ltkstub8.5 -ltcl8.5"``. The directory ``Misc/rhel7`` contains ``.pc`` files and instructions - how to build Python with RHEL 7's and CentOS 7's Tcl/Tk and OpenSSL. - -* CPython now has :pep:`11` tier 3 support for cross compiling to WebAssembly - platform ``wasm32-unknown-emscripten`` (Python in the browser). The effort - is inspired by previous work like `Pyodide `_. - Emscripten provides a limited subset of POSIX APIs. Python standard - libraries features and modules related to networking, processes, threading, - signals, mmap, and users/groups are not available or don't work. - (Contributed by Christian Heimes and Ethan Smith in :gh:`84461`, - promoted in :gh:`95085`) - -* CPython now has :pep:`11` tier 3 support for cross compiling to WebAssembly - platform ``wasm32-unknown-wasi`` (WebAssembly System Interface). Like on - Emscripten, only a subset of Python's standard library is available on WASI. - (Contributed by Christian Heimes in :gh:`90473`, promoted in :gh:`95085`) + on how to build Python with RHEL 7's and CentOS 7's Tcl/Tk and OpenSSL. * CPython will now use 30-bit digits by default for the Python :class:`int` implementation. Previously, the default was to use 30-bit digits on platforms with ``SIZEOF_VOID_P >= 8``, and 15-bit digits otherwise. It's still possible to explicitly request use of 15-bit digits via either the - ``--enable-big-digits`` option to the configure script or (for Windows) the - ``PYLONG_BITS_IN_DIGIT`` variable in ``PC/pyconfig.h``, but this option may - be removed at some point in the future. (Contributed by Mark Dickinson in - :issue:`45569`.) - -* The :mod:`tkinter` package now requires Tcl/Tk version 8.5.12 or newer. - (Contributed by Serhiy Storchaka in :issue:`46996`.) + :option:`--enable-big-digits` option to the configure script + or (for Windows) the ``PYLONG_BITS_IN_DIGIT`` variable in ``PC/pyconfig.h``, + but this option may be removed at some point in the future. + (Contributed by Mark Dickinson in :issue:`45569`.) .. _whatsnew311-c-api: From webhook-mailer at python.org Mon Oct 24 08:51:31 2022 From: webhook-mailer at python.org (iritkatriel) Date: Mon, 24 Oct 2022 12:51:31 -0000 Subject: [Python-checkins] gh-95913: Edit, expand & format Bytecode sect in 3.11 WhatsNew (GH-98559) Message-ID: https://github.com/python/cpython/commit/22739a0e05fd95847e04aa27831ad4ce4f151c17 commit: 22739a0e05fd95847e04aa27831ad4ce4f151c17 branch: main author: C.A.M. Gerlach committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2022-10-24T13:51:25+01:00 summary: gh-95913: Edit, expand & format Bytecode sect in 3.11 WhatsNew (GH-98559) files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 8f3ef3ffc135..d743c2e08b05 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1481,58 +1481,100 @@ contributors are volunteers from the community. CPython bytecode changes ======================== -* The bytecode now contains inline cache entries, which take the form of - :opcode:`CACHE` instructions. Many opcodes expect to be followed by an exact - number of caches, and instruct the interpreter to skip over them at runtime. - Populated caches can look like arbitrary instructions, so great care should be - taken when reading or modifying raw, adaptive bytecode containing quickened - data. +The bytecode now contains inline cache entries, +which take the form of the newly-added :opcode:`CACHE` instructions. +Many opcodes expect to be followed by an exact number of caches, +and instruct the interpreter to skip over them at runtime. +Populated caches can look like arbitrary instructions, +so great care should be taken when reading or modifying +raw, adaptive bytecode containing quickened data. -* Replaced all numeric ``BINARY_*`` and ``INPLACE_*`` instructions with a single - :opcode:`BINARY_OP` implementation. -* Replaced the three call instructions: :opcode:`CALL_FUNCTION`, - :opcode:`CALL_FUNCTION_KW` and :opcode:`CALL_METHOD` with - :opcode:`PUSH_NULL`, :opcode:`PRECALL`, :opcode:`CALL`, - and :opcode:`KW_NAMES`. - This decouples the argument shifting for methods from the handling of - keyword arguments and allows better specialization of calls. +.. _whatsnew311-added-opcodes: -* Removed ``COPY_DICT_WITHOUT_KEYS`` and ``GEN_START``. +New opcodes +----------- + +* :opcode:`ASYNC_GEN_WRAP`, :opcode:`RETURN_GENERATOR` and :opcode:`SEND`, + used in generators and co-routines. -* :opcode:`MATCH_CLASS` and :opcode:`MATCH_KEYS` no longer push an additional - boolean value indicating whether the match succeeded or failed. Instead, they - indicate failure with :const:`None` (where a tuple of extracted values would - otherwise be). +* :opcode:`COPY_FREE_VARS`, + which avoids needing special caller-side code for closures. -* Replace several stack manipulation instructions (``DUP_TOP``, ``DUP_TOP_TWO``, - ``ROT_TWO``, ``ROT_THREE``, ``ROT_FOUR``, and ``ROT_N``) with new - :opcode:`COPY` and :opcode:`SWAP` instructions. +* :opcode:`JUMP_BACKWARD_NO_INTERRUPT`, + for use in certain loops where handling interrupts is undesirable. -* Replaced :opcode:`JUMP_IF_NOT_EXC_MATCH` by :opcode:`CHECK_EXC_MATCH` which - performs the check but does not jump. +* :opcode:`MAKE_CELL`, to create :ref:`cell-objects`. -* Replaced :opcode:`JUMP_IF_NOT_EG_MATCH` by :opcode:`CHECK_EG_MATCH` which - performs the check but does not jump. +* :opcode:`CHECK_EG_MATCH` and :opcode:`PREP_RERAISE_STAR`, + to handle the :ref:`new exception groups and except* ` + added in :pep:`654`. -* Replaced :opcode:`JUMP_ABSOLUTE` by the relative :opcode:`JUMP_BACKWARD`. +* :opcode:`PUSH_EXC_INFO`, for use in exception handlers. -* Added :opcode:`JUMP_BACKWARD_NO_INTERRUPT`, which is used in certain loops where it - is undesirable to handle interrupts. +* :opcode:`RESUME`, a no-op, + for internal tracing, debugging and optimization checks. -* Replaced :opcode:`POP_JUMP_IF_TRUE` and :opcode:`POP_JUMP_IF_FALSE` by - the relative :opcode:`POP_JUMP_FORWARD_IF_TRUE`, :opcode:`POP_JUMP_BACKWARD_IF_TRUE`, - :opcode:`POP_JUMP_FORWARD_IF_FALSE` and :opcode:`POP_JUMP_BACKWARD_IF_FALSE`. -* Added :opcode:`POP_JUMP_FORWARD_IF_NOT_NONE`, :opcode:`POP_JUMP_BACKWARD_IF_NOT_NONE`, - :opcode:`POP_JUMP_FORWARD_IF_NONE` and :opcode:`POP_JUMP_BACKWARD_IF_NONE` - opcodes to speed up conditional jumps. +.. _whatsnew311-replaced-opcodes: -* :opcode:`JUMP_IF_TRUE_OR_POP` and :opcode:`JUMP_IF_FALSE_OR_POP` are now - relative rather than absolute. +Replaced opcodes +---------------- -* :opcode:`RESUME` has been added. It is a no-op. Performs internal tracing, - debugging and optimization checks. ++------------------------------------+-----------------------------------+-----------------------------------------+ +| Replaced Opcode(s) | New Opcode(s) | Notes | ++====================================+===================================+=========================================+ +| | :opcode:`!BINARY_*` | :opcode:`BINARY_OP` | Replaced all numeric binary/in-place | +| | :opcode:`!INPLACE_*` | | opcodes with a single opcode | ++------------------------------------+-----------------------------------+-----------------------------------------+ +| | :opcode:`!CALL_FUNCTION` | | :opcode:`CALL` | Decouples argument shifting for methods | +| | :opcode:`!CALL_FUNCTION_KW` | | :opcode:`KW_NAMES` | from handling of keyword arguments; | +| | :opcode:`!CALL_METHOD` | | :opcode:`PRECALL` | allows better specialization of calls | +| | | :opcode:`PUSH_NULL` | | ++------------------------------------+-----------------------------------+-----------------------------------------+ +| | :opcode:`!DUP_TOP` | | :opcode:`COPY` | Stack manipulation instructions | +| | :opcode:`!DUP_TOP_TWO` | | :opcode:`SWAP` | | +| | :opcode:`!ROT_TWO` | | | +| | :opcode:`!ROT_THREE` | | | +| | :opcode:`!ROT_FOUR` | | | +| | :opcode:`!ROT_N` | | | ++------------------------------------+-----------------------------------+-----------------------------------------+ +| | :opcode:`!JUMP_IF_NOT_EXC_MATCH` | | :opcode:`CHECK_EXC_MATCH` | Now performs check but doesn't jump | ++------------------------------------+-----------------------------------+-----------------------------------------+ +| | :opcode:`!JUMP_ABSOLUTE` | | :opcode:`JUMP_BACKWARD` | See [#bytecode-jump]_; | +| | :opcode:`!POP_JUMP_IF_FALSE` | | :opcode:`POP_JUMP_BACKWARD_IF_* | ``TRUE``, ``FALSE``, | +| | :opcode:`!POP_JUMP_IF_TRUE` | ` | ``NONE`` and ``NOT_NONE`` variants | +| | | :opcode:`POP_JUMP_FORWARD_IF_* | for each direction | +| | ` | | ++------------------------------------+-----------------------------------+-----------------------------------------+ +| | :opcode:`!SETUP_WITH` | :opcode:`BEFORE_WITH` | :keyword:`with` block setup | +| | :opcode:`!SETUP_ASYNC_WITH` | | | ++------------------------------------+-----------------------------------+-----------------------------------------+ + +.. [#bytecode-jump] All jump opcodes are now relative, including the + existing :opcode:`JUMP_IF_TRUE_OR_POP` and :opcode:`JUMP_IF_FALSE_OR_POP`. + The argument is now an offset from the current instruction + rather than an absolute location. + + +.. _whatsnew311-changed-opcodes: +.. _whatsnew311-removed-opcodes: +.. _whatsnew311-changed-removed-opcodes: + +Changed/removed opcodes +----------------------- + +* Changed :opcode:`MATCH_CLASS` and :opcode:`MATCH_KEYS` + to no longer push an additional boolean value to indicate success/failure. + Instead, ``None`` is pushed on failure + in place of the tuple of extracted values. + +* Changed opcodes that work with exceptions to reflect them + now being represented as one item on the stack instead of three + (see :gh:`89874`). + +* Removed :opcode:`!COPY_DICT_WITHOUT_KEYS`, :opcode:`!GEN_START`, + :opcode:`!POP_BLOCK`, :opcode:`!SETUP_FINALLY` and :opcode:`!YIELD_FROM`. .. _whatsnew311-deprecated: From webhook-mailer at python.org Mon Oct 24 08:58:32 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Mon, 24 Oct 2022 12:58:32 -0000 Subject: [Python-checkins] gh-95913: Edit & expand Deprecated section of 3.11 WhatsNew (#98581) Message-ID: https://github.com/python/cpython/commit/dfb5d272e6b99c2c70c6c53620d2028ef00ba9f2 commit: dfb5d272e6b99c2c70c6c53620d2028ef00ba9f2 branch: main author: C.A.M. Gerlach committer: JelleZijlstra date: 2022-10-24T05:58:27-07:00 summary: gh-95913: Edit & expand Deprecated section of 3.11 WhatsNew (#98581) * Refine Sphinx syntax and grammar/phrasing in Deprecated section items * Organize into lang/builtins, modules & stdlib sections * Convert PEP 594 module list into a grid to not waste as much space * Add importlib.resources deprecated functions to section files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index d743c2e08b05..954b89c82792 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1587,78 +1587,107 @@ This section lists Python APIs that have been deprecated in Python 3.11. Deprecated C APIs are :ref:`listed separately `. + +.. _whatsnew311-deprecated-language: +.. _whatsnew311-deprecated-builtins: + +Language/Builtins +----------------- + * Chaining :class:`classmethod` descriptors (introduced in :issue:`19072`) is now deprecated. It can no longer be used to wrap other descriptors such as :class:`property`. The core design of this feature was flawed and caused a number of downstream problems. To "pass-through" a - :class:`classmethod`, consider using the ``__wrapped__`` attribute + :class:`classmethod`, consider using the :attr:`!__wrapped__` attribute that was added in Python 3.10. (Contributed by Raymond Hettinger in :gh:`89519`.) -* Octal escapes in string and bytes literals with value larger than ``0o377`` now - produce :exc:`DeprecationWarning`. - In a future Python version they will be a :exc:`SyntaxWarning` and +* Octal escapes in string and bytes literals with values larger than ``0o377`` + (255 in decimal) now produce a :exc:`DeprecationWarning`. + In a future Python version, they will raise a :exc:`SyntaxWarning` and eventually a :exc:`SyntaxError`. (Contributed by Serhiy Storchaka in :gh:`81548`.) -* The :mod:`lib2to3` package and ``2to3`` tool are now deprecated and may not - be able to parse Python 3.10 or newer. See the :pep:`617` (New PEG parser for - CPython). (Contributed by Victor Stinner in :issue:`40360`.) +* The delegation of :func:`int` to :meth:`~object.__trunc__` is now deprecated. + Calling ``int(a)`` when ``type(a)`` implements :meth:`!__trunc__` but not + :meth:`~object.__int__` or :meth:`~object.__index__` now raises + a :exc:`DeprecationWarning`. + (Contributed by Zackery Spytz in :issue:`44977`.) -* Undocumented modules ``sre_compile``, ``sre_constants`` and ``sre_parse`` - are now deprecated. - (Contributed by Serhiy Storchaka in :issue:`47152`.) -* :class:`webbrowser.MacOSX` is deprecated and will be removed in Python 3.13. - It is untested and undocumented and also not used by webbrowser itself. - (Contributed by Dong-hee Na in :issue:`42255`.) +.. _whatsnew311-deprecated-modules: -* The behavior of returning a value from a :class:`~unittest.TestCase` and - :class:`~unittest.IsolatedAsyncioTestCase` test methods (other than the - default ``None`` value), is now deprecated. +Modules +------- -* Deprecated the following :mod:`unittest` functions, scheduled for removal in - Python 3.13: +.. _whatsnew311-pep594: - * :func:`unittest.findTestCases` - * :func:`unittest.makeSuite` - * :func:`unittest.getTestCaseNames` +* :pep:`594` led to the deprecations of the following modules + slated for removal in Python 3.13: - Use :class:`~unittest.TestLoader` method instead: + +---------------------+---------------------+---------------------+---------------------+---------------------+ + | :mod:`aifc` | :mod:`chunk` | :mod:`msilib` | :mod:`pipes` | :mod:`telnetlib` | + +---------------------+---------------------+---------------------+---------------------+---------------------+ + | :mod:`audioop` | :mod:`crypt` | :mod:`nis` | :mod:`sndhdr` | :mod:`uu` | + +---------------------+---------------------+---------------------+---------------------+---------------------+ + | :mod:`cgi` | :mod:`imghdr` | :mod:`nntplib` | :mod:`spwd` | :mod:`xdrlib` | + +---------------------+---------------------+---------------------+---------------------+---------------------+ + | :mod:`cgitb` | :mod:`mailcap` | :mod:`ossaudiodev` | :mod:`sunau` | | + +---------------------+---------------------+---------------------+---------------------+---------------------+ - * :meth:`unittest.TestLoader.loadTestsFromModule` - * :meth:`unittest.TestLoader.loadTestsFromTestCase` - * :meth:`unittest.TestLoader.getTestCaseNames` + (Contributed by Brett Cannon in :issue:`47061` and Victor Stinner in + :gh:`68966`.) - (Contributed by Erlend E. Aasland in :issue:`5846`.) +* The :mod:`asynchat`, :mod:`asyncore` and :mod:`smtpd` modules have been + deprecated since at least Python 3.6. Their documentation and deprecation + warnings have now been updated to note they will removed in Python 3.12. + (Contributed by Hugo van Kemenade in :issue:`47022`.) -* The :meth:`turtle.RawTurtle.settiltangle` is deprecated since Python 3.1, - it now emits a deprecation warning and will be removed in Python 3.13. Use - :meth:`turtle.RawTurtle.tiltangle` instead (it was earlier incorrectly marked - as deprecated, its docstring is now corrected). - (Contributed by Hugo van Kemenade in :issue:`45837`.) +* The :mod:`lib2to3` package and :ref:`2to3 <2to3-reference>` tool + are now deprecated and may not be able to parse Python 3.10 or newer. + See :pep:`617`, introducing the new PEG parser, for details. + (Contributed by Victor Stinner in :issue:`40360`.) + +* Undocumented modules :mod:`!sre_compile`, :mod:`!sre_constants` + and :mod:`!sre_parse` are now deprecated. + (Contributed by Serhiy Storchaka in :issue:`47152`.) -* The delegation of :func:`int` to :meth:`__trunc__` is now deprecated. Calling - ``int(a)`` when ``type(a)`` implements :meth:`__trunc__` but not - :meth:`__int__` or :meth:`__index__` now raises a :exc:`DeprecationWarning`. - (Contributed by Zackery Spytz in :issue:`44977`.) + +.. _whatsnew311-deprecated-stdlib: + +Standard Library +---------------- * The following have been deprecated in :mod:`configparser` since Python 3.2. Their deprecation warnings have now been updated to note they will removed in Python 3.12: - * the :class:`configparser.SafeConfigParser` class - * the :attr:`configparser.ParsingError.filename` property + * the :class:`!configparser.SafeConfigParser` class + * the :attr:`!configparser.ParsingError.filename` property * the :meth:`configparser.RawConfigParser.readfp` method (Contributed by Hugo van Kemenade in :issue:`45173`.) -* :class:`configparser.LegacyInterpolation` has been deprecated in the docstring - since Python 3.2. It now emits a :exc:`DeprecationWarning` and will be removed +* :class:`!configparser.LegacyInterpolation` has been deprecated in the docstring + since Python 3.2, and is not listed in the :mod:`configparser` documentation. + It now emits a :exc:`DeprecationWarning` and will be removed in Python 3.13. Use :class:`configparser.BasicInterpolation` or :class:`configparser.ExtendedInterpolation` instead. (Contributed by Hugo van Kemenade in :issue:`46607`.) +* The older set of :mod:`importlib.resources` functions were deprecated + in favor of the replacements added in Python 3.9 + and will be removed in a future Python version, + due to not supporting resources located within package subdirectories: + + * :func:`importlib.resources.contents` + * :func:`importlib.resources.is_resource` + * :func:`importlib.resources.open_binary` + * :func:`importlib.resources.open_text` + * :func:`importlib.resources.read_binary` + * :func:`importlib.resources.read_text` + * :func:`importlib.resources.path` + * The :func:`locale.getdefaultlocale` function is deprecated and will be removed in Python 3.13. Use :func:`locale.setlocale`, :func:`locale.getpreferredencoding(False) ` and @@ -1669,46 +1698,25 @@ Deprecated C APIs are :ref:`listed separately `. removed in Python 3.13. Use ``locale.setlocale(locale.LC_ALL, "")`` instead. (Contributed by Victor Stinner in :gh:`90817`.) -.. _whatsnew311-pep594: - -* :pep:`594` led to the deprecations of the following modules which are - slated for removal in Python 3.13: - - * :mod:`aifc` - * :mod:`audioop` - * :mod:`cgi` - * :mod:`cgitb` - * :mod:`chunk` - * :mod:`crypt` - * :mod:`imghdr` - * :mod:`mailcap` - * :mod:`msilib` - * :mod:`nis` - * :mod:`nntplib` - * :mod:`ossaudiodev` - * :mod:`pipes` - * :mod:`sndhdr` - * :mod:`spwd` - * :mod:`sunau` - * :mod:`telnetlib` - * :mod:`uu` - * :mod:`xdrlib` - - (Contributed by Brett Cannon in :issue:`47061` and Victor Stinner in - :gh:`68966`.) +* Stricter rules will now be applied for numerical group references + and group names in :ref:`regular expressions `. + Only sequences of ASCII digits will now be accepted as a numerical reference, + and the group name in :class:`bytes` patterns and replacement strings + can only contain ASCII letters, digits and underscores. + For now, a deprecation warning is raised for syntax violating these rules. + (Contributed by Serhiy Storchaka in :gh:`91760`.) -* The :mod:`asynchat`, :mod:`asyncore` and :mod:`smtpd` modules have been - deprecated since at least Python 3.6. Their documentation and deprecation - warnings have now been updated to note they will removed in Python 3.12. - (Contributed by Hugo van Kemenade in :issue:`47022`.) +* In the :mod:`re` module, the :func:`!re.template` function + and the corresponding :data:`!re.TEMPLATE` and :data:`!re.T` flags + are deprecated, as they were undocumented and lacked an obvious purpose. + They will be removed in Python 3.13. + (Contributed by Serhiy Storchaka and Miro Hron?ok in :gh:`92728`.) -* More strict rules will be applied now applied for numerical group references - and group names in regular expressions in future Python versions. - Only sequence of ASCII digits will be now accepted as a numerical reference. - The group name in bytes patterns and replacement strings could only - contain ASCII letters and digits and underscore. - For now, a deprecation warning is raised for such syntax. - (Contributed by Serhiy Storchaka in :gh:`91760`.) +* :func:`turtle.settiltangle` has been deprecated since Python 3.1; + it now emits a deprecation warning and will be removed in Python 3.13. Use + :func:`turtle.tiltangle` instead (it was earlier incorrectly marked + as deprecated, and its docstring is now corrected). + (Contributed by Hugo van Kemenade in :issue:`45837`.) * :class:`typing.Text`, which exists solely to provide compatibility support between Python 2 and Python 3 code, is now deprecated. Its removal is @@ -1716,14 +1724,32 @@ Deprecated C APIs are :ref:`listed separately `. wherever possible. (Contributed by Alex Waygood in :gh:`92332`.) -* The keyword argument syntax for constructing :data:`~typing.TypedDict` types +* The keyword argument syntax for constructing :data:`typing.TypedDict` types is now deprecated. Support will be removed in Python 3.13. (Contributed by Jingchen Ye in :gh:`90224`.) -* The :func:`re.template` function and the corresponding :const:`re.TEMPLATE` - and :const:`re.T` flags are deprecated, as they were undocumented and - lacked an obvious purpose. They will be removed in Python 3.13. - (Contributed by Serhiy Storchaka and Miro Hron?ok in :gh:`92728`.) +* :class:`!webbrowser.MacOSX` is deprecated and will be removed in Python 3.13. + It is untested, undocumented, and not used by :mod:`webbrowser` itself. + (Contributed by Dong-hee Na in :issue:`42255`.) + +* The behavior of returning a value from a :class:`~unittest.TestCase` and + :class:`~unittest.IsolatedAsyncioTestCase` test methods (other than the + default ``None`` value) is now deprecated. + +* Deprecated the following not-formally-documented :mod:`unittest` functions, + scheduled for removal in Python 3.13: + + * :func:`!unittest.findTestCases` + * :func:`!unittest.makeSuite` + * :func:`!unittest.getTestCaseNames` + + Use :class:`~unittest.TestLoader` methods instead: + + * :meth:`unittest.TestLoader.loadTestsFromModule` + * :meth:`unittest.TestLoader.loadTestsFromTestCase` + * :meth:`unittest.TestLoader.getTestCaseNames` + + (Contributed by Erlend E. Aasland in :issue:`5846`.) .. _whatsnew311-pending-removal: From webhook-mailer at python.org Mon Oct 24 08:59:15 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 24 Oct 2022 12:59:15 -0000 Subject: [Python-checkins] gh-95913: Edit, expand & format Bytecode sect in 3.11 WhatsNew (GH-98559) Message-ID: https://github.com/python/cpython/commit/2a346b0d283c7ac43823d247d8f583b283a2af98 commit: 2a346b0d283c7ac43823d247d8f583b283a2af98 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-24T05:59:09-07:00 summary: gh-95913: Edit, expand & format Bytecode sect in 3.11 WhatsNew (GH-98559) (cherry picked from commit 22739a0e05fd95847e04aa27831ad4ce4f151c17) Co-authored-by: C.A.M. Gerlach files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 8f3ef3ffc135..d743c2e08b05 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1481,58 +1481,100 @@ contributors are volunteers from the community. CPython bytecode changes ======================== -* The bytecode now contains inline cache entries, which take the form of - :opcode:`CACHE` instructions. Many opcodes expect to be followed by an exact - number of caches, and instruct the interpreter to skip over them at runtime. - Populated caches can look like arbitrary instructions, so great care should be - taken when reading or modifying raw, adaptive bytecode containing quickened - data. +The bytecode now contains inline cache entries, +which take the form of the newly-added :opcode:`CACHE` instructions. +Many opcodes expect to be followed by an exact number of caches, +and instruct the interpreter to skip over them at runtime. +Populated caches can look like arbitrary instructions, +so great care should be taken when reading or modifying +raw, adaptive bytecode containing quickened data. -* Replaced all numeric ``BINARY_*`` and ``INPLACE_*`` instructions with a single - :opcode:`BINARY_OP` implementation. -* Replaced the three call instructions: :opcode:`CALL_FUNCTION`, - :opcode:`CALL_FUNCTION_KW` and :opcode:`CALL_METHOD` with - :opcode:`PUSH_NULL`, :opcode:`PRECALL`, :opcode:`CALL`, - and :opcode:`KW_NAMES`. - This decouples the argument shifting for methods from the handling of - keyword arguments and allows better specialization of calls. +.. _whatsnew311-added-opcodes: -* Removed ``COPY_DICT_WITHOUT_KEYS`` and ``GEN_START``. +New opcodes +----------- + +* :opcode:`ASYNC_GEN_WRAP`, :opcode:`RETURN_GENERATOR` and :opcode:`SEND`, + used in generators and co-routines. -* :opcode:`MATCH_CLASS` and :opcode:`MATCH_KEYS` no longer push an additional - boolean value indicating whether the match succeeded or failed. Instead, they - indicate failure with :const:`None` (where a tuple of extracted values would - otherwise be). +* :opcode:`COPY_FREE_VARS`, + which avoids needing special caller-side code for closures. -* Replace several stack manipulation instructions (``DUP_TOP``, ``DUP_TOP_TWO``, - ``ROT_TWO``, ``ROT_THREE``, ``ROT_FOUR``, and ``ROT_N``) with new - :opcode:`COPY` and :opcode:`SWAP` instructions. +* :opcode:`JUMP_BACKWARD_NO_INTERRUPT`, + for use in certain loops where handling interrupts is undesirable. -* Replaced :opcode:`JUMP_IF_NOT_EXC_MATCH` by :opcode:`CHECK_EXC_MATCH` which - performs the check but does not jump. +* :opcode:`MAKE_CELL`, to create :ref:`cell-objects`. -* Replaced :opcode:`JUMP_IF_NOT_EG_MATCH` by :opcode:`CHECK_EG_MATCH` which - performs the check but does not jump. +* :opcode:`CHECK_EG_MATCH` and :opcode:`PREP_RERAISE_STAR`, + to handle the :ref:`new exception groups and except* ` + added in :pep:`654`. -* Replaced :opcode:`JUMP_ABSOLUTE` by the relative :opcode:`JUMP_BACKWARD`. +* :opcode:`PUSH_EXC_INFO`, for use in exception handlers. -* Added :opcode:`JUMP_BACKWARD_NO_INTERRUPT`, which is used in certain loops where it - is undesirable to handle interrupts. +* :opcode:`RESUME`, a no-op, + for internal tracing, debugging and optimization checks. -* Replaced :opcode:`POP_JUMP_IF_TRUE` and :opcode:`POP_JUMP_IF_FALSE` by - the relative :opcode:`POP_JUMP_FORWARD_IF_TRUE`, :opcode:`POP_JUMP_BACKWARD_IF_TRUE`, - :opcode:`POP_JUMP_FORWARD_IF_FALSE` and :opcode:`POP_JUMP_BACKWARD_IF_FALSE`. -* Added :opcode:`POP_JUMP_FORWARD_IF_NOT_NONE`, :opcode:`POP_JUMP_BACKWARD_IF_NOT_NONE`, - :opcode:`POP_JUMP_FORWARD_IF_NONE` and :opcode:`POP_JUMP_BACKWARD_IF_NONE` - opcodes to speed up conditional jumps. +.. _whatsnew311-replaced-opcodes: -* :opcode:`JUMP_IF_TRUE_OR_POP` and :opcode:`JUMP_IF_FALSE_OR_POP` are now - relative rather than absolute. +Replaced opcodes +---------------- -* :opcode:`RESUME` has been added. It is a no-op. Performs internal tracing, - debugging and optimization checks. ++------------------------------------+-----------------------------------+-----------------------------------------+ +| Replaced Opcode(s) | New Opcode(s) | Notes | ++====================================+===================================+=========================================+ +| | :opcode:`!BINARY_*` | :opcode:`BINARY_OP` | Replaced all numeric binary/in-place | +| | :opcode:`!INPLACE_*` | | opcodes with a single opcode | ++------------------------------------+-----------------------------------+-----------------------------------------+ +| | :opcode:`!CALL_FUNCTION` | | :opcode:`CALL` | Decouples argument shifting for methods | +| | :opcode:`!CALL_FUNCTION_KW` | | :opcode:`KW_NAMES` | from handling of keyword arguments; | +| | :opcode:`!CALL_METHOD` | | :opcode:`PRECALL` | allows better specialization of calls | +| | | :opcode:`PUSH_NULL` | | ++------------------------------------+-----------------------------------+-----------------------------------------+ +| | :opcode:`!DUP_TOP` | | :opcode:`COPY` | Stack manipulation instructions | +| | :opcode:`!DUP_TOP_TWO` | | :opcode:`SWAP` | | +| | :opcode:`!ROT_TWO` | | | +| | :opcode:`!ROT_THREE` | | | +| | :opcode:`!ROT_FOUR` | | | +| | :opcode:`!ROT_N` | | | ++------------------------------------+-----------------------------------+-----------------------------------------+ +| | :opcode:`!JUMP_IF_NOT_EXC_MATCH` | | :opcode:`CHECK_EXC_MATCH` | Now performs check but doesn't jump | ++------------------------------------+-----------------------------------+-----------------------------------------+ +| | :opcode:`!JUMP_ABSOLUTE` | | :opcode:`JUMP_BACKWARD` | See [#bytecode-jump]_; | +| | :opcode:`!POP_JUMP_IF_FALSE` | | :opcode:`POP_JUMP_BACKWARD_IF_* | ``TRUE``, ``FALSE``, | +| | :opcode:`!POP_JUMP_IF_TRUE` | ` | ``NONE`` and ``NOT_NONE`` variants | +| | | :opcode:`POP_JUMP_FORWARD_IF_* | for each direction | +| | ` | | ++------------------------------------+-----------------------------------+-----------------------------------------+ +| | :opcode:`!SETUP_WITH` | :opcode:`BEFORE_WITH` | :keyword:`with` block setup | +| | :opcode:`!SETUP_ASYNC_WITH` | | | ++------------------------------------+-----------------------------------+-----------------------------------------+ + +.. [#bytecode-jump] All jump opcodes are now relative, including the + existing :opcode:`JUMP_IF_TRUE_OR_POP` and :opcode:`JUMP_IF_FALSE_OR_POP`. + The argument is now an offset from the current instruction + rather than an absolute location. + + +.. _whatsnew311-changed-opcodes: +.. _whatsnew311-removed-opcodes: +.. _whatsnew311-changed-removed-opcodes: + +Changed/removed opcodes +----------------------- + +* Changed :opcode:`MATCH_CLASS` and :opcode:`MATCH_KEYS` + to no longer push an additional boolean value to indicate success/failure. + Instead, ``None`` is pushed on failure + in place of the tuple of extracted values. + +* Changed opcodes that work with exceptions to reflect them + now being represented as one item on the stack instead of three + (see :gh:`89874`). + +* Removed :opcode:`!COPY_DICT_WITHOUT_KEYS`, :opcode:`!GEN_START`, + :opcode:`!POP_BLOCK`, :opcode:`!SETUP_FINALLY` and :opcode:`!YIELD_FROM`. .. _whatsnew311-deprecated: From webhook-mailer at python.org Mon Oct 24 09:05:20 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Mon, 24 Oct 2022 13:05:20 -0000 Subject: [Python-checkins] gh-95913: Add io support for SpooledTemporaryFile in 3.11 Whatsnew (#98312) Message-ID: https://github.com/python/cpython/commit/f3f8b6fca53c02eb8841c1a7b85a5af05aeaf4db commit: f3f8b6fca53c02eb8841c1a7b85a5af05aeaf4db branch: main author: C.A.M. Gerlach committer: JelleZijlstra date: 2022-10-24T06:05:14-07:00 summary: gh-95913: Add io support for SpooledTemporaryFile in 3.11 Whatsnew (#98312) files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 954b89c82792..d9528c62e67c 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -995,6 +995,19 @@ sysconfig (Contributed by Miro Hron?ok in :issue:`45413`.) +.. _whatsnew311-tempfile: + +tempfile +-------- + +* :class:`~tempfile.SpooledTemporaryFile` objects now fully implements the methods + of :class:`io.BufferedIOBase` or :class:`io.TextIOBase` + (depending on file mode). + This lets them work correctly with APIs that expect file-like objects, + such as compression modules. + (Contributed by Carey Metcalfe in :gh:`70363`.) + + threading --------- From webhook-mailer at python.org Mon Oct 24 09:08:27 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 24 Oct 2022 13:08:27 -0000 Subject: [Python-checkins] gh-95913: Edit & expand Deprecated section of 3.11 WhatsNew (GH-98581) Message-ID: https://github.com/python/cpython/commit/3aed2ac002800a5174d9d0fac73a67af13c1cdf5 commit: 3aed2ac002800a5174d9d0fac73a67af13c1cdf5 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-24T06:08:20-07:00 summary: gh-95913: Edit & expand Deprecated section of 3.11 WhatsNew (GH-98581) * Refine Sphinx syntax and grammar/phrasing in Deprecated section items * Organize into lang/builtins, modules & stdlib sections * Convert PEP 594 module list into a grid to not waste as much space * Add importlib.resources deprecated functions to section (cherry picked from commit dfb5d272e6b99c2c70c6c53620d2028ef00ba9f2) Co-authored-by: C.A.M. Gerlach files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index d743c2e08b05..954b89c82792 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1587,78 +1587,107 @@ This section lists Python APIs that have been deprecated in Python 3.11. Deprecated C APIs are :ref:`listed separately `. + +.. _whatsnew311-deprecated-language: +.. _whatsnew311-deprecated-builtins: + +Language/Builtins +----------------- + * Chaining :class:`classmethod` descriptors (introduced in :issue:`19072`) is now deprecated. It can no longer be used to wrap other descriptors such as :class:`property`. The core design of this feature was flawed and caused a number of downstream problems. To "pass-through" a - :class:`classmethod`, consider using the ``__wrapped__`` attribute + :class:`classmethod`, consider using the :attr:`!__wrapped__` attribute that was added in Python 3.10. (Contributed by Raymond Hettinger in :gh:`89519`.) -* Octal escapes in string and bytes literals with value larger than ``0o377`` now - produce :exc:`DeprecationWarning`. - In a future Python version they will be a :exc:`SyntaxWarning` and +* Octal escapes in string and bytes literals with values larger than ``0o377`` + (255 in decimal) now produce a :exc:`DeprecationWarning`. + In a future Python version, they will raise a :exc:`SyntaxWarning` and eventually a :exc:`SyntaxError`. (Contributed by Serhiy Storchaka in :gh:`81548`.) -* The :mod:`lib2to3` package and ``2to3`` tool are now deprecated and may not - be able to parse Python 3.10 or newer. See the :pep:`617` (New PEG parser for - CPython). (Contributed by Victor Stinner in :issue:`40360`.) +* The delegation of :func:`int` to :meth:`~object.__trunc__` is now deprecated. + Calling ``int(a)`` when ``type(a)`` implements :meth:`!__trunc__` but not + :meth:`~object.__int__` or :meth:`~object.__index__` now raises + a :exc:`DeprecationWarning`. + (Contributed by Zackery Spytz in :issue:`44977`.) -* Undocumented modules ``sre_compile``, ``sre_constants`` and ``sre_parse`` - are now deprecated. - (Contributed by Serhiy Storchaka in :issue:`47152`.) -* :class:`webbrowser.MacOSX` is deprecated and will be removed in Python 3.13. - It is untested and undocumented and also not used by webbrowser itself. - (Contributed by Dong-hee Na in :issue:`42255`.) +.. _whatsnew311-deprecated-modules: -* The behavior of returning a value from a :class:`~unittest.TestCase` and - :class:`~unittest.IsolatedAsyncioTestCase` test methods (other than the - default ``None`` value), is now deprecated. +Modules +------- -* Deprecated the following :mod:`unittest` functions, scheduled for removal in - Python 3.13: +.. _whatsnew311-pep594: - * :func:`unittest.findTestCases` - * :func:`unittest.makeSuite` - * :func:`unittest.getTestCaseNames` +* :pep:`594` led to the deprecations of the following modules + slated for removal in Python 3.13: - Use :class:`~unittest.TestLoader` method instead: + +---------------------+---------------------+---------------------+---------------------+---------------------+ + | :mod:`aifc` | :mod:`chunk` | :mod:`msilib` | :mod:`pipes` | :mod:`telnetlib` | + +---------------------+---------------------+---------------------+---------------------+---------------------+ + | :mod:`audioop` | :mod:`crypt` | :mod:`nis` | :mod:`sndhdr` | :mod:`uu` | + +---------------------+---------------------+---------------------+---------------------+---------------------+ + | :mod:`cgi` | :mod:`imghdr` | :mod:`nntplib` | :mod:`spwd` | :mod:`xdrlib` | + +---------------------+---------------------+---------------------+---------------------+---------------------+ + | :mod:`cgitb` | :mod:`mailcap` | :mod:`ossaudiodev` | :mod:`sunau` | | + +---------------------+---------------------+---------------------+---------------------+---------------------+ - * :meth:`unittest.TestLoader.loadTestsFromModule` - * :meth:`unittest.TestLoader.loadTestsFromTestCase` - * :meth:`unittest.TestLoader.getTestCaseNames` + (Contributed by Brett Cannon in :issue:`47061` and Victor Stinner in + :gh:`68966`.) - (Contributed by Erlend E. Aasland in :issue:`5846`.) +* The :mod:`asynchat`, :mod:`asyncore` and :mod:`smtpd` modules have been + deprecated since at least Python 3.6. Their documentation and deprecation + warnings have now been updated to note they will removed in Python 3.12. + (Contributed by Hugo van Kemenade in :issue:`47022`.) -* The :meth:`turtle.RawTurtle.settiltangle` is deprecated since Python 3.1, - it now emits a deprecation warning and will be removed in Python 3.13. Use - :meth:`turtle.RawTurtle.tiltangle` instead (it was earlier incorrectly marked - as deprecated, its docstring is now corrected). - (Contributed by Hugo van Kemenade in :issue:`45837`.) +* The :mod:`lib2to3` package and :ref:`2to3 <2to3-reference>` tool + are now deprecated and may not be able to parse Python 3.10 or newer. + See :pep:`617`, introducing the new PEG parser, for details. + (Contributed by Victor Stinner in :issue:`40360`.) + +* Undocumented modules :mod:`!sre_compile`, :mod:`!sre_constants` + and :mod:`!sre_parse` are now deprecated. + (Contributed by Serhiy Storchaka in :issue:`47152`.) -* The delegation of :func:`int` to :meth:`__trunc__` is now deprecated. Calling - ``int(a)`` when ``type(a)`` implements :meth:`__trunc__` but not - :meth:`__int__` or :meth:`__index__` now raises a :exc:`DeprecationWarning`. - (Contributed by Zackery Spytz in :issue:`44977`.) + +.. _whatsnew311-deprecated-stdlib: + +Standard Library +---------------- * The following have been deprecated in :mod:`configparser` since Python 3.2. Their deprecation warnings have now been updated to note they will removed in Python 3.12: - * the :class:`configparser.SafeConfigParser` class - * the :attr:`configparser.ParsingError.filename` property + * the :class:`!configparser.SafeConfigParser` class + * the :attr:`!configparser.ParsingError.filename` property * the :meth:`configparser.RawConfigParser.readfp` method (Contributed by Hugo van Kemenade in :issue:`45173`.) -* :class:`configparser.LegacyInterpolation` has been deprecated in the docstring - since Python 3.2. It now emits a :exc:`DeprecationWarning` and will be removed +* :class:`!configparser.LegacyInterpolation` has been deprecated in the docstring + since Python 3.2, and is not listed in the :mod:`configparser` documentation. + It now emits a :exc:`DeprecationWarning` and will be removed in Python 3.13. Use :class:`configparser.BasicInterpolation` or :class:`configparser.ExtendedInterpolation` instead. (Contributed by Hugo van Kemenade in :issue:`46607`.) +* The older set of :mod:`importlib.resources` functions were deprecated + in favor of the replacements added in Python 3.9 + and will be removed in a future Python version, + due to not supporting resources located within package subdirectories: + + * :func:`importlib.resources.contents` + * :func:`importlib.resources.is_resource` + * :func:`importlib.resources.open_binary` + * :func:`importlib.resources.open_text` + * :func:`importlib.resources.read_binary` + * :func:`importlib.resources.read_text` + * :func:`importlib.resources.path` + * The :func:`locale.getdefaultlocale` function is deprecated and will be removed in Python 3.13. Use :func:`locale.setlocale`, :func:`locale.getpreferredencoding(False) ` and @@ -1669,46 +1698,25 @@ Deprecated C APIs are :ref:`listed separately `. removed in Python 3.13. Use ``locale.setlocale(locale.LC_ALL, "")`` instead. (Contributed by Victor Stinner in :gh:`90817`.) -.. _whatsnew311-pep594: - -* :pep:`594` led to the deprecations of the following modules which are - slated for removal in Python 3.13: - - * :mod:`aifc` - * :mod:`audioop` - * :mod:`cgi` - * :mod:`cgitb` - * :mod:`chunk` - * :mod:`crypt` - * :mod:`imghdr` - * :mod:`mailcap` - * :mod:`msilib` - * :mod:`nis` - * :mod:`nntplib` - * :mod:`ossaudiodev` - * :mod:`pipes` - * :mod:`sndhdr` - * :mod:`spwd` - * :mod:`sunau` - * :mod:`telnetlib` - * :mod:`uu` - * :mod:`xdrlib` - - (Contributed by Brett Cannon in :issue:`47061` and Victor Stinner in - :gh:`68966`.) +* Stricter rules will now be applied for numerical group references + and group names in :ref:`regular expressions `. + Only sequences of ASCII digits will now be accepted as a numerical reference, + and the group name in :class:`bytes` patterns and replacement strings + can only contain ASCII letters, digits and underscores. + For now, a deprecation warning is raised for syntax violating these rules. + (Contributed by Serhiy Storchaka in :gh:`91760`.) -* The :mod:`asynchat`, :mod:`asyncore` and :mod:`smtpd` modules have been - deprecated since at least Python 3.6. Their documentation and deprecation - warnings have now been updated to note they will removed in Python 3.12. - (Contributed by Hugo van Kemenade in :issue:`47022`.) +* In the :mod:`re` module, the :func:`!re.template` function + and the corresponding :data:`!re.TEMPLATE` and :data:`!re.T` flags + are deprecated, as they were undocumented and lacked an obvious purpose. + They will be removed in Python 3.13. + (Contributed by Serhiy Storchaka and Miro Hron?ok in :gh:`92728`.) -* More strict rules will be applied now applied for numerical group references - and group names in regular expressions in future Python versions. - Only sequence of ASCII digits will be now accepted as a numerical reference. - The group name in bytes patterns and replacement strings could only - contain ASCII letters and digits and underscore. - For now, a deprecation warning is raised for such syntax. - (Contributed by Serhiy Storchaka in :gh:`91760`.) +* :func:`turtle.settiltangle` has been deprecated since Python 3.1; + it now emits a deprecation warning and will be removed in Python 3.13. Use + :func:`turtle.tiltangle` instead (it was earlier incorrectly marked + as deprecated, and its docstring is now corrected). + (Contributed by Hugo van Kemenade in :issue:`45837`.) * :class:`typing.Text`, which exists solely to provide compatibility support between Python 2 and Python 3 code, is now deprecated. Its removal is @@ -1716,14 +1724,32 @@ Deprecated C APIs are :ref:`listed separately `. wherever possible. (Contributed by Alex Waygood in :gh:`92332`.) -* The keyword argument syntax for constructing :data:`~typing.TypedDict` types +* The keyword argument syntax for constructing :data:`typing.TypedDict` types is now deprecated. Support will be removed in Python 3.13. (Contributed by Jingchen Ye in :gh:`90224`.) -* The :func:`re.template` function and the corresponding :const:`re.TEMPLATE` - and :const:`re.T` flags are deprecated, as they were undocumented and - lacked an obvious purpose. They will be removed in Python 3.13. - (Contributed by Serhiy Storchaka and Miro Hron?ok in :gh:`92728`.) +* :class:`!webbrowser.MacOSX` is deprecated and will be removed in Python 3.13. + It is untested, undocumented, and not used by :mod:`webbrowser` itself. + (Contributed by Dong-hee Na in :issue:`42255`.) + +* The behavior of returning a value from a :class:`~unittest.TestCase` and + :class:`~unittest.IsolatedAsyncioTestCase` test methods (other than the + default ``None`` value) is now deprecated. + +* Deprecated the following not-formally-documented :mod:`unittest` functions, + scheduled for removal in Python 3.13: + + * :func:`!unittest.findTestCases` + * :func:`!unittest.makeSuite` + * :func:`!unittest.getTestCaseNames` + + Use :class:`~unittest.TestLoader` methods instead: + + * :meth:`unittest.TestLoader.loadTestsFromModule` + * :meth:`unittest.TestLoader.loadTestsFromTestCase` + * :meth:`unittest.TestLoader.getTestCaseNames` + + (Contributed by Erlend E. Aasland in :issue:`5846`.) .. _whatsnew311-pending-removal: From webhook-mailer at python.org Mon Oct 24 09:13:51 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 24 Oct 2022 13:13:51 -0000 Subject: [Python-checkins] gh-95913: Add io support for SpooledTemporaryFile in 3.11 Whatsnew (GH-98312) Message-ID: https://github.com/python/cpython/commit/c4ad3fce6653020cfe16c2512faedc3be80ed09d commit: c4ad3fce6653020cfe16c2512faedc3be80ed09d branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-24T06:13:46-07:00 summary: gh-95913: Add io support for SpooledTemporaryFile in 3.11 Whatsnew (GH-98312) (cherry picked from commit f3f8b6fca53c02eb8841c1a7b85a5af05aeaf4db) Co-authored-by: C.A.M. Gerlach files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 954b89c82792..d9528c62e67c 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -995,6 +995,19 @@ sysconfig (Contributed by Miro Hron?ok in :issue:`45413`.) +.. _whatsnew311-tempfile: + +tempfile +-------- + +* :class:`~tempfile.SpooledTemporaryFile` objects now fully implements the methods + of :class:`io.BufferedIOBase` or :class:`io.TextIOBase` + (depending on file mode). + This lets them work correctly with APIs that expect file-like objects, + such as compression modules. + (Contributed by Carey Metcalfe in :gh:`70363`.) + + threading --------- From webhook-mailer at python.org Mon Oct 24 09:35:33 2022 From: webhook-mailer at python.org (encukou) Date: Mon, 24 Oct 2022 13:35:33 -0000 Subject: [Python-checkins] gh-95913: Fix, sort & expand pending removal sect in 3.11 WhatsNew (GH-98583) Message-ID: https://github.com/python/cpython/commit/e19c2b979fab3483dc6c04774053dbbe83e769fb commit: e19c2b979fab3483dc6c04774053dbbe83e769fb branch: main author: C.A.M. Gerlach committer: encukou date: 2022-10-24T15:35:28+02:00 summary: gh-95913: Fix, sort & expand pending removal sect in 3.11 WhatsNew (GH-98583) * Fix names/references of pending removal APIs * Sort list of APIs pending removal alphabetically * Add missing modules/submodules pending removal in 3.12 * Add table of unittest deprecated aliases to 3.11 What's New Co-authored-by: Jelle Zijlstra Co-authored-by: Petr Viktorin files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index d9528c62e67c..d91307abf141 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1777,33 +1777,56 @@ and will be removed in Python 3.12. C APIs pending removal are :ref:`listed separately `. -* :class:`pkgutil.ImpImporter` -* :class:`pkgutil.ImpLoader` -* :envvar:`PYTHONTHREADDEBUG` +* The :mod:`asynchat` module +* The :mod:`asyncore` module +* The :ref:`entire distutils package ` +* The :mod:`imp` module +* The :class:`typing.io ` namespace +* The :class:`typing.re ` namespace +* :func:`!cgi.log` * :func:`importlib.find_loader` -* :func:`importlib.util.module_for_loader` -* :func:`importlib.util.set_loader_wrapper` -* :func:`importlib.util.set_package_wrapper` * :meth:`importlib.abc.Loader.module_repr` -* :meth:`importlib.abc.Loadermodule_repr` -* :meth:`importlib.abc.MetaPathFinder.find_module` * :meth:`importlib.abc.MetaPathFinder.find_module` * :meth:`importlib.abc.PathEntryFinder.find_loader` * :meth:`importlib.abc.PathEntryFinder.find_module` -* :meth:`importlib.machinery.BuiltinImporter.find_module` -* :meth:`importlib.machinery.BuiltinLoader.module_repr` -* :meth:`importlib.machinery.FileFinder.find_loader` -* :meth:`importlib.machinery.FileFinder.find_module` -* :meth:`importlib.machinery.FrozenImporter.find_module` -* :meth:`importlib.machinery.FrozenLoader.module_repr` +* :meth:`!importlib.machinery.BuiltinImporter.find_module` +* :meth:`!importlib.machinery.BuiltinLoader.module_repr` +* :meth:`!importlib.machinery.FileFinder.find_loader` +* :meth:`!importlib.machinery.FileFinder.find_module` +* :meth:`!importlib.machinery.FrozenImporter.find_module` +* :meth:`!importlib.machinery.FrozenLoader.module_repr` * :meth:`importlib.machinery.PathFinder.find_module` -* :meth:`importlib.machinery.WindowsRegistryFinder.find_module` +* :meth:`!importlib.machinery.WindowsRegistryFinder.find_module` +* :func:`importlib.util.module_for_loader` +* :func:`!importlib.util.set_loader_wrapper` +* :func:`!importlib.util.set_package_wrapper` +* :class:`pkgutil.ImpImporter` +* :class:`pkgutil.ImpLoader` * :meth:`pathlib.Path.link_to` -* The entire :ref:`distutils namespace ` -* :func:`cgi.log` -* :func:`sqlite3.OptimizedUnicode` -* :func:`sqlite3.enable_shared_cache` - +* :func:`!sqlite3.enable_shared_cache` +* :func:`!sqlite3.OptimizedUnicode` +* :envvar:`PYTHONTHREADDEBUG` environment variable +* The following deprecated aliases in :mod:`unittest`: + + ============================ =============================== =============== + Deprecated alias Method Name Deprecated in + ============================ =============================== =============== + ``failUnless`` :meth:`.assertTrue` 3.1 + ``failIf`` :meth:`.assertFalse` 3.1 + ``failUnlessEqual`` :meth:`.assertEqual` 3.1 + ``failIfEqual`` :meth:`.assertNotEqual` 3.1 + ``failUnlessAlmostEqual`` :meth:`.assertAlmostEqual` 3.1 + ``failIfAlmostEqual`` :meth:`.assertNotAlmostEqual` 3.1 + ``failUnlessRaises`` :meth:`.assertRaises` 3.1 + ``assert_`` :meth:`.assertTrue` 3.2 + ``assertEquals`` :meth:`.assertEqual` 3.2 + ``assertNotEquals`` :meth:`.assertNotEqual` 3.2 + ``assertAlmostEquals`` :meth:`.assertAlmostEqual` 3.2 + ``assertNotAlmostEquals`` :meth:`.assertNotAlmostEqual` 3.2 + ``assertRegexpMatches`` :meth:`.assertRegex` 3.2 + ``assertRaisesRegexp`` :meth:`.assertRaisesRegex` 3.2 + ``assertNotRegexpMatches`` :meth:`.assertNotRegex` 3.5 + ============================ =============================== =============== .. _whatsnew311-removed: .. _whatsnew311-python-api-removed: From webhook-mailer at python.org Mon Oct 24 10:13:44 2022 From: webhook-mailer at python.org (encukou) Date: Mon, 24 Oct 2022 14:13:44 -0000 Subject: [Python-checkins] gh-97909: Mark up members of PyMemberDef (GH-98473) Message-ID: https://github.com/python/cpython/commit/c2370763793734aa6be8dbc326b70132770eaeaa commit: c2370763793734aa6be8dbc326b70132770eaeaa branch: main author: Johnny11502 <113304663+Johnny11502 at users.noreply.github.com> committer: encukou date: 2022-10-24T16:13:38+02:00 summary: gh-97909: Mark up members of PyMemberDef (GH-98473) Co-authored-by: T files: M Doc/c-api/structures.rst diff --git a/Doc/c-api/structures.rst b/Doc/c-api/structures.rst index ee757e3a186e..183ac144c50d 100644 --- a/Doc/c-api/structures.rst +++ b/Doc/c-api/structures.rst @@ -387,27 +387,27 @@ Accessing attributes of extension types Structure which describes an attribute of a type which corresponds to a C struct member. Its fields are: - +------------------+---------------+-------------------------------+ - | Field | C Type | Meaning | - +==================+===============+===============================+ - | :attr:`name` | const char \* | name of the member | - +------------------+---------------+-------------------------------+ - | :attr:`!type` | int | the type of the member in the | - | | | C struct | - +------------------+---------------+-------------------------------+ - | :attr:`offset` | Py_ssize_t | the offset in bytes that the | - | | | member is located on the | - | | | type's object struct | - +------------------+---------------+-------------------------------+ - | :attr:`flags` | int | flag bits indicating if the | - | | | field should be read-only or | - | | | writable | - +------------------+---------------+-------------------------------+ - | :attr:`doc` | const char \* | points to the contents of the | - | | | docstring | - +------------------+---------------+-------------------------------+ + .. c:member:: const char* PyMemberDef.name + + Name of the member + + .. c:member:: int PyMemberDef.type + + The type of the member in the C struct. + + .. c:member:: Py_ssize_t PyMemberDef.offset + + The offset in bytes that the member is located on the type?s object struct. + + .. c:member:: int PyMemberDef.flags + + Flag bits indicating if the field should be read-only or writable. + + .. c:member:: const char* PyMemberDef.doc + + Points to the contents of the docstring. - :attr:`!type` can be one of many ``T_`` macros corresponding to various C + :c:member:`PyMemberDef.type` can be one of many ``T_`` macros corresponding to various C types. When the member is accessed in Python, it will be converted to the equivalent Python type. @@ -441,7 +441,7 @@ Accessing attributes of extension types handles use of the :keyword:`del` statement on that attribute more correctly than :c:macro:`T_OBJECT`. - :attr:`flags` can be ``0`` for write and read access or :c:macro:`READONLY` for + :c:member:`PyMemberDef.flags` can be ``0`` for write and read access or :c:macro:`READONLY` for read-only access. Using :c:macro:`T_STRING` for :attr:`type` implies :c:macro:`READONLY`. :c:macro:`T_STRING` data is interpreted as UTF-8. Only :c:macro:`T_OBJECT` and :c:macro:`T_OBJECT_EX` From webhook-mailer at python.org Mon Oct 24 12:26:51 2022 From: webhook-mailer at python.org (gvanrossum) Date: Mon, 24 Oct 2022 16:26:51 -0000 Subject: [Python-checkins] [3.11] GH-98539: fix ref cycle in `_SSLProtocolTransport` after close (GH-98540) (#98551) Message-ID: https://github.com/python/cpython/commit/bd8b32b519055b5411e1954698e596d728fc848e commit: bd8b32b519055b5411e1954698e596d728fc848e branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: gvanrossum date: 2022-10-24T09:26:32-07:00 summary: [3.11] GH-98539: fix ref cycle in `_SSLProtocolTransport` after close (GH-98540) (#98551) GH-98539: fix ref cycle in `_SSLProtocolTransport` after close (GH-98540) (cherry picked from commit 62bf5d8d0a36112619436a813ceefb7e4af52c24) Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> files: M Lib/asyncio/sslproto.py diff --git a/Lib/asyncio/sslproto.py b/Lib/asyncio/sslproto.py index de00953cc1d0..5cb5cd35883f 100644 --- a/Lib/asyncio/sslproto.py +++ b/Lib/asyncio/sslproto.py @@ -107,8 +107,11 @@ def close(self): protocol's connection_lost() method will (eventually) called with None as its argument. """ - self._closed = True - self._ssl_protocol._start_shutdown() + if not self._closed: + self._closed = True + self._ssl_protocol._start_shutdown() + else: + self._ssl_protocol = None def __del__(self, _warnings=warnings): if not self._closed: From webhook-mailer at python.org Mon Oct 24 12:45:57 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Mon, 24 Oct 2022 16:45:57 -0000 Subject: [Python-checkins] gh-95913: Fix grammar for SpooledTemporaryFile 3.11 whatsnew entry (#98604) Message-ID: https://github.com/python/cpython/commit/c5a9d3f67fc4b62543ddf6bc7b9ed392c2a81ec3 commit: c5a9d3f67fc4b62543ddf6bc7b9ed392c2a81ec3 branch: main author: Jelle Zijlstra committer: JelleZijlstra date: 2022-10-24T09:45:43-07:00 summary: gh-95913: Fix grammar for SpooledTemporaryFile 3.11 whatsnew entry (#98604) Followup from #98312. files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index d91307abf141..deec42006850 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1000,7 +1000,7 @@ sysconfig tempfile -------- -* :class:`~tempfile.SpooledTemporaryFile` objects now fully implements the methods +* :class:`~tempfile.SpooledTemporaryFile` objects now fully implement the methods of :class:`io.BufferedIOBase` or :class:`io.TextIOBase` (depending on file mode). This lets them work correctly with APIs that expect file-like objects, From webhook-mailer at python.org Mon Oct 24 12:53:21 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 24 Oct 2022 16:53:21 -0000 Subject: [Python-checkins] gh-95913: Fix grammar for SpooledTemporaryFile 3.11 whatsnew entry (GH-98604) Message-ID: https://github.com/python/cpython/commit/3f6cfc5678092e51804113dbd45c621921eb1f29 commit: 3f6cfc5678092e51804113dbd45c621921eb1f29 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-24T09:53:15-07:00 summary: gh-95913: Fix grammar for SpooledTemporaryFile 3.11 whatsnew entry (GH-98604) Followup from GH-98312. (cherry picked from commit c5a9d3f67fc4b62543ddf6bc7b9ed392c2a81ec3) Co-authored-by: Jelle Zijlstra files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index d9528c62e67c..7aa071cc97cc 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1000,7 +1000,7 @@ sysconfig tempfile -------- -* :class:`~tempfile.SpooledTemporaryFile` objects now fully implements the methods +* :class:`~tempfile.SpooledTemporaryFile` objects now fully implement the methods of :class:`io.BufferedIOBase` or :class:`io.TextIOBase` (depending on file mode). This lets them work correctly with APIs that expect file-like objects, From webhook-mailer at python.org Mon Oct 24 13:48:01 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Mon, 24 Oct 2022 17:48:01 -0000 Subject: [Python-checkins] gh-98500: Fix typing docs for `*View` classes (#98511) Message-ID: https://github.com/python/cpython/commit/1a217f9ffc6d014536c08d7fb0136d117b8a0add commit: 1a217f9ffc6d014536c08d7fb0136d117b8a0add branch: main author: Nikita Sobolev committer: JelleZijlstra date: 2022-10-24T10:47:32-07:00 summary: gh-98500: Fix typing docs for `*View` classes (#98511) files: M Doc/library/typing.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index ae7e22306996..53690ec7f60a 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -2096,7 +2096,7 @@ Corresponding to collections in :mod:`collections.abc` :class:`collections.abc.Container` now supports ``[]``. See :pep:`585` and :ref:`types-genericalias`. -.. class:: ItemsView(MappingView, Generic[KT_co, VT_co]) +.. class:: ItemsView(MappingView, AbstractSet[tuple[KT_co, VT_co]]) A generic version of :class:`collections.abc.ItemsView`. @@ -2104,7 +2104,7 @@ Corresponding to collections in :mod:`collections.abc` :class:`collections.abc.ItemsView` now supports ``[]``. See :pep:`585` and :ref:`types-genericalias`. -.. class:: KeysView(MappingView[KT_co], AbstractSet[KT_co]) +.. class:: KeysView(MappingView, AbstractSet[KT_co]) A generic version of :class:`collections.abc.KeysView`. @@ -2124,7 +2124,7 @@ Corresponding to collections in :mod:`collections.abc` :class:`collections.abc.Mapping` now supports ``[]``. See :pep:`585` and :ref:`types-genericalias`. -.. class:: MappingView(Sized, Iterable[T_co]) +.. class:: MappingView(Sized) A generic version of :class:`collections.abc.MappingView`. @@ -2164,7 +2164,7 @@ Corresponding to collections in :mod:`collections.abc` :class:`collections.abc.Sequence` now supports ``[]``. See :pep:`585` and :ref:`types-genericalias`. -.. class:: ValuesView(MappingView[VT_co]) +.. class:: ValuesView(MappingView, Collection[_VT_co]) A generic version of :class:`collections.abc.ValuesView`. From webhook-mailer at python.org Mon Oct 24 13:50:41 2022 From: webhook-mailer at python.org (gvanrossum) Date: Mon, 24 Oct 2022 17:50:41 -0000 Subject: [Python-checkins] GH-98407: fix `test_kill_issue43884` to not leak child processes (#98491) Message-ID: https://github.com/python/cpython/commit/3b2724abcfef7cbe5bf1717be1bb029e4c6b6600 commit: 3b2724abcfef7cbe5bf1717be1bb029e4c6b6600 branch: main author: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> committer: gvanrossum date: 2022-10-24T10:50:35-07:00 summary: GH-98407: fix `test_kill_issue43884` to not leak child processes (#98491) files: M Lib/test/test_asyncio/test_subprocess.py diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py index fe1d060c77d4..20bca3e6b727 100644 --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -184,7 +184,10 @@ def test_kill(self): self.assertEqual(-signal.SIGKILL, returncode) def test_kill_issue43884(self): - blocking_shell_command = f'{sys.executable} -c "import time; time.sleep(100000000)"' + if sys.platform == 'win32': + blocking_shell_command = f'{sys.executable} -c "import time; time.sleep(100000000)"' + else: + blocking_shell_command = 'sleep 1; sleep 1' creationflags = 0 if sys.platform == 'win32': from subprocess import CREATE_NEW_PROCESS_GROUP From webhook-mailer at python.org Mon Oct 24 13:52:07 2022 From: webhook-mailer at python.org (gvanrossum) Date: Mon, 24 Oct 2022 17:52:07 -0000 Subject: [Python-checkins] GH-91635: clarify docs about closing of transport in asyncio (#98563) Message-ID: https://github.com/python/cpython/commit/2fdcc6f2cb5e3e1e09b8dff179f4c11193799998 commit: 2fdcc6f2cb5e3e1e09b8dff179f4c11193799998 branch: main author: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> committer: gvanrossum date: 2022-10-24T10:52:02-07:00 summary: GH-91635: clarify docs about closing of transport in asyncio (#98563) files: M Doc/library/asyncio-protocol.rst diff --git a/Doc/library/asyncio-protocol.rst b/Doc/library/asyncio-protocol.rst index 969354ceb163..7bc906eaafc1 100644 --- a/Doc/library/asyncio-protocol.rst +++ b/Doc/library/asyncio-protocol.rst @@ -156,7 +156,8 @@ Base Transport will be received. After all buffered data is flushed, the protocol's :meth:`protocol.connection_lost() ` method will be called with - :const:`None` as its argument. + :const:`None` as its argument. The transport should not be + used once it is closed. .. method:: BaseTransport.is_closing() From webhook-mailer at python.org Mon Oct 24 13:54:41 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 24 Oct 2022 17:54:41 -0000 Subject: [Python-checkins] gh-98500: Fix typing docs for `*View` classes (GH-98511) Message-ID: https://github.com/python/cpython/commit/e69509f468f2c6f3802eb4595dd008cf4352e326 commit: e69509f468f2c6f3802eb4595dd008cf4352e326 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-24T10:54:35-07:00 summary: gh-98500: Fix typing docs for `*View` classes (GH-98511) (cherry picked from commit 1a217f9ffc6d014536c08d7fb0136d117b8a0add) Co-authored-by: Nikita Sobolev files: M Doc/library/typing.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 198bc880f9d7..41571035a3a9 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -1791,7 +1791,7 @@ Corresponding to collections in :mod:`collections.abc` :class:`collections.abc.Container` now supports ``[]``. See :pep:`585` and :ref:`types-genericalias`. -.. class:: ItemsView(MappingView, Generic[KT_co, VT_co]) +.. class:: ItemsView(MappingView, AbstractSet[tuple[KT_co, VT_co]]) A generic version of :class:`collections.abc.ItemsView`. @@ -1799,7 +1799,7 @@ Corresponding to collections in :mod:`collections.abc` :class:`collections.abc.ItemsView` now supports ``[]``. See :pep:`585` and :ref:`types-genericalias`. -.. class:: KeysView(MappingView[KT_co], AbstractSet[KT_co]) +.. class:: KeysView(MappingView, AbstractSet[KT_co]) A generic version of :class:`collections.abc.KeysView`. @@ -1819,7 +1819,7 @@ Corresponding to collections in :mod:`collections.abc` :class:`collections.abc.Mapping` now supports ``[]``. See :pep:`585` and :ref:`types-genericalias`. -.. class:: MappingView(Sized, Iterable[T_co]) +.. class:: MappingView(Sized) A generic version of :class:`collections.abc.MappingView`. @@ -1859,7 +1859,7 @@ Corresponding to collections in :mod:`collections.abc` :class:`collections.abc.Sequence` now supports ``[]``. See :pep:`585` and :ref:`types-genericalias`. -.. class:: ValuesView(MappingView[VT_co]) +.. class:: ValuesView(MappingView, Collection[_VT_co]) A generic version of :class:`collections.abc.ValuesView`. From webhook-mailer at python.org Mon Oct 24 13:55:16 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 24 Oct 2022 17:55:16 -0000 Subject: [Python-checkins] gh-98500: Fix typing docs for `*View` classes (GH-98511) Message-ID: https://github.com/python/cpython/commit/d9abd8a584794430c7df22c248fa41bfaa3d1124 commit: d9abd8a584794430c7df22c248fa41bfaa3d1124 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-24T10:55:11-07:00 summary: gh-98500: Fix typing docs for `*View` classes (GH-98511) (cherry picked from commit 1a217f9ffc6d014536c08d7fb0136d117b8a0add) Co-authored-by: Nikita Sobolev files: M Doc/library/typing.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index a9c71c466205..42aa52980a76 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -2096,7 +2096,7 @@ Corresponding to collections in :mod:`collections.abc` :class:`collections.abc.Container` now supports ``[]``. See :pep:`585` and :ref:`types-genericalias`. -.. class:: ItemsView(MappingView, Generic[KT_co, VT_co]) +.. class:: ItemsView(MappingView, AbstractSet[tuple[KT_co, VT_co]]) A generic version of :class:`collections.abc.ItemsView`. @@ -2104,7 +2104,7 @@ Corresponding to collections in :mod:`collections.abc` :class:`collections.abc.ItemsView` now supports ``[]``. See :pep:`585` and :ref:`types-genericalias`. -.. class:: KeysView(MappingView[KT_co], AbstractSet[KT_co]) +.. class:: KeysView(MappingView, AbstractSet[KT_co]) A generic version of :class:`collections.abc.KeysView`. @@ -2124,7 +2124,7 @@ Corresponding to collections in :mod:`collections.abc` :class:`collections.abc.Mapping` now supports ``[]``. See :pep:`585` and :ref:`types-genericalias`. -.. class:: MappingView(Sized, Iterable[T_co]) +.. class:: MappingView(Sized) A generic version of :class:`collections.abc.MappingView`. @@ -2164,7 +2164,7 @@ Corresponding to collections in :mod:`collections.abc` :class:`collections.abc.Sequence` now supports ``[]``. See :pep:`585` and :ref:`types-genericalias`. -.. class:: ValuesView(MappingView[VT_co]) +.. class:: ValuesView(MappingView, Collection[_VT_co]) A generic version of :class:`collections.abc.ValuesView`. From webhook-mailer at python.org Mon Oct 24 14:00:24 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 24 Oct 2022 18:00:24 -0000 Subject: [Python-checkins] GH-91635: clarify docs about closing of transport in asyncio (GH-98563) Message-ID: https://github.com/python/cpython/commit/032d1276edd5bedd99f199ea53be101e0816f018 commit: 032d1276edd5bedd99f199ea53be101e0816f018 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-24T11:00:18-07:00 summary: GH-91635: clarify docs about closing of transport in asyncio (GH-98563) (cherry picked from commit 2fdcc6f2cb5e3e1e09b8dff179f4c11193799998) Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> files: M Doc/library/asyncio-protocol.rst diff --git a/Doc/library/asyncio-protocol.rst b/Doc/library/asyncio-protocol.rst index 969354ceb163..7bc906eaafc1 100644 --- a/Doc/library/asyncio-protocol.rst +++ b/Doc/library/asyncio-protocol.rst @@ -156,7 +156,8 @@ Base Transport will be received. After all buffered data is flushed, the protocol's :meth:`protocol.connection_lost() ` method will be called with - :const:`None` as its argument. + :const:`None` as its argument. The transport should not be + used once it is closed. .. method:: BaseTransport.is_closing() From webhook-mailer at python.org Mon Oct 24 14:01:42 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 24 Oct 2022 18:01:42 -0000 Subject: [Python-checkins] GH-91635: clarify docs about closing of transport in asyncio (GH-98563) Message-ID: https://github.com/python/cpython/commit/39e914c03aa14c60c78b93f126eb845cea18b3d9 commit: 39e914c03aa14c60c78b93f126eb845cea18b3d9 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-24T11:01:37-07:00 summary: GH-91635: clarify docs about closing of transport in asyncio (GH-98563) (cherry picked from commit 2fdcc6f2cb5e3e1e09b8dff179f4c11193799998) Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> files: M Doc/library/asyncio-protocol.rst diff --git a/Doc/library/asyncio-protocol.rst b/Doc/library/asyncio-protocol.rst index 969354ceb163..7bc906eaafc1 100644 --- a/Doc/library/asyncio-protocol.rst +++ b/Doc/library/asyncio-protocol.rst @@ -156,7 +156,8 @@ Base Transport will be received. After all buffered data is flushed, the protocol's :meth:`protocol.connection_lost() ` method will be called with - :const:`None` as its argument. + :const:`None` as its argument. The transport should not be + used once it is closed. .. method:: BaseTransport.is_closing() From webhook-mailer at python.org Mon Oct 24 14:08:34 2022 From: webhook-mailer at python.org (gvanrossum) Date: Mon, 24 Oct 2022 18:08:34 -0000 Subject: [Python-checkins] [3.11] GH-98543: Fix `asyncio.TaskGroup` to not keep reference to errors after raising ExceptionGroup (GH-98544) (#98550) Message-ID: https://github.com/python/cpython/commit/36d25a4f7f8263cac9f8609e0347d4060d1dce3b commit: 36d25a4f7f8263cac9f8609e0347d4060d1dce3b branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: gvanrossum date: 2022-10-24T11:08:22-07:00 summary: [3.11] GH-98543: Fix `asyncio.TaskGroup` to not keep reference to errors after raising ExceptionGroup (GH-98544) (#98550) GH-98543: Fix `asyncio.TaskGroup` to not keep reference to errors after raising ExceptionGroup (GH-98544) (cherry picked from commit f4a14941e6e54b15012fca067f6a9b2ff29f201a) Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> files: M Lib/asyncio/taskgroups.py diff --git a/Lib/asyncio/taskgroups.py b/Lib/asyncio/taskgroups.py index 5d5e2a8a85dd..911419e1769c 100644 --- a/Lib/asyncio/taskgroups.py +++ b/Lib/asyncio/taskgroups.py @@ -128,11 +128,11 @@ async def __aexit__(self, et, exc, tb): # Exceptions are heavy objects that can have object # cycles (bad for GC); let's not keep a reference to # a bunch of them. - errors = self._errors - self._errors = None - - me = BaseExceptionGroup('unhandled errors in a TaskGroup', errors) - raise me from None + try: + me = BaseExceptionGroup('unhandled errors in a TaskGroup', self._errors) + raise me from None + finally: + self._errors = None def create_task(self, coro, *, name=None, context=None): if not self._entered: From webhook-mailer at python.org Mon Oct 24 14:10:30 2022 From: webhook-mailer at python.org (AlexWaygood) Date: Mon, 24 Oct 2022 18:10:30 -0000 Subject: [Python-checkins] gh-98507: [typing docs] Rephrase "now supports `[]`" to "now supports subscripting" (#98508) Message-ID: https://github.com/python/cpython/commit/e3b9dd8e870a61016e0f221e30d4f7d0b99cddb3 commit: e3b9dd8e870a61016e0f221e30d4f7d0b99cddb3 branch: main author: Nikita Sobolev committer: AlexWaygood date: 2022-10-24T19:10:25+01:00 summary: gh-98507: [typing docs] Rephrase "now supports `[]`" to "now supports subscripting" (#98508) files: M Doc/library/typing.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 53690ec7f60a..886b5ca42dd9 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -760,8 +760,8 @@ These can be used as types in annotations using ``[]``, each having a unique syn is equivalent to ``Tuple[Any, ...]``, and in turn to :class:`tuple`. .. deprecated:: 3.9 - :class:`builtins.tuple ` now supports ``[]``. See :pep:`585` and - :ref:`types-genericalias`. + :class:`builtins.tuple ` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. data:: Union @@ -849,8 +849,8 @@ These can be used as types in annotations using ``[]``, each having a unique syn respectively. .. deprecated:: 3.9 - :class:`collections.abc.Callable` now supports ``[]``. See :pep:`585` and - :ref:`types-genericalias`. + :class:`collections.abc.Callable` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. versionchanged:: 3.10 ``Callable`` now supports :class:`ParamSpec` and :data:`Concatenate`. @@ -957,8 +957,8 @@ These can be used as types in annotations using ``[]``, each having a unique syn .. versionadded:: 3.5.2 .. deprecated:: 3.9 - :class:`builtins.type ` now supports ``[]``. See :pep:`585` and - :ref:`types-genericalias`. + :class:`builtins.type ` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. data:: Literal @@ -1896,8 +1896,8 @@ Corresponding to built-in types ... .. deprecated:: 3.9 - :class:`builtins.dict ` now supports ``[]``. See :pep:`585` and - :ref:`types-genericalias`. + :class:`builtins.dict ` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: List(list, MutableSequence[T]) @@ -1917,8 +1917,8 @@ Corresponding to built-in types return [item for item in vector if item > 0] .. deprecated:: 3.9 - :class:`builtins.list ` now supports ``[]``. See :pep:`585` and - :ref:`types-genericalias`. + :class:`builtins.list ` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: Set(set, MutableSet[T]) @@ -1927,16 +1927,17 @@ Corresponding to built-in types to use an abstract collection type such as :class:`AbstractSet`. .. deprecated:: 3.9 - :class:`builtins.set ` now supports ``[]``. See :pep:`585` and - :ref:`types-genericalias`. + :class:`builtins.set ` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: FrozenSet(frozenset, AbstractSet[T_co]) A generic version of :class:`builtins.frozenset `. .. deprecated:: 3.9 - :class:`builtins.frozenset ` now supports ``[]``. See - :pep:`585` and :ref:`types-genericalias`. + :class:`builtins.frozenset ` + now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. note:: :data:`Tuple` is a special form. @@ -1950,8 +1951,8 @@ Corresponding to types in :mod:`collections` .. versionadded:: 3.5.2 .. deprecated:: 3.9 - :class:`collections.defaultdict` now supports ``[]``. See :pep:`585` and - :ref:`types-genericalias`. + :class:`collections.defaultdict` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: OrderedDict(collections.OrderedDict, MutableMapping[KT, VT]) @@ -1960,8 +1961,8 @@ Corresponding to types in :mod:`collections` .. versionadded:: 3.7.2 .. deprecated:: 3.9 - :class:`collections.OrderedDict` now supports ``[]``. See :pep:`585` and - :ref:`types-genericalias`. + :class:`collections.OrderedDict` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: ChainMap(collections.ChainMap, MutableMapping[KT, VT]) @@ -1971,8 +1972,8 @@ Corresponding to types in :mod:`collections` .. versionadded:: 3.6.1 .. deprecated:: 3.9 - :class:`collections.ChainMap` now supports ``[]``. See :pep:`585` and - :ref:`types-genericalias`. + :class:`collections.ChainMap` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: Counter(collections.Counter, Dict[T, int]) @@ -1982,8 +1983,8 @@ Corresponding to types in :mod:`collections` .. versionadded:: 3.6.1 .. deprecated:: 3.9 - :class:`collections.Counter` now supports ``[]``. See :pep:`585` and - :ref:`types-genericalias`. + :class:`collections.Counter` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: Deque(deque, MutableSequence[T]) @@ -1993,8 +1994,8 @@ Corresponding to types in :mod:`collections` .. versionadded:: 3.6.1 .. deprecated:: 3.9 - :class:`collections.deque` now supports ``[]``. See :pep:`585` and - :ref:`types-genericalias`. + :class:`collections.deque` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. Other concrete types """""""""""""""""""" @@ -2061,8 +2062,8 @@ Corresponding to collections in :mod:`collections.abc` A generic version of :class:`collections.abc.Set`. .. deprecated:: 3.9 - :class:`collections.abc.Set` now supports ``[]``. See :pep:`585` and - :ref:`types-genericalias`. + :class:`collections.abc.Set` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: ByteString(Sequence[int]) @@ -2075,8 +2076,8 @@ Corresponding to collections in :mod:`collections.abc` annotate arguments of any of the types mentioned above. .. deprecated:: 3.9 - :class:`collections.abc.ByteString` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.ByteString` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: Collection(Sized, Iterable[T_co], Container[T_co]) @@ -2085,32 +2086,32 @@ Corresponding to collections in :mod:`collections.abc` .. versionadded:: 3.6.0 .. deprecated:: 3.9 - :class:`collections.abc.Collection` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.Collection` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: Container(Generic[T_co]) A generic version of :class:`collections.abc.Container`. .. deprecated:: 3.9 - :class:`collections.abc.Container` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.Container` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: ItemsView(MappingView, AbstractSet[tuple[KT_co, VT_co]]) A generic version of :class:`collections.abc.ItemsView`. .. deprecated:: 3.9 - :class:`collections.abc.ItemsView` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.ItemsView` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: KeysView(MappingView, AbstractSet[KT_co]) A generic version of :class:`collections.abc.KeysView`. .. deprecated:: 3.9 - :class:`collections.abc.KeysView` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.KeysView` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: Mapping(Sized, Collection[KT], Generic[VT_co]) @@ -2121,56 +2122,58 @@ Corresponding to collections in :mod:`collections.abc` return word_list[word] .. deprecated:: 3.9 - :class:`collections.abc.Mapping` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.Mapping` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: MappingView(Sized) A generic version of :class:`collections.abc.MappingView`. .. deprecated:: 3.9 - :class:`collections.abc.MappingView` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.MappingView` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: MutableMapping(Mapping[KT, VT]) A generic version of :class:`collections.abc.MutableMapping`. .. deprecated:: 3.9 - :class:`collections.abc.MutableMapping` now supports ``[]``. See - :pep:`585` and :ref:`types-genericalias`. + :class:`collections.abc.MutableMapping` + now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: MutableSequence(Sequence[T]) A generic version of :class:`collections.abc.MutableSequence`. .. deprecated:: 3.9 - :class:`collections.abc.MutableSequence` now supports ``[]``. See - :pep:`585` and :ref:`types-genericalias`. + :class:`collections.abc.MutableSequence` + now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: MutableSet(AbstractSet[T]) A generic version of :class:`collections.abc.MutableSet`. .. deprecated:: 3.9 - :class:`collections.abc.MutableSet` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.MutableSet` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: Sequence(Reversible[T_co], Collection[T_co]) A generic version of :class:`collections.abc.Sequence`. .. deprecated:: 3.9 - :class:`collections.abc.Sequence` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.Sequence` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: ValuesView(MappingView, Collection[_VT_co]) A generic version of :class:`collections.abc.ValuesView`. .. deprecated:: 3.9 - :class:`collections.abc.ValuesView` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.ValuesView` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. Corresponding to other types in :mod:`collections.abc` """""""""""""""""""""""""""""""""""""""""""""""""""""" @@ -2180,16 +2183,16 @@ Corresponding to other types in :mod:`collections.abc` A generic version of :class:`collections.abc.Iterable`. .. deprecated:: 3.9 - :class:`collections.abc.Iterable` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.Iterable` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: Iterator(Iterable[T_co]) A generic version of :class:`collections.abc.Iterator`. .. deprecated:: 3.9 - :class:`collections.abc.Iterator` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.Iterator` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: Generator(Iterator[T_co], Generic[T_co, T_contra, V_co]) @@ -2223,8 +2226,8 @@ Corresponding to other types in :mod:`collections.abc` start += 1 .. deprecated:: 3.9 - :class:`collections.abc.Generator` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.Generator` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: Hashable @@ -2238,8 +2241,8 @@ Corresponding to other types in :mod:`collections.abc` A generic version of :class:`collections.abc.Reversible`. .. deprecated:: 3.9 - :class:`collections.abc.Reversible` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.Reversible` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: Sized @@ -2266,8 +2269,8 @@ Asynchronous programming .. versionadded:: 3.5.3 .. deprecated:: 3.9 - :class:`collections.abc.Coroutine` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.Coroutine` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: AsyncGenerator(AsyncIterator[T_co], Generic[T_co, T_contra]) @@ -2303,8 +2306,9 @@ Asynchronous programming .. versionadded:: 3.6.1 .. deprecated:: 3.9 - :class:`collections.abc.AsyncGenerator` now supports ``[]``. See - :pep:`585` and :ref:`types-genericalias`. + :class:`collections.abc.AsyncGenerator` + now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: AsyncIterable(Generic[T_co]) @@ -2313,8 +2317,8 @@ Asynchronous programming .. versionadded:: 3.5.2 .. deprecated:: 3.9 - :class:`collections.abc.AsyncIterable` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.AsyncIterable` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: AsyncIterator(AsyncIterable[T_co]) @@ -2323,8 +2327,8 @@ Asynchronous programming .. versionadded:: 3.5.2 .. deprecated:: 3.9 - :class:`collections.abc.AsyncIterator` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.AsyncIterator` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: Awaitable(Generic[T_co]) @@ -2333,8 +2337,8 @@ Asynchronous programming .. versionadded:: 3.5.2 .. deprecated:: 3.9 - :class:`collections.abc.Awaitable` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.Awaitable` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. Context manager types @@ -2348,8 +2352,9 @@ Context manager types .. versionadded:: 3.6.0 .. deprecated:: 3.9 - :class:`contextlib.AbstractContextManager` now supports ``[]``. See - :pep:`585` and :ref:`types-genericalias`. + :class:`contextlib.AbstractContextManager` + now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: AsyncContextManager(Generic[T_co]) @@ -2359,8 +2364,9 @@ Context manager types .. versionadded:: 3.6.2 .. deprecated:: 3.9 - :class:`contextlib.AbstractAsyncContextManager` now supports ``[]``. See - :pep:`585` and :ref:`types-genericalias`. + :class:`contextlib.AbstractAsyncContextManager` + now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. Protocols --------- From webhook-mailer at python.org Mon Oct 24 14:17:04 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 24 Oct 2022 18:17:04 -0000 Subject: [Python-checkins] gh-98507: [typing docs] Rephrase "now supports `[]`" to "now supports subscripting" (GH-98508) Message-ID: https://github.com/python/cpython/commit/cdbfce121fb046153e282bfe7e37cba49444b07b commit: cdbfce121fb046153e282bfe7e37cba49444b07b branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-24T11:16:58-07:00 summary: gh-98507: [typing docs] Rephrase "now supports `[]`" to "now supports subscripting" (GH-98508) (cherry picked from commit e3b9dd8e870a61016e0f221e30d4f7d0b99cddb3) Co-authored-by: Nikita Sobolev files: M Doc/library/typing.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 42aa52980a76..d49bae8cc2f3 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -760,8 +760,8 @@ These can be used as types in annotations using ``[]``, each having a unique syn is equivalent to ``Tuple[Any, ...]``, and in turn to :class:`tuple`. .. deprecated:: 3.9 - :class:`builtins.tuple ` now supports ``[]``. See :pep:`585` and - :ref:`types-genericalias`. + :class:`builtins.tuple ` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. data:: Union @@ -849,8 +849,8 @@ These can be used as types in annotations using ``[]``, each having a unique syn respectively. .. deprecated:: 3.9 - :class:`collections.abc.Callable` now supports ``[]``. See :pep:`585` and - :ref:`types-genericalias`. + :class:`collections.abc.Callable` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. versionchanged:: 3.10 ``Callable`` now supports :class:`ParamSpec` and :data:`Concatenate`. @@ -957,8 +957,8 @@ These can be used as types in annotations using ``[]``, each having a unique syn .. versionadded:: 3.5.2 .. deprecated:: 3.9 - :class:`builtins.type ` now supports ``[]``. See :pep:`585` and - :ref:`types-genericalias`. + :class:`builtins.type ` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. data:: Literal @@ -1896,8 +1896,8 @@ Corresponding to built-in types ... .. deprecated:: 3.9 - :class:`builtins.dict ` now supports ``[]``. See :pep:`585` and - :ref:`types-genericalias`. + :class:`builtins.dict ` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: List(list, MutableSequence[T]) @@ -1917,8 +1917,8 @@ Corresponding to built-in types return [item for item in vector if item > 0] .. deprecated:: 3.9 - :class:`builtins.list ` now supports ``[]``. See :pep:`585` and - :ref:`types-genericalias`. + :class:`builtins.list ` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: Set(set, MutableSet[T]) @@ -1927,16 +1927,17 @@ Corresponding to built-in types to use an abstract collection type such as :class:`AbstractSet`. .. deprecated:: 3.9 - :class:`builtins.set ` now supports ``[]``. See :pep:`585` and - :ref:`types-genericalias`. + :class:`builtins.set ` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: FrozenSet(frozenset, AbstractSet[T_co]) A generic version of :class:`builtins.frozenset `. .. deprecated:: 3.9 - :class:`builtins.frozenset ` now supports ``[]``. See - :pep:`585` and :ref:`types-genericalias`. + :class:`builtins.frozenset ` + now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. note:: :data:`Tuple` is a special form. @@ -1950,8 +1951,8 @@ Corresponding to types in :mod:`collections` .. versionadded:: 3.5.2 .. deprecated:: 3.9 - :class:`collections.defaultdict` now supports ``[]``. See :pep:`585` and - :ref:`types-genericalias`. + :class:`collections.defaultdict` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: OrderedDict(collections.OrderedDict, MutableMapping[KT, VT]) @@ -1960,8 +1961,8 @@ Corresponding to types in :mod:`collections` .. versionadded:: 3.7.2 .. deprecated:: 3.9 - :class:`collections.OrderedDict` now supports ``[]``. See :pep:`585` and - :ref:`types-genericalias`. + :class:`collections.OrderedDict` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: ChainMap(collections.ChainMap, MutableMapping[KT, VT]) @@ -1971,8 +1972,8 @@ Corresponding to types in :mod:`collections` .. versionadded:: 3.6.1 .. deprecated:: 3.9 - :class:`collections.ChainMap` now supports ``[]``. See :pep:`585` and - :ref:`types-genericalias`. + :class:`collections.ChainMap` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: Counter(collections.Counter, Dict[T, int]) @@ -1982,8 +1983,8 @@ Corresponding to types in :mod:`collections` .. versionadded:: 3.6.1 .. deprecated:: 3.9 - :class:`collections.Counter` now supports ``[]``. See :pep:`585` and - :ref:`types-genericalias`. + :class:`collections.Counter` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: Deque(deque, MutableSequence[T]) @@ -1993,8 +1994,8 @@ Corresponding to types in :mod:`collections` .. versionadded:: 3.6.1 .. deprecated:: 3.9 - :class:`collections.deque` now supports ``[]``. See :pep:`585` and - :ref:`types-genericalias`. + :class:`collections.deque` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. Other concrete types """""""""""""""""""" @@ -2061,8 +2062,8 @@ Corresponding to collections in :mod:`collections.abc` A generic version of :class:`collections.abc.Set`. .. deprecated:: 3.9 - :class:`collections.abc.Set` now supports ``[]``. See :pep:`585` and - :ref:`types-genericalias`. + :class:`collections.abc.Set` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: ByteString(Sequence[int]) @@ -2075,8 +2076,8 @@ Corresponding to collections in :mod:`collections.abc` annotate arguments of any of the types mentioned above. .. deprecated:: 3.9 - :class:`collections.abc.ByteString` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.ByteString` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: Collection(Sized, Iterable[T_co], Container[T_co]) @@ -2085,32 +2086,32 @@ Corresponding to collections in :mod:`collections.abc` .. versionadded:: 3.6.0 .. deprecated:: 3.9 - :class:`collections.abc.Collection` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.Collection` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: Container(Generic[T_co]) A generic version of :class:`collections.abc.Container`. .. deprecated:: 3.9 - :class:`collections.abc.Container` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.Container` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: ItemsView(MappingView, AbstractSet[tuple[KT_co, VT_co]]) A generic version of :class:`collections.abc.ItemsView`. .. deprecated:: 3.9 - :class:`collections.abc.ItemsView` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.ItemsView` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: KeysView(MappingView, AbstractSet[KT_co]) A generic version of :class:`collections.abc.KeysView`. .. deprecated:: 3.9 - :class:`collections.abc.KeysView` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.KeysView` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: Mapping(Sized, Collection[KT], Generic[VT_co]) @@ -2121,56 +2122,58 @@ Corresponding to collections in :mod:`collections.abc` return word_list[word] .. deprecated:: 3.9 - :class:`collections.abc.Mapping` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.Mapping` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: MappingView(Sized) A generic version of :class:`collections.abc.MappingView`. .. deprecated:: 3.9 - :class:`collections.abc.MappingView` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.MappingView` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: MutableMapping(Mapping[KT, VT]) A generic version of :class:`collections.abc.MutableMapping`. .. deprecated:: 3.9 - :class:`collections.abc.MutableMapping` now supports ``[]``. See - :pep:`585` and :ref:`types-genericalias`. + :class:`collections.abc.MutableMapping` + now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: MutableSequence(Sequence[T]) A generic version of :class:`collections.abc.MutableSequence`. .. deprecated:: 3.9 - :class:`collections.abc.MutableSequence` now supports ``[]``. See - :pep:`585` and :ref:`types-genericalias`. + :class:`collections.abc.MutableSequence` + now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: MutableSet(AbstractSet[T]) A generic version of :class:`collections.abc.MutableSet`. .. deprecated:: 3.9 - :class:`collections.abc.MutableSet` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.MutableSet` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: Sequence(Reversible[T_co], Collection[T_co]) A generic version of :class:`collections.abc.Sequence`. .. deprecated:: 3.9 - :class:`collections.abc.Sequence` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.Sequence` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: ValuesView(MappingView, Collection[_VT_co]) A generic version of :class:`collections.abc.ValuesView`. .. deprecated:: 3.9 - :class:`collections.abc.ValuesView` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.ValuesView` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. Corresponding to other types in :mod:`collections.abc` """""""""""""""""""""""""""""""""""""""""""""""""""""" @@ -2180,16 +2183,16 @@ Corresponding to other types in :mod:`collections.abc` A generic version of :class:`collections.abc.Iterable`. .. deprecated:: 3.9 - :class:`collections.abc.Iterable` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.Iterable` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: Iterator(Iterable[T_co]) A generic version of :class:`collections.abc.Iterator`. .. deprecated:: 3.9 - :class:`collections.abc.Iterator` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.Iterator` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: Generator(Iterator[T_co], Generic[T_co, T_contra, V_co]) @@ -2223,8 +2226,8 @@ Corresponding to other types in :mod:`collections.abc` start += 1 .. deprecated:: 3.9 - :class:`collections.abc.Generator` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.Generator` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: Hashable @@ -2235,8 +2238,8 @@ Corresponding to other types in :mod:`collections.abc` A generic version of :class:`collections.abc.Reversible`. .. deprecated:: 3.9 - :class:`collections.abc.Reversible` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.Reversible` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: Sized @@ -2260,8 +2263,8 @@ Asynchronous programming .. versionadded:: 3.5.3 .. deprecated:: 3.9 - :class:`collections.abc.Coroutine` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.Coroutine` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: AsyncGenerator(AsyncIterator[T_co], Generic[T_co, T_contra]) @@ -2297,8 +2300,9 @@ Asynchronous programming .. versionadded:: 3.6.1 .. deprecated:: 3.9 - :class:`collections.abc.AsyncGenerator` now supports ``[]``. See - :pep:`585` and :ref:`types-genericalias`. + :class:`collections.abc.AsyncGenerator` + now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: AsyncIterable(Generic[T_co]) @@ -2307,8 +2311,8 @@ Asynchronous programming .. versionadded:: 3.5.2 .. deprecated:: 3.9 - :class:`collections.abc.AsyncIterable` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.AsyncIterable` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: AsyncIterator(AsyncIterable[T_co]) @@ -2317,8 +2321,8 @@ Asynchronous programming .. versionadded:: 3.5.2 .. deprecated:: 3.9 - :class:`collections.abc.AsyncIterator` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.AsyncIterator` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: Awaitable(Generic[T_co]) @@ -2327,8 +2331,8 @@ Asynchronous programming .. versionadded:: 3.5.2 .. deprecated:: 3.9 - :class:`collections.abc.Awaitable` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.Awaitable` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. Context manager types @@ -2342,8 +2346,9 @@ Context manager types .. versionadded:: 3.6.0 .. deprecated:: 3.9 - :class:`contextlib.AbstractContextManager` now supports ``[]``. See - :pep:`585` and :ref:`types-genericalias`. + :class:`contextlib.AbstractContextManager` + now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: AsyncContextManager(Generic[T_co]) @@ -2353,8 +2358,9 @@ Context manager types .. versionadded:: 3.6.2 .. deprecated:: 3.9 - :class:`contextlib.AbstractAsyncContextManager` now supports ``[]``. See - :pep:`585` and :ref:`types-genericalias`. + :class:`contextlib.AbstractAsyncContextManager` + now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. Protocols --------- From webhook-mailer at python.org Mon Oct 24 14:17:39 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 24 Oct 2022 18:17:39 -0000 Subject: [Python-checkins] gh-98507: [typing docs] Rephrase "now supports `[]`" to "now supports subscripting" (GH-98508) Message-ID: https://github.com/python/cpython/commit/d79a42aac83a5420d47ecfffffebcdcecb3cf2d0 commit: d79a42aac83a5420d47ecfffffebcdcecb3cf2d0 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-24T11:17:33-07:00 summary: gh-98507: [typing docs] Rephrase "now supports `[]`" to "now supports subscripting" (GH-98508) (cherry picked from commit e3b9dd8e870a61016e0f221e30d4f7d0b99cddb3) Co-authored-by: Nikita Sobolev files: M Doc/library/typing.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 41571035a3a9..de63735ed0f1 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -631,8 +631,8 @@ These can be used as types in annotations using ``[]``, each having a unique syn is equivalent to ``Tuple[Any, ...]``, and in turn to :class:`tuple`. .. deprecated:: 3.9 - :class:`builtins.tuple ` now supports ``[]``. See :pep:`585` and - :ref:`types-genericalias`. + :class:`builtins.tuple ` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. data:: Union @@ -720,8 +720,8 @@ These can be used as types in annotations using ``[]``, each having a unique syn respectively. .. deprecated:: 3.9 - :class:`collections.abc.Callable` now supports ``[]``. See :pep:`585` and - :ref:`types-genericalias`. + :class:`collections.abc.Callable` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. versionchanged:: 3.10 ``Callable`` now supports :class:`ParamSpec` and :data:`Concatenate`. @@ -827,8 +827,8 @@ These can be used as types in annotations using ``[]``, each having a unique syn .. versionadded:: 3.5.2 .. deprecated:: 3.9 - :class:`builtins.type ` now supports ``[]``. See :pep:`585` and - :ref:`types-genericalias`. + :class:`builtins.type ` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. data:: Literal @@ -1597,8 +1597,8 @@ Corresponding to built-in types ... .. deprecated:: 3.9 - :class:`builtins.dict ` now supports ``[]``. See :pep:`585` and - :ref:`types-genericalias`. + :class:`builtins.dict ` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: List(list, MutableSequence[T]) @@ -1618,8 +1618,8 @@ Corresponding to built-in types return [item for item in vector if item > 0] .. deprecated:: 3.9 - :class:`builtins.list ` now supports ``[]``. See :pep:`585` and - :ref:`types-genericalias`. + :class:`builtins.list ` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: Set(set, MutableSet[T]) @@ -1628,16 +1628,17 @@ Corresponding to built-in types to use an abstract collection type such as :class:`AbstractSet`. .. deprecated:: 3.9 - :class:`builtins.set ` now supports ``[]``. See :pep:`585` and - :ref:`types-genericalias`. + :class:`builtins.set ` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: FrozenSet(frozenset, AbstractSet[T_co]) A generic version of :class:`builtins.frozenset `. .. deprecated:: 3.9 - :class:`builtins.frozenset ` now supports ``[]``. See - :pep:`585` and :ref:`types-genericalias`. + :class:`builtins.frozenset ` + now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. note:: :data:`Tuple` is a special form. @@ -1651,8 +1652,8 @@ Corresponding to types in :mod:`collections` .. versionadded:: 3.5.2 .. deprecated:: 3.9 - :class:`collections.defaultdict` now supports ``[]``. See :pep:`585` and - :ref:`types-genericalias`. + :class:`collections.defaultdict` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: OrderedDict(collections.OrderedDict, MutableMapping[KT, VT]) @@ -1661,8 +1662,8 @@ Corresponding to types in :mod:`collections` .. versionadded:: 3.7.2 .. deprecated:: 3.9 - :class:`collections.OrderedDict` now supports ``[]``. See :pep:`585` and - :ref:`types-genericalias`. + :class:`collections.OrderedDict` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: ChainMap(collections.ChainMap, MutableMapping[KT, VT]) @@ -1672,8 +1673,8 @@ Corresponding to types in :mod:`collections` .. versionadded:: 3.6.1 .. deprecated:: 3.9 - :class:`collections.ChainMap` now supports ``[]``. See :pep:`585` and - :ref:`types-genericalias`. + :class:`collections.ChainMap` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: Counter(collections.Counter, Dict[T, int]) @@ -1683,8 +1684,8 @@ Corresponding to types in :mod:`collections` .. versionadded:: 3.6.1 .. deprecated:: 3.9 - :class:`collections.Counter` now supports ``[]``. See :pep:`585` and - :ref:`types-genericalias`. + :class:`collections.Counter` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: Deque(deque, MutableSequence[T]) @@ -1694,8 +1695,8 @@ Corresponding to types in :mod:`collections` .. versionadded:: 3.6.1 .. deprecated:: 3.9 - :class:`collections.deque` now supports ``[]``. See :pep:`585` and - :ref:`types-genericalias`. + :class:`collections.deque` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. Other concrete types """""""""""""""""""" @@ -1756,8 +1757,8 @@ Corresponding to collections in :mod:`collections.abc` A generic version of :class:`collections.abc.Set`. .. deprecated:: 3.9 - :class:`collections.abc.Set` now supports ``[]``. See :pep:`585` and - :ref:`types-genericalias`. + :class:`collections.abc.Set` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: ByteString(Sequence[int]) @@ -1770,8 +1771,8 @@ Corresponding to collections in :mod:`collections.abc` annotate arguments of any of the types mentioned above. .. deprecated:: 3.9 - :class:`collections.abc.ByteString` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.ByteString` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: Collection(Sized, Iterable[T_co], Container[T_co]) @@ -1780,32 +1781,32 @@ Corresponding to collections in :mod:`collections.abc` .. versionadded:: 3.6.0 .. deprecated:: 3.9 - :class:`collections.abc.Collection` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.Collection` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: Container(Generic[T_co]) A generic version of :class:`collections.abc.Container`. .. deprecated:: 3.9 - :class:`collections.abc.Container` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.Container` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: ItemsView(MappingView, AbstractSet[tuple[KT_co, VT_co]]) A generic version of :class:`collections.abc.ItemsView`. .. deprecated:: 3.9 - :class:`collections.abc.ItemsView` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.ItemsView` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: KeysView(MappingView, AbstractSet[KT_co]) A generic version of :class:`collections.abc.KeysView`. .. deprecated:: 3.9 - :class:`collections.abc.KeysView` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.KeysView` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: Mapping(Sized, Collection[KT], Generic[VT_co]) @@ -1816,56 +1817,58 @@ Corresponding to collections in :mod:`collections.abc` return word_list[word] .. deprecated:: 3.9 - :class:`collections.abc.Mapping` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.Mapping` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: MappingView(Sized) A generic version of :class:`collections.abc.MappingView`. .. deprecated:: 3.9 - :class:`collections.abc.MappingView` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.MappingView` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: MutableMapping(Mapping[KT, VT]) A generic version of :class:`collections.abc.MutableMapping`. .. deprecated:: 3.9 - :class:`collections.abc.MutableMapping` now supports ``[]``. See - :pep:`585` and :ref:`types-genericalias`. + :class:`collections.abc.MutableMapping` + now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: MutableSequence(Sequence[T]) A generic version of :class:`collections.abc.MutableSequence`. .. deprecated:: 3.9 - :class:`collections.abc.MutableSequence` now supports ``[]``. See - :pep:`585` and :ref:`types-genericalias`. + :class:`collections.abc.MutableSequence` + now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: MutableSet(AbstractSet[T]) A generic version of :class:`collections.abc.MutableSet`. .. deprecated:: 3.9 - :class:`collections.abc.MutableSet` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.MutableSet` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: Sequence(Reversible[T_co], Collection[T_co]) A generic version of :class:`collections.abc.Sequence`. .. deprecated:: 3.9 - :class:`collections.abc.Sequence` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.Sequence` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: ValuesView(MappingView, Collection[_VT_co]) A generic version of :class:`collections.abc.ValuesView`. .. deprecated:: 3.9 - :class:`collections.abc.ValuesView` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.ValuesView` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. Corresponding to other types in :mod:`collections.abc` """""""""""""""""""""""""""""""""""""""""""""""""""""" @@ -1875,16 +1878,16 @@ Corresponding to other types in :mod:`collections.abc` A generic version of :class:`collections.abc.Iterable`. .. deprecated:: 3.9 - :class:`collections.abc.Iterable` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.Iterable` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: Iterator(Iterable[T_co]) A generic version of :class:`collections.abc.Iterator`. .. deprecated:: 3.9 - :class:`collections.abc.Iterator` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.Iterator` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: Generator(Iterator[T_co], Generic[T_co, T_contra, V_co]) @@ -1918,8 +1921,8 @@ Corresponding to other types in :mod:`collections.abc` start += 1 .. deprecated:: 3.9 - :class:`collections.abc.Generator` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.Generator` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: Hashable @@ -1930,8 +1933,8 @@ Corresponding to other types in :mod:`collections.abc` A generic version of :class:`collections.abc.Reversible`. .. deprecated:: 3.9 - :class:`collections.abc.Reversible` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.Reversible` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: Sized @@ -1955,8 +1958,8 @@ Asynchronous programming .. versionadded:: 3.5.3 .. deprecated:: 3.9 - :class:`collections.abc.Coroutine` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.Coroutine` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: AsyncGenerator(AsyncIterator[T_co], Generic[T_co, T_contra]) @@ -1992,8 +1995,9 @@ Asynchronous programming .. versionadded:: 3.6.1 .. deprecated:: 3.9 - :class:`collections.abc.AsyncGenerator` now supports ``[]``. See - :pep:`585` and :ref:`types-genericalias`. + :class:`collections.abc.AsyncGenerator` + now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: AsyncIterable(Generic[T_co]) @@ -2002,8 +2006,8 @@ Asynchronous programming .. versionadded:: 3.5.2 .. deprecated:: 3.9 - :class:`collections.abc.AsyncIterable` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.AsyncIterable` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: AsyncIterator(AsyncIterable[T_co]) @@ -2012,8 +2016,8 @@ Asynchronous programming .. versionadded:: 3.5.2 .. deprecated:: 3.9 - :class:`collections.abc.AsyncIterator` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.AsyncIterator` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: Awaitable(Generic[T_co]) @@ -2022,8 +2026,8 @@ Asynchronous programming .. versionadded:: 3.5.2 .. deprecated:: 3.9 - :class:`collections.abc.Awaitable` now supports ``[]``. See :pep:`585` - and :ref:`types-genericalias`. + :class:`collections.abc.Awaitable` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. Context manager types @@ -2037,8 +2041,9 @@ Context manager types .. versionadded:: 3.6.0 .. deprecated:: 3.9 - :class:`contextlib.AbstractContextManager` now supports ``[]``. See - :pep:`585` and :ref:`types-genericalias`. + :class:`contextlib.AbstractContextManager` + now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. class:: AsyncContextManager(Generic[T_co]) @@ -2048,8 +2053,9 @@ Context manager types .. versionadded:: 3.6.2 .. deprecated:: 3.9 - :class:`contextlib.AbstractAsyncContextManager` now supports ``[]``. See - :pep:`585` and :ref:`types-genericalias`. + :class:`contextlib.AbstractAsyncContextManager` + now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. Protocols --------- From webhook-mailer at python.org Mon Oct 24 15:31:02 2022 From: webhook-mailer at python.org (pablogsal) Date: Mon, 24 Oct 2022 19:31:02 -0000 Subject: [Python-checkins] Post 3.11.0rc2 Message-ID: https://github.com/python/cpython/commit/b0925211f405f6aa353e9e8fd748dca773b9b8aa commit: b0925211f405f6aa353e9e8fd748dca773b9b8aa branch: 3.11 author: Pablo Galindo committer: pablogsal date: 2022-10-22T20:04:32+01:00 summary: Post 3.11.0rc2 files: M Include/patchlevel.h diff --git a/Include/patchlevel.h b/Include/patchlevel.h index f727dc2883f7..a54a2ce6c70d 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -23,7 +23,7 @@ #define PY_RELEASE_SERIAL 2 /* Version as a string */ -#define PY_VERSION "3.11.0rc2" +#define PY_VERSION "3.11.0rc2+" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. From webhook-mailer at python.org Mon Oct 24 15:41:18 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 24 Oct 2022 19:41:18 -0000 Subject: [Python-checkins] GH-98407: fix `test_kill_issue43884` to not leak child processes (GH-98491) Message-ID: https://github.com/python/cpython/commit/3a1eb81abf9494bdb34125eca667d282ae0fca9f commit: 3a1eb81abf9494bdb34125eca667d282ae0fca9f branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-24T12:41:10-07:00 summary: GH-98407: fix `test_kill_issue43884` to not leak child processes (GH-98491) (cherry picked from commit 3b2724abcfef7cbe5bf1717be1bb029e4c6b6600) Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> files: M Lib/test/test_asyncio/test_subprocess.py diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py index 7b7df4005631..4c0140d80ba7 100644 --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -184,7 +184,10 @@ def test_kill(self): self.assertEqual(-signal.SIGKILL, returncode) def test_kill_issue43884(self): - blocking_shell_command = f'{sys.executable} -c "import time; time.sleep(100000000)"' + if sys.platform == 'win32': + blocking_shell_command = f'{sys.executable} -c "import time; time.sleep(100000000)"' + else: + blocking_shell_command = 'sleep 1; sleep 1' creationflags = 0 if sys.platform == 'win32': from subprocess import CREATE_NEW_PROCESS_GROUP From webhook-mailer at python.org Mon Oct 24 16:22:01 2022 From: webhook-mailer at python.org (gvanrossum) Date: Mon, 24 Oct 2022 20:22:01 -0000 Subject: [Python-checkins] GH-89237: fix hang in proactor `subprocess.wait_closed()` (#98572) Message-ID: https://github.com/python/cpython/commit/ad1dc3ebb6aadaeeeacde13d4ed2d62bf302bf62 commit: ad1dc3ebb6aadaeeeacde13d4ed2d62bf302bf62 branch: main author: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> committer: gvanrossum date: 2022-10-24T13:21:42-07:00 summary: GH-89237: fix hang in proactor `subprocess.wait_closed()` (#98572) files: A Misc/NEWS.d/next/Library/2022-10-23-18-30-39.gh-issue-89237.kBui30.rst M Lib/asyncio/proactor_events.py M Lib/test/test_asyncio/test_proactor_events.py diff --git a/Lib/asyncio/proactor_events.py b/Lib/asyncio/proactor_events.py index ddb9daca0269..2685a3376cfd 100644 --- a/Lib/asyncio/proactor_events.py +++ b/Lib/asyncio/proactor_events.py @@ -60,6 +60,7 @@ def __init__(self, loop, sock, protocol, waiter=None, self._pending_write = 0 self._conn_lost = 0 self._closing = False # Set when close() called. + self._called_connection_lost = False self._eof_written = False if self._server is not None: self._server._attach() @@ -136,7 +137,7 @@ def _force_close(self, exc): self._empty_waiter.set_result(None) else: self._empty_waiter.set_exception(exc) - if self._closing: + if self._closing and self._called_connection_lost: return self._closing = True self._conn_lost += 1 @@ -166,6 +167,7 @@ def _call_connection_lost(self, exc): if server is not None: server._detach() self._server = None + self._called_connection_lost = True def get_write_buffer_size(self): size = self._pending_write diff --git a/Lib/test/test_asyncio/test_proactor_events.py b/Lib/test/test_asyncio/test_proactor_events.py index 7fca0541ee75..7fd8b261cd5e 100644 --- a/Lib/test/test_asyncio/test_proactor_events.py +++ b/Lib/test/test_asyncio/test_proactor_events.py @@ -290,7 +290,12 @@ def test_force_close_idempotent(self): tr._closing = True tr._force_close(None) test_utils.run_briefly(self.loop) - self.assertFalse(self.protocol.connection_lost.called) + # See https://github.com/python/cpython/issues/89237 + # `protocol.connection_lost` should be called even if + # the transport was closed forcefully otherwise + # the resources held by protocol will never be freed + # and waiters will never be notified leading to hang. + self.assertTrue(self.protocol.connection_lost.called) def test_fatal_error_2(self): tr = self.socket_transport() diff --git a/Misc/NEWS.d/next/Library/2022-10-23-18-30-39.gh-issue-89237.kBui30.rst b/Misc/NEWS.d/next/Library/2022-10-23-18-30-39.gh-issue-89237.kBui30.rst new file mode 100644 index 000000000000..668ea4c7a4ea --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-23-18-30-39.gh-issue-89237.kBui30.rst @@ -0,0 +1 @@ +Fix hang on Windows in ``subprocess.wait_closed()`` in :mod:`asyncio` with :class:`~asyncio.ProactorEventLoop`. Patch by Kumar Aditya. From webhook-mailer at python.org Mon Oct 24 16:42:52 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 24 Oct 2022 20:42:52 -0000 Subject: [Python-checkins] GH-89237: fix hang in proactor `subprocess.wait_closed()` (GH-98572) Message-ID: https://github.com/python/cpython/commit/8ba086f70b593fcdd2dc63d516af8e7240a9d28d commit: 8ba086f70b593fcdd2dc63d516af8e7240a9d28d branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-24T13:42:20-07:00 summary: GH-89237: fix hang in proactor `subprocess.wait_closed()` (GH-98572) (cherry picked from commit ad1dc3ebb6aadaeeeacde13d4ed2d62bf302bf62) Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> files: A Misc/NEWS.d/next/Library/2022-10-23-18-30-39.gh-issue-89237.kBui30.rst M Lib/asyncio/proactor_events.py M Lib/test/test_asyncio/test_proactor_events.py diff --git a/Lib/asyncio/proactor_events.py b/Lib/asyncio/proactor_events.py index 9657f9680422..610d67387d12 100644 --- a/Lib/asyncio/proactor_events.py +++ b/Lib/asyncio/proactor_events.py @@ -60,6 +60,7 @@ def __init__(self, loop, sock, protocol, waiter=None, self._pending_write = 0 self._conn_lost = 0 self._closing = False # Set when close() called. + self._called_connection_lost = False self._eof_written = False if self._server is not None: self._server._attach() @@ -136,7 +137,7 @@ def _force_close(self, exc): self._empty_waiter.set_result(None) else: self._empty_waiter.set_exception(exc) - if self._closing: + if self._closing and self._called_connection_lost: return self._closing = True self._conn_lost += 1 @@ -166,6 +167,7 @@ def _call_connection_lost(self, exc): if server is not None: server._detach() self._server = None + self._called_connection_lost = True def get_write_buffer_size(self): size = self._pending_write diff --git a/Lib/test/test_asyncio/test_proactor_events.py b/Lib/test/test_asyncio/test_proactor_events.py index fc6ee1c1c423..3b219609eefc 100644 --- a/Lib/test/test_asyncio/test_proactor_events.py +++ b/Lib/test/test_asyncio/test_proactor_events.py @@ -289,7 +289,12 @@ def test_force_close_idempotent(self): tr._closing = True tr._force_close(None) test_utils.run_briefly(self.loop) - self.assertFalse(self.protocol.connection_lost.called) + # See https://github.com/python/cpython/issues/89237 + # `protocol.connection_lost` should be called even if + # the transport was closed forcefully otherwise + # the resources held by protocol will never be freed + # and waiters will never be notified leading to hang. + self.assertTrue(self.protocol.connection_lost.called) def test_fatal_error_2(self): tr = self.socket_transport() diff --git a/Misc/NEWS.d/next/Library/2022-10-23-18-30-39.gh-issue-89237.kBui30.rst b/Misc/NEWS.d/next/Library/2022-10-23-18-30-39.gh-issue-89237.kBui30.rst new file mode 100644 index 000000000000..668ea4c7a4ea --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-23-18-30-39.gh-issue-89237.kBui30.rst @@ -0,0 +1 @@ +Fix hang on Windows in ``subprocess.wait_closed()`` in :mod:`asyncio` with :class:`~asyncio.ProactorEventLoop`. Patch by Kumar Aditya. From webhook-mailer at python.org Mon Oct 24 19:30:16 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 24 Oct 2022 23:30:16 -0000 Subject: [Python-checkins] [3.11] Fix v3.11.0 release merge problems (GH-98622) Message-ID: https://github.com/python/cpython/commit/b3cafb60afeb2300002af9982d43703435b8302d commit: b3cafb60afeb2300002af9982d43703435b8302d branch: 3.11 author: Pablo Galindo Salgado committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-24T16:30:06-07:00 summary: [3.11] Fix v3.11.0 release merge problems (GH-98622) When merging the v3.11.0 tag into 3.11, some files were incorrectly updated and some others were not properly deleted. Automerge-Triggered-By: GH:pablogsal files: D Misc/NEWS.d/next/Build/2022-09-11-14-23-49.gh-issue-96729.W4uBWL.rst D Misc/NEWS.d/next/Core and Builtins/2020-11-15-02-08-43.bpo-42316.LqdkWK.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-05-19-20-44.gh-issue-96587.bVxhX2.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-16-19-02-40.gh-issue-95778.cJmnst.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-18-08-47-40.gh-issue-96821.Co2iOq.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-21-14-38-31.gh-issue-96848.WuoLzU.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-21-16-06-37.gh-issue-96975.BmE0XY.rst D Misc/NEWS.d/next/Core and Builtins/2022-10-03-13-35-48.gh-issue-97752.0xTjJY.rst D Misc/NEWS.d/next/Core and Builtins/2022-10-06-02-11-34.gh-issue-97002.Zvsk71.rst D Misc/NEWS.d/next/Documentation/2022-05-20-18-42-10.gh-issue-93031.c2RdJe.rst D Misc/NEWS.d/next/Documentation/2022-10-02-10-58-52.gh-issue-97741.39l023.rst D Misc/NEWS.d/next/Library/2022-05-25-15-57-39.gh-issue-90155.YMstB5.rst D Misc/NEWS.d/next/Library/2022-09-24-18-56-23.gh-issue-96865.o9WUkW.rst D Misc/NEWS.d/next/Library/2022-09-25-23-24-52.gh-issue-97545.HZLSNt.rst D Misc/NEWS.d/next/Library/2022-10-16-15-31-50.gh-issue-98331.Y5kPOX.rst D Misc/NEWS.d/next/Security/2022-09-07-10-42-00.gh-issue-97514.Yggdsl.rst D Misc/NEWS.d/next/Security/2022-09-28-17-09-37.gh-issue-97616.K1e3Xs.rst D Misc/NEWS.d/next/Tests/2022-10-20-17-49-50.gh-issue-95027.viRpJB.rst D Misc/NEWS.d/next/Windows/2022-09-29-23-08-49.gh-issue-90989.no89Q2.rst D Misc/NEWS.d/next/Windows/2022-10-19-19-35-37.gh-issue-98414.FbHZuS.rst D Misc/NEWS.d/next/Windows/2022-10-19-20-00-28.gh-issue-98360.O2m6YG.rst D Misc/NEWS.d/next/macOS/2022-10-05-15-26-58.gh-issue-97897.Rf-C6u.rst M Doc/library/venv.rst M Doc/whatsnew/3.11.rst M Include/patchlevel.h M Lib/test/test_frame.py diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst index e0f2f2babfb0..adc6cd339ac1 100644 --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -129,19 +129,6 @@ You can deactivate a virtual environment by typing ``deactivate`` in your shell. The exact mechanism is platform-specific and is an internal implementation detail (typically, a script or shell function will be used). -.. warning:: Because scripts installed in environments should not expect the - environment to be activated, their shebang lines contain the absolute paths - to their environment's interpreters. Because of this, environments are - inherently non-portable, in the general case. You should always have a - simple means of recreating an environment (for example, if you have a - requirements file ``requirements.txt``, you can invoke ``pip install -r - requirements.txt`` using the environment's ``pip`` to install all of the - packages needed by the environment). If for any reason you need to move the - environment to a new location, you should recreate it at the desired - location and delete the one at the old location. If you move an environment - because you moved a parent directory of it, you should recreate the - environment in its new location. Otherwise, software installed into the - environment may not work as expected. .. _venv-api: diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index b42c6529303b..3e94c40bca69 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -4,6 +4,7 @@ :Release: |release| :Date: |today| +:Editor: Pablo Galindo Salgado .. Rules for maintenance: @@ -1590,10 +1591,6 @@ Changed/removed opcodes :opcode:`!POP_BLOCK`, :opcode:`!SETUP_FINALLY` and :opcode:`!YIELD_FROM`. -.. _whatsnew311-deprecated: -.. _whatsnew311-python-api-deprecated: - - .. _whatsnew311-deprecated: .. _whatsnew311-python-api-deprecated: @@ -1769,9 +1766,6 @@ Standard Library (Contributed by Erlend E. Aasland in :issue:`5846`.) -.. _whatsnew311-pending-removal: -.. _whatsnew311-python-api-pending-removal: - .. _whatsnew311-pending-removal: .. _whatsnew311-python-api-pending-removal: diff --git a/Include/patchlevel.h b/Include/patchlevel.h index c62cdf19e165..c37154baa22b 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -23,7 +23,7 @@ #define PY_RELEASE_SERIAL 0 /* Version as a string */ -#define PY_VERSION "3.11.0rc2+" +#define PY_VERSION "3.11.0+" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Lib/test/test_frame.py b/Lib/test/test_frame.py index 2222ad6ed514..4b86a60d2f4c 100644 --- a/Lib/test/test_frame.py +++ b/Lib/test/test_frame.py @@ -326,69 +326,5 @@ def f(): gc.enable() - @support.cpython_only - def test_sneaky_frame_object(self): - - def trace(frame, event, arg): - """ - Don't actually do anything, just force a frame object to be created. - """ - - def callback(phase, info): - """ - Yo dawg, I heard you like frames, so I'm allocating a frame while - you're allocating a frame, so you can have a frame while you have a - frame! - """ - nonlocal sneaky_frame_object - sneaky_frame_object = sys._getframe().f_back - # We're done here: - gc.callbacks.remove(callback) - - def f(): - while True: - yield - - old_threshold = gc.get_threshold() - old_callbacks = gc.callbacks[:] - old_enabled = gc.isenabled() - old_trace = sys.gettrace() - try: - # Stop the GC for a second while we set things up: - gc.disable() - # Create a paused generator: - g = f() - next(g) - # Move all objects to the oldest generation, and tell the GC to run - # on the *very next* allocation: - gc.collect() - gc.set_threshold(1, 0, 0) - # Okay, so here's the nightmare scenario: - # - We're tracing the resumption of a generator, which creates a new - # frame object. - # - The allocation of this frame object triggers a collection - # *before* the frame object is actually created. - # - During the collection, we request the exact same frame object. - # This test does it with a GC callback, but in real code it would - # likely be a trace function, weakref callback, or finalizer. - # - The collection finishes, and the original frame object is - # created. We now have two frame objects fighting over ownership - # of the same interpreter frame! - sys.settrace(trace) - gc.callbacks.append(callback) - sneaky_frame_object = None - gc.enable() - next(g) - # g.gi_frame should be the the frame object from the callback (the - # one that was *requested* second, but *created* first): - self.assertIs(g.gi_frame, sneaky_frame_object) - finally: - gc.set_threshold(*old_threshold) - gc.callbacks[:] = old_callbacks - sys.settrace(old_trace) - if old_enabled: - gc.enable() - - if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Build/2022-09-11-14-23-49.gh-issue-96729.W4uBWL.rst b/Misc/NEWS.d/next/Build/2022-09-11-14-23-49.gh-issue-96729.W4uBWL.rst deleted file mode 100644 index b67cd200e2d3..000000000000 --- a/Misc/NEWS.d/next/Build/2022-09-11-14-23-49.gh-issue-96729.W4uBWL.rst +++ /dev/null @@ -1,2 +0,0 @@ -Ensure that Windows releases built with ``Tools\msi\buildrelease.bat`` are -upgradable to and from official Python releases. diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-11-15-02-08-43.bpo-42316.LqdkWK.rst b/Misc/NEWS.d/next/Core and Builtins/2020-11-15-02-08-43.bpo-42316.LqdkWK.rst deleted file mode 100644 index ea997800bf07..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-11-15-02-08-43.bpo-42316.LqdkWK.rst +++ /dev/null @@ -1 +0,0 @@ -Document some places where an assignment expression needs parentheses. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-05-19-20-44.gh-issue-96587.bVxhX2.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-05-19-20-44.gh-issue-96587.bVxhX2.rst deleted file mode 100644 index 37e9dcbb11f0..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-05-19-20-44.gh-issue-96587.bVxhX2.rst +++ /dev/null @@ -1,2 +0,0 @@ -Correctly raise ``SyntaxError`` on exception groups (:pep:`654`) on python -versions prior to 3.11 diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-16-19-02-40.gh-issue-95778.cJmnst.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-16-19-02-40.gh-issue-95778.cJmnst.rst deleted file mode 100644 index ebf63778a605..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-16-19-02-40.gh-issue-95778.cJmnst.rst +++ /dev/null @@ -1,3 +0,0 @@ -When :exc:`ValueError` is raised if an integer is larger than the limit, -mention the :func:`sys.set_int_max_str_digits` function in the error message. -Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-18-08-47-40.gh-issue-96821.Co2iOq.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-18-08-47-40.gh-issue-96821.Co2iOq.rst deleted file mode 100644 index 4fd0532e827d..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-18-08-47-40.gh-issue-96821.Co2iOq.rst +++ /dev/null @@ -1 +0,0 @@ -Fix undefined behaviour in ``_testcapimodule.c``. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-21-14-38-31.gh-issue-96848.WuoLzU.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-21-14-38-31.gh-issue-96848.WuoLzU.rst deleted file mode 100644 index a9b04ce87d4d..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-21-14-38-31.gh-issue-96848.WuoLzU.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix command line parsing: reject :option:`-X int_max_str_digits <-X>` option -with no value (invalid) when the :envvar:`PYTHONINTMAXSTRDIGITS` environment -variable is set to a valid limit. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-21-16-06-37.gh-issue-96975.BmE0XY.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-21-16-06-37.gh-issue-96975.BmE0XY.rst deleted file mode 100644 index e6fcb84d7bff..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-21-16-06-37.gh-issue-96975.BmE0XY.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a crash occurring when :c:func:`PyEval_GetFrame` is called while the -topmost Python frame is in a partially-initialized state. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-03-13-35-48.gh-issue-97752.0xTjJY.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-03-13-35-48.gh-issue-97752.0xTjJY.rst deleted file mode 100644 index c65635070348..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-10-03-13-35-48.gh-issue-97752.0xTjJY.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix possible data corruption or crashes when accessing the ``f_back`` member -of newly-created generator or coroutine frames. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-06-02-11-34.gh-issue-97002.Zvsk71.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-06-02-11-34.gh-issue-97002.Zvsk71.rst deleted file mode 100644 index 1f577e02e1fd..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-10-06-02-11-34.gh-issue-97002.Zvsk71.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix an issue where several frame objects could be backed by the same -interpreter frame, possibly leading to corrupted memory and hard crashes of -the interpreter. diff --git a/Misc/NEWS.d/next/Documentation/2022-05-20-18-42-10.gh-issue-93031.c2RdJe.rst b/Misc/NEWS.d/next/Documentation/2022-05-20-18-42-10.gh-issue-93031.c2RdJe.rst deleted file mode 100644 index c46b45d2433c..000000000000 --- a/Misc/NEWS.d/next/Documentation/2022-05-20-18-42-10.gh-issue-93031.c2RdJe.rst +++ /dev/null @@ -1 +0,0 @@ -Update tutorial introduction output to use 3.10+ SyntaxError invalid range. diff --git a/Misc/NEWS.d/next/Documentation/2022-10-02-10-58-52.gh-issue-97741.39l023.rst b/Misc/NEWS.d/next/Documentation/2022-10-02-10-58-52.gh-issue-97741.39l023.rst deleted file mode 100644 index 8da9c92f6fd8..000000000000 --- a/Misc/NEWS.d/next/Documentation/2022-10-02-10-58-52.gh-issue-97741.39l023.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix ``!`` in c domain ref target syntax via a ``conf.py`` patch, so it works -as intended to disable ref target resolution. diff --git a/Misc/NEWS.d/next/Library/2022-05-25-15-57-39.gh-issue-90155.YMstB5.rst b/Misc/NEWS.d/next/Library/2022-05-25-15-57-39.gh-issue-90155.YMstB5.rst deleted file mode 100644 index 8def76914eda..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-25-15-57-39.gh-issue-90155.YMstB5.rst +++ /dev/null @@ -1 +0,0 @@ -Fix broken :class:`asyncio.Semaphore` when acquire is cancelled. diff --git a/Misc/NEWS.d/next/Library/2022-09-24-18-56-23.gh-issue-96865.o9WUkW.rst b/Misc/NEWS.d/next/Library/2022-09-24-18-56-23.gh-issue-96865.o9WUkW.rst deleted file mode 100644 index b054fdeee078..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-24-18-56-23.gh-issue-96865.o9WUkW.rst +++ /dev/null @@ -1,9 +0,0 @@ -fix Flag to use boundary CONFORM - -This restores previous Flag behavior of allowing flags with non-sequential values to be combined; e.g. - - class Skip(Flag): - TWO = 2 - EIGHT = 8 - - Skip.TWO | Skip.EIGHT -> diff --git a/Misc/NEWS.d/next/Library/2022-09-25-23-24-52.gh-issue-97545.HZLSNt.rst b/Misc/NEWS.d/next/Library/2022-09-25-23-24-52.gh-issue-97545.HZLSNt.rst deleted file mode 100644 index a53902ea670b..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-25-23-24-52.gh-issue-97545.HZLSNt.rst +++ /dev/null @@ -1 +0,0 @@ -Make Semaphore run faster. diff --git a/Misc/NEWS.d/next/Library/2022-10-16-15-31-50.gh-issue-98331.Y5kPOX.rst b/Misc/NEWS.d/next/Library/2022-10-16-15-31-50.gh-issue-98331.Y5kPOX.rst deleted file mode 100644 index b4cf94310af6..000000000000 --- a/Misc/NEWS.d/next/Library/2022-10-16-15-31-50.gh-issue-98331.Y5kPOX.rst +++ /dev/null @@ -1 +0,0 @@ -Update the bundled copies of pip and setuptools to versions 22.3 and 65.5.0 respectively. diff --git a/Misc/NEWS.d/next/Security/2022-09-07-10-42-00.gh-issue-97514.Yggdsl.rst b/Misc/NEWS.d/next/Security/2022-09-07-10-42-00.gh-issue-97514.Yggdsl.rst deleted file mode 100644 index 02d95b570520..000000000000 --- a/Misc/NEWS.d/next/Security/2022-09-07-10-42-00.gh-issue-97514.Yggdsl.rst +++ /dev/null @@ -1,15 +0,0 @@ -On Linux the :mod:`multiprocessing` module returns to using filesystem backed -unix domain sockets for communication with the *forkserver* process instead of -the Linux abstract socket namespace. Only code that chooses to use the -:ref:`"forkserver" start method ` is affected. - -Abstract sockets have no permissions and could allow any user on the system in -the same `network namespace -`_ (often the -whole system) to inject code into the multiprocessing *forkserver* process. -This was a potential privilege escalation. Filesystem based socket permissions -restrict this to the *forkserver* process user as was the default in Python 3.8 -and earlier. - -This prevents Linux `CVE-2022-42919 -`_. diff --git a/Misc/NEWS.d/next/Security/2022-09-28-17-09-37.gh-issue-97616.K1e3Xs.rst b/Misc/NEWS.d/next/Security/2022-09-28-17-09-37.gh-issue-97616.K1e3Xs.rst deleted file mode 100644 index 721427fe6465..000000000000 --- a/Misc/NEWS.d/next/Security/2022-09-28-17-09-37.gh-issue-97616.K1e3Xs.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix multiplying a list by an integer (``list *= int``): detect the integer -overflow when the new allocated length is close to the maximum size. Issue -reported by Jordan Limor. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Tests/2022-10-20-17-49-50.gh-issue-95027.viRpJB.rst b/Misc/NEWS.d/next/Tests/2022-10-20-17-49-50.gh-issue-95027.viRpJB.rst deleted file mode 100644 index 8bf1a9d33573..000000000000 --- a/Misc/NEWS.d/next/Tests/2022-10-20-17-49-50.gh-issue-95027.viRpJB.rst +++ /dev/null @@ -1,4 +0,0 @@ -On Windows, when the Python test suite is run with the ``-jN`` option, the -ANSI code page is now used as the encoding for the stdout temporary file, -rather than using UTF-8 which can lead to decoding errors. Patch by Victor -Stinner. diff --git a/Misc/NEWS.d/next/Windows/2022-09-29-23-08-49.gh-issue-90989.no89Q2.rst b/Misc/NEWS.d/next/Windows/2022-09-29-23-08-49.gh-issue-90989.no89Q2.rst deleted file mode 100644 index 34fffdf9a97b..000000000000 --- a/Misc/NEWS.d/next/Windows/2022-09-29-23-08-49.gh-issue-90989.no89Q2.rst +++ /dev/null @@ -1 +0,0 @@ -Clarify some text in the Windows installer. diff --git a/Misc/NEWS.d/next/Windows/2022-10-19-19-35-37.gh-issue-98414.FbHZuS.rst b/Misc/NEWS.d/next/Windows/2022-10-19-19-35-37.gh-issue-98414.FbHZuS.rst deleted file mode 100644 index df07b7f547df..000000000000 --- a/Misc/NEWS.d/next/Windows/2022-10-19-19-35-37.gh-issue-98414.FbHZuS.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix :file:`py.exe` launcher handling of ``-V:/`` option when -default preferences have been set in environment variables or configuration -files. diff --git a/Misc/NEWS.d/next/Windows/2022-10-19-20-00-28.gh-issue-98360.O2m6YG.rst b/Misc/NEWS.d/next/Windows/2022-10-19-20-00-28.gh-issue-98360.O2m6YG.rst deleted file mode 100644 index 61c1e5e837fe..000000000000 --- a/Misc/NEWS.d/next/Windows/2022-10-19-20-00-28.gh-issue-98360.O2m6YG.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fixes :mod:`multiprocessing` spawning child processes on Windows from a -virtual environment to ensure that child processes that also use -:mod:`multiprocessing` to spawn more children will recognize that they are -in a virtual environment. diff --git a/Misc/NEWS.d/next/macOS/2022-10-05-15-26-58.gh-issue-97897.Rf-C6u.rst b/Misc/NEWS.d/next/macOS/2022-10-05-15-26-58.gh-issue-97897.Rf-C6u.rst deleted file mode 100644 index 0d21e98b37c5..000000000000 --- a/Misc/NEWS.d/next/macOS/2022-10-05-15-26-58.gh-issue-97897.Rf-C6u.rst +++ /dev/null @@ -1,6 +0,0 @@ -The macOS 13 SDK includes support for the ``mkfifoat`` and ``mknodat`` system calls. -Using the ``dir_fd`` option with either :func:`os.mkfifo` or :func:`os.mknod` could result in a -segfault if cpython is built with the macOS 13 SDK but run on an earlier -version of macOS. Prevent this by adding runtime support for detection of -these system calls ("weaklinking") as is done for other newer syscalls on -macOS. From webhook-mailer at python.org Mon Oct 24 22:23:20 2022 From: webhook-mailer at python.org (Yhg1s) Date: Tue, 25 Oct 2022 02:23:20 -0000 Subject: [Python-checkins] Python 3.12.0a1 Message-ID: https://github.com/python/cpython/commit/4ae1a0ecaffe4320fe9774fad1f395f732c17959 commit: 4ae1a0ecaffe4320fe9774fad1f395f732c17959 branch: main author: Thomas Wouters committer: Yhg1s date: 2022-10-25T00:08:22+02:00 summary: Python 3.12.0a1 files: A Misc/NEWS.d/3.12.0a1.rst D Misc/NEWS.d/next/Build/2018-08-21-11-10-18.bpo-34449.Z3qm3c.rst D Misc/NEWS.d/next/Build/2022-05-12-10-19-15.gh-issue-90473.-syvqK.rst D Misc/NEWS.d/next/Build/2022-05-25-05-46-00.gh-issue-93202.T37jtj.rst D Misc/NEWS.d/next/Build/2022-05-25-13-56-00.gh-issue-93207.B9Rubf.rst D Misc/NEWS.d/next/Build/2022-05-31-18-04-58.gh-issue-69093.6lSa0C.rst D Misc/NEWS.d/next/Build/2022-06-04-12-53-53.gh-issue-93491.ehM211.rst D Misc/NEWS.d/next/Build/2022-06-08-14-28-03.gh-issue-93584.0xfHOK.rst D Misc/NEWS.d/next/Build/2022-06-25-23-25-47.gh-issue-94280.YhEyW_.rst D Misc/NEWS.d/next/Build/2022-06-27-11-57-15.gh-issue-93939.rv7s8W.rst D Misc/NEWS.d/next/Build/2022-06-28-09-42-10.gh-issue-93939._VWxKW.rst D Misc/NEWS.d/next/Build/2022-06-29-08-58-31.gh-issue-94404.3MadM6.rst D Misc/NEWS.d/next/Build/2022-06-30-09-57-39.gh-issue-90005.9-pQyR.rst D Misc/NEWS.d/next/Build/2022-06-30-17-00-54.gh-issue-90005.iiq5qD.rst D Misc/NEWS.d/next/Build/2022-06-30-17-18-23.gh-issue-90005.EIOOla.rst D Misc/NEWS.d/next/Build/2022-07-08-10-28-23.gh-issue-94682.ZtGt_0.rst D Misc/NEWS.d/next/Build/2022-07-12-13-39-18.gh-issue-94773.koHKm5.rst D Misc/NEWS.d/next/Build/2022-07-13-10-13-10.gh-issue-94801.3xUB24.rst D Misc/NEWS.d/next/Build/2022-07-14-02-45-44.gh-issue-94841.lLRTdf.rst D Misc/NEWS.d/next/Build/2022-07-14-11-13-26.gh-issue-94847.s3Kr5p.rst D Misc/NEWS.d/next/Build/2022-07-21-09-17-01.gh-issue-95085.E9x2S_.rst D Misc/NEWS.d/next/Build/2022-07-23-21-39-09.gh-issue-95174.7cYMZR.rst D Misc/NEWS.d/next/Build/2022-07-25-08-59-35.gh-issue-95174.g8woUW.rst D Misc/NEWS.d/next/Build/2022-07-25-09-48-43.gh-issue-95145.ZNS3dj.rst D Misc/NEWS.d/next/Build/2022-07-26-18-13-34.gh-issue-94801.9fREfy.rst D Misc/NEWS.d/next/Build/2022-08-04-15-29-35.gh-issue-93744.svRuqm.rst D Misc/NEWS.d/next/Build/2022-08-12-13-06-03.gh-issue-90536.qMpF6p.rst D Misc/NEWS.d/next/Build/2022-08-15-10-56-07.gh-issue-95973.Bsswsc.rst D Misc/NEWS.d/next/Build/2022-08-26-11-09-11.gh-issue-84461.Nsdn_R.rst D Misc/NEWS.d/next/Build/2022-08-26-11-50-03.gh-issue-96269.x_J5h0.rst D Misc/NEWS.d/next/Build/2022-09-11-14-23-49.gh-issue-96729.W4uBWL.rst D Misc/NEWS.d/next/Build/2022-09-12-18-34-51.gh-issue-85936.tX4VCU.rst D Misc/NEWS.d/next/Build/2022-09-17-11-19-24.gh-issue-96883.p_gr62.rst D Misc/NEWS.d/next/Build/2022-09-20-12-43-44.gh-issue-96761.IF29kR.rst D Misc/NEWS.d/next/C API/2021-10-05-21-59-43.bpo-45383.TVClgf.rst D Misc/NEWS.d/next/C API/2022-04-13-16-10-55.gh-issue-59121.-B7mKp.rst D Misc/NEWS.d/next/C API/2022-05-03-19-35-37.gh-issue-92193.61VoFL.rst D Misc/NEWS.d/next/C API/2022-05-09-23-16-38.gh-issue-85858.VIcNDL.rst D Misc/NEWS.d/next/C API/2022-05-10-12-35-42.gh-issue-92536.cAoRCZ.rst D Misc/NEWS.d/next/C API/2022-05-11-02-33-10.gh-issue-92651.FIXLf0.rst D Misc/NEWS.d/next/C API/2022-05-13-18-17-48.gh-issue-92781.TVDr3-.rst D Misc/NEWS.d/next/C API/2022-05-19-18-05-51.gh-issue-92913.Ass1Hv.rst D Misc/NEWS.d/next/C API/2022-05-23-12-31-04.gh-issue-77782.ugC8dn.rst D Misc/NEWS.d/next/C API/2022-05-23-13-33-18.gh-issue-93103.ooD3Eb.rst D Misc/NEWS.d/next/C API/2022-05-23-15-22-18.gh-issue-92898.Qjc9d3.rst D Misc/NEWS.d/next/C API/2022-06-03-14-54-41.gh-issue-93466.DDtH0X.rst D Misc/NEWS.d/next/C API/2022-06-04-13-15-41.gh-issue-93442.4M4NDb.rst D Misc/NEWS.d/next/C API/2022-06-06-16-04-14.gh-issue-93503.MHJTu8.rst D Misc/NEWS.d/next/C API/2022-06-10-16-50-27.gh-issue-89546.mX1f10.rst D Misc/NEWS.d/next/C API/2022-06-10-23-41-48.gh-issue-91731.fhYUQG.rst D Misc/NEWS.d/next/C API/2022-06-13-21-37-31.gh-issue-91321.DgJFvS.rst D Misc/NEWS.d/next/C API/2022-06-17-13-41-38.gh-issue-93937.uKVTEh.rst D Misc/NEWS.d/next/C API/2022-07-12-17-39-32.gh-issue-94731.9CPJNU.rst D Misc/NEWS.d/next/C API/2022-07-17-18-21-40.gh-issue-94930.gPFGDL.rst D Misc/NEWS.d/next/C API/2022-07-19-22-37-40.gh-issue-94936.LGlmKv.rst D Misc/NEWS.d/next/C API/2022-07-25-15-54-27.gh-issue-92678.ziZpxz.rst D Misc/NEWS.d/next/C API/2022-07-29-10-41-59.gh-issue-95388.aiRSgr.rst D Misc/NEWS.d/next/C API/2022-07-29-15-24-45.gh-issue-93012.-DdGEy.rst D Misc/NEWS.d/next/C API/2022-07-31-21-58-27.gh-issue-95504.wy7B1F.rst D Misc/NEWS.d/next/C API/2022-08-01-16-21-39.gh-issue-93274.QoDHEu.rst D Misc/NEWS.d/next/C API/2022-08-03-13-01-57.gh-issue-92678.DLwONN.rst D Misc/NEWS.d/next/C API/2022-08-03-14-39-08.gh-issue-92678.ozFTEx.rst D Misc/NEWS.d/next/C API/2022-08-08-14-36-31.gh-issue-95781.W_G8YW.rst D Misc/NEWS.d/next/C API/2022-08-16-16-54-42.gh-issue-95589.6xE1ar.rst D Misc/NEWS.d/next/C API/2022-09-20-01-04-57.gh-issue-96512.msZTjF.rst D Misc/NEWS.d/next/C API/2022-10-03-20-33-24.gh-issue-95756.SSmXlG.rst D Misc/NEWS.d/next/C API/2022-10-05-10-43-32.gh-issue-91051.ODDRsQ.rst D Misc/NEWS.d/next/C API/2022-10-18-16-16-27.gh-issue-98393.55u4BF.rst D Misc/NEWS.d/next/Core and Builtins/2020-11-15-02-08-43.bpo-42316.LqdkWK.rst D Misc/NEWS.d/next/Core and Builtins/2022-01-02-14-53-59.bpo-46142.WayjgT.rst D Misc/NEWS.d/next/Core and Builtins/2022-03-22-13-12-27.bpo-47091.tJcy-P.rst D Misc/NEWS.d/next/Core and Builtins/2022-04-15-22-12-53.gh-issue-91578.rDOtyK.rst D Misc/NEWS.d/next/Core and Builtins/2022-04-16-15-37-55.gh-issue-91399.trLbK6.rst D Misc/NEWS.d/next/Core and Builtins/2022-04-24-02-22-10.gh-issue-91432.YPJAK6.rst D Misc/NEWS.d/next/Core and Builtins/2022-05-03-20-12-18.gh-issue-92261.aigLnb.rst D Misc/NEWS.d/next/Core and Builtins/2022-05-08-19-43-31.gh-issue-88750.1BjJg-.rst D Misc/NEWS.d/next/Core and Builtins/2022-05-10-11-34-35.gh-issue-92619.u0V0lY.rst D Misc/NEWS.d/next/Core and Builtins/2022-05-11-09-16-54.gh-issue-91102.lenv9h.rst D Misc/NEWS.d/next/Core and Builtins/2022-05-12-13-23-19.gh-issue-92236.sDRzUe.rst D Misc/NEWS.d/next/Core and Builtins/2022-05-13-00-57-18.gh-issue-92658.YdhFE2.rst D Misc/NEWS.d/next/Core and Builtins/2022-05-13-12-36-10.gh-issue-92777.Odo4vP.rst D Misc/NEWS.d/next/Core and Builtins/2022-05-14-13-22-11.gh-issue-92804.rAqpI2.rst D Misc/NEWS.d/next/Core and Builtins/2022-05-15-15-25-05.gh-issue-90473.MoPHYW.rst D Misc/NEWS.d/next/Core and Builtins/2022-05-17-20-41-43.gh-issue-92858.eIXJTn.rst D Misc/NEWS.d/next/Core and Builtins/2022-05-18-08-32-33.gh-issue-92914.tJUeTD.rst D Misc/NEWS.d/next/Core and Builtins/2022-05-18-12-55-35.gh-issue-90690.TKuoTa.rst D Misc/NEWS.d/next/Core and Builtins/2022-05-18-18-34-45.gh-issue-92930.kpYPOb.rst D Misc/NEWS.d/next/Core and Builtins/2022-05-19-13-25-50.gh-issue-92955.kmNV33.rst D Misc/NEWS.d/next/Core and Builtins/2022-05-19-15-29-53.gh-issue-89914.8bAffH.rst D Misc/NEWS.d/next/Core and Builtins/2022-05-20-09-25-34.gh-issue-93021.k3Aji2.rst D Misc/NEWS.d/next/Core and Builtins/2022-05-20-13-32-24.gh-issue-93012.e9B-pv.rst D Misc/NEWS.d/next/Core and Builtins/2022-05-21-23-21-37.gh-issue-93065.5I18WC.rst D Misc/NEWS.d/next/Core and Builtins/2022-05-22-02-37-50.gh-issue-93061.r70Imp.rst D Misc/NEWS.d/next/Core and Builtins/2022-05-23-18-36-07.gh-issue-93143.X1Yqxm.rst D Misc/NEWS.d/next/Core and Builtins/2022-05-24-14-35-48.gh-issue-93040.9X6Ofu.rst D Misc/NEWS.d/next/Core and Builtins/2022-05-25-04-07-22.gh-issue-91924.-UyO4q.rst D Misc/NEWS.d/next/Core and Builtins/2022-05-25-12-30-12.gh-issue-84694.5sjy2w.rst D Misc/NEWS.d/next/Core and Builtins/2022-05-25-21-56-25.gh-issue-93223.gTOGVZ.rst D Misc/NEWS.d/next/Core and Builtins/2022-05-30-10-22-46.gh-issue-93345.gi1A4L.rst D Misc/NEWS.d/next/Core and Builtins/2022-05-30-14-50-03.gh-issue-93283.XDO2ZQ.rst D Misc/NEWS.d/next/Core and Builtins/2022-05-30-15-35-42.gh-issue-93354.RZk8gs.rst D Misc/NEWS.d/next/Core and Builtins/2022-05-30-15-51-11.gh-issue-93356.l5wnzW.rst D Misc/NEWS.d/next/Core and Builtins/2022-05-30-19-00-38.gh-issue-93359.zXV3A0.rst D Misc/NEWS.d/next/Core and Builtins/2022-05-31-16-36-30.gh-issue-93382.Jf6gAj.rst D Misc/NEWS.d/next/Core and Builtins/2022-06-01-17-47-40.gh-issue-93418.24dJuc.rst D Misc/NEWS.d/next/Core and Builtins/2022-06-02-08-28-55.gh-issue-93429.DZTWHx.rst D Misc/NEWS.d/next/Core and Builtins/2022-06-02-23-00-08.gh-issue-93444.m63DIs.rst D Misc/NEWS.d/next/Core and Builtins/2022-06-06-14-28-24.gh-issue-93533.lnC0CC.rst D Misc/NEWS.d/next/Core and Builtins/2022-06-09-09-08-29.gh-issue-93621.-_Pn1d.rst D Misc/NEWS.d/next/Core and Builtins/2022-06-09-19-19-02.gh-issue-93461.5DqP1e.rst D Misc/NEWS.d/next/Core and Builtins/2022-06-10-10-31-18.gh-issue-93662.-7RSC1.rst D Misc/NEWS.d/next/Core and Builtins/2022-06-10-12-03-17.gh-issue-93671.idkQqG.rst D Misc/NEWS.d/next/Core and Builtins/2022-06-10-16-57-35.gh-issue-93678.1WBnHt.rst D Misc/NEWS.d/next/Core and Builtins/2022-06-12-19-31-56.gh-issue-89828.bq02M7.rst D Misc/NEWS.d/next/Core and Builtins/2022-06-13-10-48-09.gh-issue-93516.yJSait.rst D Misc/NEWS.d/next/Core and Builtins/2022-06-13-13-55-34.gh-issue-93516.HILrDl.rst D Misc/NEWS.d/next/Core and Builtins/2022-06-15-11-16-13.gh-issue-93841.06zqX3.rst D Misc/NEWS.d/next/Core and Builtins/2022-06-15-16-45-53.gh-issue-93678.1I_ZT3.rst D Misc/NEWS.d/next/Core and Builtins/2022-06-16-16-53-22.gh-issue-93911.RDwIiK.rst D Misc/NEWS.d/next/Core and Builtins/2022-06-17-16-30-24.gh-issue-93955.LmiAe9.rst D Misc/NEWS.d/next/Core and Builtins/2022-06-18-17-00-33.gh-issue-93911.y286of.rst D Misc/NEWS.d/next/Core and Builtins/2022-06-20-13-48-57.gh-issue-94021.o78q3G.rst D Misc/NEWS.d/next/Core and Builtins/2022-06-23-12-10-39.gh-issue-94163.SqAfQq.rst D Misc/NEWS.d/next/Core and Builtins/2022-06-24-14-06-20.gh-issue-93883.8jVQQ4.rst D Misc/NEWS.d/next/Core and Builtins/2022-06-25-10-19-43.gh-issue-87995.aMDHnp.rst D Misc/NEWS.d/next/Core and Builtins/2022-06-26-14-37-03.gh-issue-94192.ab7tn7.rst D Misc/NEWS.d/next/Core and Builtins/2022-06-28-10-08-06.gh-issue-94262.m-HWUZ.rst D Misc/NEWS.d/next/Core and Builtins/2022-06-28-12-41-17.gh-issue-88116.A7fEl_.rst D Misc/NEWS.d/next/Core and Builtins/2022-06-28-14-20-36.gh-issue-94360.DiEnen.rst D Misc/NEWS.d/next/Core and Builtins/2022-06-29-15-45-04.gh-issue-94329.olUQyk.rst D Misc/NEWS.d/next/Core and Builtins/2022-06-29-22-18-36.gh-issue-91719.3APYYI.rst D Misc/NEWS.d/next/Core and Builtins/2022-06-30-15-07-26.gh-issue-94438.btzHSk.rst D Misc/NEWS.d/next/Core and Builtins/2022-07-01-20-00-19.gh-issue-94485.mo5st7.rst D Misc/NEWS.d/next/Core and Builtins/2022-07-06-14-02-26.gh-issue-92228.44Cbly.rst D Misc/NEWS.d/next/Core and Builtins/2022-07-07-21-13-25.gh-issue-94215._Sv9Ms.rst D Misc/NEWS.d/next/Core and Builtins/2022-07-08-11-44-45.gh-issue-93252.i2358c.rst D Misc/NEWS.d/next/Core and Builtins/2022-07-08-16-44-11.gh-issue-94694.VkL2CM.rst D Misc/NEWS.d/next/Core and Builtins/2022-07-14-10-07-53.gh-issue-90699.x3aG9m.rst D Misc/NEWS.d/next/Core and Builtins/2022-07-15-16-15-04.gh-issue-91153.HiBmtt.rst D Misc/NEWS.d/next/Core and Builtins/2022-07-15-22-16-08.gh-issue-94822.zRRzBN.rst D Misc/NEWS.d/next/Core and Builtins/2022-07-15-22-47-44.gh-issue-94893.YiJYcW.rst D Misc/NEWS.d/next/Core and Builtins/2022-07-16-08-14-17.gh-issue-94869.eRwMsX.rst D Misc/NEWS.d/next/Core and Builtins/2022-07-17-15-54-29.gh-issue-91256.z7i7Q5.rst D Misc/NEWS.d/next/Core and Builtins/2022-07-18-04-48-34.gh-issue-94947.df9gUw.rst D Misc/NEWS.d/next/Core and Builtins/2022-07-18-05-10-29.gh-issue-94949.OsZ7_s.rst D Misc/NEWS.d/next/Core and Builtins/2022-07-18-14-19-21.gh-issue-94739.NQJQi7.rst D Misc/NEWS.d/next/Core and Builtins/2022-07-19-04-34-56.gh-issue-94996.dV564A.rst D Misc/NEWS.d/next/Core and Builtins/2022-07-19-09-41-55.gh-issue-94938.xYBlM7.rst D Misc/NEWS.d/next/Core and Builtins/2022-07-19-16-30-59.gh-issue-94036._6Utkm.rst D Misc/NEWS.d/next/Core and Builtins/2022-07-20-09-04-55.gh-issue-95023.bs-xd7.rst D Misc/NEWS.d/next/Core and Builtins/2022-07-20-13-46-01.gh-issue-91409.dhL8Zo.rst D Misc/NEWS.d/next/Core and Builtins/2022-07-21-17-54-52.gh-issue-95113.NnSLpT.rst D Misc/NEWS.d/next/Core and Builtins/2022-07-21-19-19-20.gh-issue-95060.4xdT1f.rst D Misc/NEWS.d/next/Core and Builtins/2022-07-22-12-53-34.gh-issue-94438.hNqACc.rst D Misc/NEWS.d/next/Core and Builtins/2022-07-23-19-16-25.gh-issue-93351.0Jyvu-.rst D Misc/NEWS.d/next/Core and Builtins/2022-07-24-00-27-47.gh-issue-95185.ghYTZx.rst D Misc/NEWS.d/next/Core and Builtins/2022-07-26-09-31-12.gh-issue-93678.W8vvgT.rst D Misc/NEWS.d/next/Core and Builtins/2022-07-26-12-59-03.gh-issue-95245.GHWczn.rst D Misc/NEWS.d/next/Core and Builtins/2022-07-27-14-05-07.gh-issue-95324.28Q5u7.rst D Misc/NEWS.d/next/Core and Builtins/2022-07-27-14-21-57.gh-issue-90081.HVAS5x.rst D Misc/NEWS.d/next/Core and Builtins/2022-07-28-08-33-31.gh-issue-95355.yN4XVk.rst D Misc/NEWS.d/next/Core and Builtins/2022-07-28-19-07-06.gh-issue-87092.73IPS1.rst D Misc/NEWS.d/next/Core and Builtins/2022-07-31-03-22-58.gh-issue-91146.Y2Hziy.rst D Misc/NEWS.d/next/Core and Builtins/2022-07-31-13-23-12.gh-issue-95150.67FXVo.rst D Misc/NEWS.d/next/Core and Builtins/2022-08-04-18-46-54.gh-issue-95605.FbpCoG.rst D Misc/NEWS.d/next/Core and Builtins/2022-08-11-09-19-55.gh-issue-95876.YpQfoV.rst D Misc/NEWS.d/next/Core and Builtins/2022-08-11-11-01-56.gh-issue-95818.iClLdl.rst D Misc/NEWS.d/next/Core and Builtins/2022-08-12-13-04-25.gh-issue-95922.YNCtyX.rst D Misc/NEWS.d/next/Core and Builtins/2022-08-12-18-13-49.gh-issue-91210.AWMSLj.rst D Misc/NEWS.d/next/Core and Builtins/2022-08-14-10-04-44.gh-issue-95977.gCTZb9.rst D Misc/NEWS.d/next/Core and Builtins/2022-08-15-11-58-05.gh-issue-90997.bWwV8Q.rst D Misc/NEWS.d/next/Core and Builtins/2022-08-15-12-41-14.gh-issue-95245.N4gOUV.rst D Misc/NEWS.d/next/Core and Builtins/2022-08-15-20-52-41.gh-issue-93678.X7GuIJ.rst D Misc/NEWS.d/next/Core and Builtins/2022-08-15-21-08-11.gh-issue-96005.6eoc8k.rst D Misc/NEWS.d/next/Core and Builtins/2022-08-18-13-47-59.gh-issue-96046.5Hqbka.rst D Misc/NEWS.d/next/Core and Builtins/2022-08-19-06-51-17.gh-issue-96071.mVgPAo.rst D Misc/NEWS.d/next/Core and Builtins/2022-08-20-18-36-40.gh-issue-96143.nh3GFM.rst D Misc/NEWS.d/next/Core and Builtins/2022-08-22-21-33-28.gh-issue-96187.W_6SRG.rst D Misc/NEWS.d/next/Core and Builtins/2022-08-24-14-30-26.gh-issue-96237.msif5f.rst D Misc/NEWS.d/next/Core and Builtins/2022-08-25-10-19-34.gh-issue-96268.AbYrLB.rst D Misc/NEWS.d/next/Core and Builtins/2022-08-26-18-46-32.gh-issue-93554.QEaCcK.rst D Misc/NEWS.d/next/Core and Builtins/2022-08-28-10-51-19.gh-issue-96352.jTLD2d.rst D Misc/NEWS.d/next/Core and Builtins/2022-08-29-00-37-21.gh-issue-96364.c-IVyb.rst D Misc/NEWS.d/next/Core and Builtins/2022-08-29-13-06-58.gh-issue-95196.eGRR4b.rst D Misc/NEWS.d/next/Core and Builtins/2022-08-31-18-46-13.gh-issue-96348.xzCoTP.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-02-16-47-52.gh-issue-93911.vF-GWe.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-05-09-56-32.gh-issue-91079.H4-DdU.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-05-15-07-25.gh-issue-96582.HEsL5s.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-05-16-43-44.gh-issue-96569.9lmTCC.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-05-19-20-44.gh-issue-96587.bVxhX2.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-06-11-19-03.gh-issue-90230.YOtzs5.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-06-14-26-36.gh-issue-96612.P4ZbeY.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-06-16-22-13.gh-issue-96611.14wIX8.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-06-16-54-49.gh-issue-96572.8DRsaW.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-07-12-02-11.gh-issue-96636.YvN-K6.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-07-13-38-37.gh-issue-96641.wky0Fc.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-08-20-58-10.gh-issue-64373.AfCi36.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-09-13-13-27.gh-issue-96678.vMxi9F.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-11-00-37-50.gh-issue-90751.VE8-zf.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-11-12-43-43.gh-issue-96751.anRT6a.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-12-15-15-04.gh-issue-90997.sZO8c9.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-12-16-58-22.gh-issue-96754.0GRme5.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-13-12-06-46.gh-issue-96678.NqGFyb.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-13-21-45-07.gh-issue-95778.Oll4_5.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-16-12-36-13.gh-issue-96864.PLU3i8.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-16-16-54-35.gh-issue-96387.GRzewg.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-16-19-02-40.gh-issue-95778.cJmnst.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-18-08-47-40.gh-issue-96821.Co2iOq.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-19-03-35-01.gh-issue-96821.izK6JA.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-20-11-06-45.gh-issue-95921.dkcRQn.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-21-14-38-31.gh-issue-96848.WuoLzU.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-21-16-06-37.gh-issue-96975.BmE0XY.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-27-11-59-13.gh-issue-96670.XrBBit.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-29-15-19-29.gh-issue-94526.wq5m6T.rst D Misc/NEWS.d/next/Core and Builtins/2022-09-30-13-26-58.gh-issue-97670.n61vMR.rst D Misc/NEWS.d/next/Core and Builtins/2022-10-01-08-55-09.gh-issue-97591.pw6kkH.rst D Misc/NEWS.d/next/Core and Builtins/2022-10-03-13-35-48.gh-issue-97752.0xTjJY.rst D Misc/NEWS.d/next/Core and Builtins/2022-10-03-16-12-39.gh-issue-91052.MsYL9d.rst D Misc/NEWS.d/next/Core and Builtins/2022-10-04-02-00-10.gh-issue-97779.f3N1hI.rst D Misc/NEWS.d/next/Core and Builtins/2022-10-04-14-04-40.gh-issue-86298.QVM7G1.rst D Misc/NEWS.d/next/Core and Builtins/2022-10-04-17-02-18.gh-issue-97850.E3QTRA.rst D Misc/NEWS.d/next/Core and Builtins/2022-10-05-00-37-27.gh-issue-65961.z0Ys0y.rst D Misc/NEWS.d/next/Core and Builtins/2022-10-05-11-37-15.gh-issue-97922.Zu9Bge.rst D Misc/NEWS.d/next/Core and Builtins/2022-10-05-17-02-22.gh-issue-97943.LYAWlE.rst D Misc/NEWS.d/next/Core and Builtins/2022-10-06-02-11-34.gh-issue-97002.Zvsk71.rst D Misc/NEWS.d/next/Core and Builtins/2022-10-06-06-36-29.gh-issue-97912.jGRJpa.rst D Misc/NEWS.d/next/Core and Builtins/2022-10-06-14-14-28.gh-issue-97955.Nq5VXD.rst D Misc/NEWS.d/next/Core and Builtins/2022-10-06-15-45-57.gh-issue-96078.fS-6mU.rst D Misc/NEWS.d/next/Core and Builtins/2022-10-06-20-41-29.gh-issue-97973.gB-xWi.rst D Misc/NEWS.d/next/Core and Builtins/2022-10-06-23-13-34.gh-issue-97997.JQaJKF.rst D Misc/NEWS.d/next/Core and Builtins/2022-10-13-23-23-01.gh-issue-98254.bC8IKt.rst D Misc/NEWS.d/next/Core and Builtins/2022-10-18-14-11-32.gh-issue-98390.H1sxJu.rst D Misc/NEWS.d/next/Core and Builtins/2022-10-18-16-17-44.gh-issue-98398.x4rYK_.rst D Misc/NEWS.d/next/Core and Builtins/2022-10-19-18-03-28.gh-issue-98354.GRGta3.rst D Misc/NEWS.d/next/Core and Builtins/2022-10-19-20-53-38.gh-issue-98461.iNmPDV.rst D Misc/NEWS.d/next/Core and Builtins/2022-10-19-23-48-46.gh-issue-98374.eOBh8M.rst D Misc/NEWS.d/next/Documentation/2017-12-10-19-13-39.bpo-13553.gQbZs4.rst D Misc/NEWS.d/next/Documentation/2019-09-12-08-28-17.bpo-38056.6ktYkc.rst D Misc/NEWS.d/next/Documentation/2021-04-01-08-09-34.bpo-43689.mqCfLe.rst D Misc/NEWS.d/next/Documentation/2022-01-13-16-03-15.bpo-40838.k3NVCf.rst D Misc/NEWS.d/next/Documentation/2022-03-30-17-56-01.bpo-47161.gesHfS.rst D Misc/NEWS.d/next/Documentation/2022-05-18-23-58-26.gh-issue-92240.bHvYiz.rst D Misc/NEWS.d/next/Documentation/2022-05-20-18-42-10.gh-issue-93031.c2RdJe.rst D Misc/NEWS.d/next/Documentation/2022-05-26-11-33-23.gh-issue-86438.kEGGmK.rst D Misc/NEWS.d/next/Documentation/2022-05-26-14-51-25.gh-issue-88831.5Cccr5.rst D Misc/NEWS.d/next/Documentation/2022-05-29-21-22-54.gh-issue-86986.lFXw8j.rst D Misc/NEWS.d/next/Documentation/2022-06-15-12-12-49.gh-issue-87260.epyI7D.rst D Misc/NEWS.d/next/Documentation/2022-06-16-10-10-59.gh-issue-61162.1ypkG8.rst D Misc/NEWS.d/next/Documentation/2022-06-19-18-18-22.gh-issue-86128.39DDTD.rst D Misc/NEWS.d/next/Documentation/2022-07-07-08-42-05.gh-issue-94321.pmCIPb.rst D Misc/NEWS.d/next/Documentation/2022-07-29-09-04-02.gh-issue-95415.LKTyw6.rst D Misc/NEWS.d/next/Documentation/2022-07-29-23-02-19.gh-issue-95451.-tgB93.rst D Misc/NEWS.d/next/Documentation/2022-07-30-00-23-11.gh-issue-95454.we7AFm.rst D Misc/NEWS.d/next/Documentation/2022-08-03-13-35-08.gh-issue-91207.eJ4pPf.rst D Misc/NEWS.d/next/Documentation/2022-08-12-01-12-52.gh-issue-95588.PA0FI7.rst D Misc/NEWS.d/next/Documentation/2022-08-13-20-34-51.gh-issue-95957.W9ZZAx.rst D Misc/NEWS.d/next/Documentation/2022-08-19-17-07-45.gh-issue-96098.nDp43u.rst D Misc/NEWS.d/next/Documentation/2022-09-01-17-03-04.gh-issue-96432.1EJ1-4.rst D Misc/NEWS.d/next/Documentation/2022-10-02-10-58-52.gh-issue-97741.39l023.rst D Misc/NEWS.d/next/Documentation/2022-10-11-09-40-50.gh-issue-86404.dEAb8W.rst D Misc/NEWS.d/next/Documentation/2022-10-16-17-34-45.gh-issue-85525.DvkD0v.rst D Misc/NEWS.d/next/IDLE/2022-07-28-18-56-57.gh-issue-89610.hcosiM.rst D Misc/NEWS.d/next/IDLE/2022-07-29-11-08-52.gh-issue-95411.dazlqH.rst D Misc/NEWS.d/next/IDLE/2022-07-30-15-10-39.gh-issue-95471.z3scVG.rst D Misc/NEWS.d/next/IDLE/2022-07-31-22-15-14.gh-issue-95511.WX6PmB.rst D Misc/NEWS.d/next/IDLE/2022-08-01-23-31-48.gh-issue-95191.U7vryB.rst D Misc/NEWS.d/next/IDLE/2022-08-04-20-07-51.gh-issue-65802.xnThWe.rst D Misc/NEWS.d/next/IDLE/2022-10-15-21-20-40.gh-issue-97527.otAHJM.rst D Misc/NEWS.d/next/Library/2017-07-31-13-35-28.bpo-26253.8v_sCs.rst D Misc/NEWS.d/next/Library/2018-09-23-07-47-29.bpo-32990.2FVVTU.rst D Misc/NEWS.d/next/Library/2018-09-28-22-18-03.bpo-34828.5Zyi_S.rst D Misc/NEWS.d/next/Library/2019-09-25-00-37-51.bpo-38267.X9Jb5V.rst D Misc/NEWS.d/next/Library/2019-11-04-22-21-27.bpo-38693.w_OAov.rst D Misc/NEWS.d/next/Library/2020-01-09-01-57-12.bpo-39264.GsBL9-.rst D Misc/NEWS.d/next/Library/2020-07-08-20-32-13.bpo-41246.2trYf3.rst D Misc/NEWS.d/next/Library/2020-09-28-04-56-04.bpo-14243.YECnxv.rst D Misc/NEWS.d/next/Library/2020-10-15-18-37-12.bpo-42047.XDdoSF.rst D Misc/NEWS.d/next/Library/2021-05-22-07-58-59.bpo-42627.EejtD0.rst D Misc/NEWS.d/next/Library/2021-08-27-18-07-35.bpo-44173.oW92Ev.rst D Misc/NEWS.d/next/Library/2021-08-29-19-59-16.bpo-45046.eGq0NC.rst D Misc/NEWS.d/next/Library/2021-12-27-15-32-15.bpo-45924.0ZpHX2.rst D Misc/NEWS.d/next/Library/2022-01-03-15-07-06.bpo-46197.Z0djv6.rst D Misc/NEWS.d/next/Library/2022-01-09-14-23-00.bpo-28249.4dzB80.rst D Misc/NEWS.d/next/Library/2022-01-14-10-49-20.bpo-46364.SzhlU9.rst D Misc/NEWS.d/next/Library/2022-02-05-18-46-54.bpo-46642.YI6nHQ.rst D Misc/NEWS.d/next/Library/2022-02-09-23-44-27.bpo-45393.9v5Y8U.rst D Misc/NEWS.d/next/Library/2022-02-15-12-40-48.bpo-46755.zePJfx.rst D Misc/NEWS.d/next/Library/2022-02-21-01-37-00.bpo-42777.nWK3E6.rst D Misc/NEWS.d/next/Library/2022-03-08-04-46-44.bpo-46951.SWAz97.rst D Misc/NEWS.d/next/Library/2022-03-16-14-24-14.bpo-47025.qtT3CE.rst D Misc/NEWS.d/next/Library/2022-03-19-04-41-42.bpo-47063.nwRfUo.rst D Misc/NEWS.d/next/Library/2022-03-22-18-28-55.bpo-35540.nyijX9.rst D Misc/NEWS.d/next/Library/2022-04-01-09-43-54.bpo-32547.NIUiNC.rst D Misc/NEWS.d/next/Library/2022-04-01-12-35-44.gh-issue-90005.pvaLHQ.rst D Misc/NEWS.d/next/Library/2022-04-03-11-25-02.bpo-41287.8CTdwf.rst D Misc/NEWS.d/next/Library/2022-04-03-19-40-09.bpo-39064.76PbIz.rst D Misc/NEWS.d/next/Library/2022-04-08-22-12-11.bpo-47231.lvyglt.rst D Misc/NEWS.d/next/Library/2022-04-11-16-55-41.gh-issue-91456.DK3KKl.rst D Misc/NEWS.d/next/Library/2022-04-12-18-05-40.gh-issue-91447.N_Fs4H.rst D Misc/NEWS.d/next/Library/2022-04-14-08-37-16.gh-issue-91524.g8PiIu.rst D Misc/NEWS.d/next/Library/2022-04-15-11-29-38.gh-issue-91539.7WgVuA.rst D Misc/NEWS.d/next/Library/2022-04-15-13-16-25.gh-issue-91581.9OGsrN.rst D Misc/NEWS.d/next/Library/2022-04-15-17-38-55.gh-issue-91577.Ah7cLL.rst D Misc/NEWS.d/next/Library/2022-04-15-22-07-36.gh-issue-90622.0C6l8h.rst D Misc/NEWS.d/next/Library/2022-04-21-19-14-29.gh-issue-91760.54AR-m.rst D Misc/NEWS.d/next/Library/2022-04-24-22-26-45.gh-issue-81790.M5Rvpm.rst D Misc/NEWS.d/next/Library/2022-04-25-10-23-01.gh-issue-91810.DOHa6B.rst D Misc/NEWS.d/next/Library/2022-04-26-18-37-24.gh-issue-91968.fuuH1_.rst D Misc/NEWS.d/next/Library/2022-05-06-13-00-57.gh-issue-92391.s-Lase.rst D Misc/NEWS.d/next/Library/2022-05-08-18-51-14.gh-issue-89336.TL6ip7.rst D Misc/NEWS.d/next/Library/2022-05-08-19-21-14.gh-issue-84131.rG5kI7.rst D Misc/NEWS.d/next/Library/2022-05-09-01-27-25.gh-issue-92531.vV7S_O.rst D Misc/NEWS.d/next/Library/2022-05-09-09-28-02.gh-issue-92530.M4Q1RS.rst D Misc/NEWS.d/next/Library/2022-05-09-11-55-04.gh-issue-92547.CzVZft.rst D Misc/NEWS.d/next/Library/2022-05-09-21-31-41.gh-issue-92445.tJosdm.rst D Misc/NEWS.d/next/Library/2022-05-09-22-27-11.gh-issue-92591.V7RCk2.rst D Misc/NEWS.d/next/Library/2022-05-10-07-57-27.gh-issue-92550.Rk_UzM.rst D Misc/NEWS.d/next/Library/2022-05-10-16-30-40.gh-issue-90385.1_wBRQ.rst D Misc/NEWS.d/next/Library/2022-05-11-10-06-31.gh-issue-86388.7ivUtT.rst D Misc/NEWS.d/next/Library/2022-05-11-14-34-09.gh-issue-91581.glkou2.rst D Misc/NEWS.d/next/Library/2022-05-11-19-33-27.gh-issue-92671.KE4v6a.rst D Misc/NEWS.d/next/Library/2022-05-12-15-19-00.gh-issue-92734.d0wjDt.rst D Misc/NEWS.d/next/Library/2022-05-14-09-01-38.gh-issue-89325.ys-2BZ.rst D Misc/NEWS.d/next/Library/2022-05-14-11-41-23.gh-issue-90473.kPdOZl.rst D Misc/NEWS.d/next/Library/2022-05-16-14-35-39.gh-issue-92839.owSMyo.rst D Misc/NEWS.d/next/Library/2022-05-17-06-27-39.gh-issue-92869.t8oBkw.rst D Misc/NEWS.d/next/Library/2022-05-18-17-18-41.gh-issue-91922.DwWIsJ.rst D Misc/NEWS.d/next/Library/2022-05-18-21-04-09.gh-issue-87901.lnf041.rst D Misc/NEWS.d/next/Library/2022-05-19-13-33-18.gh-issue-92675.ZeerMZ.rst D Misc/NEWS.d/next/Library/2022-05-19-17-49-58.gh-issue-92932.o2peTh.rst D Misc/NEWS.d/next/Library/2022-05-19-22-34-42.gh-issue-92986.e6uKxj.rst D Misc/NEWS.d/next/Library/2022-05-20-15-52-43.gh-issue-93010.WF-cAc.rst D Misc/NEWS.d/next/Library/2022-05-21-13-16-16.gh-issue-93044.eJ_XkZ.rst D Misc/NEWS.d/next/Library/2022-05-22-16-08-01.gh-issue-89973.jc-Q4g.rst D Misc/NEWS.d/next/Library/2022-05-22-23-46-18.gh-issue-93033.wZfiL-.rst D Misc/NEWS.d/next/Library/2022-05-24-10-59-02.gh-issue-92728.zxTifq.rst D Misc/NEWS.d/next/Library/2022-05-24-11-19-04.gh-issue-74696.-cnf-A.rst D Misc/NEWS.d/next/Library/2022-05-25-00-21-28.gh-issue-91513.9VyCT4.rst D Misc/NEWS.d/next/Library/2022-05-25-02-45-41.gh-issue-90817.yxANgU.rst D Misc/NEWS.d/next/Library/2022-05-25-15-57-39.gh-issue-90155.YMstB5.rst D Misc/NEWS.d/next/Library/2022-05-25-22-09-38.gh-issue-92886.ylwDSc.rst D Misc/NEWS.d/next/Library/2022-05-26-08-41-34.gh-issue-93243.uw6x5z.rst D Misc/NEWS.d/next/Library/2022-05-26-09-24-41.gh-issue-93162.W1VuhU.rst D Misc/NEWS.d/next/Library/2022-05-26-23-10-55.gh-issue-93156.4XfDVN.rst D Misc/NEWS.d/next/Library/2022-05-27-10-52-06.gh-issue-85308.K6r-tJ.rst D Misc/NEWS.d/next/Library/2022-05-27-13-18-18.gh-issue-93297.e2zuHz.rst D Misc/NEWS.d/next/Library/2022-05-27-22-17-11.gh-issue-88123.mkYl5q.rst D Misc/NEWS.d/next/Library/2022-05-28-08-02-55.gh-issue-93312.HY0Uzj.rst D Misc/NEWS.d/next/Library/2022-05-30-21-42-50.gh-issue-83658.01Ntx0.rst D Misc/NEWS.d/next/Library/2022-05-31-14-58-40.gh-issue-93353.9Hvm6o.rst D Misc/NEWS.d/next/Library/2022-06-01-11-24-13.gh-issue-91162.NxvU_u.rst D Misc/NEWS.d/next/Library/2022-06-02-08-40-58.gh-issue-91810.Gtk44w.rst D Misc/NEWS.d/next/Library/2022-06-03-22-13-28.gh-issue-93370.tjfu9L.rst D Misc/NEWS.d/next/Library/2022-06-04-00-11-54.gh-issue-93475.vffFw1.rst D Misc/NEWS.d/next/Library/2022-06-05-22-22-42.gh-issue-93421.43UO_8.rst D Misc/NEWS.d/next/Library/2022-06-06-12-58-27.gh-issue-79579.e8rB-M.rst D Misc/NEWS.d/next/Library/2022-06-06-13-19-43.gh-issue-93521._vE8m9.rst D Misc/NEWS.d/next/Library/2022-06-07-14-53-46.gh-issue-90549.T4FMKY.rst D Misc/NEWS.d/next/Library/2022-06-08-20-11-02.gh-issue-90494.LIZT85.rst D Misc/NEWS.d/next/Library/2022-06-09-10-12-55.gh-issue-90473.683m_C.rst D Misc/NEWS.d/next/Library/2022-06-09-14-44-21.gh-issue-93626.sfghs46.rst D Misc/NEWS.d/next/Library/2022-06-09-17-15-26.gh-issue-91389.OE4vS5.rst D Misc/NEWS.d/next/Library/2022-06-11-13-32-17.gh-issue-79512.A1KTDr.rst D Misc/NEWS.d/next/Library/2022-06-15-21-20-02.gh-issue-93820.FAMLY8.rst D Misc/NEWS.d/next/Library/2022-06-15-21-28-16.gh-issue-83499.u3DQJ-.rst D Misc/NEWS.d/next/Library/2022-06-15-21-35-11.gh-issue-91404.39TZzW.rst D Misc/NEWS.d/next/Library/2022-06-16-09-24-50.gh-issue-93847.kuv8bN.rst D Misc/NEWS.d/next/Library/2022-06-16-11-16-53.gh-issue-93820.00X0Y5.rst D Misc/NEWS.d/next/Library/2022-06-17-12-02-30.gh-issue-93858.R49ARc.rst D Misc/NEWS.d/next/Library/2022-06-17-16-00-55.gh-issue-93963.8YYZ-2.rst D Misc/NEWS.d/next/Library/2022-06-18-15-06-54.gh-issue-93973.4y6UQT.rst D Misc/NEWS.d/next/Library/2022-06-20-23-14-43.gh-issue-94028.UofEcX.rst D Misc/NEWS.d/next/Library/2022-06-21-11-40-31.gh-issue-84753.FW1pxO.rst D Misc/NEWS.d/next/Library/2022-06-22-11-16-11.gh-issue-94101.V9vDG8.rst D Misc/NEWS.d/next/Library/2022-06-23-13-12-05.gh-issue-91742.sNytVX.rst D Misc/NEWS.d/next/Library/2022-06-23-14-35-10.gh-issue-94169.jeba90.rst D Misc/NEWS.d/next/Library/2022-06-24-08-49-47.gh-issue-94182.Wknau0.rst D Misc/NEWS.d/next/Library/2022-06-24-09-41-41.gh-issue-94196.r2KyfS.rst D Misc/NEWS.d/next/Library/2022-06-24-10-18-59.gh-issue-94199.kYOo8g.rst D Misc/NEWS.d/next/Library/2022-06-24-10-29-19.gh-issue-94199.pfehmz.rst D Misc/NEWS.d/next/Library/2022-06-24-10-39-56.gh-issue-94199.MIuckY.rst D Misc/NEWS.d/next/Library/2022-06-24-14-25-26.gh-issue-94214.03pXR5.rst D Misc/NEWS.d/next/Library/2022-06-24-17-11-33.gh-issue-94199.7releN.rst D Misc/NEWS.d/next/Library/2022-06-24-18-20-42.gh-issue-94226.8ZL4Fm.rst D Misc/NEWS.d/next/Library/2022-06-24-19-16-09.gh-issue-93096.r1_oIc.rst D Misc/NEWS.d/next/Library/2022-06-24-19-23-59.gh-issue-94207.VhS1eS.rst D Misc/NEWS.d/next/Library/2022-06-24-19-40-40.gh-issue-93096.3RlK2d.rst D Misc/NEWS.d/next/Library/2022-06-24-20-00-57.gh-issue-94216.hxnQPu.rst D Misc/NEWS.d/next/Library/2022-06-25-09-12-23.gh-issue-74696.fxC9ua.rst D Misc/NEWS.d/next/Library/2022-06-25-13-38-53.gh-issue-93259.FAGw-2.rst D Misc/NEWS.d/next/Library/2022-06-25-16-27-02.gh-issue-94254.beP16v.rst D Misc/NEWS.d/next/Library/2022-06-25-23-44-44.gh-issue-90016.EB409s.rst D Misc/NEWS.d/next/Library/2022-06-26-10-59-15.gh-issue-89988.K8rnmt.rst D Misc/NEWS.d/next/Library/2022-06-27-10-33-18.gh-issue-94318.jR4_QV.rst D Misc/NEWS.d/next/Library/2022-06-28-00-24-48.gh-issue-94352.JY1Ayt.rst D Misc/NEWS.d/next/Library/2022-06-28-14-29-21.gh-issue-94379.RrgKfh.rst D Misc/NEWS.d/next/Library/2022-06-28-14-41-22.gh-issue-94383.CXnquo.rst D Misc/NEWS.d/next/Library/2022-06-29-04-42-56.gh-issue-94398.YOq_bJ.rst D Misc/NEWS.d/next/Library/2022-06-29-09-48-37.gh-issue-92336.otA6c6.rst D Misc/NEWS.d/next/Library/2022-07-02-19-46-30.gh-issue-94510.xOatDC.rst D Misc/NEWS.d/next/Library/2022-07-03-16-26-35.gh-issue-78724.XNiJzf.rst D Misc/NEWS.d/next/Library/2022-07-03-16-41-03.gh-issue-94382.zuVZeM.rst D Misc/NEWS.d/next/Library/2022-07-05-17-22-00.gh-issue-94343.kf4H5r.rst D Misc/NEWS.d/next/Library/2022-07-06-06-02-02.gh-issue-93896.vIgWGr.rst D Misc/NEWS.d/next/Library/2022-07-06-14-45-12.gh-issue-93910.iZcp67.rst D Misc/NEWS.d/next/Library/2022-07-06-14-57-33.gh-issue-94619.PRqKVX.rst D Misc/NEWS.d/next/Library/2022-07-06-16-01-08.gh-issue-94607.Q6RYfz.rst D Misc/NEWS.d/next/Library/2022-07-06-21-24-03.gh-issue-92546.s5Upkh.rst D Misc/NEWS.d/next/Library/2022-07-06-22-41-51.gh-issue-94309._XswsX.rst D Misc/NEWS.d/next/Library/2022-07-07-15-46-55.gh-issue-94637.IYEiUM.rst D Misc/NEWS.d/next/Library/2022-07-08-08-39-35.gh-issue-88050.0aOC_m.rst D Misc/NEWS.d/next/Library/2022-07-08-17-49-12.gh-issue-87822.F9dzkf.rst D Misc/NEWS.d/next/Library/2022-07-09-08-55-04.gh-issue-74116.0XwYC1.rst D Misc/NEWS.d/next/Library/2022-07-09-15-17-02.gh-issue-81620.L0O_bV.rst D Misc/NEWS.d/next/Library/2022-07-11-10-41-48.gh-issue-94736.EbsgeK.rst D Misc/NEWS.d/next/Library/2022-07-14-00-43-52.gh-issue-94821.e17ghU.rst D Misc/NEWS.d/next/Library/2022-07-15-08-13-51.gh-issue-94857.9_KvZJ.rst D Misc/NEWS.d/next/Library/2022-07-17-22-31-32.gh-issue-90085.c4FWcS.rst D Misc/NEWS.d/next/Library/2022-07-19-15-37-11.gh-issue-95005.iRmZ74.rst D Misc/NEWS.d/next/Library/2022-07-20-00-23-58.gh-issue-77617.XGaqSQ.rst D Misc/NEWS.d/next/Library/2022-07-20-22-49-48.gh-issue-95066.TuCu0E.rst D Misc/NEWS.d/next/Library/2022-07-21-19-55-49.gh-issue-95105.BIX2Km.rst D Misc/NEWS.d/next/Library/2022-07-21-22-59-22.gh-issue-95109.usxA9r.rst D Misc/NEWS.d/next/Library/2022-07-22-00-58-49.gh-issue-95077.4Z6CNC.rst D Misc/NEWS.d/next/Library/2022-07-22-09-09-08.gh-issue-91212.53O8Ab.rst D Misc/NEWS.d/next/Library/2022-07-22-17-19-57.gh-issue-93157.RXByAk.rst D Misc/NEWS.d/next/Library/2022-07-22-21-18-17.gh-issue-95132.n9anlw.rst D Misc/NEWS.d/next/Library/2022-07-23-10-42-05.gh-issue-95166.xw6p3C.rst D Misc/NEWS.d/next/Library/2022-07-23-10-50-05.gh-issue-93899.VT34A5.rst D Misc/NEWS.d/next/Library/2022-07-24-09-15-35.gh-issue-95194.ERVmqG.rst D Misc/NEWS.d/next/Library/2022-07-24-12-00-06.gh-issue-95199.-5A64k.rst D Misc/NEWS.d/next/Library/2022-07-24-12-59-02.gh-issue-95087.VvqXkN.rst D Misc/NEWS.d/next/Library/2022-07-24-18-00-42.gh-issue-95097.lu5qNf.rst D Misc/NEWS.d/next/Library/2022-07-25-15-45-06.gh-issue-95231.i807-g.rst D Misc/NEWS.d/next/Library/2022-07-27-11-35-45.gh-issue-95045.iysT-Q.rst D Misc/NEWS.d/next/Library/2022-07-27-19-43-07.gh-issue-95339.NuVQ68.rst D Misc/NEWS.d/next/Library/2022-07-27-19-47-51.gh-issue-83901.OSw06c.rst D Misc/NEWS.d/next/Library/2022-07-28-17-14-38.gh-issue-95385.6YlsDI.rst D Misc/NEWS.d/next/Library/2022-07-29-20-58-37.gh-issue-94909.YjMusj.rst D Misc/NEWS.d/next/Library/2022-08-03-16-52-32.gh-issue-95289.FMnHlV.rst D Misc/NEWS.d/next/Library/2022-08-03-21-01-17.gh-issue-95609.xxyjyX.rst D Misc/NEWS.d/next/Library/2022-08-07-14-56-23.gh-issue-95149.U0c6Ib.rst D Misc/NEWS.d/next/Library/2022-08-08-01-42-11.gh-issue-95704.MOPFfX.rst D Misc/NEWS.d/next/Library/2022-08-10-11-54-04.gh-issue-95804.i5FCFK.rst D Misc/NEWS.d/next/Library/2022-08-10-17-34-07.gh-issue-95861.qv-T5s.rst D Misc/NEWS.d/next/Library/2022-08-11-03-16-48.gh-issue-95865.0IOkFP.rst D Misc/NEWS.d/next/Library/2022-08-11-18-22-29.gh-issue-95736.LzRZXe.rst D Misc/NEWS.d/next/Library/2022-08-11-18-52-17.gh-issue-95899._Bi4uG.rst D Misc/NEWS.d/next/Library/2022-08-14-18-59-54.gh-issue-69142.6is5Pq.rst D Misc/NEWS.d/next/Library/2022-08-18-14-53-53.gh-issue-95463.GpP05c.rst D Misc/NEWS.d/next/Library/2022-08-19-10-19-32.gh-issue-96019.b7uAVP.rst D Misc/NEWS.d/next/Library/2022-08-19-18-21-01.gh-issue-96125.ODcF1Y.rst D Misc/NEWS.d/next/Library/2022-08-20-10-31-01.gh-issue-96052.a6FhaD.rst D Misc/NEWS.d/next/Library/2022-08-20-12-56-15.gh-issue-96145.8ah3pE.rst D Misc/NEWS.d/next/Library/2022-08-22-13-54-20.gh-issue-96175.bH7zGU.rst D Misc/NEWS.d/next/Library/2022-08-22-18-42-17.gh-issue-96159.3bFU39.rst D Misc/NEWS.d/next/Library/2022-08-23-13-30-30.gh-issue-96172.7WTHer.rst D Misc/NEWS.d/next/Library/2022-08-27-14-38-49.gh-issue-90467.VOOB0p.rst D Misc/NEWS.d/next/Library/2022-08-27-21-26-52.gh-issue-96349.XyYLlO.rst D Misc/NEWS.d/next/Library/2022-08-27-23-16-09.gh-issue-96346.jJX14I.rst D Misc/NEWS.d/next/Library/2022-08-29-07-04-03.gh-issue-89258.ri7ncj.rst D Misc/NEWS.d/next/Library/2022-08-29-12-35-28.gh-issue-96073.WaGstf.rst D Misc/NEWS.d/next/Library/2022-08-29-12-49-30.gh-issue-96142.PdCMez.rst D Misc/NEWS.d/next/Library/2022-08-29-15-28-39.gh-issue-96385.uLRTsf.rst D Misc/NEWS.d/next/Library/2022-08-29-16-54-36.gh-issue-96388.dCpJcu.rst D Misc/NEWS.d/next/Library/2022-08-30-11-46-36.gh-issue-95987.CV7_u4.rst D Misc/NEWS.d/next/Library/2022-08-30-12-32-00.gh-issue-96415.6W7ORH.rst D Misc/NEWS.d/next/Library/2022-08-31-11-10-21.gh-issue-96079.uqrXdJ.rst D Misc/NEWS.d/next/Library/2022-09-01-13-54-38.gh-issue-96465.0IJmrH.rst D Misc/NEWS.d/next/Library/2022-09-03-18-39-05.gh-issue-96538.W156-D.rst D Misc/NEWS.d/next/Library/2022-09-04-12-32-52.gh-issue-68163.h6TJCc.rst D Misc/NEWS.d/next/Library/2022-09-07-22-49-37.gh-issue-96652.YqOKxI.rst D Misc/NEWS.d/next/Library/2022-09-08-20-12-48.gh-issue-46412.r_cfTh.rst D Misc/NEWS.d/next/Library/2022-09-10-16-46-16.gh-issue-96735.0YzJuG.rst D Misc/NEWS.d/next/Library/2022-09-13-15-12-31.gh-issue-96734.G08vjz.rst D Misc/NEWS.d/next/Library/2022-09-15-00-37-33.gh-issue-96741.4b6czN.rst D Misc/NEWS.d/next/Library/2022-09-16-07-53-29.gh-issue-95865.oHjX0A.rst D Misc/NEWS.d/next/Library/2022-09-17-13-15-10.gh-issue-96819.6RfqM7.rst D Misc/NEWS.d/next/Library/2022-09-18-04-51-30.gh-issue-96704.DmamRX.rst D Misc/NEWS.d/next/Library/2022-09-22-11-50-29.gh-issue-85760.DETTPd.rst D Misc/NEWS.d/next/Library/2022-09-22-14-35-02.gh-issue-97005.yf21Q7.rst D Misc/NEWS.d/next/Library/2022-09-24-18-56-23.gh-issue-96865.o9WUkW.rst D Misc/NEWS.d/next/Library/2022-09-25-20-42-33.gh-issue-73588.uVtjEA.rst D Misc/NEWS.d/next/Library/2022-09-25-23-24-52.gh-issue-97545.HZLSNt.rst D Misc/NEWS.d/next/Library/2022-09-29-08-15-55.gh-issue-97639.JSjWYW.rst D Misc/NEWS.d/next/Library/2022-09-29-23-22-24.gh-issue-97592.tpJg_J.rst D Misc/NEWS.d/next/Library/2022-09-30-09-22-37.gh-issue-95534.ndEfPj.rst D Misc/NEWS.d/next/Library/2022-09-30-15-56-20.gh-issue-96827.lzy1iw.rst D Misc/NEWS.d/next/Library/2022-10-03-13-25-19.gh-issue-97781.gCLLef.rst D Misc/NEWS.d/next/Library/2022-10-03-14-42-13.gh-issue-97799.Y1iJvf.rst D Misc/NEWS.d/next/Library/2022-10-04-00-43-43.gh-issue-97008.3rjtt6.rst D Misc/NEWS.d/next/Library/2022-10-04-07-55-19.gh-issue-97825.mNdv1l.rst D Misc/NEWS.d/next/Library/2022-10-04-21-21-41.gh-issue-97837.19q-eg.rst D Misc/NEWS.d/next/Library/2022-10-05-11-40-02.gh-issue-97850.NzdREm.rst D Misc/NEWS.d/next/Library/2022-10-05-16-10-24.gh-issue-97930.NPSrzE.rst D Misc/NEWS.d/next/Library/2022-10-05-20-52-17.gh-issue-97646.Q4fVww.rst D Misc/NEWS.d/next/Library/2022-10-06-17-59-22.gh-issue-65961.SXlQnI.rst D Misc/NEWS.d/next/Library/2022-10-06-23-42-00.gh-issue-90985.s280JY.rst D Misc/NEWS.d/next/Library/2022-10-07-09-52-37.gh-issue-98023.aliEcl.rst D Misc/NEWS.d/next/Library/2022-10-08-06-59-46.gh-issue-94597.TsS0oT.rst D Misc/NEWS.d/next/Library/2022-10-09-12-12-38.gh-issue-87730.ClgP3f.rst D Misc/NEWS.d/next/Library/2022-10-10-09-52-21.gh-issue-44098.okcqJt.rst D Misc/NEWS.d/next/Library/2022-10-12-10-00-40.gh-issue-98178.hspH51.rst D Misc/NEWS.d/next/Library/2022-10-12-11-20-54.gh-issue-94597.GYJZlb.rst D Misc/NEWS.d/next/Library/2022-10-14-11-46-31.gh-issue-98251.Uxc9al.rst D Misc/NEWS.d/next/Library/2022-10-14-12-29-05.gh-issue-98257.aMSMs2.rst D Misc/NEWS.d/next/Library/2022-10-14-19-57-37.gh-issue-96035.0xcX-p.rst D Misc/NEWS.d/next/Library/2022-10-16-06-18-59.gh-issue-98307.b2_CDu.rst D Misc/NEWS.d/next/Library/2022-10-16-15-31-50.gh-issue-98331.Y5kPOX.rst D Misc/NEWS.d/next/Library/2022-10-17-12-49-02.gh-issue-98363.aFmSP-.rst D Misc/NEWS.d/next/Library/2022-10-18-15-41-37.gh-issue-98393.vhPu4L.rst D Misc/NEWS.d/next/Library/2022-10-19-09-29-12.gh-issue-97928.xj3im7.rst D Misc/NEWS.d/next/Library/2022-10-23-18-30-39.gh-issue-89237.kBui30.rst D Misc/NEWS.d/next/Security/2022-04-27-18-25-30.gh-issue-68966.gjS8zs.rst D Misc/NEWS.d/next/Security/2022-05-19-08-53-07.gh-issue-92888.TLtR9W.rst D Misc/NEWS.d/next/Security/2022-06-03-12-52-53.gh-issue-79096.YVoxgC.rst D Misc/NEWS.d/next/Security/2022-06-15-20-09-23.gh-issue-87389.QVaC3f.rst D Misc/NEWS.d/next/Security/2022-09-07-10-42-00.gh-issue-97514.Yggdsl.rst D Misc/NEWS.d/next/Security/2022-09-28-17-09-37.gh-issue-97616.K1e3Xs.rst D Misc/NEWS.d/next/Tests/2022-03-14-23-28-17.bpo-47016.K-t2QX.rst D Misc/NEWS.d/next/Tests/2022-05-08-15-40-41.gh-issue-92514.Xbf5JY.rst D Misc/NEWS.d/next/Tests/2022-05-12-05-51-06.gh-issue-92670.7L43Z_.rst D Misc/NEWS.d/next/Tests/2022-05-25-22-34-10.gh-issue-92886.1Lkt8S.rst D Misc/NEWS.d/next/Tests/2022-05-25-22-43-11.gh-issue-92886.9HQb9e.rst D Misc/NEWS.d/next/Tests/2022-05-25-22-53-30.gh-issue-92886.mIfdtz.rst D Misc/NEWS.d/next/Tests/2022-05-25-23-00-35.gh-issue-92886.Y-vrWj.rst D Misc/NEWS.d/next/Tests/2022-05-25-23-07-15.gh-issue-92886.Aki63_.rst D Misc/NEWS.d/next/Tests/2022-06-03-12-22-44.gh-issue-89858.ftBvjE.rst D Misc/NEWS.d/next/Tests/2022-06-03-14-18-37.gh-issue-90473.7iXVRK.rst D Misc/NEWS.d/next/Tests/2022-06-03-16-26-04.gh-issue-57539.HxWgYO.rst D Misc/NEWS.d/next/Tests/2022-06-04-12-05-31.gh-issue-90473.RSpjF7.rst D Misc/NEWS.d/next/Tests/2022-06-05-10-16-45.gh-issue-90473.QMu7A8.rst D Misc/NEWS.d/next/Tests/2022-06-08-14-17-59.gh-issue-93575.Xb2LNB.rst D Misc/NEWS.d/next/Tests/2022-06-08-22-32-56.gh-issue-93616.e5Kkx2.rst D Misc/NEWS.d/next/Tests/2022-06-10-21-18-14.gh-issue-84461.9TAb26.rst D Misc/NEWS.d/next/Tests/2022-06-16-17-50-58.gh-issue-93353.JdpATx.rst D Misc/NEWS.d/next/Tests/2022-06-16-21-38-18.gh-issue-93852.U_Hl6s.rst D Misc/NEWS.d/next/Tests/2022-06-17-13-27-21.gh-issue-93884.5pvPvl.rst D Misc/NEWS.d/next/Tests/2022-06-17-13-55-11.gh-issue-93957.X4ovYV.rst D Misc/NEWS.d/next/Tests/2022-06-17-15-20-09.gh-issue-93951.CW1Vv4.rst D Misc/NEWS.d/next/Tests/2022-06-20-23-04-52.gh-issue-93839.OE3Ybk.rst D Misc/NEWS.d/next/Tests/2022-06-21-17-37-46.gh-issue-54781.BjVAVg.rst D Misc/NEWS.d/next/Tests/2022-06-27-08-53-40.gh-issue-94315.MoZT9t.rst D Misc/NEWS.d/next/Tests/2022-06-27-21-27-20.gh-issue-94208.VR6HX-.rst D Misc/NEWS.d/next/Tests/2022-07-05-17-53-13.gh-issue-91330.Qys5IL.rst D Misc/NEWS.d/next/Tests/2022-07-08-12-22-00.gh-issue-94675.IiTs5f.rst D Misc/NEWS.d/next/Tests/2022-07-24-16-28-31.gh-issue-93963.UB9azu.rst D Misc/NEWS.d/next/Tests/2022-07-24-17-24-42.gh-issue-95218.zfBLtu.rst D Misc/NEWS.d/next/Tests/2022-07-24-20-19-05.gh-issue-95212.fHiU4e.rst D Misc/NEWS.d/next/Tests/2022-07-26-15-22-19.gh-issue-95280.h8HvbP.rst D Misc/NEWS.d/next/Tests/2022-08-05-09-57-43.gh-issue-95573.edMdQB.rst D Misc/NEWS.d/next/Tests/2022-08-22-14-59-42.gh-issue-95243.DeD66V.rst D Misc/NEWS.d/next/Tests/2022-09-08-18-31-26.gh-issue-96624.5cANM1.rst D Misc/NEWS.d/next/Tests/2022-10-20-17-49-50.gh-issue-95027.viRpJB.rst D Misc/NEWS.d/next/Tools-Demos/2022-06-19-14-56-33.gh-issue-86087.R8MkRy.rst D Misc/NEWS.d/next/Tools-Demos/2022-06-29-22-47-11.gh-issue-94430.hdov8L.rst D Misc/NEWS.d/next/Tools-Demos/2022-07-04-01-37-42.gh-issue-94538.1rgy1Y.rst D Misc/NEWS.d/next/Tools-Demos/2022-07-04-10-02-02.gh-issue-93939.U6sW6H.rst D Misc/NEWS.d/next/Tools-Demos/2022-08-05-23-25-59.gh-issue-95731.N2KohU.rst D Misc/NEWS.d/next/Tools-Demos/2022-08-10-17-08-43.gh-issue-95853.HCjC2m.rst D Misc/NEWS.d/next/Tools-Demos/2022-08-29-17-25-13.gh-issue-95853.Ce17cT.rst D Misc/NEWS.d/next/Tools-Demos/2022-09-30-14-30-12.gh-issue-97669.gvbgcg.rst D Misc/NEWS.d/next/Tools-Demos/2022-09-30-18-35-11.gh-issue-97681.-KO1Ba.rst D Misc/NEWS.d/next/Tools-Demos/2022-10-07-22-06-11.gh-issue-68686.6KNIQ4.rst D Misc/NEWS.d/next/Windows/2020-01-10-23-33-03.bpo-38704.2Idtdn.rst D Misc/NEWS.d/next/Windows/2022-03-20-15-47-35.bpo-42658.16eXtb.rst D Misc/NEWS.d/next/Windows/2022-04-12-18-35-20.gh-issue-91061.x40hSK.rst D Misc/NEWS.d/next/Windows/2022-05-05-06-27-59.bpo-46907.IW-uvT.rst D Misc/NEWS.d/next/Windows/2022-05-16-11-45-06.gh-issue-92841.NQx107.rst D Misc/NEWS.d/next/Windows/2022-05-19-14-01-30.gh-issue-92984.Dsxnlr.rst D Misc/NEWS.d/next/Windows/2022-05-19-21-44-25.gh-issue-92817.Jrf-Kv.rst D Misc/NEWS.d/next/Windows/2022-05-28-19-36-13.gh-issue-43414.NGMJ3g.rst D Misc/NEWS.d/next/Windows/2022-06-15-01-03-52.gh-issue-93824.mR4mxu.rst D Misc/NEWS.d/next/Windows/2022-06-20-22-32-14.gh-issue-94018.bycC3A.rst D Misc/NEWS.d/next/Windows/2022-07-12-20-45-43.gh-issue-94772.uNMmdG.rst D Misc/NEWS.d/next/Windows/2022-07-16-16-18-32.gh-issue-90844.vwITT3.rst D Misc/NEWS.d/next/Windows/2022-07-26-20-33-12.gh-issue-95285.w6fa22.rst D Misc/NEWS.d/next/Windows/2022-07-28-20-21-38.gh-issue-95359.ywMrgu.rst D Misc/NEWS.d/next/Windows/2022-07-30-14-18-33.gh-issue-95445.mjrTaq.rst D Misc/NEWS.d/next/Windows/2022-08-03-00-49-46.gh-issue-94399.KvxHc0.rst D Misc/NEWS.d/next/Windows/2022-08-04-01-12-27.gh-issue-95587.Fvdv5q.rst D Misc/NEWS.d/next/Windows/2022-08-04-18-47-54.gh-issue-95656.VJ1d13.rst D Misc/NEWS.d/next/Windows/2022-08-10-22-46-48.gh-issue-95733.2_urOp.rst D Misc/NEWS.d/next/Windows/2022-08-26-00-11-18.gh-issue-89545.zmJMY_.rst D Misc/NEWS.d/next/Windows/2022-08-30-12-01-51.gh-issue-94781.OxO-Gr.rst D Misc/NEWS.d/next/Windows/2022-09-05-18-32-47.gh-issue-96559.561sUd.rst D Misc/NEWS.d/next/Windows/2022-09-07-00-11-33.gh-issue-96577.kV4K_1.rst D Misc/NEWS.d/next/Windows/2022-09-23-15-40-04.gh-issue-96965.CsnEGs.rst D Misc/NEWS.d/next/Windows/2022-09-29-22-27-04.gh-issue-97649.bI7OQU.rst D Misc/NEWS.d/next/Windows/2022-09-29-23-08-49.gh-issue-90989.no89Q2.rst D Misc/NEWS.d/next/Windows/2022-10-02-11-59-23.gh-issue-97728.dIdlPE.rst D Misc/NEWS.d/next/Windows/2022-10-19-19-35-37.gh-issue-98414.FbHZuS.rst D Misc/NEWS.d/next/Windows/2022-10-19-20-00-28.gh-issue-98360.O2m6YG.rst D Misc/NEWS.d/next/macOS/2022-10-05-15-26-58.gh-issue-97897.Rf-C6u.rst M Include/patchlevel.h M Lib/pydoc_data/topics.py M README.rst diff --git a/Include/patchlevel.h b/Include/patchlevel.h index 37a984494d71..1d72b74dd235 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -20,10 +20,10 @@ #define PY_MINOR_VERSION 12 #define PY_MICRO_VERSION 0 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_ALPHA -#define PY_RELEASE_SERIAL 0 +#define PY_RELEASE_SERIAL 1 /* Version as a string */ -#define PY_VERSION "3.12.0a0" +#define PY_VERSION "3.12.0a1" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py index f3ceaadfad64..52a3ee1e1cb5 100644 --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Autogenerated by Sphinx on Fri May 6 23:53:34 2022 +# Autogenerated by Sphinx on Tue Oct 25 00:07:40 2022 topics = {'assert': 'The "assert" statement\n' '**********************\n' '\n' @@ -1671,10 +1671,26 @@ 'If the syntax "**expression" appears in the function call,\n' '"expression" must evaluate to a *mapping*, the contents of which ' 'are\n' - 'treated as additional keyword arguments. If a keyword is already\n' - 'present (as an explicit keyword argument, or from another ' - 'unpacking),\n' - 'a "TypeError" exception is raised.\n' + 'treated as additional keyword arguments. If a parameter matching a ' + 'key\n' + 'has already been given a value (by an explicit keyword argument, ' + 'or\n' + 'from another unpacking), a "TypeError" exception is raised.\n' + '\n' + 'When "**expression" is used, each key in this mapping must be a\n' + 'string. Each value from the mapping is assigned to the first ' + 'formal\n' + 'parameter eligible for keyword assignment whose name is equal to ' + 'the\n' + 'key. A key need not be a Python identifier (e.g. ""max-temp ?F"" ' + 'is\n' + 'acceptable, although it will not match any formal parameter that ' + 'could\n' + 'be declared). If there is no match to a formal parameter the ' + 'key-value\n' + 'pair is collected by the "**" parameter, if there is one, or if ' + 'there\n' + 'is not, a "TypeError" exception is raised.\n' '\n' 'Formal parameters using the syntax "*identifier" or "**identifier"\n' 'cannot be used as positional argument slots or as keyword argument\n' @@ -2022,7 +2038,7 @@ '\n' '* Mappings (instances of "dict") compare equal if and only if ' 'they\n' - ' have equal *(key, value)* pairs. Equality comparison of the ' + ' have equal "(key, value)" pairs. Equality comparison of the ' 'keys and\n' ' values enforces reflexivity.\n' '\n' @@ -2398,35 +2414,43 @@ ' try3_stmt ::= "try" ":" suite\n' ' "finally" ":" suite\n' '\n' + 'Additional information on exceptions can be found in section\n' + 'Exceptions, and information on using the "raise" statement to ' + 'generate\n' + 'exceptions may be found in section The raise statement.\n' + '\n' + '\n' + '"except" clause\n' + '---------------\n' + '\n' 'The "except" clause(s) specify one or more exception handlers. ' 'When no\n' 'exception occurs in the "try" clause, no exception handler is\n' 'executed. When an exception occurs in the "try" suite, a search ' 'for an\n' - 'exception handler is started. This search inspects the except ' - 'clauses\n' - 'in turn until one is found that matches the exception. An ' - 'expression-\n' - 'less except clause, if present, must be last; it matches any\n' - 'exception. For an except clause with an expression, that ' - 'expression\n' - 'is evaluated, and the clause matches the exception if the ' - 'resulting\n' - 'object is ?compatible? with the exception. An object is ' - 'compatible\n' - 'with an exception if the object is the class or a *non-virtual ' - 'base\n' - 'class* of the exception object, or a tuple containing an item ' - 'that is\n' - 'the class or a non-virtual base class of the exception object.\n' - '\n' - 'If no except clause matches the exception, the search for an ' + 'exception handler is started. This search inspects the "except"\n' + 'clauses in turn until one is found that matches the exception. ' + 'An\n' + 'expression-less "except" clause, if present, must be last; it ' + 'matches\n' + 'any exception. For an "except" clause with an expression, that\n' + 'expression is evaluated, and the clause matches the exception if ' + 'the\n' + 'resulting object is ?compatible? with the exception. An object ' + 'is\n' + 'compatible with an exception if the object is the class or a ' + '*non-\n' + 'virtual base class* of the exception object, or a tuple ' + 'containing an\n' + 'item that is the class or a non-virtual base class of the ' 'exception\n' - 'handler continues in the surrounding code and on the invocation ' - 'stack.\n' - '[1]\n' + 'object.\n' + '\n' + 'If no "except" clause matches the exception, the search for an\n' + 'exception handler continues in the surrounding code and on the\n' + 'invocation stack. [1]\n' '\n' - 'If the evaluation of an expression in the header of an except ' + 'If the evaluation of an expression in the header of an "except" ' 'clause\n' 'raises an exception, the original search for a handler is ' 'canceled and\n' @@ -2436,24 +2460,24 @@ 'raised\n' 'the exception).\n' '\n' - 'When a matching except clause is found, the exception is ' + 'When a matching "except" clause is found, the exception is ' 'assigned to\n' - 'the target specified after the "as" keyword in that except ' - 'clause, if\n' - 'present, and the except clause?s suite is executed. All except\n' - 'clauses must have an executable block. When the end of this ' + 'the target specified after the "as" keyword in that "except" ' + 'clause,\n' + 'if present, and the "except" clause?s suite is executed. All ' + '"except"\n' + 'clauses must have an executable block. When the end of this ' 'block is\n' - 'reached, execution continues normally after the entire try ' - 'statement.\n' - '(This means that if two nested handlers exist for the same ' - 'exception,\n' - 'and the exception occurs in the try clause of the inner handler, ' - 'the\n' - 'outer handler will not handle the exception.)\n' + 'reached, execution continues normally after the entire "try"\n' + 'statement. (This means that if two nested handlers exist for the ' + 'same\n' + 'exception, and the exception occurs in the "try" clause of the ' + 'inner\n' + 'handler, the outer handler will not handle the exception.)\n' '\n' 'When an exception has been assigned using "as target", it is ' 'cleared\n' - 'at the end of the except clause. This is as if\n' + 'at the end of the "except" clause. This is as if\n' '\n' ' except E as N:\n' ' foo\n' @@ -2468,7 +2492,7 @@ '\n' 'This means the exception must be assigned to a different name to ' 'be\n' - 'able to refer to it after the except clause. Exceptions are ' + 'able to refer to it after the "except" clause. Exceptions are ' 'cleared\n' 'because with the traceback attached to them, they form a ' 'reference\n' @@ -2476,7 +2500,8 @@ 'alive\n' 'until the next garbage collection occurs.\n' '\n' - 'Before an except clause?s suite is executed, details about the\n' + 'Before an "except" clause?s suite is executed, details about ' + 'the\n' 'exception are stored in the "sys" module and can be accessed ' 'via\n' '"sys.exc_info()". "sys.exc_info()" returns a 3-tuple consisting ' @@ -2512,6 +2537,10 @@ ' >>> print(sys.exc_info())\n' ' (None, None, None)\n' '\n' + '\n' + '"except*" clause\n' + '----------------\n' + '\n' 'The "except*" clause(s) are used for handling "ExceptionGroup"s. ' 'The\n' 'exception type for matching is interpreted as in the case of ' @@ -2520,13 +2549,15 @@ 'when\n' 'the type matches some of the exceptions in the group. This means ' 'that\n' - 'multiple except* clauses can execute, each handling part of the\n' - 'exception group. Each clause executes once and handles an ' - 'exception\n' - 'group of all matching exceptions. Each exception in the group ' - 'is\n' - 'handled by at most one except* clause, the first that matches ' - 'it.\n' + 'multiple "except*" clauses can execute, each handling part of ' + 'the\n' + 'exception group. Each clause executes at most once and handles ' + 'an\n' + 'exception group of all matching exceptions. Each exception in ' + 'the\n' + 'group is handled by at most one "except*" clause, the first ' + 'that\n' + 'matches it.\n' '\n' ' >>> try:\n' ' ... raise ExceptionGroup("eg",\n' @@ -2548,22 +2579,37 @@ ' +-+---------------- 1 ----------------\n' ' | ValueError: 1\n' ' +------------------------------------\n' - ' >>>\n' '\n' - ' Any remaining exceptions that were not handled by any except* ' + 'Any remaining exceptions that were not handled by any "except*" ' 'clause\n' - ' are re-raised at the end, combined into an exception group ' - 'along with\n' - ' all exceptions that were raised from within except* clauses.\n' - '\n' - ' An except* clause must have a matching type, and this type ' - 'cannot be a\n' - ' subclass of :exc:`BaseExceptionGroup`. It is not possible to ' - 'mix except\n' - ' and except* in the same :keyword:`try`. :keyword:`break`,\n' - ' :keyword:`continue` and :keyword:`return` cannot appear in an ' - 'except*\n' - ' clause.\n' + 'are re-raised at the end, combined into an exception group along ' + 'with\n' + 'all exceptions that were raised from within "except*" clauses.\n' + '\n' + 'If the raised exception is not an exception group and its type ' + 'matches\n' + 'one of the "except*" clauses, it is caught and wrapped by an ' + 'exception\n' + 'group with an empty message string.\n' + '\n' + ' >>> try:\n' + ' ... raise BlockingIOError\n' + ' ... except* BlockingIOError as e:\n' + ' ... print(repr(e))\n' + ' ...\n' + " ExceptionGroup('', (BlockingIOError()))\n" + '\n' + 'An "except*" clause must have a matching type, and this type ' + 'cannot be\n' + 'a subclass of "BaseExceptionGroup". It is not possible to mix ' + '"except"\n' + 'and "except*" in the same "try". "break", "continue" and ' + '"return"\n' + 'cannot appear in an "except*" clause.\n' + '\n' + '\n' + '"else" clause\n' + '-------------\n' '\n' 'The optional "else" clause is executed if the control flow ' 'leaves the\n' @@ -2573,6 +2619,10 @@ 'are\n' 'not handled by the preceding "except" clauses.\n' '\n' + '\n' + '"finally" clause\n' + '----------------\n' + '\n' 'If "finally" is present, it specifies a ?cleanup? handler. The ' '"try"\n' 'clause is executed, including any "except" and "else" clauses. ' @@ -2626,11 +2676,6 @@ ' >>> foo()\n' " 'finally'\n" '\n' - 'Additional information on exceptions can be found in section\n' - 'Exceptions, and information on using the "raise" statement to ' - 'generate\n' - 'exceptions may be found in section The raise statement.\n' - '\n' 'Changed in version 3.8: Prior to Python 3.8, a "continue" ' 'statement\n' 'was illegal in the "finally" clause due to a problem with the\n' @@ -3482,8 +3527,8 @@ ' there is matched against the whole object rather than an ' 'attribute.\n' ' For example "int(0|1)" matches the value "0", but not the ' - 'values\n' - ' "0.0" or "False".\n' + 'value\n' + ' "0.0".\n' '\n' 'In simple terms "CLS(P1, attr=P2)" matches only if the ' 'following\n' @@ -4144,7 +4189,7 @@ ' invoking the superclass?s "__new__()" method using\n' ' "super().__new__(cls[, ...])" with appropriate arguments ' 'and then\n' - ' modifying the newly-created instance as necessary before ' + ' modifying the newly created instance as necessary before ' 'returning\n' ' it.\n' '\n' @@ -4547,7 +4592,7 @@ 'Python.This is\n' ' intended to provide protection against a ' 'denial-of-service caused\n' - ' by carefully-chosen inputs that exploit the worst ' + ' by carefully chosen inputs that exploit the worst ' 'case\n' ' performance of a dict insertion, O(n^2) complexity. ' 'See\n' @@ -4861,7 +4906,10 @@ 'is\n' 'applied to separating the commands; the input is split at the ' 'first\n' - '";;" pair, even if it is in the middle of a quoted string.\n' + '";;" pair, even if it is in the middle of a quoted string. A\n' + 'workaround for strings with double semicolons is to use ' + 'implicit\n' + 'string concatenation "\';\'\';\'" or "";"";"".\n' '\n' 'If a file ".pdbrc" exists in the user?s home directory or in ' 'the\n' @@ -5537,9 +5585,10 @@ '\n' ' * "for" loop header,\n' '\n' - ' * after "as" in a "with" statement, "except" clause or in the ' - 'as-\n' - ' pattern in structural pattern matching,\n' + ' * after "as" in a "with" statement, "except" clause, ' + '"except*"\n' + ' clause, or in the as-pattern in structural pattern ' + 'matching,\n' '\n' ' * in a capture pattern in structural pattern matching\n' '\n' @@ -7100,8 +7149,8 @@ '\n' 'A non-normative HTML file listing all valid identifier ' 'characters for\n' - 'Unicode 14.0.0 can be found at\n' - 'https://www.unicode.org/Public/14.0.0/ucd/DerivedCoreProperties.txt\n' + 'Unicode 15.0.0 can be found at\n' + 'https://www.unicode.org/Public/15.0.0/ucd/DerivedCoreProperties.txt\n' '\n' '\n' 'Keywords\n' @@ -7654,9 +7703,8 @@ '\n' ' * "for" loop header,\n' '\n' - ' * after "as" in a "with" statement, "except" clause or in the ' - 'as-\n' - ' pattern in structural pattern matching,\n' + ' * after "as" in a "with" statement, "except" clause, "except*"\n' + ' clause, or in the as-pattern in structural pattern matching,\n' '\n' ' * in a capture pattern in structural pattern matching\n' '\n' @@ -8229,8 +8277,9 @@ 'the syntax is explicitly given, operators are binary. ' 'Operators in\n' 'the same box group left to right (except for ' - 'exponentiation, which\n' - 'groups from right to left).\n' + 'exponentiation and\n' + 'conditional expressions, which group from right to ' + 'left).\n' '\n' 'Note that comparisons, membership tests, and identity ' 'tests, all have\n' @@ -8254,7 +8303,7 @@ '| "x(arguments...)", "x.attribute" | ' 'attribute reference |\n' '+-------------------------------------------------+---------------------------------------+\n' - '| "await" "x" | ' + '| "await x" | ' 'Await expression |\n' '+-------------------------------------------------+---------------------------------------+\n' '| "**" | ' @@ -8290,7 +8339,7 @@ '| ">=", "!=", "==" | ' 'tests and identity tests |\n' '+-------------------------------------------------+---------------------------------------+\n' - '| "not" "x" | ' + '| "not x" | ' 'Boolean NOT |\n' '+-------------------------------------------------+---------------------------------------+\n' '| "and" | ' @@ -8980,31 +9029,7 @@ ' still alive. The list is in definition order. Example:\n' '\n' ' >>> int.__subclasses__()\n' - " []\n" - '\n' - '-[ Footnotes ]-\n' - '\n' - '[1] Additional information on these special methods may be ' - 'found in\n' - ' the Python Reference Manual (Basic customization).\n' - '\n' - '[2] As a consequence, the list "[1, 2]" is considered equal ' - 'to "[1.0,\n' - ' 2.0]", and similarly for tuples.\n' - '\n' - '[3] They must have since the parser can?t tell the type of ' - 'the\n' - ' operands.\n' - '\n' - '[4] Cased characters are those with general category ' - 'property being\n' - ' one of ?Lu? (Letter, uppercase), ?Ll? (Letter, ' - 'lowercase), or ?Lt?\n' - ' (Letter, titlecase).\n' - '\n' - '[5] To format only a tuple you should therefore provide a ' - 'singleton\n' - ' tuple whose only element is the tuple to be formatted.\n', + " []\n", 'specialnames': 'Special method names\n' '********************\n' '\n' @@ -9073,7 +9098,7 @@ ' invoking the superclass?s "__new__()" method using\n' ' "super().__new__(cls[, ...])" with appropriate arguments ' 'and then\n' - ' modifying the newly-created instance as necessary before ' + ' modifying the newly created instance as necessary before ' 'returning\n' ' it.\n' '\n' @@ -9474,7 +9499,7 @@ 'is\n' ' intended to provide protection against a ' 'denial-of-service caused\n' - ' by carefully-chosen inputs that exploit the worst case\n' + ' by carefully chosen inputs that exploit the worst case\n' ' performance of a dict insertion, O(n^2) complexity. ' 'See\n' ' http://www.ocert.org/advisories/ocert-2011-003.html ' @@ -12191,12 +12216,15 @@ 'single quotes ("\'") or double quotes ("""). They can also be ' 'enclosed\n' 'in matching groups of three single or double quotes (these are\n' - 'generally referred to as *triple-quoted strings*). The ' - 'backslash\n' - '("\\") character is used to escape characters that otherwise have ' - 'a\n' - 'special meaning, such as newline, backslash itself, or the quote\n' + 'generally referred to as *triple-quoted strings*). The backslash ' + '("\\")\n' + 'character is used to give special meaning to otherwise ordinary\n' + 'characters like "n", which means ?newline? when escaped ("\\n"). ' + 'It can\n' + 'also be used to escape characters that otherwise have a special\n' + 'meaning, such as newline, backslash itself, or the quote ' 'character.\n' + 'See escape sequences below for examples.\n' '\n' 'Bytes literals are always prefixed with "\'b\'" or "\'B\'"; they ' 'produce\n' @@ -12253,8 +12281,8 @@ '| Escape Sequence | Meaning | Notes ' '|\n' '|===================|===================================|=========|\n' - '| "\\newline" | Backslash and newline ignored ' - '| |\n' + '| "\\" | Backslash and newline ignored | ' + '(1) |\n' '+-------------------+-----------------------------------+---------+\n' '| "\\\\" | Backslash ("\\") ' '| |\n' @@ -12287,10 +12315,10 @@ '| |\n' '+-------------------+-----------------------------------+---------+\n' '| "\\ooo" | Character with octal value *ooo* | ' - '(1,3) |\n' + '(2,4) |\n' '+-------------------+-----------------------------------+---------+\n' '| "\\xhh" | Character with hex value *hh* | ' - '(2,3) |\n' + '(3,4) |\n' '+-------------------+-----------------------------------+---------+\n' '\n' 'Escape sequences only recognized in string literals are:\n' @@ -12300,24 +12328,36 @@ '|\n' '|===================|===================================|=========|\n' '| "\\N{name}" | Character named *name* in the | ' - '(4) |\n' + '(5) |\n' '| | Unicode database | ' '|\n' '+-------------------+-----------------------------------+---------+\n' '| "\\uxxxx" | Character with 16-bit hex value | ' - '(5) |\n' + '(6) |\n' '| | *xxxx* | ' '|\n' '+-------------------+-----------------------------------+---------+\n' '| "\\Uxxxxxxxx" | Character with 32-bit hex value | ' - '(6) |\n' + '(7) |\n' '| | *xxxxxxxx* | ' '|\n' '+-------------------+-----------------------------------+---------+\n' '\n' 'Notes:\n' '\n' - '1. As in Standard C, up to three octal digits are accepted.\n' + '1. A backslash can be added at the end of a line to ignore the\n' + ' newline:\n' + '\n' + " >>> 'This string will not include \\\n" + " ... backslashes or newline characters.'\n" + " 'This string will not include backslashes or newline " + "characters.'\n" + '\n' + ' The same result can be achieved using triple-quoted strings, ' + 'or\n' + ' parentheses and string literal concatenation.\n' + '\n' + '2. As in Standard C, up to three octal digits are accepted.\n' '\n' ' Changed in version 3.11: Octal escapes with value larger than\n' ' "0o377" produce a "DeprecationWarning". In a future Python ' @@ -12325,20 +12365,20 @@ ' they will be a "SyntaxWarning" and eventually a ' '"SyntaxError".\n' '\n' - '2. Unlike in Standard C, exactly two hex digits are required.\n' + '3. Unlike in Standard C, exactly two hex digits are required.\n' '\n' - '3. In a bytes literal, hexadecimal and octal escapes denote the ' + '4. In a bytes literal, hexadecimal and octal escapes denote the ' 'byte\n' ' with the given value. In a string literal, these escapes ' 'denote a\n' ' Unicode character with the given value.\n' '\n' - '4. Changed in version 3.3: Support for name aliases [1] has been\n' + '5. Changed in version 3.3: Support for name aliases [1] has been\n' ' added.\n' '\n' - '5. Exactly four hex digits are required.\n' + '6. Exactly four hex digits are required.\n' '\n' - '6. Any Unicode character can be encoded this way. Exactly eight ' + '7. Any Unicode character can be encoded this way. Exactly eight ' 'hex\n' ' digits are required.\n' '\n' @@ -12509,31 +12549,39 @@ ' try3_stmt ::= "try" ":" suite\n' ' "finally" ":" suite\n' '\n' + 'Additional information on exceptions can be found in section\n' + 'Exceptions, and information on using the "raise" statement to ' + 'generate\n' + 'exceptions may be found in section The raise statement.\n' + '\n' + '\n' + '"except" clause\n' + '===============\n' + '\n' 'The "except" clause(s) specify one or more exception handlers. When ' 'no\n' 'exception occurs in the "try" clause, no exception handler is\n' 'executed. When an exception occurs in the "try" suite, a search for ' 'an\n' - 'exception handler is started. This search inspects the except ' - 'clauses\n' - 'in turn until one is found that matches the exception. An ' - 'expression-\n' - 'less except clause, if present, must be last; it matches any\n' - 'exception. For an except clause with an expression, that expression\n' - 'is evaluated, and the clause matches the exception if the resulting\n' - 'object is ?compatible? with the exception. An object is compatible\n' - 'with an exception if the object is the class or a *non-virtual base\n' - 'class* of the exception object, or a tuple containing an item that ' - 'is\n' - 'the class or a non-virtual base class of the exception object.\n' + 'exception handler is started. This search inspects the "except"\n' + 'clauses in turn until one is found that matches the exception. An\n' + 'expression-less "except" clause, if present, must be last; it ' + 'matches\n' + 'any exception. For an "except" clause with an expression, that\n' + 'expression is evaluated, and the clause matches the exception if the\n' + 'resulting object is ?compatible? with the exception. An object is\n' + 'compatible with an exception if the object is the class or a *non-\n' + 'virtual base class* of the exception object, or a tuple containing ' + 'an\n' + 'item that is the class or a non-virtual base class of the exception\n' + 'object.\n' '\n' - 'If no except clause matches the exception, the search for an ' - 'exception\n' - 'handler continues in the surrounding code and on the invocation ' - 'stack.\n' - '[1]\n' + 'If no "except" clause matches the exception, the search for an\n' + 'exception handler continues in the surrounding code and on the\n' + 'invocation stack. [1]\n' '\n' - 'If the evaluation of an expression in the header of an except clause\n' + 'If the evaluation of an expression in the header of an "except" ' + 'clause\n' 'raises an exception, the original search for a handler is canceled ' 'and\n' 'a search starts for the new exception in the surrounding code and on\n' @@ -12541,21 +12589,20 @@ 'raised\n' 'the exception).\n' '\n' - 'When a matching except clause is found, the exception is assigned to\n' - 'the target specified after the "as" keyword in that except clause, ' - 'if\n' - 'present, and the except clause?s suite is executed. All except\n' - 'clauses must have an executable block. When the end of this block ' - 'is\n' - 'reached, execution continues normally after the entire try ' - 'statement.\n' - '(This means that if two nested handlers exist for the same ' - 'exception,\n' - 'and the exception occurs in the try clause of the inner handler, the\n' - 'outer handler will not handle the exception.)\n' + 'When a matching "except" clause is found, the exception is assigned ' + 'to\n' + 'the target specified after the "as" keyword in that "except" clause,\n' + 'if present, and the "except" clause?s suite is executed. All ' + '"except"\n' + 'clauses must have an executable block. When the end of this block is\n' + 'reached, execution continues normally after the entire "try"\n' + 'statement. (This means that if two nested handlers exist for the ' + 'same\n' + 'exception, and the exception occurs in the "try" clause of the inner\n' + 'handler, the outer handler will not handle the exception.)\n' '\n' 'When an exception has been assigned using "as target", it is cleared\n' - 'at the end of the except clause. This is as if\n' + 'at the end of the "except" clause. This is as if\n' '\n' ' except E as N:\n' ' foo\n' @@ -12569,12 +12616,13 @@ ' del N\n' '\n' 'This means the exception must be assigned to a different name to be\n' - 'able to refer to it after the except clause. Exceptions are cleared\n' + 'able to refer to it after the "except" clause. Exceptions are ' + 'cleared\n' 'because with the traceback attached to them, they form a reference\n' 'cycle with the stack frame, keeping all locals in that frame alive\n' 'until the next garbage collection occurs.\n' '\n' - 'Before an except clause?s suite is executed, details about the\n' + 'Before an "except" clause?s suite is executed, details about the\n' 'exception 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\n' @@ -12606,16 +12654,21 @@ ' >>> print(sys.exc_info())\n' ' (None, None, None)\n' '\n' + '\n' + '"except*" clause\n' + '================\n' + '\n' 'The "except*" clause(s) are used for handling "ExceptionGroup"s. The\n' 'exception type for matching is interpreted as in the case of ' '"except",\n' 'but in the case of exception groups we can have partial matches when\n' 'the type matches some of the exceptions in the group. This means ' 'that\n' - 'multiple except* clauses can execute, each handling part of the\n' - 'exception group. Each clause executes once and handles an exception\n' - 'group of all matching exceptions. Each exception in the group is\n' - 'handled by at most one except* clause, the first that matches it.\n' + 'multiple "except*" clauses can execute, each handling part of the\n' + 'exception group. Each clause executes at most once and handles an\n' + 'exception group of all matching exceptions. Each exception in the\n' + 'group is handled by at most one "except*" clause, the first that\n' + 'matches it.\n' '\n' ' >>> try:\n' ' ... raise ExceptionGroup("eg",\n' @@ -12635,22 +12688,36 @@ ' +-+---------------- 1 ----------------\n' ' | ValueError: 1\n' ' +------------------------------------\n' - ' >>>\n' '\n' - ' Any remaining exceptions that were not handled by any except* ' + 'Any remaining exceptions that were not handled by any "except*" ' 'clause\n' - ' are re-raised at the end, combined into an exception group along ' + 'are re-raised at the end, combined into an exception group along ' 'with\n' - ' all exceptions that were raised from within except* clauses.\n' + 'all exceptions that were raised from within "except*" clauses.\n' + '\n' + 'If the raised exception is not an exception group and its type ' + 'matches\n' + 'one of the "except*" clauses, it is caught and wrapped by an ' + 'exception\n' + 'group with an empty message string.\n' '\n' - ' An except* clause must have a matching type, and this type cannot ' - 'be a\n' - ' subclass of :exc:`BaseExceptionGroup`. It is not possible to mix ' - 'except\n' - ' and except* in the same :keyword:`try`. :keyword:`break`,\n' - ' :keyword:`continue` and :keyword:`return` cannot appear in an ' - 'except*\n' - ' clause.\n' + ' >>> try:\n' + ' ... raise BlockingIOError\n' + ' ... except* BlockingIOError as e:\n' + ' ... print(repr(e))\n' + ' ...\n' + " ExceptionGroup('', (BlockingIOError()))\n" + '\n' + 'An "except*" clause must have a matching type, and this type cannot ' + 'be\n' + 'a subclass of "BaseExceptionGroup". It is not possible to mix ' + '"except"\n' + 'and "except*" in the same "try". "break", "continue" and "return"\n' + 'cannot appear in an "except*" clause.\n' + '\n' + '\n' + '"else" clause\n' + '=============\n' '\n' 'The optional "else" clause is executed if the control flow leaves ' 'the\n' @@ -12659,6 +12726,10 @@ '"break" statement was executed. Exceptions in the "else" clause are\n' 'not handled by the preceding "except" clauses.\n' '\n' + '\n' + '"finally" clause\n' + '================\n' + '\n' 'If "finally" is present, it specifies a ?cleanup? handler. The ' '"try"\n' 'clause is executed, including any "except" and "else" clauses. If ' @@ -12706,11 +12777,6 @@ ' >>> foo()\n' " 'finally'\n" '\n' - 'Additional information on exceptions can be found in section\n' - 'Exceptions, and information on using the "raise" statement to ' - 'generate\n' - 'exceptions may be found in section The raise statement.\n' - '\n' 'Changed in version 3.8: Prior to Python 3.8, a "continue" statement\n' 'was illegal in the "finally" clause due to a problem with the\n' 'implementation.\n', @@ -12910,7 +12976,7 @@ ' 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' + 'char\n' ' type; instead, every code point in the string is ' 'represented\n' ' as a string object with length "1". The built-in ' @@ -14336,7 +14402,11 @@ 'abstract\n' 'base class "collections.abc.Set" are available (for example, ' '"==",\n' - '"<", or "^").\n' + '"<", or "^"). While using set operators, set-like views ' + 'accept any\n' + 'iterable as the other operand, unlike sets which only accept ' + 'sets as\n' + 'the input.\n' '\n' 'An example of dictionary view usage:\n' '\n' @@ -14370,6 +14440,8 @@ " {'bacon'}\n" " >>> keys ^ {'sausage', 'juice'}\n" " {'juice', 'sausage', 'bacon', 'spam'}\n" + " >>> keys | ['juice', 'juice', 'juice']\n" + " {'juice', 'sausage', 'bacon', 'spam', 'eggs'}\n" '\n' ' >>> # get back a read-only proxy for the original ' 'dictionary\n' diff --git a/Misc/NEWS.d/3.12.0a1.rst b/Misc/NEWS.d/3.12.0a1.rst new file mode 100644 index 000000000000..2a943fe481af --- /dev/null +++ b/Misc/NEWS.d/3.12.0a1.rst @@ -0,0 +1,6194 @@ +.. date: 2022-09-28-17-09-37 +.. gh-issue: 97616 +.. nonce: K1e3Xs +.. release date: 2022-10-25 +.. section: Security + +Fix multiplying a list by an integer (``list *= int``): detect the integer +overflow when the new allocated length is close to the maximum size. Issue +reported by Jordan Limor. Patch by Victor Stinner. + +.. + +.. date: 2022-09-07-10-42-00 +.. gh-issue: 97514 +.. nonce: Yggdsl +.. section: Security + +On Linux the :mod:`multiprocessing` module returns to using filesystem +backed unix domain sockets for communication with the *forkserver* process +instead of the Linux abstract socket namespace. Only code that chooses to +use the :ref:`"forkserver" start method ` is +affected. + +Abstract sockets have no permissions and could allow any user on the system +in the same `network namespace +`_ (often +the whole system) to inject code into the multiprocessing *forkserver* +process. This was a potential privilege escalation. Filesystem based socket +permissions restrict this to the *forkserver* process user as was the +default in Python 3.8 and earlier. + +This prevents Linux `CVE-2022-42919 +`_. + +.. + +.. date: 2022-06-15-20-09-23 +.. gh-issue: 87389 +.. nonce: QVaC3f +.. section: Security + +:mod:`http.server`: Fix an open redirection vulnerability in the HTTP server +when an URI path starts with ``//``. Vulnerability discovered, and initial +fix proposed, by Hamza Avvan. + +.. + +.. date: 2022-06-03-12-52-53 +.. gh-issue: 79096 +.. nonce: YVoxgC +.. section: Security + +LWPCookieJar and MozillaCookieJar create files with file mode 600 instead of +644 (Microsoft Windows is not affected) + +.. + +.. date: 2022-05-19-08-53-07 +.. gh-issue: 92888 +.. nonce: TLtR9W +.. section: Security + +Fix ``memoryview`` use after free when accessing the backing buffer in +certain cases. + +.. + +.. date: 2022-04-27-18-25-30 +.. gh-issue: 68966 +.. nonce: gjS8zs +.. section: Security + +The deprecated mailcap module now refuses to inject unsafe text (filenames, +MIME types, parameters) into shell commands. Instead of using such text, it +will warn and act as if a match was not found (or for test commands, as if +the test failed). + +.. + +.. date: 2022-10-19-23-48-46 +.. gh-issue: 98374 +.. nonce: eOBh8M +.. section: Core and Builtins + +Suppress ImportError for invalid query for help() command. Patch by Dong-hee +Na. + +.. + +.. date: 2022-10-19-20-53-38 +.. gh-issue: 98461 +.. nonce: iNmPDV +.. section: Core and Builtins + +Fix source location in bytecode for list, set and dict comprehensions as +well as generator expressions. + +.. + +.. date: 2022-10-19-18-03-28 +.. gh-issue: 98354 +.. nonce: GRGta3 +.. section: Core and Builtins + +Added unicode check for ``name`` attribute of ``spec`` argument passed in +:func:`_imp.create_builtin` function. + +.. + +.. date: 2022-10-18-16-17-44 +.. gh-issue: 98398 +.. nonce: x4rYK_ +.. section: Core and Builtins + +Fix source location of 'assert' bytecodes. + +.. + +.. date: 2022-10-18-14-11-32 +.. gh-issue: 98390 +.. nonce: H1sxJu +.. section: Core and Builtins + +Fix location of sub-expressions of boolean expressions, by reducing their +scope to that of the sub-expression. + +.. + +.. date: 2022-10-13-23-23-01 +.. gh-issue: 98254 +.. nonce: bC8IKt +.. section: Core and Builtins + +Modules from the standard library are now potentially suggested as part of +the error messages displayed by the interpreter when an :exc:`NameError` is +raised to the top level. Patch by Pablo Galindo + +.. + +.. date: 2022-10-06-23-13-34 +.. gh-issue: 97997 +.. nonce: JQaJKF +.. section: Core and Builtins + +Add running column offset to the tokenizer state to avoid calculating AST +column information with pointer arithmetic. + +.. + +.. date: 2022-10-06-20-41-29 +.. gh-issue: 97973 +.. nonce: gB-xWi +.. section: Core and Builtins + +Modify the tokenizer to return all necessary information the parser needs to +set location information in the AST nodes, so that the parser does not have +to calculate those doing pointer arithmetic. + +.. + +.. date: 2022-10-06-15-45-57 +.. gh-issue: 96078 +.. nonce: fS-6mU +.. section: Core and Builtins + +:func:`os.sched_yield` now release the GIL while calling sched_yield(2). +Patch by Dong-hee Na. + +.. + +.. date: 2022-10-06-14-14-28 +.. gh-issue: 97955 +.. nonce: Nq5VXD +.. section: Core and Builtins + +Migrate :mod:`zoneinfo` to Argument Clinic. + +.. + +.. date: 2022-10-06-06-36-29 +.. gh-issue: 97912 +.. nonce: jGRJpa +.. section: Core and Builtins + +The compiler now avoids quadratic behavior when finding which instructions +should use the :opcode:`LOAD_FAST_CHECK` opcode. + +.. + +.. date: 2022-10-06-02-11-34 +.. gh-issue: 97002 +.. nonce: Zvsk71 +.. section: Core and Builtins + +Fix an issue where several frame objects could be backed by the same +interpreter frame, possibly leading to corrupted memory and hard crashes of +the interpreter. + +.. + +.. date: 2022-10-05-17-02-22 +.. gh-issue: 97943 +.. nonce: LYAWlE +.. section: Core and Builtins + +Bugfix: :func:`PyFunction_GetAnnotations` should return a borrowed +reference. It was returning a new reference. + +.. + +.. date: 2022-10-05-11-37-15 +.. gh-issue: 97922 +.. nonce: Zu9Bge +.. section: Core and Builtins + +The Garbage Collector now runs only on the eval breaker mechanism of the +Python bytecode evaluation loop instead on object allocations. The GC can +also run when :c:func:`PyErr_CheckSignals` is called so C extensions that +need to run for a long time without executing any Python code also have a +chance to execute the GC periodically. + +.. + +.. date: 2022-10-05-00-37-27 +.. gh-issue: 65961 +.. nonce: z0Ys0y +.. section: Core and Builtins + +When ``__package__`` is different than ``__spec__.parent``, raise a +``DeprecationWarning`` instead of ``ImportWarning``. + +Also remove ``importlib.util.set_package()`` which was scheduled for +removal. + +.. + +.. date: 2022-10-04-17-02-18 +.. gh-issue: 97850 +.. nonce: E3QTRA +.. section: Core and Builtins + +Long deprecated, ``module_repr()`` should now be completely eradicated. + +.. + +.. date: 2022-10-04-14-04-40 +.. gh-issue: 86298 +.. nonce: QVM7G1 +.. section: Core and Builtins + +In cases where ``warnings.warn_explicit()`` consults the module's loader, an +``DeprecationWarning`` is issued when ``m.__loader__`` differs from +``m.__spec__.loader``. + +.. + +.. date: 2022-10-04-02-00-10 +.. gh-issue: 97779 +.. nonce: f3N1hI +.. section: Core and Builtins + +Ensure that all Python frame objects are backed by "complete" frames. + +.. + +.. date: 2022-10-03-16-12-39 +.. gh-issue: 91052 +.. nonce: MsYL9d +.. section: Core and Builtins + +Add API for subscribing to modification events on selected dictionaries. + +.. + +.. date: 2022-10-03-13-35-48 +.. gh-issue: 97752 +.. nonce: 0xTjJY +.. section: Core and Builtins + +Fix possible data corruption or crashes when accessing the ``f_back`` member +of newly-created generator or coroutine frames. + +.. + +.. date: 2022-10-01-08-55-09 +.. gh-issue: 97591 +.. nonce: pw6kkH +.. section: Core and Builtins + +Fixed a missing incref/decref pair in ``Exception.__setstate__()``. Patch by +Ofey Chan. + +.. + +.. date: 2022-09-30-13-26-58 +.. gh-issue: 97670 +.. nonce: n61vMR +.. section: Core and Builtins + +Remove the :func:`sys.getdxp` function and the +``Tools/scripts/analyze_dxp.py`` script. DXP stands for "dynamic execution +pairs". They were related to ``DYNAMIC_EXECUTION_PROFILE`` and ``DXPAIRS`` +macros which have been removed in Python 3.11. Python can now be built with +:option:`./configure --enable-pystats <--enable-pystats>` to gather +statistics on Python opcodes. Patch by Victor Stinner. + +.. + +.. date: 2022-09-29-15-19-29 +.. gh-issue: 94526 +.. nonce: wq5m6T +.. section: Core and Builtins + +Fix the Python path configuration used to initialized :data:`sys.path` at +Python startup. Paths are no longer encoded to UTF-8/strict to avoid +encoding errors if it contains surrogate characters (bytes paths are decoded +with the surrogateescape error handler). Patch by Victor Stinner. + +.. + +.. date: 2022-09-27-11-59-13 +.. gh-issue: 96670 +.. nonce: XrBBit +.. section: Core and Builtins + +The parser now raises :exc:`SyntaxError` when parsing source code containing +null bytes. Patch by Pablo Galindo + +.. + +.. date: 2022-09-21-16-06-37 +.. gh-issue: 96975 +.. nonce: BmE0XY +.. section: Core and Builtins + +Fix a crash occurring when :c:func:`PyEval_GetFrame` is called while the +topmost Python frame is in a partially-initialized state. + +.. + +.. date: 2022-09-21-14-38-31 +.. gh-issue: 96848 +.. nonce: WuoLzU +.. section: Core and Builtins + +Fix command line parsing: reject :option:`-X int_max_str_digits <-X>` option +with no value (invalid) when the :envvar:`PYTHONINTMAXSTRDIGITS` environment +variable is set to a valid limit. Patch by Victor Stinner. + +.. + +.. date: 2022-09-20-11-06-45 +.. gh-issue: 95921 +.. nonce: dkcRQn +.. section: Core and Builtins + +Fix overly-broad source position information for chained comparisons used as +branching conditions. + +.. + +.. date: 2022-09-19-03-35-01 +.. gh-issue: 96821 +.. nonce: izK6JA +.. section: Core and Builtins + +Fix undefined behaviour in ``audioop.c``. + +.. + +.. date: 2022-09-18-08-47-40 +.. gh-issue: 96821 +.. nonce: Co2iOq +.. section: Core and Builtins + +Fix undefined behaviour in ``_testcapimodule.c``. + +.. + +.. date: 2022-09-16-19-02-40 +.. gh-issue: 95778 +.. nonce: cJmnst +.. section: Core and Builtins + +When :exc:`ValueError` is raised if an integer is larger than the limit, +mention the :func:`sys.set_int_max_str_digits` function in the error +message. Patch by Victor Stinner. + +.. + +.. date: 2022-09-16-16-54-35 +.. gh-issue: 96387 +.. nonce: GRzewg +.. section: Core and Builtins + +At Python exit, sometimes a thread holding the GIL can wait forever for a +thread (usually a daemon thread) which requested to drop the GIL, whereas +the thread already exited. To fix the race condition, the thread which +requested the GIL drop now resets its request before exiting. Issue +discovered and analyzed by Mingliang ZHAO. Patch by Victor Stinner. + +.. + +.. date: 2022-09-16-12-36-13 +.. gh-issue: 96864 +.. nonce: PLU3i8 +.. section: Core and Builtins + +Fix a possible assertion failure, fatal error, or :exc:`SystemError` if a +line tracing event raises an exception while opcode tracing is enabled. + +.. + +.. date: 2022-09-13-21-45-07 +.. gh-issue: 95778 +.. nonce: Oll4_5 +.. section: Core and Builtins + +The ``PyLong_FromString`` function was refactored to make it more +maintainable and extensible. + +.. + +.. date: 2022-09-13-12-06-46 +.. gh-issue: 96678 +.. nonce: NqGFyb +.. section: Core and Builtins + +Fix undefined behaviour in C code of null pointer arithmetic. + +.. + +.. date: 2022-09-12-16-58-22 +.. gh-issue: 96754 +.. nonce: 0GRme5 +.. section: Core and Builtins + +Make sure that all frame objects created are created from valid interpreter +frames. Prevents the possibility of invalid frames in backtraces and signal +handlers. + +.. + +.. date: 2022-09-12-15-15-04 +.. gh-issue: 90997 +.. nonce: sZO8c9 +.. section: Core and Builtins + +Improve the performance of reading and writing inline bytecode caches on +some platforms. + +.. + +.. date: 2022-09-11-12-43-43 +.. gh-issue: 96751 +.. nonce: anRT6a +.. section: Core and Builtins + +Remove dead code from ``CALL_FUNCTION_EX`` opcode. + +.. + +.. date: 2022-09-11-00-37-50 +.. gh-issue: 90751 +.. nonce: VE8-zf +.. section: Core and Builtins + +:class:`memoryview` now supports half-floats. Patch by Dong-hee Na and +Antoine Pitrou. + +.. + +.. date: 2022-09-09-13-13-27 +.. gh-issue: 96678 +.. nonce: vMxi9F +.. section: Core and Builtins + +Fix case of undefined behavior in ceval.c + +.. + +.. date: 2022-09-08-20-58-10 +.. gh-issue: 64373 +.. nonce: AfCi36 +.. section: Core and Builtins + +Convert :mod:`_functools` to argument clinic. + +.. + +.. date: 2022-09-07-13-38-37 +.. gh-issue: 96641 +.. nonce: wky0Fc +.. section: Core and Builtins + +Do not expose ``KeyWrapper`` in :mod:`_functools`. + +.. + +.. date: 2022-09-07-12-02-11 +.. gh-issue: 96636 +.. nonce: YvN-K6 +.. section: Core and Builtins + +Ensure that tracing, ``sys.setrace()``, is turned on immediately. In +pre-release versions of 3.11, some tracing events might have been lost when +turning on tracing in a ``__del__`` method or interrupt. + +.. + +.. date: 2022-09-06-16-54-49 +.. gh-issue: 96572 +.. nonce: 8DRsaW +.. section: Core and Builtins + +Fix use after free in trace refs build mode. Patch by Kumar Aditya. + +.. + +.. date: 2022-09-06-16-22-13 +.. gh-issue: 96611 +.. nonce: 14wIX8 +.. section: Core and Builtins + +When loading a file with invalid UTF-8 inside a multi-line string, a correct +SyntaxError is emitted. + +.. + +.. date: 2022-09-06-14-26-36 +.. gh-issue: 96612 +.. nonce: P4ZbeY +.. section: Core and Builtins + +Make sure that incomplete frames do not show up in tracemalloc traces. + +.. + +.. date: 2022-09-06-11-19-03 +.. gh-issue: 90230 +.. nonce: YOtzs5 +.. section: Core and Builtins + +Fix compiler warnings and test failures when building with +``--enable-pystats``. + +.. + +.. date: 2022-09-05-19-20-44 +.. gh-issue: 96587 +.. nonce: bVxhX2 +.. section: Core and Builtins + +Correctly raise ``SyntaxError`` on exception groups (:pep:`654`) on python +versions prior to 3.11 + +.. + +.. date: 2022-09-05-16-43-44 +.. gh-issue: 96569 +.. nonce: 9lmTCC +.. section: Core and Builtins + +Remove two cases of undefined behavoir, by adding NULL checks. + +.. + +.. date: 2022-09-05-15-07-25 +.. gh-issue: 96582 +.. nonce: HEsL5s +.. section: Core and Builtins + +Fix possible ``NULL`` pointer dereference in ``_PyThread_CurrentFrames``. +Patch by Kumar Aditya. + +.. + +.. date: 2022-09-05-09-56-32 +.. gh-issue: 91079 +.. nonce: H4-DdU +.. section: Core and Builtins + +Separate Python recursion checking from C recursion checking which reduces +the chance of C stack overflow and allows the recursion limit to be +increased safely. + +.. + +.. date: 2022-09-02-16-47-52 +.. gh-issue: 93911 +.. nonce: vF-GWe +.. section: Core and Builtins + +Fix an issue that could prevent :opcode:`LOAD_ATTR` from specializing +properly when accessing properties. + +.. + +.. date: 2022-08-31-18-46-13 +.. gh-issue: 96348 +.. nonce: xzCoTP +.. section: Core and Builtins + +Emit a DeprecationWarning when :meth:`~generator.throw`, +:meth:`~coroutine.throw` or :meth:`~agen.athrow` are called with more than +one argument. + +.. + +.. date: 2022-08-29-13-06-58 +.. gh-issue: 95196 +.. nonce: eGRR4b +.. section: Core and Builtins + +Disable incorrect pickling of the C implemented classmethod descriptors. + +.. + +.. date: 2022-08-29-00-37-21 +.. gh-issue: 96364 +.. nonce: c-IVyb +.. section: Core and Builtins + +Fix text signatures of ``list.__getitem__`` and ``dict.__getitem__``. + +.. + +.. date: 2022-08-28-10-51-19 +.. gh-issue: 96352 +.. nonce: jTLD2d +.. section: Core and Builtins + +Fix :exc:`AttributeError` missing ``name`` and ``obj`` attributes in +:meth:`object.__getattribute__`. Patch by Philip Georgi. + +.. + +.. date: 2022-08-26-18-46-32 +.. gh-issue: 93554 +.. nonce: QEaCcK +.. section: Core and Builtins + +Change the jump opcodes so that all conditional jumps are forward jumps. +Backward jumps are converted by the assembler into a conditional forward +jump whose target is the fallthrough block (and with a reversed condition), +followed by an unconditional backward jump. For example: + +``POP_JUMP_IF_TRUE BACKWARD_TARGET`` becomes ``POP_JUMP_IF_FALSE NEXT_BLOCK; +JUMP BACKWARD_TARGET``. + +All the directed conditional jump opcodes were removed: +``POP_JUMP_FORWARD_IF_TRUE``, ``POP_JUMP_BACKWARD_IF_TRUE``, +``POP_JUMP_FORWARD_IF_FALSE``, ``POP_JUMP_BACKWARD_IF_FALSE``, +``POP_JUMP_FORWARD_IF_NONE``, ``POP_JUMP_BACKWARD_IF_NONE``, +``POP_JUMP_FORWARD_IF_NOT_NONE``, ``POP_JUMP_BACKWARD_IF_NOT_NONE``. + +The corresponding opcodes without direction are no longer +pseudo-instructions, and they implement the forward conditional jumps. + +.. + +.. date: 2022-08-25-10-19-34 +.. gh-issue: 96268 +.. nonce: AbYrLB +.. section: Core and Builtins + +Loading a file with invalid UTF-8 will now report the broken character at +the correct location. + +.. + +.. date: 2022-08-24-14-30-26 +.. gh-issue: 96237 +.. nonce: msif5f +.. section: Core and Builtins + +The internal field ``_PyInterpreterFrame.f_func`` is renamed to +``_PyInterpreterFrame.f_funcobj`` and may be any object. The ``f_globals`` +and ``f_builtin`` fields may hold junk values. + +It is safest to treat the ``_PyInterpreterFrame`` struct as opaque. + +.. + +.. date: 2022-08-22-21-33-28 +.. gh-issue: 96187 +.. nonce: W_6SRG +.. section: Core and Builtins + +Fixed a bug that caused ``_PyCode_GetExtra`` to return garbage for negative +indexes. Patch by Pablo Galindo + +.. + +.. date: 2022-08-20-18-36-40 +.. gh-issue: 96143 +.. nonce: nh3GFM +.. section: Core and Builtins + +Add a new ``-X perf`` Python command line option as well as +:func:`sys.activate_stack_trampoline` and +:func:`sys.deactivate_stack_trampoline` function in the :mod:`sys` module +that allows to set/unset the interpreter in a way that the Linux ``perf`` +profiler can detect Python calls. The new +:func:`sys.is_stack_trampoline_active` function allows to query the state of +the perf trampoline. Design by Pablo Galindo. Patch by Pablo Galindo and +Christian Heimes with contributions from Gregory P. Smith [Google] and Mark +Shannon. + +.. + +.. date: 2022-08-19-06-51-17 +.. gh-issue: 96071 +.. nonce: mVgPAo +.. section: Core and Builtins + +Fix a deadlock in :c:func:`PyGILState_Ensure` when allocating new thread +state. Patch by Kumar Aditya. + +.. + +.. date: 2022-08-18-13-47-59 +.. gh-issue: 96046 +.. nonce: 5Hqbka +.. section: Core and Builtins + +:c:func:`PyType_Ready` now initializes ``ht_cached_keys`` and performs +additional checks to ensure that type objects are properly configured. This +avoids crashes in 3rd party packages that don't use regular API to create +new types. + +.. + +.. date: 2022-08-15-21-08-11 +.. gh-issue: 96005 +.. nonce: 6eoc8k +.. section: Core and Builtins + +On WASI :data:`~errno.ENOTCAPABLE` is now mapped to :exc:`PermissionError`. +The :mod:`errno` modules exposes the new error number. ``getpath.py`` now +ignores :exc:`PermissionError` when it cannot open landmark files +``pybuilddir.txt`` and ``pyenv.cfg``. + +.. + +.. date: 2022-08-15-20-52-41 +.. gh-issue: 93678 +.. nonce: X7GuIJ +.. section: Core and Builtins + +Added test a harness for direct unit tests of the compiler's optimization +stage. The ``_testinternalcapi.optimize_cfg()`` function runs the optimiser +on a sequence of instructions. The ``CfgOptimizationTestCase`` class in +``test.support`` has utilities for invoking the optimizer and checking the +output. + +.. + +.. date: 2022-08-15-12-41-14 +.. gh-issue: 95245 +.. nonce: N4gOUV +.. section: Core and Builtins + +Reduces the size of a "simple" Python object from 8 to 6 words by moving the +weakreflist pointer into the pre-header directly before the object's +dict/values pointer. + +.. + +.. date: 2022-08-15-11-58-05 +.. gh-issue: 90997 +.. nonce: bWwV8Q +.. section: Core and Builtins + +Compile virtual :keyword:`try`/:keyword:`except` blocks to handle exceptions +raised during :meth:`~generator.close` or :meth:`~generator.throw` calls +through a suspended frame. + +.. + +.. date: 2022-08-14-10-04-44 +.. gh-issue: 95977 +.. nonce: gCTZb9 +.. section: Core and Builtins + +Optimized calling :meth:`~object.__get__` with vectorcall. Patch by Kumar +Aditya. + +.. + +.. date: 2022-08-12-18-13-49 +.. gh-issue: 91210 +.. nonce: AWMSLj +.. section: Core and Builtins + +Improve error message when a parameter without a default value follows one +with a default value, and show the same message, even when the +non-default/default sequence is preceded by positional-only parameters. + +.. + +.. date: 2022-08-12-13-04-25 +.. gh-issue: 95922 +.. nonce: YNCtyX +.. section: Core and Builtins + +Fixed bug where the compiler's ``eliminate_empty_basic_blocks`` function +ignores the last block of the code unit. + +.. + +.. date: 2022-08-11-11-01-56 +.. gh-issue: 95818 +.. nonce: iClLdl +.. section: Core and Builtins + +Skip over incomplete frames in :c:func:`PyThreadState_GetFrame`. + +.. + +.. date: 2022-08-11-09-19-55 +.. gh-issue: 95876 +.. nonce: YpQfoV +.. section: Core and Builtins + +Fix format string in ``_PyPegen_raise_error_known_location`` that can lead +to memory corruption on some 64bit systems. The function was building a +tuple with ``i`` (int) instead of ``n`` (Py_ssize_t) for Py_ssize_t +arguments. + +.. + +.. date: 2022-08-04-18-46-54 +.. gh-issue: 95605 +.. nonce: FbpCoG +.. section: Core and Builtins + +Fix misleading contents of error message when converting an all-whitespace +string to :class:`float`. + +.. + +.. date: 2022-07-31-13-23-12 +.. gh-issue: 95150 +.. nonce: 67FXVo +.. section: Core and Builtins + +Update code object hashing and equality to consider all debugging and +exception handling tables. This fixes an issue where certain non-identical +code objects could be "deduplicated" during compilation. + +.. + +.. date: 2022-07-31-03-22-58 +.. gh-issue: 91146 +.. nonce: Y2Hziy +.. section: Core and Builtins + +Reduce allocation size of :class:`list` from :meth:`str.split` and +:meth:`str.rsplit`. Patch by Dong-hee Na and Inada Naoki. + +.. + +.. date: 2022-07-28-19-07-06 +.. gh-issue: 87092 +.. nonce: 73IPS1 +.. section: Core and Builtins + +Create a 'jump target label' abstraction in the compiler so that the +compiler's codegen stage does not work directly with basic blocks. This +prepares the code for changes to the underlying CFG generation mechanism. + +.. + +.. date: 2022-07-28-08-33-31 +.. gh-issue: 95355 +.. nonce: yN4XVk +.. section: Core and Builtins + +``_PyPegen_Parser_New`` now properly detects token memory allocation errors. +Patch by Honglin Zhu. + +.. + +.. date: 2022-07-27-14-21-57 +.. gh-issue: 90081 +.. nonce: HVAS5x +.. section: Core and Builtins + +Run Python code in tracer/profiler function at full speed. Fixes slowdown in +earlier versions of 3.11. + +.. + +.. date: 2022-07-27-14-05-07 +.. gh-issue: 95324 +.. nonce: 28Q5u7 +.. section: Core and Builtins + +Emit a warning in debug mode if an object does not call +:c:func:`PyObject_GC_UnTrack` before deallocation. Patch by Pablo Galindo. + +.. + +.. date: 2022-07-26-12-59-03 +.. gh-issue: 95245 +.. nonce: GHWczn +.. section: Core and Builtins + +Merge managed dict and values pointer into a single tagged pointer to save +one word in the pre-header. + +.. + +.. date: 2022-07-26-09-31-12 +.. gh-issue: 93678 +.. nonce: W8vvgT +.. section: Core and Builtins + +Add cfg_builder struct and refactor the relevant code so that a cfg can be +constructed without an instance of the compiler struct. + +.. + +.. date: 2022-07-24-00-27-47 +.. gh-issue: 95185 +.. nonce: ghYTZx +.. section: Core and Builtins + +Prevented crashes in the AST constructor when compiling some absurdly long +expressions like ``"+0"*1000000``. :exc:`RecursionError` is now raised +instead. Patch by Pablo Galindo + +.. + +.. date: 2022-07-23-19-16-25 +.. gh-issue: 93351 +.. nonce: 0Jyvu- +.. section: Core and Builtins + +:class:`ast.AST` node positions are now validated when provided to +:func:`compile` and other related functions. If invalid positions are +detected, a :exc:`ValueError` will be raised. + +.. + +.. date: 2022-07-22-12-53-34 +.. gh-issue: 94438 +.. nonce: hNqACc +.. section: Core and Builtins + +Fix an issue that caused extended opcode arguments and some conditional pops +to be ignored when calculating valid jump targets for assignments to the +``f_lineno`` attribute of frame objects. In some cases, this could cause +inconsistent internal state, resulting in a hard crash of the interpreter. + +.. + +.. date: 2022-07-21-19-19-20 +.. gh-issue: 95060 +.. nonce: 4xdT1f +.. section: Core and Builtins + +Undocumented ``PyCode_Addr2Location`` function now properly returns when +``addrq`` argument is less than zero. + +.. + +.. date: 2022-07-21-17-54-52 +.. gh-issue: 95113 +.. nonce: NnSLpT +.. section: Core and Builtins + +Replace all ``EXTENDED_ARG_QUICK`` instructions with basic +:opcode:`EXTENDED_ARG` instructions in unquickened code. Consumers of +non-adaptive bytecode should be able to handle extended arguments the same +way they were handled in CPython 3.10 and older. + +.. + +.. date: 2022-07-20-13-46-01 +.. gh-issue: 91409 +.. nonce: dhL8Zo +.. section: Core and Builtins + +Fix incorrect source location info caused by certain optimizations in the +bytecode compiler. + +.. + +.. date: 2022-07-20-09-04-55 +.. gh-issue: 95023 +.. nonce: bs-xd7 +.. section: Core and Builtins + +Implement :func:`os.setns` and :func:`os.unshare` for Linux. Patch by Noam +Cohen. + +.. + +.. date: 2022-07-19-16-30-59 +.. gh-issue: 94036 +.. nonce: _6Utkm +.. section: Core and Builtins + +Fix incorrect source location info for some multi-line attribute accesses +and method calls. + +.. + +.. date: 2022-07-19-09-41-55 +.. gh-issue: 94938 +.. nonce: xYBlM7 +.. section: Core and Builtins + +Fix error detection in some builtin functions when keyword argument name is +an instance of a str subclass with overloaded ``__eq__`` and ``__hash__``. +Previously it could cause SystemError or other undesired behavior. + +.. + +.. date: 2022-07-19-04-34-56 +.. gh-issue: 94996 +.. nonce: dV564A +.. section: Core and Builtins + +:func:`ast.parse` will no longer parse function definitions with +positional-only params when passed ``feature_version`` less than ``(3, 8)``. +Patch by Shantanu Jain. + +.. + +.. date: 2022-07-18-14-19-21 +.. gh-issue: 94739 +.. nonce: NQJQi7 +.. section: Core and Builtins + +Allow jumping within, out of, and across exception handlers in the debugger. + +.. + +.. date: 2022-07-18-05-10-29 +.. gh-issue: 94949 +.. nonce: OsZ7_s +.. section: Core and Builtins + +:func:`ast.parse` will no longer parse parenthesized context managers when +passed ``feature_version`` less than ``(3, 9)``. Patch by Shantanu Jain. + +.. + +.. date: 2022-07-18-04-48-34 +.. gh-issue: 94947 +.. nonce: df9gUw +.. section: Core and Builtins + +:func:`ast.parse` will no longer parse assignment expressions when passed +``feature_version`` less than ``(3, 8)``. Patch by Shantanu Jain. + +.. + +.. date: 2022-07-17-15-54-29 +.. gh-issue: 91256 +.. nonce: z7i7Q5 +.. section: Core and Builtins + +Ensures the program name is known for help text during interpreter startup. + +.. + +.. date: 2022-07-16-08-14-17 +.. gh-issue: 94869 +.. nonce: eRwMsX +.. section: Core and Builtins + +Fix the column offsets for some expressions in multi-line f-strings +:mod:`ast` nodes. Patch by Pablo Galindo. + +.. + +.. date: 2022-07-15-22-47-44 +.. gh-issue: 94893 +.. nonce: YiJYcW +.. section: Core and Builtins + +Fix an issue where frame object manipulations could corrupt inline bytecode +caches. + +.. + +.. date: 2022-07-15-22-16-08 +.. gh-issue: 94822 +.. nonce: zRRzBN +.. section: Core and Builtins + +Fix an issue where lookups of metaclass descriptors may be ignored when an +identically-named attribute also exists on the class itself. + +.. + +.. date: 2022-07-15-16-15-04 +.. gh-issue: 91153 +.. nonce: HiBmtt +.. section: Core and Builtins + +Fix an issue where a :class:`bytearray` item assignment could crash if it's +resized by the new value's :meth:`__index__` method. + +.. + +.. date: 2022-07-14-10-07-53 +.. gh-issue: 90699 +.. nonce: x3aG9m +.. section: Core and Builtins + +Fix reference counting bug in :meth:`bool.__repr__`. Patch by Kumar Aditya. + +.. + +.. date: 2022-07-08-16-44-11 +.. gh-issue: 94694 +.. nonce: VkL2CM +.. section: Core and Builtins + +Fix an issue that could cause code with multi-line method lookups to have +misleading or incorrect column offset information. In some cases (when +compiling a hand-built AST) this could have resulted in a hard crash of the +interpreter. + +.. + +.. date: 2022-07-08-11-44-45 +.. gh-issue: 93252 +.. nonce: i2358c +.. section: Core and Builtins + +Fix an issue that caused internal frames to outlive failed Python function +calls, possibly resulting in memory leaks or hard interpreter crashes. + +.. + +.. date: 2022-07-07-21-13-25 +.. gh-issue: 94215 +.. nonce: _Sv9Ms +.. section: Core and Builtins + +Fix an issue where exceptions raised by line-tracing events would cause +frames to be left in an invalid state, possibly resulting in a hard crash of +the interpreter. + +.. + +.. date: 2022-07-06-14-02-26 +.. gh-issue: 92228 +.. nonce: 44Cbly +.. section: Core and Builtins + +Disable the compiler's inline-small-exit-blocks optimization for exit blocks +that are associated with source code lines. This fixes a bug where the +debugger cannot tell where an exception handler ends and the following code +block begins. + +.. + +.. date: 2022-07-01-20-00-19 +.. gh-issue: 94485 +.. nonce: mo5st7 +.. section: Core and Builtins + +Line number of a module's ``RESUME`` instruction is set to 0 as specified in +:pep:`626`. + +.. + +.. date: 2022-06-30-15-07-26 +.. gh-issue: 94438 +.. nonce: btzHSk +.. section: Core and Builtins + +Account for instructions that can push NULL to the stack when setting line +number in a frame. Prevents some (unlikely) crashes. + +.. + +.. date: 2022-06-29-22-18-36 +.. gh-issue: 91719 +.. nonce: 3APYYI +.. section: Core and Builtins + +Reload ``opcode`` when raising ``unknown opcode error`` in the interpreter +main loop, for C compilers to generate dispatching code independently. + +.. + +.. date: 2022-06-29-15-45-04 +.. gh-issue: 94329 +.. nonce: olUQyk +.. section: Core and Builtins + +Compile and run code with unpacking of extremely large sequences (1000s of +elements). Such code failed to compile. It now compiles and runs correctly. + +.. + +.. date: 2022-06-28-14-20-36 +.. gh-issue: 94360 +.. nonce: DiEnen +.. section: Core and Builtins + +Fixed a tokenizer crash when reading encoded files with syntax errors from +``stdin`` with non utf-8 encoded text. Patch by Pablo Galindo + +.. + +.. date: 2022-06-28-12-41-17 +.. gh-issue: 88116 +.. nonce: A7fEl_ +.. section: Core and Builtins + +Fix an issue when reading line numbers from code objects if the encoded line +numbers are close to ``INT_MIN``. Patch by Pablo Galindo + +.. + +.. date: 2022-06-28-10-08-06 +.. gh-issue: 94262 +.. nonce: m-HWUZ +.. section: Core and Builtins + +Don't create frame objects for incomplete frames. Prevents the creation of +generators and closures from being observable to Python and C extensions, +restoring the behavior of 3.10 and earlier. + +.. + +.. date: 2022-06-26-14-37-03 +.. gh-issue: 94192 +.. nonce: ab7tn7 +.. section: Core and Builtins + +Fix error for dictionary literals with invalid expression as value. + +.. + +.. date: 2022-06-25-10-19-43 +.. gh-issue: 87995 +.. nonce: aMDHnp +.. section: Core and Builtins + +:class:`types.MappingProxyType` instances are now hashable if the underlying +mapping is hashable. + +.. + +.. date: 2022-06-24-14-06-20 +.. gh-issue: 93883 +.. nonce: 8jVQQ4 +.. section: Core and Builtins + +Revise the display strategy of traceback enhanced error locations. The +indicators are only shown when the location doesn't span the whole line. + +.. + +.. date: 2022-06-23-12-10-39 +.. gh-issue: 94163 +.. nonce: SqAfQq +.. section: Core and Builtins + +Add :opcode:`BINARY_SLICE` and :opcode:`STORE_SLICE` instructions for more +efficient handling and better specialization of slicing operations, where +the slice is explicit in the source code. + +.. + +.. date: 2022-06-20-13-48-57 +.. gh-issue: 94021 +.. nonce: o78q3G +.. section: Core and Builtins + +Fix unreachable code warning in ``Python/specialize.c``. + +.. + +.. date: 2022-06-18-17-00-33 +.. gh-issue: 93911 +.. nonce: y286of +.. section: Core and Builtins + +Specialize ``LOAD_ATTR`` for objects with custom ``__getattribute__``. + +.. + +.. date: 2022-06-17-16-30-24 +.. gh-issue: 93955 +.. nonce: LmiAe9 +.. section: Core and Builtins + +Improve performance of attribute lookups on objects with custom +``__getattribute__`` and ``__getattr__``. Patch by Ken Jin. + +.. + +.. date: 2022-06-16-16-53-22 +.. gh-issue: 93911 +.. nonce: RDwIiK +.. section: Core and Builtins + +Specialize ``LOAD_ATTR`` for ``property()`` attributes. + +.. + +.. date: 2022-06-15-16-45-53 +.. gh-issue: 93678 +.. nonce: 1I_ZT3 +.. section: Core and Builtins + +Refactor compiler optimisation code so that it no longer needs the ``struct +assembler`` and ``struct compiler`` passed around. Instead, each function +takes the CFG and other data that it actually needs. This will make it +possible to test this code directly. + +.. + +.. date: 2022-06-15-11-16-13 +.. gh-issue: 93841 +.. nonce: 06zqX3 +.. section: Core and Builtins + +When built with ``-enable-pystats``, ``sys._stats_on()``, +``sys._stats_off()``, ``sys._stats_clear()`` and ``sys._stats_dump()`` +functions have been added to enable gathering stats for parts of programs. + +.. + +.. date: 2022-06-13-13-55-34 +.. gh-issue: 93516 +.. nonce: HILrDl +.. section: Core and Builtins + +Store offset of first traceable instruction in code object to avoid having +to recompute it for each instruction when tracing. + +.. + +.. date: 2022-06-13-10-48-09 +.. gh-issue: 93516 +.. nonce: yJSait +.. section: Core and Builtins + +Lazily create a table mapping bytecode offsets to line numbers to speed up +calculation of line numbers when tracing. + +.. + +.. date: 2022-06-12-19-31-56 +.. gh-issue: 89828 +.. nonce: bq02M7 +.. section: Core and Builtins + +:class:`types.GenericAlias` no longer relays the ``__class__`` attribute. +For example, ``isinstance(list[int], type)`` no longer returns ``True``. + +.. + +.. date: 2022-06-10-16-57-35 +.. gh-issue: 93678 +.. nonce: 1WBnHt +.. section: Core and Builtins + +Refactor the compiler to reduce boilerplate and repetition. + +.. + +.. date: 2022-06-10-12-03-17 +.. gh-issue: 93671 +.. nonce: idkQqG +.. section: Core and Builtins + +Fix some exponential backtrace case happening with deeply nested sequence +patterns in match statements. Patch by Pablo Galindo + +.. + +.. date: 2022-06-10-10-31-18 +.. gh-issue: 93662 +.. nonce: -7RSC1 +.. section: Core and Builtins + +Make sure that the end column offsets are correct in multi-line method +calls. Previously, the end column could precede the column offset. + +.. + +.. date: 2022-06-09-19-19-02 +.. gh-issue: 93461 +.. nonce: 5DqP1e +.. section: Core and Builtins + +:func:`importlib.invalidate_caches` now drops entries from +:data:`sys.path_importer_cache` with a relative path as name. This solves a +caching issue when a process changes its current working directory. + +``FileFinder`` no longer inserts a dot in the path, e.g. ``/egg/./spam`` is +now ``/egg/spam``. + +.. + +.. date: 2022-06-09-09-08-29 +.. gh-issue: 93621 +.. nonce: -_Pn1d +.. section: Core and Builtins + +Change order of bytecode instructions emitted for :keyword:`with` and +:keyword:`async with` to reduce the number of entries in the exception +table. + +.. + +.. date: 2022-06-06-14-28-24 +.. gh-issue: 93533 +.. nonce: lnC0CC +.. section: Core and Builtins + +Reduce the size of the inline cache for ``LOAD_METHOD`` by 2 bytes. + +.. + +.. date: 2022-06-02-23-00-08 +.. gh-issue: 93444 +.. nonce: m63DIs +.. section: Core and Builtins + +Removed redundant fields from the compiler's basicblock struct: +``b_nofallthrough``, ``b_exit``, ``b_return``. They can be easily calculated +from the opcode of the last instruction of the block. + +.. + +.. date: 2022-06-02-08-28-55 +.. gh-issue: 93429 +.. nonce: DZTWHx +.. section: Core and Builtins + +``LOAD_METHOD`` instruction has been removed. It was merged back into +``LOAD_ATTR``. + +.. + +.. date: 2022-06-01-17-47-40 +.. gh-issue: 93418 +.. nonce: 24dJuc +.. section: Core and Builtins + +Fixed an assert where an f-string has an equal sign '=' following an +expression, but there's no trailing brace. For example, f"{i=". + +.. + +.. date: 2022-05-31-16-36-30 +.. gh-issue: 93382 +.. nonce: Jf6gAj +.. section: Core and Builtins + +Cache the result of :c:func:`PyCode_GetCode` function to restore the O(1) +lookup of the :attr:`~types.CodeType.co_code` attribute. + +.. + +.. date: 2022-05-30-19-00-38 +.. gh-issue: 93359 +.. nonce: zXV3A0 +.. section: Core and Builtins + +Ensure that custom :mod:`ast` nodes without explicit end positions can be +compiled. Patch by Pablo Galindo. + +.. + +.. date: 2022-05-30-15-51-11 +.. gh-issue: 93356 +.. nonce: l5wnzW +.. section: Core and Builtins + +Code for exception handlers is emitted at the end of the code unit's +bytecode. This avoids one jump when no exception is raised. + +.. + +.. date: 2022-05-30-15-35-42 +.. gh-issue: 93354 +.. nonce: RZk8gs +.. section: Core and Builtins + +Use exponential backoff for specialization counters in the interpreter. Can +reduce the number of failed specializations significantly and avoid slowdown +for those parts of a program that are not suitable for specialization. + +.. + +.. date: 2022-05-30-14-50-03 +.. gh-issue: 93283 +.. nonce: XDO2ZQ +.. section: Core and Builtins + +Improve error message for invalid syntax of conversion character in f-string +expressions. + +.. + +.. date: 2022-05-30-10-22-46 +.. gh-issue: 93345 +.. nonce: gi1A4L +.. section: Core and Builtins + +Fix a crash in substitution of a ``TypeVar`` in nested generic alias after +``TypeVarTuple``. + +.. + +.. date: 2022-05-25-21-56-25 +.. gh-issue: 93223 +.. nonce: gTOGVZ +.. section: Core and Builtins + +When a bytecode instruction jumps to an unconditional jump instruction, the +first instruction can often be optimized to target the unconditional jump's +target directly. For tracing reasons, this would previously only occur if +both instructions have the same line number. This also now occurs if the +unconditional jump is artificial, i.e., if it has no associated line number. + +.. + +.. date: 2022-05-25-12-30-12 +.. gh-issue: 84694 +.. nonce: 5sjy2w +.. section: Core and Builtins + +The ``--experimental-isolated-subinterpreters`` configure option and +``EXPERIMENTAL_ISOLATED_SUBINTERPRETERS`` macro have been removed. + +.. + +.. date: 2022-05-25-04-07-22 +.. gh-issue: 91924 +.. nonce: -UyO4q +.. section: Core and Builtins + +Fix ``__lltrace__`` debug feature if the stdout encoding is not UTF-8. Patch +by Victor Stinner. + +.. + +.. date: 2022-05-24-14-35-48 +.. gh-issue: 93040 +.. nonce: 9X6Ofu +.. section: Core and Builtins + +Wraps unused parameters in ``Objects/obmalloc.c`` with ``Py_UNUSED``. + +.. + +.. date: 2022-05-23-18-36-07 +.. gh-issue: 93143 +.. nonce: X1Yqxm +.. section: Core and Builtins + +Avoid ``NULL`` checks for uninitialized local variables by determining at +compile time which variables must be initialized. + +.. + +.. date: 2022-05-22-02-37-50 +.. gh-issue: 93061 +.. nonce: r70Imp +.. section: Core and Builtins + +Backward jumps after ``async for`` loops are no longer given dubious line +numbers. + +.. + +.. date: 2022-05-21-23-21-37 +.. gh-issue: 93065 +.. nonce: 5I18WC +.. section: Core and Builtins + +Fix contextvars HAMT implementation to handle iteration over deep trees. + +The bug was discovered and fixed by Eli Libman. See +`MagicStack/immutables#84 +`_ for more details. + +.. + +.. date: 2022-05-20-13-32-24 +.. gh-issue: 93012 +.. nonce: e9B-pv +.. section: Core and Builtins + +Added the new function :c:func:`PyType_FromMetaclass`, which generalizes the +existing :c:func:`PyType_FromModuleAndSpec` using an additional metaclass +argument. This is useful for language binding tools, where it can be used to +intercept type-related operations like subclassing or static attribute +access by specifying a metaclass with custom slots. + +Importantly, :c:func:`PyType_FromMetaclass` is available in the Limited API, +which provides a path towards migrating more binding tools onto the Stable +ABI. + +.. + +.. date: 2022-05-20-09-25-34 +.. gh-issue: 93021 +.. nonce: k3Aji2 +.. section: Core and Builtins + +Fix the :attr:`__text_signature__` for :meth:`__get__` methods implemented +in C. Patch by Jelle Zijlstra. + +.. + +.. date: 2022-05-19-15-29-53 +.. gh-issue: 89914 +.. nonce: 8bAffH +.. section: Core and Builtins + +The operand of the ``YIELD_VALUE`` instruction is set to the stack depth. +This is done to help frame handling on ``yield`` and may assist debuggers. + +.. + +.. date: 2022-05-19-13-25-50 +.. gh-issue: 92955 +.. nonce: kmNV33 +.. section: Core and Builtins + +Fix memory leak in code object's lines and positions iterators as they were +not finalized at exit. Patch by Kumar Aditya. + +.. + +.. date: 2022-05-18-18-34-45 +.. gh-issue: 92930 +.. nonce: kpYPOb +.. section: Core and Builtins + +Fixed a crash in ``_pickle.c`` from mutating collections during +``__reduce__`` or ``persistent_id``. + +.. + +.. date: 2022-05-18-12-55-35 +.. gh-issue: 90690 +.. nonce: TKuoTa +.. section: Core and Builtins + +The PRECALL instruction has been removed. It offered only a small advantage +for specialization and is not needed in the vast majority of cases. + +.. + +.. date: 2022-05-18-08-32-33 +.. gh-issue: 92914 +.. nonce: tJUeTD +.. section: Core and Builtins + +Always round the allocated size for lists up to the nearest even number. + +.. + +.. date: 2022-05-17-20-41-43 +.. gh-issue: 92858 +.. nonce: eIXJTn +.. section: Core and Builtins + +Improve error message for some suites with syntax error before ':' + +.. + +.. date: 2022-05-15-15-25-05 +.. gh-issue: 90473 +.. nonce: MoPHYW +.. section: Core and Builtins + +Decrease default recursion limit on WASI to address limited call stack size. + +.. + +.. date: 2022-05-14-13-22-11 +.. gh-issue: 92804 +.. nonce: rAqpI2 +.. section: Core and Builtins + +Fix memory leak in ``memoryview`` iterator as it was not finalized at exit. +Patch by Kumar Aditya. + +.. + +.. date: 2022-05-13-12-36-10 +.. gh-issue: 92777 +.. nonce: Odo4vP +.. section: Core and Builtins + +Specialize ``LOAD_METHOD`` for objects with lazy dictionaries. Patch by Ken +Jin. + +.. + +.. date: 2022-05-13-00-57-18 +.. gh-issue: 92658 +.. nonce: YdhFE2 +.. section: Core and Builtins + +Add support for connecting and binding to Hyper-V sockets on Windows Hyper-V +hosts and guests. + +.. + +.. date: 2022-05-12-13-23-19 +.. gh-issue: 92236 +.. nonce: sDRzUe +.. section: Core and Builtins + +Remove spurious "LINE" event when starting a generator or coroutine, visible +tracing functions implemented in C. + +.. + +.. date: 2022-05-11-09-16-54 +.. gh-issue: 91102 +.. nonce: lenv9h +.. section: Core and Builtins + +:meth:`_warnings.warn_explicit` is ported to Argument Clinic. + +.. + +.. date: 2022-05-10-11-34-35 +.. gh-issue: 92619 +.. nonce: u0V0lY +.. section: Core and Builtins + +Make the compiler duplicate an exit block only if none of its instructions +have a lineno (previously only the first instruction in the block was +checked, leading to unnecessarily duplicated blocks). + +.. + +.. date: 2022-05-08-19-43-31 +.. gh-issue: 88750 +.. nonce: 1BjJg- +.. section: Core and Builtins + +The deprecated debug build only ``PYTHONTHREADDEBUG`` environment variable +no longer does anything. + +.. + +.. date: 2022-05-03-20-12-18 +.. gh-issue: 92261 +.. nonce: aigLnb +.. section: Core and Builtins + +Fix hang when trying to iterate over a ``typing.Union``. + +.. + +.. date: 2022-04-24-02-22-10 +.. gh-issue: 91432 +.. nonce: YPJAK6 +.. section: Core and Builtins + +Specialized the :opcode:`FOR_ITER` opcode using the PEP 659 machinery + +.. + +.. date: 2022-04-16-15-37-55 +.. gh-issue: 91399 +.. nonce: trLbK6 +.. section: Core and Builtins + +Removed duplicate '{0, 0, 0, 0, 0, 0}' entry in 'Objects/unicodetype_db.h'. + +.. + +.. date: 2022-04-15-22-12-53 +.. gh-issue: 91578 +.. nonce: rDOtyK +.. section: Core and Builtins + +Updates the error message for abstract class. + +.. + +.. bpo: 47091 +.. date: 2022-03-22-13-12-27 +.. nonce: tJcy-P +.. section: Core and Builtins + +Improve performance of repetition of :class:`list` and :class:`tuple` by +using ``memcpy`` to copy data and performing the reference increments in one +step. + +.. + +.. bpo: 46142 +.. date: 2022-01-02-14-53-59 +.. nonce: WayjgT +.. section: Core and Builtins + +Make ``--help`` output shorter by moving some info to the new ``--help-env`` +and ``--help-xoptions`` command-line options. Also add ``--help-all`` option +to print complete usage. + +.. + +.. bpo: 42316 +.. date: 2020-11-15-02-08-43 +.. nonce: LqdkWK +.. section: Core and Builtins + +Document some places where an assignment expression needs parentheses. + +.. + +.. date: 2022-10-23-18-30-39 +.. gh-issue: 89237 +.. nonce: kBui30 +.. section: Library + +Fix hang on Windows in ``subprocess.wait_closed()`` in :mod:`asyncio` with +:class:`~asyncio.ProactorEventLoop`. Patch by Kumar Aditya. + +.. + +.. date: 2022-10-19-09-29-12 +.. gh-issue: 97928 +.. nonce: xj3im7 +.. section: Library + +:meth:`tkinter.Text.count` raises now an exception for options starting with +"-" instead of silently ignoring them. + +.. + +.. date: 2022-10-18-15-41-37 +.. gh-issue: 98393 +.. nonce: vhPu4L +.. section: Library + +The :mod:`os` module no longer accepts bytes-like paths, like +:class:`bytearray` and :class:`memoryview` types: only the exact +:class:`bytes` type is accepted for bytes strings. Patch by Victor Stinner. + +.. + +.. date: 2022-10-17-12-49-02 +.. gh-issue: 98363 +.. nonce: aFmSP- +.. section: Library + +Added itertools.batched() to batch data into lists of a given length with +the last list possibly being shorter than the others. + +.. + +.. date: 2022-10-16-15-31-50 +.. gh-issue: 98331 +.. nonce: Y5kPOX +.. section: Library + +Update the bundled copies of pip and setuptools to versions 22.3 and 65.5.0 +respectively. + +.. + +.. date: 2022-10-16-06-18-59 +.. gh-issue: 98307 +.. nonce: b2_CDu +.. section: Library + +A :meth:`~logging.handlers.SysLogHandler.createSocket` method was added to +:class:`~logging.handlers.SysLogHandler`. + +.. + +.. date: 2022-10-14-19-57-37 +.. gh-issue: 96035 +.. nonce: 0xcX-p +.. section: Library + +Fix bug in :func:`urllib.parse.urlparse` that causes certain port numbers +containing whitespace, underscores, plus and minus signs, or non-ASCII +digits to be incorrectly accepted. + +.. + +.. date: 2022-10-14-12-29-05 +.. gh-issue: 98257 +.. nonce: aMSMs2 +.. section: Library + +Make :func:`sys.setprofile` and :func:`sys.settrace` functions reentrant. +They can no long fail with: ``RuntimeError("Cannot install a trace function +while another trace function is being installed")``. Patch by Victor +Stinner. + +.. + +.. date: 2022-10-14-11-46-31 +.. gh-issue: 98251 +.. nonce: Uxc9al +.. section: Library + +Allow :mod:`venv` to pass along :envvar:`PYTHON*` variables to ``ensurepip`` +and ``pip`` when they do not impact path resolution + +.. + +.. date: 2022-10-12-11-20-54 +.. gh-issue: 94597 +.. nonce: GYJZlb +.. section: Library + +Deprecated :meth:`asyncio.AbstractEventLoopPolicy.get_child_watcher` and +:meth:`asyncio.AbstractEventLoopPolicy.set_child_watcher` methods to be +removed in Python 3.14. Patch by Kumar Aditya. + +.. + +.. date: 2022-10-12-10-00-40 +.. gh-issue: 98178 +.. nonce: hspH51 +.. section: Library + +On macOS, fix a crash in :func:`syslog.syslog` in multi-threaded +applications. On macOS, the libc ``syslog()`` function is not thread-safe, +so :func:`syslog.syslog` no longer releases the GIL to call it. Patch by +Victor Stinner. + +.. + +.. date: 2022-10-10-09-52-21 +.. gh-issue: 44098 +.. nonce: okcqJt +.. section: Library + +Release the GIL when creating :class:`mmap.mmap` objects on Unix. + +.. + +.. date: 2022-10-09-12-12-38 +.. gh-issue: 87730 +.. nonce: ClgP3f +.. section: Library + +Wrap network errors consistently in urllib FTP support, so the test suite +doesn't fail when a network is available but the public internet is not +reachable. + +.. + +.. date: 2022-10-08-06-59-46 +.. gh-issue: 94597 +.. nonce: TsS0oT +.. section: Library + +The child watcher classes :class:`~asyncio.MultiLoopChildWatcher`, +:class:`~asyncio.FastChildWatcher` and :class:`~asyncio.SafeChildWatcher` +are deprecated and will be removed in Python 3.14. Patch by Kumar Aditya. + +.. + +.. date: 2022-10-07-09-52-37 +.. gh-issue: 98023 +.. nonce: aliEcl +.. section: Library + +Change default child watcher to :class:`~asyncio.PidfdChildWatcher` on Linux +systems which supports it. Patch by Kumar Aditya. + +.. + +.. date: 2022-10-06-23-42-00 +.. gh-issue: 90985 +.. nonce: s280JY +.. section: Library + +Earlier in 3.11 we deprecated ``asyncio.Task.cancel("message")``. We +realized we were too harsh, and have undeprecated it. + +.. + +.. date: 2022-10-06-17-59-22 +.. gh-issue: 65961 +.. nonce: SXlQnI +.. section: Library + +Do not rely solely on ``__cached__`` on modules; code will also support +``__spec__.cached``. + +.. + +.. date: 2022-10-05-20-52-17 +.. gh-issue: 97646 +.. nonce: Q4fVww +.. section: Library + +Replace deprecated ``application/javascript`` with ``text/javascript`` in +:mod:`mimetypes`. See :rfc:`9239`. Patch by Noam Cohen. + +.. + +.. date: 2022-10-05-16-10-24 +.. gh-issue: 97930 +.. nonce: NPSrzE +.. section: Library + +Apply changes from importlib_resources 5.8 and 5.9: ``Traversable.joinpath`` +provides a concrete implementation. ``as_file`` now supports directories of +resources. + +.. + +.. date: 2022-10-05-11-40-02 +.. gh-issue: 97850 +.. nonce: NzdREm +.. section: Library + +Remove deprecated :func:`importlib.utils.set_loader` and +:func:`importlib.utils.module_for_loader` from :mod:`importlib.utils`. + +.. + +.. date: 2022-10-04-21-21-41 +.. gh-issue: 97837 +.. nonce: 19q-eg +.. section: Library + +Change deprecate warning message in :mod:`unittest` from + +``It is deprecated to return a value!=None`` + +to + +``It is deprecated to return a value that is not None from a test case`` + +.. + +.. date: 2022-10-04-07-55-19 +.. gh-issue: 97825 +.. nonce: mNdv1l +.. section: Library + +Fixes :exc:`AttributeError` when :meth:`subprocess.check_output` is used +with argument ``input=None`` and either of the arguments *encoding* or +*errors* are used. + +.. + +.. date: 2022-10-04-00-43-43 +.. gh-issue: 97008 +.. nonce: 3rjtt6 +.. section: Library + +:exc:`NameError` and :exc:`AttributeError` spelling suggestions provided +since :gh:`82711` are now also emitted by the pure Python :mod:`traceback` +module. Tests for those suggestions now exercise both implementations to +ensure they are equivalent. Patch by Carl Friedrich Bolz-Tereick and ?ukasz +Langa. + +.. + +.. date: 2022-10-03-14-42-13 +.. gh-issue: 97799 +.. nonce: Y1iJvf +.. section: Library + +:mod:`dataclass` now uses :func:`inspect.get_annotations` to examine the +annotations on class objects. + +.. + +.. date: 2022-10-03-13-25-19 +.. gh-issue: 97781 +.. nonce: gCLLef +.. section: Library + +Removed deprecated interfaces in ``importlib.metadata`` (entry points +accessed as dictionary, implicit dictionary construction of sequence of +``EntryPoint`` objects, mutablility of ``EntryPoints`` result, access of +entry point by index). ``entry_points`` now has a simpler, more +straightforward API (returning ``EntryPoints``). + +.. + +.. date: 2022-09-30-15-56-20 +.. gh-issue: 96827 +.. nonce: lzy1iw +.. section: Library + +Avoid spurious tracebacks from :mod:`asyncio` when default executor cleanup +is delayed until after the event loop is closed (e.g. as the result of a +keyboard interrupt). + +.. + +.. date: 2022-09-30-09-22-37 +.. gh-issue: 95534 +.. nonce: ndEfPj +.. section: Library + +:meth:`gzip.GzipFile.read` reads 10% faster. + +.. + +.. date: 2022-09-29-23-22-24 +.. gh-issue: 97592 +.. nonce: tpJg_J +.. section: Library + +Avoid a crash in the C version of +:meth:`asyncio.Future.remove_done_callback` when an evil argument is passed. + +.. + +.. date: 2022-09-29-08-15-55 +.. gh-issue: 97639 +.. nonce: JSjWYW +.. section: Library + +Remove ``tokenize.NL`` check from :mod:`tabnanny`. + +.. + +.. date: 2022-09-25-23-24-52 +.. gh-issue: 97545 +.. nonce: HZLSNt +.. section: Library + +Make Semaphore run faster. + +.. + +.. date: 2022-09-25-20-42-33 +.. gh-issue: 73588 +.. nonce: uVtjEA +.. section: Library + +Fix generation of the default name of :class:`tkinter.Checkbutton`. +Previously, checkbuttons in different parent widgets could have the same +short name and share the same state if arguments "name" and "variable" are +not specified. Now they are globally unique. + +.. + +.. date: 2022-09-24-18-56-23 +.. gh-issue: 96865 +.. nonce: o9WUkW +.. section: Library + +fix Flag to use boundary CONFORM + +This restores previous Flag behavior of allowing flags with non-sequential +values to be combined; e.g. + +class Skip(Flag): TWO = 2 EIGHT = 8 + +Skip.TWO | Skip.EIGHT -> + +.. + +.. date: 2022-09-22-14-35-02 +.. gh-issue: 97005 +.. nonce: yf21Q7 +.. section: Library + +Update bundled libexpat to 2.4.9 + +.. + +.. date: 2022-09-22-11-50-29 +.. gh-issue: 85760 +.. nonce: DETTPd +.. section: Library + +Fix race condition in :mod:`asyncio` where +:meth:`~asyncio.SubprocessProtocol.process_exited` called before the +:meth:`~asyncio.SubprocessProtocol.pipe_data_received` leading to +inconsistent output. Patch by Kumar Aditya. + +.. + +.. date: 2022-09-18-04-51-30 +.. gh-issue: 96704 +.. nonce: DmamRX +.. section: Library + +Pass the correct ``contextvars.Context`` when a ``asyncio`` exception +handler is called on behalf of a task or callback handle. This adds a new +``Task`` method, ``get_context``, and also a new ``Handle`` method with the +same name. If this method is not found on a task object (perhaps because it +is a third-party library that does not yet provide this method), the context +prevailing at the time the exception handler is called is used. + +.. + +.. date: 2022-09-17-13-15-10 +.. gh-issue: 96819 +.. nonce: 6RfqM7 +.. section: Library + +Fixed check in :mod:`multiprocessing.resource_tracker` that guarantees that +the length of a write to a pipe is not greater than ``PIPE_BUF``. + +.. + +.. date: 2022-09-16-07-53-29 +.. gh-issue: 95865 +.. nonce: oHjX0A +.. section: Library + +Reduce :func:`urllib.parse.quote_from_bytes` memory use on large values. + +Contributed by Dennis Sweeney. + +.. + +.. date: 2022-09-15-00-37-33 +.. gh-issue: 96741 +.. nonce: 4b6czN +.. section: Library + +Corrected type annotation for dataclass attribute +``pstats.FunctionProfile.ncalls`` to be ``str``. + +.. + +.. date: 2022-09-13-15-12-31 +.. gh-issue: 96734 +.. nonce: G08vjz +.. section: Library + +Update :mod:`unicodedata` database to Unicode 15.0.0. + +.. + +.. date: 2022-09-10-16-46-16 +.. gh-issue: 96735 +.. nonce: 0YzJuG +.. section: Library + +Fix undefined behaviour in :func:`struct.unpack`. + +.. + +.. date: 2022-09-08-20-12-48 +.. gh-issue: 46412 +.. nonce: r_cfTh +.. section: Library + +Improve performance of ``bool(db)`` for large ndb/gdb databases. Previously +this would call ``len(db)`` which would iterate over all keys -- the answer +(empty or not) is known after the first key. + +.. + +.. date: 2022-09-07-22-49-37 +.. gh-issue: 96652 +.. nonce: YqOKxI +.. section: Library + +Fix the faulthandler implementation of ``faulthandler.register(signal, +chain=True)`` if the ``sigaction()`` function is not available: don't call +the previous signal handler if it's NULL. Patch by Victor Stinner. + +.. + +.. date: 2022-09-04-12-32-52 +.. gh-issue: 68163 +.. nonce: h6TJCc +.. section: Library + +Correct conversion of :class:`numbers.Rational`'s to :class:`float`. + +.. + +.. date: 2022-09-03-18-39-05 +.. gh-issue: 96538 +.. nonce: W156-D +.. section: Library + +Speed up ``bisect.bisect()`` functions by taking advantage of +type-stability. + +.. + +.. date: 2022-09-01-13-54-38 +.. gh-issue: 96465 +.. nonce: 0IJmrH +.. section: Library + +Fraction hashes are now cached. + +.. + +.. date: 2022-08-31-11-10-21 +.. gh-issue: 96079 +.. nonce: uqrXdJ +.. section: Library + +In :mod:`typing`, fix missing field ``name`` and incorrect ``__module__`` in +_AnnotatedAlias. + +.. + +.. date: 2022-08-30-12-32-00 +.. gh-issue: 96415 +.. nonce: 6W7ORH +.. section: Library + +Remove ``types._cell_factory`` from module namespace. + +.. + +.. date: 2022-08-30-11-46-36 +.. gh-issue: 95987 +.. nonce: CV7_u4 +.. section: Library + +Fix ``repr`` of ``Any`` subclasses. + +.. + +.. date: 2022-08-29-16-54-36 +.. gh-issue: 96388 +.. nonce: dCpJcu +.. section: Library + +Work around missing socket functions in :class:`~socket.socket`'s +``__repr__``. + +.. + +.. date: 2022-08-29-15-28-39 +.. gh-issue: 96385 +.. nonce: uLRTsf +.. section: Library + +Fix ``TypeVarTuple.__typing_prepare_subst__``. ``TypeError`` was not raised +when using more than one ``TypeVarTuple``, like ``[*T, *V]`` in type alias +substitutions. + +.. + +.. date: 2022-08-29-12-49-30 +.. gh-issue: 96142 +.. nonce: PdCMez +.. section: Library + +Add ``match_args``, ``kw_only``, ``slots``, and ``weakref_slot`` to +``_DataclassParams``. + +.. + +.. date: 2022-08-29-12-35-28 +.. gh-issue: 96073 +.. nonce: WaGstf +.. section: Library + +In :mod:`inspect`, fix overeager replacement of "``typing.``" in formatting +annotations. + +.. + +.. date: 2022-08-29-07-04-03 +.. gh-issue: 89258 +.. nonce: ri7ncj +.. section: Library + +Added a :meth:`~logging.Logger.getChildren` method to +:class:`logging.Logger`, to get the immediate child loggers of a logger. + +.. + +.. date: 2022-08-27-23-16-09 +.. gh-issue: 96346 +.. nonce: jJX14I +.. section: Library + +Use double caching for compiled RE patterns. + +.. + +.. date: 2022-08-27-21-26-52 +.. gh-issue: 96349 +.. nonce: XyYLlO +.. section: Library + +Fixed a minor performance regression in :func:`threading.Event.__init__` + +.. + +.. date: 2022-08-27-14-38-49 +.. gh-issue: 90467 +.. nonce: VOOB0p +.. section: Library + +Fix :class:`asyncio.streams.StreamReaderProtocol` to keep a strong reference +to the created task, so that it's not garbage collected + +.. + +.. date: 2022-08-23-13-30-30 +.. gh-issue: 96172 +.. nonce: 7WTHer +.. section: Library + +Fix a bug in ``unicodedata``: ``east_asian_width`` used to return the wrong +value for unassigned characters; and for yet unassigned, but reserved +characters. + +.. + +.. date: 2022-08-22-18-42-17 +.. gh-issue: 96159 +.. nonce: 3bFU39 +.. section: Library + +Fix a performance regression in logging TimedRotatingFileHandler. Only check +for special files when the rollover time has passed. + +.. + +.. date: 2022-08-22-13-54-20 +.. gh-issue: 96175 +.. nonce: bH7zGU +.. section: Library + +Fix unused ``localName`` parameter in the ``Attr`` class in +:mod:`xml.dom.minidom`. + +.. + +.. date: 2022-08-20-12-56-15 +.. gh-issue: 96145 +.. nonce: 8ah3pE +.. section: Library + +Add AttrDict to JSON module for use with object_hook. + +.. + +.. date: 2022-08-20-10-31-01 +.. gh-issue: 96052 +.. nonce: a6FhaD +.. section: Library + +Fix handling compiler warnings (SyntaxWarning and DeprecationWarning) in +:func:`codeop.compile_command` when checking for incomplete input. +Previously it emitted warnings and raised a SyntaxError. Now it always +returns ``None`` for incomplete input without emitting any warnings. + +.. + +.. date: 2022-08-19-18-21-01 +.. gh-issue: 96125 +.. nonce: ODcF1Y +.. section: Library + +Fix incorrect condition that causes ``sys.thread_info.name`` to be wrong on +pthread platforms. + +.. + +.. date: 2022-08-19-10-19-32 +.. gh-issue: 96019 +.. nonce: b7uAVP +.. section: Library + +Fix a bug in the ``makeunicodedata.py`` script leading to about 13 KiB of +space saving in the ``unicodedata`` module, specifically the character +decomposition data. + +.. + +.. date: 2022-08-18-14-53-53 +.. gh-issue: 95463 +.. nonce: GpP05c +.. section: Library + +Remove an incompatible change from :issue:`28080` that caused a regression +that ignored the utf8 in ``ZipInfo.flag_bits``. Patch by Pablo Galindo. + +.. + +.. date: 2022-08-14-18-59-54 +.. gh-issue: 69142 +.. nonce: 6is5Pq +.. section: Library + +Add ``%:z`` strftime format code (generates tzoffset with colons as +separator), see :ref:`strftime-strptime-behavior`. + +.. + +.. date: 2022-08-11-18-52-17 +.. gh-issue: 95899 +.. nonce: _Bi4uG +.. section: Library + +Fix :class:`asyncio.Runner` to call :func:`asyncio.set_event_loop` only once +to avoid calling :meth:`~asyncio.AbstractChildWatcher.attach_loop` multiple +times on child watchers. Patch by Kumar Aditya. + +.. + +.. date: 2022-08-11-18-22-29 +.. gh-issue: 95736 +.. nonce: LzRZXe +.. section: Library + +Fix :class:`unittest.IsolatedAsyncioTestCase` to set event loop before +calling setup functions. Patch by Kumar Aditya. + +.. + +.. date: 2022-08-11-03-16-48 +.. gh-issue: 95865 +.. nonce: 0IOkFP +.. section: Library + +Speed up :func:`urllib.parse.quote_from_bytes` by replacing a list +comprehension with ``map()``. + +.. + +.. date: 2022-08-10-17-34-07 +.. gh-issue: 95861 +.. nonce: qv-T5s +.. section: Library + +Add support for computing Spearman's correlation coefficient to the existing +statistics.correlation() function. + +.. + +.. date: 2022-08-10-11-54-04 +.. gh-issue: 95804 +.. nonce: i5FCFK +.. section: Library + +Fix ``logging`` shutdown handler so it respects +``MemoryHandler.flushOnClose``. + +.. + +.. date: 2022-08-08-01-42-11 +.. gh-issue: 95704 +.. nonce: MOPFfX +.. section: Library + +When a task catches :exc:`asyncio.CancelledError` and raises some other +error, the other error should generally not silently be suppressed. + +.. + +.. date: 2022-08-07-14-56-23 +.. gh-issue: 95149 +.. nonce: U0c6Ib +.. section: Library + +The :class:`HTTPStatus ` enum offers a couple of properties +to indicate the HTTP status category e.g. ``HTTPStatus.OK.is_success``. + +.. + +.. date: 2022-08-03-21-01-17 +.. gh-issue: 95609 +.. nonce: xxyjyX +.. section: Library + +Update bundled pip to 22.2.2. + +.. + +.. date: 2022-08-03-16-52-32 +.. gh-issue: 95289 +.. nonce: FMnHlV +.. section: Library + +Fix :class:`asyncio.TaskGroup` to propagate exception when +:exc:`asyncio.CancelledError` was replaced with another exception by a +context manger. Patch by Kumar Aditya and Guido van Rossum. + +.. + +.. date: 2022-07-29-20-58-37 +.. gh-issue: 94909 +.. nonce: YjMusj +.. section: Library + +Fix incorrect joining of relative Windows paths with drives in +:class:`pathlib.PurePath` initializer. + +.. + +.. date: 2022-07-28-17-14-38 +.. gh-issue: 95385 +.. nonce: 6YlsDI +.. section: Library + +Faster ``json.dumps()`` when sorting of keys is not requested (default). + +.. + +.. date: 2022-07-27-19-47-51 +.. gh-issue: 83901 +.. nonce: OSw06c +.. section: Library + +Improve :meth:`Signature.bind ` error message for +missing keyword-only arguments. + +.. + +.. date: 2022-07-27-19-43-07 +.. gh-issue: 95339 +.. nonce: NuVQ68 +.. section: Library + +Update bundled pip to 22.2.1. + +.. + +.. date: 2022-07-27-11-35-45 +.. gh-issue: 95045 +.. nonce: iysT-Q +.. section: Library + +Fix GC crash when deallocating ``_lsprof.Profiler`` by untracking it before +calling any callbacks. Patch by Kumar Aditya. + +.. + +.. date: 2022-07-25-15-45-06 +.. gh-issue: 95231 +.. nonce: i807-g +.. section: Library + +Fail gracefully if :data:`~errno.EPERM` or :data:`~errno.ENOSYS` is raised +when loading :mod:`crypt` methods. This may happen when trying to load +``MD5`` on a Linux kernel with :abbr:`FIPS (Federal Information Processing +Standard)` enabled. + +.. + +.. date: 2022-07-24-18-00-42 +.. gh-issue: 95097 +.. nonce: lu5qNf +.. section: Library + +Fix :func:`asyncio.run` for :class:`asyncio.Task` implementations without +:meth:`~asyncio.Task.uncancel` method. Patch by Kumar Aditya. + +.. + +.. date: 2022-07-24-12-59-02 +.. gh-issue: 95087 +.. nonce: VvqXkN +.. section: Library + +Fix IndexError in parsing invalid date in the :mod:`email` module. + +.. + +.. date: 2022-07-24-12-00-06 +.. gh-issue: 95199 +.. nonce: -5A64k +.. section: Library + +Upgrade bundled setuptools to 63.2.0. + +.. + +.. date: 2022-07-24-09-15-35 +.. gh-issue: 95194 +.. nonce: ERVmqG +.. section: Library + +Upgrade bundled pip to 22.2. + +.. + +.. date: 2022-07-23-10-50-05 +.. gh-issue: 93899 +.. nonce: VT34A5 +.. section: Library + +Fix check for existence of :data:`os.EFD_CLOEXEC`, :data:`os.EFD_NONBLOCK` +and :data:`os.EFD_SEMAPHORE` flags on older kernel versions where these +flags are not present. Patch by Kumar Aditya. + +.. + +.. date: 2022-07-23-10-42-05 +.. gh-issue: 95166 +.. nonce: xw6p3C +.. section: Library + +Fix :meth:`concurrent.futures.Executor.map` to cancel the currently waiting +on future on an error - e.g. TimeoutError or KeyboardInterrupt. + +.. + +.. date: 2022-07-22-21-18-17 +.. gh-issue: 95132 +.. nonce: n9anlw +.. section: Library + +Fix a :mod:`sqlite3` regression where ``*args`` and ``**kwds`` were +incorrectly relayed from :py:func:`~sqlite3.connect` to the +:class:`~sqlite3.Connection` factory. The regression was introduced in +3.11a1 with PR 24421 (:gh:`85128`). Patch by Erlend E. Aasland.` + +.. + +.. date: 2022-07-22-17-19-57 +.. gh-issue: 93157 +.. nonce: RXByAk +.. section: Library + +Fix :mod:`fileinput` module didn't support ``errors`` option when +``inplace`` is true. + +.. + +.. date: 2022-07-22-09-09-08 +.. gh-issue: 91212 +.. nonce: 53O8Ab +.. section: Library + +Fixed flickering of the turtle window when the tracer is turned off. Patch +by Shin-myoung-serp. + +.. + +.. date: 2022-07-22-00-58-49 +.. gh-issue: 95077 +.. nonce: 4Z6CNC +.. section: Library + +Add deprecation warning for enum ``member.member`` access (e.g. +``Color.RED.BLUE``). + +.. + +.. date: 2022-07-21-22-59-22 +.. gh-issue: 95109 +.. nonce: usxA9r +.. section: Library + +Ensure that timeouts scheduled with :class:`asyncio.Timeout` that have +already expired are delivered promptly. + +.. + +.. date: 2022-07-21-19-55-49 +.. gh-issue: 95105 +.. nonce: BIX2Km +.. section: Library + +:meth:`wsgiref.types.InputStream.__iter__` should return +``Iterator[bytes]``, not ``Iterable[bytes]``. Patch by Shantanu Jain. + +.. + +.. date: 2022-07-20-22-49-48 +.. gh-issue: 95066 +.. nonce: TuCu0E +.. section: Library + +Replaced assert with exception in :func:`ast.parse`, when +``feature_version`` has an invalid major version. Patch by Shantanu Jain. + +.. + +.. date: 2022-07-20-00-23-58 +.. gh-issue: 77617 +.. nonce: XGaqSQ +.. section: Library + +Add :mod:`sqlite3` :ref:`command-line interface `. Patch by +Erlend Aasland. + +.. + +.. date: 2022-07-19-15-37-11 +.. gh-issue: 95005 +.. nonce: iRmZ74 +.. section: Library + +Replace :c:expr:`_PyAccu` with :c:expr:`_PyUnicodeWriter` in JSON encoder +and StringIO and remove the :c:expr:`_PyAccu` implementation. + +.. + +.. date: 2022-07-17-22-31-32 +.. gh-issue: 90085 +.. nonce: c4FWcS +.. section: Library + +Remove ``-c/--clock`` and ``-t/--time`` CLI options of :mod:`timeit`. The +options had been deprecated since Python 3.3 and the functionality was +removed in Python 3.7. Patch by Shantanu Jain. + +.. + +.. date: 2022-07-15-08-13-51 +.. gh-issue: 94857 +.. nonce: 9_KvZJ +.. section: Library + +Fix refleak in ``_io.TextIOWrapper.reconfigure``. Patch by Kumar Aditya. + +.. + +.. date: 2022-07-14-00-43-52 +.. gh-issue: 94821 +.. nonce: e17ghU +.. section: Library + +Fix binding of unix socket to empty address on Linux to use an available +address from the abstract namespace, instead of "\0". + +.. + +.. date: 2022-07-11-10-41-48 +.. gh-issue: 94736 +.. nonce: EbsgeK +.. section: Library + +Fix crash when deallocating an instance of a subclass of +``_multiprocessing.SemLock``. Patch by Kumar Aditya. + +.. + +.. date: 2022-07-09-15-17-02 +.. gh-issue: 81620 +.. nonce: L0O_bV +.. section: Library + +Add random.binomialvariate(). + +.. + +.. date: 2022-07-09-08-55-04 +.. gh-issue: 74116 +.. nonce: 0XwYC1 +.. section: Library + +Allow :meth:`asyncio.StreamWriter.drain` to be awaited concurrently by +multiple tasks. Patch by Kumar Aditya. + +.. + +.. date: 2022-07-08-17-49-12 +.. gh-issue: 87822 +.. nonce: F9dzkf +.. section: Library + +When called with ``capture_locals=True``, the :mod:`traceback` module +functions swallow exceptions raised from calls to ``repr()`` on local +variables of frames. This is in order to prioritize the original exception +over rendering errors. An indication of the failure is printed in place of +the missing value. (Patch by Simon-Martin Schroeder). + +.. + +.. date: 2022-07-08-08-39-35 +.. gh-issue: 88050 +.. nonce: 0aOC_m +.. section: Library + +Fix :mod:`asyncio` subprocess transport to kill process cleanly when process +is blocked and avoid ``RuntimeError`` when loop is closed. Patch by Kumar +Aditya. + +.. + +.. date: 2022-07-07-15-46-55 +.. gh-issue: 94637 +.. nonce: IYEiUM +.. section: Library + +:meth:`SSLContext.set_default_verify_paths` now releases the GIL around +``SSL_CTX_set_default_verify_paths`` call. The function call performs I/O +and CPU intensive work. + +.. + +.. date: 2022-07-06-22-41-51 +.. gh-issue: 94309 +.. nonce: _XswsX +.. section: Library + +Deprecate aliases :class:`typing.Hashable` and :class:`typing.Sized` + +.. + +.. date: 2022-07-06-21-24-03 +.. gh-issue: 92546 +.. nonce: s5Upkh +.. section: Library + +An undocumented ``python -m pprint`` benchmark is moved into ``pprint`` +suite of pyperformance. Patch by Oleg Iarygin. + +.. + +.. date: 2022-07-06-16-01-08 +.. gh-issue: 94607 +.. nonce: Q6RYfz +.. section: Library + +Fix subclassing complex generics with type variables in :mod:`typing`. +Previously an error message saying ``Some type variables ... are not listed +in Generic[...]`` was shown. :mod:`typing` no longer populates +``__parameters__`` with the ``__parameters__`` of a Python class. + +.. + +.. date: 2022-07-06-14-57-33 +.. gh-issue: 94619 +.. nonce: PRqKVX +.. section: Library + +Remove the long-deprecated ``module_repr()`` from :mod:`importlib`. + +.. + +.. date: 2022-07-06-14-45-12 +.. gh-issue: 93910 +.. nonce: iZcp67 +.. section: Library + +The ability to access the other values of an enum on an enum (e.g. +``Color.RED.BLUE``) has been restored in order to fix a performance +regression. + +.. + +.. date: 2022-07-06-06-02-02 +.. gh-issue: 93896 +.. nonce: vIgWGr +.. section: Library + +Fix :func:`asyncio.run` and :class:`unittest.IsolatedAsyncioTestCase` to +always the set event loop as it was done in Python 3.10 and earlier. Patch +by Kumar Aditya. + +.. + +.. date: 2022-07-05-17-22-00 +.. gh-issue: 94343 +.. nonce: kf4H5r +.. section: Library + +Allow setting the attributes of ``reprlib.Repr`` during object +initialization + +.. + +.. date: 2022-07-03-16-41-03 +.. gh-issue: 94382 +.. nonce: zuVZeM +.. section: Library + +Port static types of ``_multiprocessing`` module to heap types. Patch by +Kumar Aditya. + +.. + +.. date: 2022-07-03-16-26-35 +.. gh-issue: 78724 +.. nonce: XNiJzf +.. section: Library + +Fix crash in :class:`struct.Struct` when it was not completely initialized +by initializing it in :meth:`~object.__new__``. Patch by Kumar Aditya. + +.. + +.. date: 2022-07-02-19-46-30 +.. gh-issue: 94510 +.. nonce: xOatDC +.. section: Library + +Re-entrant calls to :func:`sys.setprofile` and :func:`sys.settrace` now +raise :exc:`RuntimeError`. Patch by Pablo Galindo. + +.. + +.. date: 2022-06-29-09-48-37 +.. gh-issue: 92336 +.. nonce: otA6c6 +.. section: Library + +Fix bug where :meth:`linecache.getline` fails on bad files with +:exc:`UnicodeDecodeError` or :exc:`SyntaxError`. It now returns an empty +string as per the documentation. + +.. + +.. date: 2022-06-29-04-42-56 +.. gh-issue: 94398 +.. nonce: YOq_bJ +.. section: Library + +Once a :class:`asyncio.TaskGroup` has started shutting down (i.e., at least +one task has failed and the task group has started cancelling the remaining +tasks), it should not be possible to add new tasks to the task group. + +.. + +.. date: 2022-06-28-14-41-22 +.. gh-issue: 94383 +.. nonce: CXnquo +.. section: Library + +:mod:`xml.etree`: Remove the ``ElementTree.Element.copy()`` method of the +pure Python implementation, deprecated in Python 3.10, use the +:func:`copy.copy` function instead. The C implementation of :mod:`xml.etree` +has no ``copy()`` method, only a ``__copy__()`` method. Patch by Victor +Stinner. + +.. + +.. date: 2022-06-28-14-29-21 +.. gh-issue: 94379 +.. nonce: RrgKfh +.. section: Library + +:mod:`zipimport`: Remove ``find_loader()`` and ``find_module()`` methods, +deprecated in Python 3.10: use the ``find_spec()`` method instead. See +:pep:`451` for the rationale. Patch by Victor Stinner. + +.. + +.. date: 2022-06-28-00-24-48 +.. gh-issue: 94352 +.. nonce: JY1Ayt +.. section: Library + +:func:`shlex.split`: Passing ``None`` for *s* argument now raises an +exception, rather than reading :data:`sys.stdin`. The feature was deprecated +in Python 3.9. Patch by Victor Stinner. + +.. + +.. date: 2022-06-27-10-33-18 +.. gh-issue: 94318 +.. nonce: jR4_QV +.. section: Library + +Strip trailing spaces in :mod:`pydoc` text output. + +.. + +.. date: 2022-06-26-10-59-15 +.. gh-issue: 89988 +.. nonce: K8rnmt +.. section: Library + +Fix memory leak in :class:`pickle.Pickler` when looking up +:attr:`dispatch_table`. Patch by Kumar Aditya. + +.. + +.. date: 2022-06-25-23-44-44 +.. gh-issue: 90016 +.. nonce: EB409s +.. section: Library + +Deprecate :mod:`sqlite3` :ref:`default adapters and converters +`. Patch by Erlend E. Aasland. + +.. + +.. date: 2022-06-25-16-27-02 +.. gh-issue: 94254 +.. nonce: beP16v +.. section: Library + +Fixed types of :mod:`struct` module to be immutable. Patch by Kumar Aditya. + +.. + +.. date: 2022-06-25-13-38-53 +.. gh-issue: 93259 +.. nonce: FAGw-2 +.. section: Library + +Now raise ``ValueError`` when ``None`` or an empty string are passed to +``Distribution.from_name`` (and other callers). + +.. + +.. date: 2022-06-25-09-12-23 +.. gh-issue: 74696 +.. nonce: fxC9ua +.. section: Library + +:func:`shutil.make_archive` now passes the *root_dir* argument to custom +archivers which support it. + +.. + +.. date: 2022-06-24-20-00-57 +.. gh-issue: 94216 +.. nonce: hxnQPu +.. section: Library + +The :mod:`dis` module now has the opcodes for pseudo instructions (those +which are used by the compiler during code generation but then removed or +replaced by real opcodes before the final bytecode is emitted). + +.. + +.. date: 2022-06-24-19-40-40 +.. gh-issue: 93096 +.. nonce: 3RlK2d +.. section: Library + +Removed undocumented ``python -m codecs``. Use ``python -m unittest +test.test_codecs.EncodedFileTest`` instead. + +.. + +.. date: 2022-06-24-19-23-59 +.. gh-issue: 94207 +.. nonce: VhS1eS +.. section: Library + +Made :class:`_struct.Struct` GC-tracked in order to fix a reference leak in +the :mod:`_struct` module. + +.. + +.. date: 2022-06-24-19-16-09 +.. gh-issue: 93096 +.. nonce: r1_oIc +.. section: Library + +Removed undocumented ``-t`` argument of ``python -m base64``. Use ``python +-m unittest test.test_base64.LegacyBase64TestCase.test_encodebytes`` +instead. + +.. + +.. date: 2022-06-24-18-20-42 +.. gh-issue: 94226 +.. nonce: 8ZL4Fm +.. section: Library + +Remove the :func:`locale.format` function, deprecated in Python 3.7: use +:func:`locale.format_string` instead. Patch by Victor Stinner. + +.. + +.. date: 2022-06-24-17-11-33 +.. gh-issue: 94199 +.. nonce: 7releN +.. section: Library + +Remove the :func:`ssl.match_hostname` function. The +:func:`ssl.match_hostname` was deprecated in Python 3.7. OpenSSL performs +hostname matching since Python 3.7, Python no longer uses the +:func:`ssl.match_hostname` function. Patch by Victor Stinner. + +.. + +.. date: 2022-06-24-14-25-26 +.. gh-issue: 94214 +.. nonce: 03pXR5 +.. section: Library + +Document the ``context`` object used in the ``venv.EnvBuilder`` class, and +add the new environment's library path to it. + +.. + +.. date: 2022-06-24-10-39-56 +.. gh-issue: 94199 +.. nonce: MIuckY +.. section: Library + +Remove the :func:`ssl.wrap_socket` function, deprecated in Python 3.7: +instead, create a :class:`ssl.SSLContext` object and call its +:class:`ssl.SSLContext.wrap_socket` method. Any package that still uses +:func:`ssl.wrap_socket` is broken and insecure. The function neither sends a +SNI TLS extension nor validates server hostname. Code is subject to `CWE-295 +`_: Improper Certificate +Validation. Patch by Victor Stinner. + +.. + +.. date: 2022-06-24-10-29-19 +.. gh-issue: 94199 +.. nonce: pfehmz +.. section: Library + +Remove the :func:`ssl.RAND_pseudo_bytes` function, deprecated in Python 3.6: +use :func:`os.urandom` or :func:`ssl.RAND_bytes` instead. Patch by Victor +Stinner. + +.. + +.. date: 2022-06-24-10-18-59 +.. gh-issue: 94199 +.. nonce: kYOo8g +.. section: Library + +:mod:`hashlib`: Remove the pure Python implementation of +:func:`hashlib.pbkdf2_hmac()`, deprecated in Python 3.10. Python 3.10 and +newer requires OpenSSL 1.1.1 (:pep:`644`): this OpenSSL version provides a C +implementation of :func:`~hashlib.pbkdf2_hmac()` which is faster. Patch by +Victor Stinner. + +.. + +.. date: 2022-06-24-09-41-41 +.. gh-issue: 94196 +.. nonce: r2KyfS +.. section: Library + +:mod:`gzip`: Remove the ``filename`` attribute of :class:`gzip.GzipFile`, +deprecated since Python 2.6, use the :attr:`~gzip.GzipFile.name` attribute +instead. In write mode, the ``filename`` attribute added ``'.gz'`` file +extension if it was not present. Patch by Victor Stinner. + +.. + +.. date: 2022-06-24-08-49-47 +.. gh-issue: 94182 +.. nonce: Wknau0 +.. section: Library + +run the :class:`asyncio.PidfdChildWatcher` on the running loop, this allows +event loops to run subprocesses when there is no default event loop running +on the main thread + +.. + +.. date: 2022-06-23-14-35-10 +.. gh-issue: 94169 +.. nonce: jeba90 +.. section: Library + +Remove ``io.OpenWrapper`` and ``_pyio.OpenWrapper``, deprecated in Python +3.10: just use :func:`open` instead. The :func:`open` (:func:`io.open`) +function is a built-in function. Since Python 3.10, :func:`_pyio.open` is +also a static method. Patch by Victor Stinner. + +.. + +.. date: 2022-06-23-13-12-05 +.. gh-issue: 91742 +.. nonce: sNytVX +.. section: Library + +Fix :mod:`pdb` crash after jump caused by a null pointer dereference. Patch +by Kumar Aditya. + +.. + +.. date: 2022-06-22-11-16-11 +.. gh-issue: 94101 +.. nonce: V9vDG8 +.. section: Library + +Manual instantiation of :class:`ssl.SSLSession` objects is no longer allowed +as it lead to misconfigured instances that crashed the interpreter when +attributes where accessed on them. + +.. + +.. date: 2022-06-21-11-40-31 +.. gh-issue: 84753 +.. nonce: FW1pxO +.. section: Library + +:func:`inspect.iscoroutinefunction`, :func:`inspect.isgeneratorfunction`, +and :func:`inspect.isasyncgenfunction` now properly return ``True`` for +duck-typed function-like objects like instances of +:class:`unittest.mock.AsyncMock`. + +This makes :func:`inspect.iscoroutinefunction` consistent with the behavior +of :func:`asyncio.iscoroutinefunction`. Patch by Mehdi ABAAKOUK. + +.. + +.. date: 2022-06-20-23-14-43 +.. gh-issue: 94028 +.. nonce: UofEcX +.. section: Library + +Fix a regression in the :mod:`sqlite3` where statement objects were not +properly cleared and reset after use in cursor iters. The regression was +introduced by PR 27884 in Python 3.11a1. Patch by Erlend E. Aasland. + +.. + +.. date: 2022-06-18-15-06-54 +.. gh-issue: 93973 +.. nonce: 4y6UQT +.. section: Library + +Add keyword argument ``all_errors`` to ``asyncio.create_connection`` so that +multiple connection errors can be raised as an ``ExceptionGroup``. + +.. + +.. date: 2022-06-17-16-00-55 +.. gh-issue: 93963 +.. nonce: 8YYZ-2 +.. section: Library + +Officially deprecate from ``importlib.abc`` classes moved to +``importlib.resources.abc``. + +.. + +.. date: 2022-06-17-12-02-30 +.. gh-issue: 93858 +.. nonce: R49ARc +.. section: Library + +Prevent error when activating venv in nested fish instances. + +.. + +.. date: 2022-06-16-11-16-53 +.. gh-issue: 93820 +.. nonce: 00X0Y5 +.. section: Library + +Pickle :class:`enum.Flag` by name. + +.. + +.. date: 2022-06-16-09-24-50 +.. gh-issue: 93847 +.. nonce: kuv8bN +.. section: Library + +Fix repr of enum of generic aliases. + +.. + +.. date: 2022-06-15-21-35-11 +.. gh-issue: 91404 +.. nonce: 39TZzW +.. section: Library + +Revert the :mod:`re` memory leak when a match is terminated by a signal or +memory allocation failure as the implemented fix caused a major performance +regression. + +.. + +.. date: 2022-06-15-21-28-16 +.. gh-issue: 83499 +.. nonce: u3DQJ- +.. section: Library + +Fix double closing of file description in :mod:`tempfile`. + +.. + +.. date: 2022-06-15-21-20-02 +.. gh-issue: 93820 +.. nonce: FAMLY8 +.. section: Library + +Fixed a regression when :func:`copy.copy`-ing :class:`enum.Flag` with +multiple flag members. + +.. + +.. date: 2022-06-11-13-32-17 +.. gh-issue: 79512 +.. nonce: A1KTDr +.. section: Library + +Fixed names and ``__module__`` value of :mod:`weakref` classes +:class:`~weakref.ReferenceType`, :class:`~weakref.ProxyType`, +:class:`~weakref.CallableProxyType`. It makes them pickleable. + +.. + +.. date: 2022-06-09-17-15-26 +.. gh-issue: 91389 +.. nonce: OE4vS5 +.. section: Library + +Fix an issue where :mod:`dis` utilities could report missing or incorrect +position information in the presence of ``CACHE`` entries. + +.. + +.. date: 2022-06-09-14-44-21 +.. gh-issue: 93626 +.. nonce: sfghs46 +.. section: Library + +Set ``__future__.annotations`` to have a ``None`` mandatoryRelease to +indicate that it is currently 'TBD'. + +.. + +.. date: 2022-06-09-10-12-55 +.. gh-issue: 90473 +.. nonce: 683m_C +.. section: Library + +Emscripten and WASI have no home directory and cannot provide :pep:`370` +user site directory. + +.. + +.. date: 2022-06-08-20-11-02 +.. gh-issue: 90494 +.. nonce: LIZT85 +.. section: Library + +:func:`copy.copy` and :func:`copy.deepcopy` now always raise a TypeError if +``__reduce__()`` returns a tuple with length 6 instead of silently ignore +the 6th item or produce incorrect result. + +.. + +.. date: 2022-06-07-14-53-46 +.. gh-issue: 90549 +.. nonce: T4FMKY +.. section: Library + +Fix a multiprocessing bug where a global named resource (such as a +semaphore) could leak when a child process is spawned (as opposed to +forked). + +.. + +.. date: 2022-06-06-13-19-43 +.. gh-issue: 93521 +.. nonce: _vE8m9 +.. section: Library + +Fixed a case where dataclasses would try to add ``__weakref__`` into the +``__slots__`` for a dataclass that specified ``weakref_slot=True`` when it +was already defined in one of its bases. This resulted in a ``TypeError`` +upon the new class being created. + +.. + +.. date: 2022-06-06-12-58-27 +.. gh-issue: 79579 +.. nonce: e8rB-M +.. section: Library + +:mod:`sqlite3` now correctly detects DML queries with leading comments. +Patch by Erlend E. Aasland. + +.. + +.. date: 2022-06-05-22-22-42 +.. gh-issue: 93421 +.. nonce: 43UO_8 +.. section: Library + +Update :data:`sqlite3.Cursor.rowcount` when a DML statement has run to +completion. This fixes the row count for SQL queries like ``UPDATE ... +RETURNING``. Patch by Erlend E. Aasland. + +.. + +.. date: 2022-06-04-00-11-54 +.. gh-issue: 93475 +.. nonce: vffFw1 +.. section: Library + +Expose ``FICLONE`` and ``FICLONERANGE`` constants in :mod:`fcntl`. Patch by +Illia Volochii. + +.. + +.. date: 2022-06-03-22-13-28 +.. gh-issue: 93370 +.. nonce: tjfu9L +.. section: Library + +Deprecate :data:`sqlite3.version` and :data:`sqlite3.version_info`. + +.. + +.. date: 2022-06-02-08-40-58 +.. gh-issue: 91810 +.. nonce: Gtk44w +.. section: Library + +Suppress writing an XML declaration in open files in ``ElementTree.write()`` +with ``encoding='unicode'`` and ``xml_declaration=None``. + +.. + +.. date: 2022-06-01-11-24-13 +.. gh-issue: 91162 +.. nonce: NxvU_u +.. section: Library + +Support splitting of unpacked arbitrary-length tuple over ``TypeVar`` and +``TypeVarTuple`` parameters. For example: + +* ``A[T, *Ts][*tuple[int, ...]]`` -> ``A[int, *tuple[int, ...]]`` +* ``A[*Ts, T][*tuple[int, ...]]`` -> ``A[*tuple[int, ...], int]`` + +.. + +.. date: 2022-05-31-14-58-40 +.. gh-issue: 93353 +.. nonce: 9Hvm6o +.. section: Library + +Fix the :func:`importlib.resources.as_file` context manager to remove the +temporary file if destroyed late during Python finalization: keep a local +reference to the :func:`os.remove` function. Patch by Victor Stinner. + +.. + +.. date: 2022-05-30-21-42-50 +.. gh-issue: 83658 +.. nonce: 01Ntx0 +.. section: Library + +Make :class:`multiprocessing.Pool` raise an exception if +``maxtasksperchild`` is not ``None`` or a positive int. + +.. + +.. date: 2022-05-28-08-02-55 +.. gh-issue: 93312 +.. nonce: HY0Uzj +.. section: Library + +Add :data:`os.PIDFD_NONBLOCK` flag to open a file descriptor for a process +with :func:`os.pidfd_open` in non-blocking mode. Patch by Kumar Aditya. + +.. + +.. date: 2022-05-27-22-17-11 +.. gh-issue: 88123 +.. nonce: mkYl5q +.. section: Library + +Implement Enum __contains__ that returns True or False to replace the +deprecated behaviour that would sometimes raise a TypeError. + +.. + +.. date: 2022-05-27-13-18-18 +.. gh-issue: 93297 +.. nonce: e2zuHz +.. section: Library + +Make asyncio task groups prevent child tasks from being GCed + +.. + +.. date: 2022-05-27-10-52-06 +.. gh-issue: 85308 +.. nonce: K6r-tJ +.. section: Library + +Changed :class:`argparse.ArgumentParser` to use :term:`filesystem encoding +and error handler` instead of default text encoding to read arguments from +file (e.g. ``fromfile_prefix_chars`` option). This change affects Windows; +argument file should be encoded with UTF-8 instead of ANSI Codepage. + +.. + +.. date: 2022-05-26-23-10-55 +.. gh-issue: 93156 +.. nonce: 4XfDVN +.. section: Library + +Accessing the :attr:`pathlib.PurePath.parents` sequence of an absolute path +using negative index values produced incorrect results. + +.. + +.. date: 2022-05-26-09-24-41 +.. gh-issue: 93162 +.. nonce: W1VuhU +.. section: Library + +Add the ability for :func:`logging.config.dictConfig` to usefully configure +:class:`~logging.handlers.QueueHandler` and +:class:`~logging.handlers.QueueListener` as a pair, and add +:func:`logging.getHandlerByName` and :func:`logging.getHandlerNames` APIs to +allow access to handlers by name. + +.. + +.. date: 2022-05-26-08-41-34 +.. gh-issue: 93243 +.. nonce: uw6x5z +.. section: Library + +The :mod:`smtpd` module was removed per the schedule in :pep:`594`. + +.. + +.. date: 2022-05-25-22-09-38 +.. gh-issue: 92886 +.. nonce: ylwDSc +.. section: Library + +Replace ``assert`` statements with ``raise AssertionError()`` in +:class:`~wsgiref.BaseHandler` so that the tested behaviour is maintained +running with optimizations ``(-O)``. + +.. + +.. date: 2022-05-25-15-57-39 +.. gh-issue: 90155 +.. nonce: YMstB5 +.. section: Library + +Fix broken :class:`asyncio.Semaphore` when acquire is cancelled. + +.. + +.. date: 2022-05-25-02-45-41 +.. gh-issue: 90817 +.. nonce: yxANgU +.. section: Library + +The :func:`locale.resetlocale` function is deprecated and will be removed in +Python 3.13. Use ``locale.setlocale(locale.LC_ALL, "")`` instead. Patch by +Victor Stinner. + +.. + +.. date: 2022-05-25-00-21-28 +.. gh-issue: 91513 +.. nonce: 9VyCT4 +.. section: Library + +Added ``taskName`` attribute to :mod:`logging` module for use with +:mod:`asyncio` tasks. + +.. + +.. date: 2022-05-24-11-19-04 +.. gh-issue: 74696 +.. nonce: -cnf-A +.. section: Library + +:func:`shutil.make_archive` no longer temporarily changes the current +working directory during creation of standard ``.zip`` or tar archives. + +.. + +.. date: 2022-05-24-10-59-02 +.. gh-issue: 92728 +.. nonce: zxTifq +.. section: Library + +The :func:`re.template` function and the corresponding :const:`re.TEMPLATE` +and :const:`re.T` flags are restored after they were removed in 3.11.0b1, +but they are now deprecated, so they might be removed from Python 3.13. + +.. + +.. date: 2022-05-22-23-46-18 +.. gh-issue: 93033 +.. nonce: wZfiL- +.. section: Library + +Search in some strings (platform dependent i.e [U+0xFFFF, U+0x0100] on +Windows or [U+0xFFFFFFFF, U+0x00010000] on Linux 64-bit) are now up to 10 +times faster. + +.. + +.. date: 2022-05-22-16-08-01 +.. gh-issue: 89973 +.. nonce: jc-Q4g +.. section: Library + +Fix :exc:`re.error` raised in :mod:`fnmatch` if the pattern contains a +character range with upper bound lower than lower bound (e.g. ``[c-a]``). +Now such ranges are interpreted as empty ranges. + +.. + +.. date: 2022-05-21-13-16-16 +.. gh-issue: 93044 +.. nonce: eJ_XkZ +.. section: Library + +No longer convert the database argument of :func:`sqlite3.connect` to bytes +before passing it to the factory. + +.. + +.. date: 2022-05-20-15-52-43 +.. gh-issue: 93010 +.. nonce: WF-cAc +.. section: Library + +In a very special case, the email package tried to append the nonexistent +``InvalidHeaderError`` to the defect list. It should have been +``InvalidHeaderDefect``. + +.. + +.. date: 2022-05-19-22-34-42 +.. gh-issue: 92986 +.. nonce: e6uKxj +.. section: Library + +Fix :func:`ast.unparse` when ``ImportFrom.level`` is None + +.. + +.. date: 2022-05-19-17-49-58 +.. gh-issue: 92932 +.. nonce: o2peTh +.. section: Library + +Now :func:`~dis.dis` and :func:`~dis.get_instructions` handle operand values +for instructions prefixed by ``EXTENDED_ARG_QUICK``. Patch by Sam Gross and +Dong-hee Na. + +.. + +.. date: 2022-05-19-13-33-18 +.. gh-issue: 92675 +.. nonce: ZeerMZ +.. section: Library + +Fix :func:`venv.ensure_directories` to accept :class:`pathlib.Path` +arguments in addition to :class:`str` paths. Patch by David Foster. + +.. + +.. date: 2022-05-18-21-04-09 +.. gh-issue: 87901 +.. nonce: lnf041 +.. section: Library + +Removed the ``encoding`` argument from :func:`os.popen` that was added in +3.11b1. + +.. + +.. date: 2022-05-18-17-18-41 +.. gh-issue: 91922 +.. nonce: DwWIsJ +.. section: Library + +Fix function :func:`sqlite.connect` and the :class:`sqlite.Connection` +constructor on non-UTF-8 locales. Also, they now support bytes paths +non-decodable with the current FS encoding. + +.. + +.. date: 2022-05-17-06-27-39 +.. gh-issue: 92869 +.. nonce: t8oBkw +.. section: Library + +Added :class:`~ctypes.c_time_t` to :mod:`ctypes`, which has the same size as +the :c:type:`time_t` type in C. + +.. + +.. date: 2022-05-16-14-35-39 +.. gh-issue: 92839 +.. nonce: owSMyo +.. section: Library + +Fixed crash resulting from calling bisect.insort() or bisect.insort_left() +with the key argument not equal to None. + +.. + +.. date: 2022-05-14-11-41-23 +.. gh-issue: 90473 +.. nonce: kPdOZl +.. section: Library + +:mod:`subprocess` now fails early on Emscripten and WASI platforms to work +around missing :func:`os.pipe` on WASI. + +.. + +.. date: 2022-05-14-09-01-38 +.. gh-issue: 89325 +.. nonce: ys-2BZ +.. section: Library + +Removed many old deprecated :mod:`unittest` features: +:class:`~unittest.TestCase` method aliases, undocumented and broken +:class:`~unittest.TestCase` method ``assertDictContainsSubset``, +undocumented :meth:`TestLoader.loadTestsFromModule +` parameter *use_load_tests*, and +an underscored alias of the :class:`~unittest.TextTestResult` class. + +.. + +.. date: 2022-05-12-15-19-00 +.. gh-issue: 92734 +.. nonce: d0wjDt +.. section: Library + +Allow multi-element reprs emitted by :mod:`reprlib` to be pretty-printed +using configurable indentation. + +.. + +.. date: 2022-05-11-19-33-27 +.. gh-issue: 92671 +.. nonce: KE4v6a +.. section: Library + +Fixed :func:`ast.unparse` for empty tuples in the assignment target context. + +.. + +.. date: 2022-05-11-14-34-09 +.. gh-issue: 91581 +.. nonce: glkou2 +.. section: Library + +:meth:`~datetime.datetime.utcfromtimestamp` no longer attempts to resolve +``fold`` in the pure Python implementation, since the fold is never 1 in +UTC. In addition to being slightly faster in the common case, this also +prevents some errors when the timestamp is close to :attr:`datetime.min +`. Patch by Paul Ganssle. + +.. + +.. date: 2022-05-11-10-06-31 +.. gh-issue: 86388 +.. nonce: 7ivUtT +.. section: Library + +Removed randrange() functionality deprecated since Python 3.10. Formerly, +randrange(10.0) losslessly converted to randrange(10). Now, it raises a +TypeError. Also, the exception raised for non-integral values such as +randrange(10.5) or randrange('10') has been changed from ValueError to +TypeError. + +.. + +.. date: 2022-05-10-16-30-40 +.. gh-issue: 90385 +.. nonce: 1_wBRQ +.. section: Library + +Add :meth:`pathlib.Path.walk` as an alternative to :func:`os.walk`. + +.. + +.. date: 2022-05-10-07-57-27 +.. gh-issue: 92550 +.. nonce: Rk_UzM +.. section: Library + +Fix :meth:`pathlib.Path.rglob` for empty pattern. + +.. + +.. date: 2022-05-09-22-27-11 +.. gh-issue: 92591 +.. nonce: V7RCk2 +.. section: Library + +Allow :mod:`logging` filters to return a :class:`logging.LogRecord` instance +so that filters attached to :class:`logging.Handler`\ s can enrich records +without side effects on other handlers. + +.. + +.. date: 2022-05-09-21-31-41 +.. gh-issue: 92445 +.. nonce: tJosdm +.. section: Library + +Fix a bug in :mod:`argparse` where ``nargs="*"`` would raise an error +instead of returning an empty list when 0 arguments were supplied if choice +was also defined in ``parser.add_argument``. + +.. + +.. date: 2022-05-09-11-55-04 +.. gh-issue: 92547 +.. nonce: CzVZft +.. section: Library + +Remove undocumented :mod:`sqlite3` features deprecated in Python 3.10: + +* ``sqlite3.enable_shared_cache()`` +* ``sqlite3.OptimizedUnicode`` + +Patch by Erlend E. Aasland. + +.. + +.. date: 2022-05-09-09-28-02 +.. gh-issue: 92530 +.. nonce: M4Q1RS +.. section: Library + +Fix an issue that occurred after interrupting +:func:`threading.Condition.notify`. + +.. + +.. date: 2022-05-09-01-27-25 +.. gh-issue: 92531 +.. nonce: vV7S_O +.. section: Library + +The statistics.median_grouped() function now always return a float. +Formerly, it did not convert the input type when for sequences of length +one. + +.. + +.. date: 2022-05-08-19-21-14 +.. gh-issue: 84131 +.. nonce: rG5kI7 +.. section: Library + +The :class:`pathlib.Path` deprecated method ``link_to`` has been removed. +Use 3.10's :meth:`~pathlib.Path.hardlink_to` method instead as its semantics +are consistent with that of :meth:`~pathlib.Path.symlink_to`. + +.. + +.. date: 2022-05-08-18-51-14 +.. gh-issue: 89336 +.. nonce: TL6ip7 +.. section: Library + +Removed :mod:`configparser` module APIs: the ``SafeConfigParser`` class +alias, the ``ParsingError.filename`` property and parameter, and the +``ConfigParser.readfp`` method, all of which were deprecated since Python +3.2. + +.. + +.. date: 2022-05-06-13-00-57 +.. gh-issue: 92391 +.. nonce: s-Lase +.. section: Library + +Add :meth:`~object.__class_getitem__` to :class:`csv.DictReader` and +:class:`csv.DictWriter`, allowing them to be parameterized at runtime. Patch +by Marc Mueller. + +.. + +.. date: 2022-04-26-18-37-24 +.. gh-issue: 91968 +.. nonce: fuuH1_ +.. section: Library + +Add ``SO_RTABLE`` and ``SO_USER_COOKIE`` constants to :mod:`socket`. + +.. + +.. date: 2022-04-25-10-23-01 +.. gh-issue: 91810 +.. nonce: DOHa6B +.. section: Library + +:class:`~xml.etree.ElementTree.ElementTree` method +:meth:`~xml.etree.ElementTree.ElementTree.write` and function +:func:`~xml.etree.ElementTree.tostring` now use the text file's encoding +("UTF-8" if not available) instead of locale encoding in XML declaration +when ``encoding="unicode"`` is specified. + +.. + +.. date: 2022-04-24-22-26-45 +.. gh-issue: 81790 +.. nonce: M5Rvpm +.. section: Library + +:func:`os.path.splitdrive` now understands DOS device paths with UNC links +(beginning ``\\?\UNC\``). Contributed by Barney Gale. + +.. + +.. date: 2022-04-21-19-14-29 +.. gh-issue: 91760 +.. nonce: 54AR-m +.. section: Library + +Apply more strict rules for numerical group references and group names in +regular expressions. Only sequence of ASCII digits is now accepted as a +numerical reference. The group name in bytes patterns and replacement +strings can now only contain ASCII letters and digits and underscore. + +.. + +.. date: 2022-04-15-22-07-36 +.. gh-issue: 90622 +.. nonce: 0C6l8h +.. section: Library + +Worker processes for :class:`concurrent.futures.ProcessPoolExecutor` are no +longer spawned on demand (a feature added in 3.9) when the multiprocessing +context start method is ``"fork"`` as that can lead to deadlocks in the +child processes due to a fork happening while threads are running. + +.. + +.. date: 2022-04-15-17-38-55 +.. gh-issue: 91577 +.. nonce: Ah7cLL +.. section: Library + +Move imports in :class:`~multiprocessing.SharedMemory` methods to module +level so that they can be executed late in python finalization. + +.. + +.. date: 2022-04-15-13-16-25 +.. gh-issue: 91581 +.. nonce: 9OGsrN +.. section: Library + +Remove an unhandled error case in the C implementation of calls to +:meth:`datetime.fromtimestamp ` with no +time zone (i.e. getting a local time from an epoch timestamp). This should +have no user-facing effect other than giving a possibly more accurate error +message when called with timestamps that fall on 10000-01-01 in the local +time. Patch by Paul Ganssle. + +.. + +.. date: 2022-04-15-11-29-38 +.. gh-issue: 91539 +.. nonce: 7WgVuA +.. section: Library + +Improve performance of ``urllib.request.getproxies_environment`` when there +are many environment variables + +.. + +.. date: 2022-04-14-08-37-16 +.. gh-issue: 91524 +.. nonce: g8PiIu +.. section: Library + +Speed up the regular expression substitution (functions :func:`re.sub` and +:func:`re.subn` and corresponding :class:`re.Pattern` methods) for +replacement strings containing group references by 2--3 times. + +.. + +.. date: 2022-04-12-18-05-40 +.. gh-issue: 91447 +.. nonce: N_Fs4H +.. section: Library + +Fix findtext in the xml module to only give an empty string when the text +attribute is set to None. + +.. + +.. date: 2022-04-11-16-55-41 +.. gh-issue: 91456 +.. nonce: DK3KKl +.. section: Library + +Deprecate current default auto() behavior: In 3.13 the default will be for +for auto() to always return the largest member value incremented by 1, and +to raise if incompatible value types are used. + +.. + +.. bpo: 47231 +.. date: 2022-04-08-22-12-11 +.. nonce: lvyglt +.. section: Library + +Fixed an issue with inconsistent trailing slashes in tarfile longname +directories. + +.. + +.. bpo: 39064 +.. date: 2022-04-03-19-40-09 +.. nonce: 76PbIz +.. section: Library + +:class:`zipfile.ZipFile` now raises :exc:`zipfile.BadZipFile` instead of +``ValueError`` when reading a corrupt zip file in which the central +directory offset is negative. + +.. + +.. bpo: 41287 +.. date: 2022-04-03-11-25-02 +.. nonce: 8CTdwf +.. section: Library + +Fix handling of the ``doc`` argument in subclasses of :func:`property`. + +.. + +.. date: 2022-04-01-12-35-44 +.. gh-issue: 90005 +.. nonce: pvaLHQ +.. section: Library + +:mod:`ctypes` dependency ``libffi`` is now detected with ``pkg-config``. + +.. + +.. bpo: 32547 +.. date: 2022-04-01-09-43-54 +.. nonce: NIUiNC +.. section: Library + +The constructors for :class:`~csv.DictWriter` and :class:`~csv.DictReader` +now coerce the ``fieldnames`` argument to a :class:`list` if it is an +iterator. + +.. + +.. bpo: 35540 +.. date: 2022-03-22-18-28-55 +.. nonce: nyijX9 +.. section: Library + +Fix :func:`dataclasses.asdict` crash when :class:`collections.defaultdict` +is present in the attributes. + +.. + +.. bpo: 47063 +.. date: 2022-03-19-04-41-42 +.. nonce: nwRfUo +.. section: Library + +Add an index_pages parameter to support using non-default index page names. + +.. + +.. bpo: 47025 +.. date: 2022-03-16-14-24-14 +.. nonce: qtT3CE +.. section: Library + +Drop support for :class:`bytes` on :attr:`sys.path`. + +.. + +.. bpo: 46951 +.. date: 2022-03-08-04-46-44 +.. nonce: SWAz97 +.. section: Library + +Order the contents of zipapp archives, to make builds more reproducible. + +.. + +.. bpo: 42777 +.. date: 2022-02-21-01-37-00 +.. nonce: nWK3E6 +.. section: Library + +Implement :meth:`pathlib.Path.is_mount` for Windows paths. + +.. + +.. bpo: 46755 +.. date: 2022-02-15-12-40-48 +.. nonce: zePJfx +.. section: Library + +In :class:`QueueHandler`, clear ``stack_info`` from :class:`LogRecord` to +prevent stack trace from being written twice. + +.. + +.. bpo: 45393 +.. date: 2022-02-09-23-44-27 +.. nonce: 9v5Y8U +.. section: Library + +Fix the formatting for ``await x`` and ``not x`` in the operator precedence +table when using the :func:`help` system. + +.. + +.. bpo: 46642 +.. date: 2022-02-05-18-46-54 +.. nonce: YI6nHQ +.. section: Library + +Improve error message when trying to subclass an instance of +:data:`typing.TypeVar`, :data:`typing.ParamSpec`, +:data:`typing.TypeVarTuple`, etc. Based on patch by Gregory Beauregard. + +.. + +.. bpo: 46364 +.. date: 2022-01-14-10-49-20 +.. nonce: SzhlU9 +.. section: Library + +Restrict use of sockets instead of pipes for stdin of subprocesses created +by :mod:`asyncio` to AIX platform only. + +.. + +.. bpo: 28249 +.. date: 2022-01-09-14-23-00 +.. nonce: 4dzB80 +.. section: Library + +Set :attr:`doctest.DocTest.lineno` to ``None`` when object does not have +:attr:`__doc__`. + +.. + +.. bpo: 46197 +.. date: 2022-01-03-15-07-06 +.. nonce: Z0djv6 +.. section: Library + +Fix :mod:`ensurepip` environment isolation for subprocess running ``pip``. + +.. + +.. bpo: 45924 +.. date: 2021-12-27-15-32-15 +.. nonce: 0ZpHX2 +.. section: Library + +Fix :mod:`asyncio` incorrect traceback when future's exception is raised +multiple times. Patch by Kumar Aditya. + +.. + +.. bpo: 45046 +.. date: 2021-08-29-19-59-16 +.. nonce: eGq0NC +.. section: Library + +Add support of context managers in :mod:`unittest`: methods +:meth:`~unittest.TestCase.enterContext` and +:meth:`~unittest.TestCase.enterClassContext` of class +:class:`~unittest.TestCase`, method +:meth:`~unittest.IsolatedAsyncioTestCase.enterAsyncContext` of class +:class:`~unittest.IsolatedAsyncioTestCase` and function +:func:`unittest.enterModuleContext`. + +.. + +.. bpo: 44173 +.. date: 2021-08-27-18-07-35 +.. nonce: oW92Ev +.. section: Library + +Enable fast seeking of uncompressed unencrypted :class:`zipfile.ZipExtFile` + +.. + +.. bpo: 42627 +.. date: 2021-05-22-07-58-59 +.. nonce: EejtD0 +.. section: Library + +Fix incorrect parsing of Windows registry proxy settings + +.. + +.. bpo: 42047 +.. date: 2020-10-15-18-37-12 +.. nonce: XDdoSF +.. section: Library + +Add :func:`threading.get_native_id` support for DragonFly BSD. Patch by +David Carlier. + +.. + +.. bpo: 14243 +.. date: 2020-09-28-04-56-04 +.. nonce: YECnxv +.. section: Library + +The :class:`tempfile.NamedTemporaryFile` function has a new optional +parameter *delete_on_close* + +.. + +.. bpo: 41246 +.. date: 2020-07-08-20-32-13 +.. nonce: 2trYf3 +.. section: Library + +Give the same callback function for when the overlapped operation is done to +the functions ``recv``, ``recv_into``, ``recvfrom``, ``sendto``, ``send`` +and ``sendfile`` inside ``IocpProactor``. + +.. + +.. bpo: 39264 +.. date: 2020-01-09-01-57-12 +.. nonce: GsBL9- +.. section: Library + +Fixed :meth:`collections.UserDict.get` to not call :meth:`__missing__` when +a value is not found. This matches the behavior of :class:`dict`. Patch by +Bar Harel. + +.. + +.. bpo: 38693 +.. date: 2019-11-04-22-21-27 +.. nonce: w_OAov +.. section: Library + +:mod:`importlib` now uses f-strings internally instead of ``str.format``. + +.. + +.. bpo: 38267 +.. date: 2019-09-25-00-37-51 +.. nonce: X9Jb5V +.. section: Library + +Add *timeout* parameter to :meth:`asyncio.loop.shutdown_default_executor`. +The default value is ``None``, which means the executor will be given an +unlimited amount of time. When called from :class:`asyncio.Runner` or +:func:`asyncio.run`, the default timeout is 5 minutes. + +.. + +.. bpo: 34828 +.. date: 2018-09-28-22-18-03 +.. nonce: 5Zyi_S +.. section: Library + +:meth:`sqlite3.Connection.iterdump` now handles databases that use +``AUTOINCREMENT`` in one or more tables. + +.. + +.. bpo: 32990 +.. date: 2018-09-23-07-47-29 +.. nonce: 2FVVTU +.. section: Library + +Support reading wave files with the ``WAVE_FORMAT_EXTENSIBLE`` format in the +:mod:`wave` module. + +.. + +.. bpo: 26253 +.. date: 2017-07-31-13-35-28 +.. nonce: 8v_sCs +.. section: Library + +Allow adjustable compression level for tarfile streams in +:func:`tarfile.open`. + +.. + +.. date: 2022-10-16-17-34-45 +.. gh-issue: 85525 +.. nonce: DvkD0v +.. section: Documentation + +Remove extra row + +.. + +.. date: 2022-10-11-09-40-50 +.. gh-issue: 86404 +.. nonce: dEAb8W +.. section: Documentation + +Deprecated tools ``make suspicious`` and ``rstlint.py`` are now removed. +They have been replaced by `spinx-lint +`_. + +.. + +.. date: 2022-10-02-10-58-52 +.. gh-issue: 97741 +.. nonce: 39l023 +.. section: Documentation + +Fix ``!`` in c domain ref target syntax via a ``conf.py`` patch, so it works +as intended to disable ref target resolution. + +.. + +.. date: 2022-09-01-17-03-04 +.. gh-issue: 96432 +.. nonce: 1EJ1-4 +.. section: Documentation + +Fraction literals now support whitespace around the forward slash, +``Fraction('2 / 3')``. + +.. + +.. date: 2022-08-19-17-07-45 +.. gh-issue: 96098 +.. nonce: nDp43u +.. section: Documentation + +Improve discoverability of the higher level concurrent.futures module by +providing clearer links from the lower level threading and multiprocessing +modules. + +.. + +.. date: 2022-08-13-20-34-51 +.. gh-issue: 95957 +.. nonce: W9ZZAx +.. section: Documentation + +What's New 3.11 now has instructions for how to provide compiler and linker +flags for Tcl/Tk and OpenSSL on RHEL 7 and CentOS 7. + +.. + +.. date: 2022-08-12-01-12-52 +.. gh-issue: 95588 +.. nonce: PA0FI7 +.. section: Documentation + +Clarified the conflicting advice given in the :mod:`ast` documentation about +:func:`ast.literal_eval` being "safe" for use on untrusted input while at +the same time warning that it can crash the process. The latter statement is +true and is deemed unfixable without a large amount of work unsuitable for a +bugfix. So we keep the warning and no longer claim that ``literal_eval`` is +safe. + +.. + +.. date: 2022-08-03-13-35-08 +.. gh-issue: 91207 +.. nonce: eJ4pPf +.. section: Documentation + +Fix stylesheet not working in Windows CHM htmlhelp docs and add warning that +they are deprecated. Contributed by C.A.M. Gerlach. + +.. + +.. date: 2022-07-30-00-23-11 +.. gh-issue: 95454 +.. nonce: we7AFm +.. section: Documentation + +Replaced incorrectly written true/false values in documentiation. Patch by +Robert O'Shea + +.. + +.. date: 2022-07-29-23-02-19 +.. gh-issue: 95451 +.. nonce: -tgB93 +.. section: Documentation + +Update library documentation with :ref:`availability information +` on WebAssembly platforms ``wasm32-emscripten`` and +``wasm32-wasi``. + +.. + +.. date: 2022-07-29-09-04-02 +.. gh-issue: 95415 +.. nonce: LKTyw6 +.. section: Documentation + +Use consistent syntax for platform availability. The directive now supports +a content body and emits a warning when it encounters an unknown platform. + +.. + +.. date: 2022-07-07-08-42-05 +.. gh-issue: 94321 +.. nonce: pmCIPb +.. section: Documentation + +Document the :pep:`246` style protocol type +:class:`sqlite3.PrepareProtocol`. + +.. + +.. date: 2022-06-19-18-18-22 +.. gh-issue: 86128 +.. nonce: 39DDTD +.. section: Documentation + +Document a limitation in ThreadPoolExecutor where its exit handler is +executed before any handlers in atexit. + +.. + +.. date: 2022-06-16-10-10-59 +.. gh-issue: 61162 +.. nonce: 1ypkG8 +.. section: Documentation + +Clarify :mod:`sqlite3` behavior when +:ref:`sqlite3-connection-context-manager`. + +.. + +.. date: 2022-06-15-12-12-49 +.. gh-issue: 87260 +.. nonce: epyI7D +.. section: Documentation + +Align :mod:`sqlite3` argument specs with the actual implementation. + +.. + +.. date: 2022-05-29-21-22-54 +.. gh-issue: 86986 +.. nonce: lFXw8j +.. section: Documentation + +The minimum Sphinx version required to build the documentation is now 3.2. + +.. + +.. date: 2022-05-26-14-51-25 +.. gh-issue: 88831 +.. nonce: 5Cccr5 +.. section: Documentation + +Augmented documentation of asyncio.create_task(). Clarified the need to keep +strong references to tasks and added a code snippet detailing how to to +this. + +.. + +.. date: 2022-05-26-11-33-23 +.. gh-issue: 86438 +.. nonce: kEGGmK +.. section: Documentation + +Clarify that :option:`-W` and :envvar:`PYTHONWARNINGS` are matched literally +and case-insensitively, rather than as regular expressions, in +:mod:`warnings`. + +.. + +.. date: 2022-05-20-18-42-10 +.. gh-issue: 93031 +.. nonce: c2RdJe +.. section: Documentation + +Update tutorial introduction output to use 3.10+ SyntaxError invalid range. + +.. + +.. date: 2022-05-18-23-58-26 +.. gh-issue: 92240 +.. nonce: bHvYiz +.. section: Documentation + +Added release dates for "What's New in Python 3.X" for 3.0, 3.1, 3.2, 3.8 +and 3.10 + +.. + +.. bpo: 47161 +.. date: 2022-03-30-17-56-01 +.. nonce: gesHfS +.. section: Documentation + +Document that :class:`pathlib.PurePath` does not collapse initial double +slashes because they denote UNC paths. + +.. + +.. bpo: 40838 +.. date: 2022-01-13-16-03-15 +.. nonce: k3NVCf +.. section: Documentation + +Document that :func:`inspect.getdoc`, :func:`inspect.getmodule`, and +:func:`inspect.getsourcefile` might return ``None``. + +.. + +.. bpo: 43689 +.. date: 2021-04-01-08-09-34 +.. nonce: mqCfLe +.. section: Documentation + +The ``Differ`` documentation now also mentions other whitespace characters, +which make it harder to understand the diff output. + +.. + +.. bpo: 38056 +.. date: 2019-09-12-08-28-17 +.. nonce: 6ktYkc +.. section: Documentation + +Overhaul the :ref:`error-handlers` documentation in :mod:`codecs`. + +.. + +.. bpo: 13553 +.. date: 2017-12-10-19-13-39 +.. nonce: gQbZs4 +.. section: Documentation + +Document tkinter.Tk args. + +.. + +.. date: 2022-10-20-17-49-50 +.. gh-issue: 95027 +.. nonce: viRpJB +.. section: Tests + +On Windows, when the Python test suite is run with the ``-jN`` option, the +ANSI code page is now used as the encoding for the stdout temporary file, +rather than using UTF-8 which can lead to decoding errors. Patch by Victor +Stinner. + +.. + +.. date: 2022-09-08-18-31-26 +.. gh-issue: 96624 +.. nonce: 5cANM1 +.. section: Tests + +Fixed the failure of repeated runs of ``test.test_unittest`` caused by side +effects in ``test_dotted_but_module_not_loaded``. + +.. + +.. date: 2022-08-22-14-59-42 +.. gh-issue: 95243 +.. nonce: DeD66V +.. section: Tests + +Mitigate the inherent race condition from using find_unused_port() in +testSockName() by trying to find an unused port a few times before failing. +Patch by Ross Burton. + +.. + +.. date: 2022-08-05-09-57-43 +.. gh-issue: 95573 +.. nonce: edMdQB +.. section: Tests + +:source:`Lib/test/test_asyncio/test_ssl.py` exposed a bug in the macOS +kernel where intense concurrent load on non-blocking sockets occasionally +causes :const:`errno.ENOBUFS` ("No buffer space available") to be emitted. +FB11063974 filed with Apple, in the mean time as a workaround buffer size +used in tests on macOS is decreased to avoid intermittent failures. Patch +by Fantix King. + +.. + +.. date: 2022-07-26-15-22-19 +.. gh-issue: 95280 +.. nonce: h8HvbP +.. section: Tests + +Fix problem with ``test_ssl`` ``test_get_ciphers`` on systems that require +perfect forward secrecy (PFS) ciphers. + +.. + +.. date: 2022-07-24-20-19-05 +.. gh-issue: 95212 +.. nonce: fHiU4e +.. section: Tests + +Make multiprocessing test case ``test_shared_memory_recreate`` +parallel-safe. + +.. + +.. date: 2022-07-24-17-24-42 +.. gh-issue: 95218 +.. nonce: zfBLtu +.. section: Tests + +Move tests for importlib.resources into test_importlib.resources. + +.. + +.. date: 2022-07-24-16-28-31 +.. gh-issue: 93963 +.. nonce: UB9azu +.. section: Tests + +Updated tests to use preferred location for ``importlib.resources`` ABCs. + +.. + +.. date: 2022-07-08-12-22-00 +.. gh-issue: 94675 +.. nonce: IiTs5f +.. section: Tests + +Add a regression test for :mod:`re` exponentional slowdown when using +rjsmin. + +.. + +.. date: 2022-07-05-17-53-13 +.. gh-issue: 91330 +.. nonce: Qys5IL +.. section: Tests + +Added more tests for :mod:`dataclasses` to cover behavior with data +descriptor-based fields. + +.. + +.. date: 2022-06-27-21-27-20 +.. gh-issue: 94208 +.. nonce: VR6HX- +.. section: Tests + +``test_ssl`` is now checking for supported TLS version and protocols in more +tests. + +.. + +.. date: 2022-06-27-08-53-40 +.. gh-issue: 94315 +.. nonce: MoZT9t +.. section: Tests + +Tests now check for DAC override capability instead of relying on +:func:`os.geteuid`. + +.. + +.. date: 2022-06-21-17-37-46 +.. gh-issue: 54781 +.. nonce: BjVAVg +.. section: Tests + +Rename test_tk to test_tkinter, and rename test_ttk_guionly to test_ttk. +Patch by Victor Stinner. + +.. + +.. date: 2022-06-20-23-04-52 +.. gh-issue: 93839 +.. nonce: OE3Ybk +.. section: Tests + +Move ``Lib/ctypes/test/`` to ``Lib/test/test_ctypes/``. Patch by Victor +Stinner. + +.. + +.. date: 2022-06-17-15-20-09 +.. gh-issue: 93951 +.. nonce: CW1Vv4 +.. section: Tests + +In test_bdb.StateTestCase.test_skip, avoid including auxiliary importers. + +.. + +.. date: 2022-06-17-13-55-11 +.. gh-issue: 93957 +.. nonce: X4ovYV +.. section: Tests + +Provide nicer error reporting from subprocesses in +test_venv.EnsurePipTest.test_with_pip. + +.. + +.. date: 2022-06-17-13-27-21 +.. gh-issue: 93884 +.. nonce: 5pvPvl +.. section: Tests + +Add test cases for :c:func:`PyNumber_ToBase` that take a large number or a +non-int object as parameter. + +.. + +.. date: 2022-06-16-21-38-18 +.. gh-issue: 93852 +.. nonce: U_Hl6s +.. section: Tests + +test_asyncio, test_logging, test_socket and test_socketserver now create +AF_UNIX domains in the current directory to no longer fail with +``OSError("AF_UNIX path too long")`` if the temporary directory (the +:envvar:`TMPDIR` environment variable) is too long. Patch by Victor Stinner. + +.. + +.. date: 2022-06-16-17-50-58 +.. gh-issue: 93353 +.. nonce: JdpATx +.. section: Tests + +regrtest now checks if a test leaks temporary files or directories if run +with -jN option. Patch by Victor Stinner. + +.. + +.. date: 2022-06-10-21-18-14 +.. gh-issue: 84461 +.. nonce: 9TAb26 +.. section: Tests + +``run_tests.py`` now handles cross compiling env vars correctly and pass +``HOSTRUNNER`` to regression tests. + +.. + +.. date: 2022-06-08-22-32-56 +.. gh-issue: 93616 +.. nonce: e5Kkx2 +.. section: Tests + +``test_modulefinder`` now creates a temporary directory in +``ModuleFinderTest.setUp()`` instead of module scope. + +.. + +.. date: 2022-06-08-14-17-59 +.. gh-issue: 93575 +.. nonce: Xb2LNB +.. section: Tests + +Fix issue with test_unicode test_raiseMemError. The test case now use +``test.support.calcobjsize`` to calculate size of PyUnicode structs. +:func:`sys.getsizeof` may return different size when string has UTF-8 +memory. + +.. + +.. date: 2022-06-05-10-16-45 +.. gh-issue: 90473 +.. nonce: QMu7A8 +.. section: Tests + +WASI does not have a ``chmod(2)`` syscall. :func:`os.chmod` is now a dummy +function on WASI. Skip all tests that depend on working :func:`os.chmod`. + +.. + +.. date: 2022-06-04-12-05-31 +.. gh-issue: 90473 +.. nonce: RSpjF7 +.. section: Tests + +Skip tests on WASI that require symlinks with absolute paths. + +.. + +.. date: 2022-06-03-16-26-04 +.. gh-issue: 57539 +.. nonce: HxWgYO +.. section: Tests + +Increase calendar test coverage for +:meth:`calendar.LocaleTextCalendar.formatweekday`. + +.. + +.. date: 2022-06-03-14-18-37 +.. gh-issue: 90473 +.. nonce: 7iXVRK +.. section: Tests + +Skip symlink tests on WASI. wasmtime uses ``openat2(2)`` with +``RESOLVE_BENEATH`` flag, which prevents symlinks with absolute paths. + +.. + +.. date: 2022-06-03-12-22-44 +.. gh-issue: 89858 +.. nonce: ftBvjE +.. section: Tests + +Fix ``test_embed`` for out-of-tree builds. Patch by Kumar Aditya. + +.. + +.. date: 2022-05-25-23-07-15 +.. gh-issue: 92886 +.. nonce: Aki63_ +.. section: Tests + +Fixing tests that fail when running with optimizations (``-O``) in +``test_imaplib.py``. + +.. + +.. date: 2022-05-25-23-00-35 +.. gh-issue: 92886 +.. nonce: Y-vrWj +.. section: Tests + +Fixing tests that fail when running with optimizations (``-O``) in +``test_zipimport.py`` + +.. + +.. date: 2022-05-25-22-53-30 +.. gh-issue: 92886 +.. nonce: mIfdtz +.. section: Tests + +Fixing tests that fail when running with optimizations (``-O``) in +``test_py_compile.py`` + +.. + +.. date: 2022-05-25-22-43-11 +.. gh-issue: 92886 +.. nonce: 9HQb9e +.. section: Tests + +Fixing tests that fail when running with optimizations (``-O``) in +``test_sys_settrace.py``. + +.. + +.. date: 2022-05-25-22-34-10 +.. gh-issue: 92886 +.. nonce: 1Lkt8S +.. section: Tests + +Fixing tests that fail when running with optimizations (``-O``) in +``_test_multiprocessing.py`` + +.. + +.. date: 2022-05-12-05-51-06 +.. gh-issue: 92670 +.. nonce: 7L43Z_ +.. section: Tests + +Skip ``test_shutil.TestCopy.test_copyfile_nonexistent_dir`` test on AIX as +the test uses a trailing slash to force the OS consider the path as a +directory, but on AIX the trailing slash has no effect and is considered as +a file. + +.. + +.. date: 2022-05-08-15-40-41 +.. gh-issue: 92514 +.. nonce: Xbf5JY +.. section: Tests + +Remove unused ``test.support.BasicTestRunner``. Patch by Jelle Zijlstra. + +.. + +.. bpo: 47016 +.. date: 2022-03-14-23-28-17 +.. nonce: K-t2QX +.. section: Tests + +Create a GitHub Actions workflow for verifying bundled pip and setuptools. +Patch by Illia Volochii and Adam Turner. + +.. + +.. date: 2022-09-20-12-43-44 +.. gh-issue: 96761 +.. nonce: IF29kR +.. section: Build + +Fix the build process of clang compiler for :program:`_bootstrap_python` if +LTO optimization is applied. Patch by Matthias G?rgens and Dong-hee Na. + +.. + +.. date: 2022-09-17-11-19-24 +.. gh-issue: 96883 +.. nonce: p_gr62 +.. section: Build + +``wasm32-emscripten`` builds for browsers now include +:mod:`concurrent.futures` for :mod:`asyncio` and :mod:`unittest.mock`. + +.. + +.. date: 2022-09-12-18-34-51 +.. gh-issue: 85936 +.. nonce: tX4VCU +.. section: Build + +CPython now uses the ThinLTO option as the default policy if the Clang +compiler accepts the flag. Patch by Dong-hee Na. + +.. + +.. date: 2022-09-11-14-23-49 +.. gh-issue: 96729 +.. nonce: W4uBWL +.. section: Build + +Ensure that Windows releases built with ``Tools\msi\buildrelease.bat`` are +upgradable to and from official Python releases. + +.. + +.. date: 2022-08-26-11-50-03 +.. gh-issue: 96269 +.. nonce: x_J5h0 +.. section: Build + +Shared module targets now depend on new ``MODULE_DEPS`` variable, which +includes ``EXPORTSYMS``. This fixes a build order issue on unsupported AIX +platform. + +.. + +.. date: 2022-08-26-11-09-11 +.. gh-issue: 84461 +.. nonce: Nsdn_R +.. section: Build + +``wasm32-emscripten`` platform no longer builds :mod:`resource` module, +:func:`~os.getresuid`, :func:`~os.getresgid`, and their setters. The APIs +are stubs and not functional. + +.. + +.. date: 2022-08-15-10-56-07 +.. gh-issue: 95973 +.. nonce: Bsswsc +.. section: Build + +Add a new ``--with-dsymutil`` configure option to to link debug information +in macOS. Patch by Pablo Galindo. + +.. + +.. date: 2022-08-12-13-06-03 +.. gh-issue: 90536 +.. nonce: qMpF6p +.. section: Build + +Use the BOLT post-link optimizer to improve performance, particularly on +medium-to-large applications. + +.. + +.. date: 2022-08-04-15-29-35 +.. gh-issue: 93744 +.. nonce: svRuqm +.. section: Build + +Remove the ``configure --with-cxx-main`` build option: it didn't work for +many years. Remove the ``MAINCC`` variable from ``configure`` and +``Makefile``. Patch by Victor Stinner. + +.. + +.. date: 2022-07-26-18-13-34 +.. gh-issue: 94801 +.. nonce: 9fREfy +.. section: Build + +Fix a regression in ``configure`` script that caused some header checks to +ignore custom ``CPPFLAGS``. The regression was introduced in :gh:`94802`. + +.. + +.. date: 2022-07-25-09-48-43 +.. gh-issue: 95145 +.. nonce: ZNS3dj +.. section: Build + +wasm32-wasi builds no longer depend on WASIX's pthread stubs. Python now has +its own stubbed pthread API. + +.. + +.. date: 2022-07-25-08-59-35 +.. gh-issue: 95174 +.. nonce: g8woUW +.. section: Build + +Python now detects missing ``dup`` function in WASI and works around some +missing :mod:`errno`, :mod:`select`, and :mod:`socket` constants. + +.. + +.. date: 2022-07-23-21-39-09 +.. gh-issue: 95174 +.. nonce: 7cYMZR +.. section: Build + +Python now skips missing :mod:`socket` functions and methods on WASI. WASI +can only create sockets from existing fd / accept and has no netdb. + +.. + +.. date: 2022-07-21-09-17-01 +.. gh-issue: 95085 +.. nonce: E9x2S_ +.. section: Build + +Platforms ``wasm32-unknown-emscripten`` and ``wasm32-unknown-wasi`` have +been promoted to :pep:`11` tier 3 platform support. + +.. + +.. date: 2022-07-14-11-13-26 +.. gh-issue: 94847 +.. nonce: s3Kr5p +.. section: Build + +Fixed ``_decimal`` module build issue on GCC when compiling with LTO and +pydebug. Debug builds no longer force inlining of functions. + +.. + +.. date: 2022-07-14-02-45-44 +.. gh-issue: 94841 +.. nonce: lLRTdf +.. section: Build + +Fix the possible performance regression of :c:func:`PyObject_Free` compiled +with MSVC version 1932. + +.. + +.. date: 2022-07-13-10-13-10 +.. gh-issue: 94801 +.. nonce: 3xUB24 +.. section: Build + +``configure`` now uses custom flags like ``ZLIB_CFLAGS`` and ``ZLIB_LIBS`` +when searching for headers and libraries. + +.. + +.. date: 2022-07-12-13-39-18 +.. gh-issue: 94773 +.. nonce: koHKm5 +.. section: Build + +``deepfreeze.py`` now supports code object with frozensets that contain +incompatible, unsortable types. + +.. + +.. date: 2022-07-08-10-28-23 +.. gh-issue: 94682 +.. nonce: ZtGt_0 +.. section: Build + +Build and test with OpenSSL 1.1.1q + +.. + +.. date: 2022-06-30-17-18-23 +.. gh-issue: 90005 +.. nonce: EIOOla +.. section: Build + +Dependencies of :mod:`readline` and :mod:`curses` module are now detected in +``configure`` script with ``pkg-config``. Only ``ncurses`` / ``ncursesw`` +are detected automatically. The old ``curses`` library is not configured +automatically. Workaround for missing ``termcap`` or ``tinfo`` library has +been removed. + +.. + +.. date: 2022-06-30-17-00-54 +.. gh-issue: 90005 +.. nonce: iiq5qD +.. section: Build + +Fix building ``_ctypes`` extension without ``pkg-config``. + +.. + +.. date: 2022-06-30-09-57-39 +.. gh-issue: 90005 +.. nonce: 9-pQyR +.. section: Build + +``_dbm`` module dependencies are now detected by configure. + +.. + +.. date: 2022-06-29-08-58-31 +.. gh-issue: 94404 +.. nonce: 3MadM6 +.. section: Build + +``makesetup`` now works around an issue with sed on macOS and uses correct +CFLAGS for object files that end up in a shared extension. Module CFLAGS are +used before PY_STDMODULE_CFLAGS to avoid clashes with system headers. + +.. + +.. date: 2022-06-28-09-42-10 +.. gh-issue: 93939 +.. nonce: _VWxKW +.. section: Build + +C extension modules are now built by ``configure`` and ``make`` instead of +``distutils`` and ``setup.py``. + +.. + +.. date: 2022-06-27-11-57-15 +.. gh-issue: 93939 +.. nonce: rv7s8W +.. section: Build + +The ``2to3``, ``idle``, and ``pydoc`` scripts are now generated and +installed by ``Makefile`` instead of ``setup.py``. + +.. + +.. date: 2022-06-25-23-25-47 +.. gh-issue: 94280 +.. nonce: YhEyW_ +.. section: Build + +Updated pegen regeneration script on Windows to find and use Python 3.9 or +higher. Prior to this, pegen regeneration already required 3.9 or higher, +but the script may have used lower versions of Python. + +.. + +.. date: 2022-06-08-14-28-03 +.. gh-issue: 93584 +.. nonce: 0xfHOK +.. section: Build + +Address race condition in ``Makefile`` when installing a PGO build. All +``test`` and ``install`` targets now depend on ``all`` target. + +.. + +.. date: 2022-06-04-12-53-53 +.. gh-issue: 93491 +.. nonce: ehM211 +.. section: Build + +``configure`` now detects and reports :pep:`11` support tiers. + +.. + +.. date: 2022-05-31-18-04-58 +.. gh-issue: 69093 +.. nonce: 6lSa0C +.. section: Build + +Fix ``Modules/Setup.stdlib.in`` rule for ``_sqlite3`` extension. + +.. + +.. date: 2022-05-25-13-56-00 +.. gh-issue: 93207 +.. nonce: B9Rubf +.. section: Build + +``va_start()`` with two parameters, like ``va_start(args, format),`` is now +required to build Python. ``va_start()`` is no longer called with a single +parameter. Patch by Kumar Aditya. + +.. + +.. date: 2022-05-25-05-46-00 +.. gh-issue: 93202 +.. nonce: T37jtj +.. section: Build + +Python now always use the ``%zu`` and ``%zd`` printf formats to format a +``size_t`` or ``Py_ssize_t`` number. Building Python 3.12 requires a C11 +compiler, so these printf formats are now always supported. Patch by Victor +Stinner. + +.. + +.. date: 2022-05-12-10-19-15 +.. gh-issue: 90473 +.. nonce: -syvqK +.. section: Build + +Disable pymalloc and increase stack size on ``wasm32-wasi``. + +.. + +.. bpo: 34449 +.. date: 2018-08-21-11-10-18 +.. nonce: Z3qm3c +.. section: Build + +Drop invalid compiler switch ``-fPIC`` for HP aCC on HP-UX. Patch by Michael +Osipov. + +.. + +.. date: 2022-10-19-20-00-28 +.. gh-issue: 98360 +.. nonce: O2m6YG +.. section: Windows + +Fixes :mod:`multiprocessing` spawning child processes on Windows from a +virtual environment to ensure that child processes that also use +:mod:`multiprocessing` to spawn more children will recognize that they are +in a virtual environment. + +.. + +.. date: 2022-10-19-19-35-37 +.. gh-issue: 98414 +.. nonce: FbHZuS +.. section: Windows + +Fix :file:`py.exe` launcher handling of ``-V:/`` option when +default preferences have been set in environment variables or configuration +files. + +.. + +.. date: 2022-10-02-11-59-23 +.. gh-issue: 97728 +.. nonce: dIdlPE +.. section: Windows + +Fix possible crashes caused by the use of uninitialized variables when pass +invalid arguments in :func:`os.system` on Windows and in Windows-specific +modules (like ``winreg``). + +.. + +.. date: 2022-09-29-23-08-49 +.. gh-issue: 90989 +.. nonce: no89Q2 +.. section: Windows + +Made :ref:`launcher` install per-user by default (unless an all users +install already exists), and clarify some text in the installer. + +.. + +.. date: 2022-09-29-22-27-04 +.. gh-issue: 97649 +.. nonce: bI7OQU +.. section: Windows + +The ``Tools`` directory is no longer installed on Windows + +.. + +.. date: 2022-09-23-15-40-04 +.. gh-issue: 96965 +.. nonce: CsnEGs +.. section: Windows + +Update libffi to 3.4.3 + +.. + +.. date: 2022-09-07-00-11-33 +.. gh-issue: 96577 +.. nonce: kV4K_1 +.. section: Windows + +Fixes a potential buffer overrun in :mod:`msilib`. + +.. + +.. date: 2022-09-05-18-32-47 +.. gh-issue: 96559 +.. nonce: 561sUd +.. section: Windows + +Fixes the Windows launcher not using the compatible interpretation of +default tags found in configuration files when no tag was passed to the +command. + +.. + +.. date: 2022-08-30-12-01-51 +.. gh-issue: 94781 +.. nonce: OxO-Gr +.. section: Windows + +Fix :file:`pcbuild.proj` to clean previous instances of output files in +``Python\deepfreeze`` and ``Python\frozen_modules`` directories on Windows. +Patch by Charlie Zhao. + +.. + +.. date: 2022-08-26-00-11-18 +.. gh-issue: 89545 +.. nonce: zmJMY_ +.. section: Windows + +Updates :mod:`platform` code getting the Windows version to use native +Windows Management Instrumentation (WMI) queries to determine OS version, +type, and architecture. + +.. + +.. date: 2022-08-10-22-46-48 +.. gh-issue: 95733 +.. nonce: 2_urOp +.. section: Windows + +Make certain requirements of the Windows Store package optional to allow +installing on earlier updates of Windows. + +.. + +.. date: 2022-08-04-18-47-54 +.. gh-issue: 95656 +.. nonce: VJ1d13 +.. section: Windows + +Enable the :meth:`~sqlite3.Connection.enable_load_extension` :mod:`sqlite3` +API. + +.. + +.. date: 2022-08-04-01-12-27 +.. gh-issue: 95587 +.. nonce: Fvdv5q +.. section: Windows + +Fixes some issues where the Windows installer would incorrectly detect +certain features of an existing install when upgrading. + +.. + +.. date: 2022-08-03-00-49-46 +.. gh-issue: 94399 +.. nonce: KvxHc0 +.. section: Windows + +Restores the behaviour of :ref:`launcher` for ``/usr/bin/env`` shebang +lines, which will now search :envvar:`PATH` for an executable matching the +given command. If none is found, the usual search process is used. + +.. + +.. date: 2022-07-30-14-18-33 +.. gh-issue: 95445 +.. nonce: mjrTaq +.. section: Windows + +Fixes the unsuccessful removal of the HTML document directory when +uninstalling with Windows msi. + +.. + +.. date: 2022-07-28-20-21-38 +.. gh-issue: 95359 +.. nonce: ywMrgu +.. section: Windows + +Fix :ref:`launcher` handling of :file:`py.ini` commands (it was incorrectly +expecting a ``py_`` prefix on keys) and crashes when reading per-user +configuration file. + +.. + +.. date: 2022-07-26-20-33-12 +.. gh-issue: 95285 +.. nonce: w6fa22 +.. section: Windows + +Fix :ref:`launcher` handling of command lines where it is only passed a +short executable name. + +.. + +.. date: 2022-07-16-16-18-32 +.. gh-issue: 90844 +.. nonce: vwITT3 +.. section: Windows + +Allow virtual environments to correctly launch when they have spaces in the +path. + +.. + +.. date: 2022-07-12-20-45-43 +.. gh-issue: 94772 +.. nonce: uNMmdG +.. section: Windows + +Fix incorrect handling of shebang lines in py.exe launcher + +.. + +.. date: 2022-06-20-22-32-14 +.. gh-issue: 94018 +.. nonce: bycC3A +.. section: Windows + +:mod:`zipfile` will now remove trailing spaces from path components when +extracting files on Windows. + +.. + +.. date: 2022-06-15-01-03-52 +.. gh-issue: 93824 +.. nonce: mR4mxu +.. section: Windows + +Drag and drop of files onto Python files in Windows Explorer has been +enabled for Windows ARM64. + +.. + +.. date: 2022-05-28-19-36-13 +.. gh-issue: 43414 +.. nonce: NGMJ3g +.. section: Windows + +:func:`os.get_terminal_size` now attempts to read the size from any provided +handle, rather than only supporting file descriptors 0, 1 and 2. + +.. + +.. date: 2022-05-19-21-44-25 +.. gh-issue: 92817 +.. nonce: Jrf-Kv +.. section: Windows + +Ensures that :file:`py.exe` will prefer an active virtual environment over +default tags specified with environment variables or through a +:file:`py.ini` file. + +.. + +.. date: 2022-05-19-14-01-30 +.. gh-issue: 92984 +.. nonce: Dsxnlr +.. section: Windows + +Explicitly disable incremental linking for non-Debug builds + +.. + +.. date: 2022-05-16-11-45-06 +.. gh-issue: 92841 +.. nonce: NQx107 +.. section: Windows + +:mod:`asyncio` no longer throws ``RuntimeError: Event loop is closed`` on +interpreter exit after asynchronous socket activity. Patch by Oleg Iarygin. + +.. + +.. bpo: 46907 +.. date: 2022-05-05-06-27-59 +.. nonce: IW-uvT +.. section: Windows + +Update Windows installer to use SQLite 3.38.4. + +.. + +.. date: 2022-04-12-18-35-20 +.. gh-issue: 91061 +.. nonce: x40hSK +.. section: Windows + +Accept os.PathLike for the argument to winsound.PlaySound + +.. + +.. bpo: 42658 +.. date: 2022-03-20-15-47-35 +.. nonce: 16eXtb +.. section: Windows + +Support native Windows case-insensitive path comparisons by using +``LCMapStringEx`` instead of :func:`str.lower` in :func:`ntpath.normcase`. +Add ``LCMapStringEx`` to the :mod:`_winapi` module. + +.. + +.. bpo: 38704 +.. date: 2020-01-10-23-33-03 +.. nonce: 2Idtdn +.. section: Windows + +Prevent installation on unsupported Windows versions. + +.. + +.. date: 2022-10-05-15-26-58 +.. gh-issue: 97897 +.. nonce: Rf-C6u +.. section: macOS + +The macOS 13 SDK includes support for the ``mkfifoat`` and ``mknodat`` +system calls. Using the ``dir_fd`` option with either :func:`os.mkfifo` or +:func:`os.mknod` could result in a segfault if cpython is built with the +macOS 13 SDK but run on an earlier version of macOS. Prevent this by adding +runtime support for detection of these system calls ("weaklinking") as is +done for other newer syscalls on macOS. + +.. + +.. date: 2022-10-15-21-20-40 +.. gh-issue: 97527 +.. nonce: otAHJM +.. section: IDLE + +Fix a bug in the previous bugfix that caused IDLE to not start when run with +3.10.8, 3.12.0a1, and at least Microsoft Python 3.10.2288.0 installed +without the Lib/test package. 3.11.0 was never affected. + +.. + +.. date: 2022-08-04-20-07-51 +.. gh-issue: 65802 +.. nonce: xnThWe +.. section: IDLE + +Document handling of extensions in Save As dialogs. + +.. + +.. date: 2022-08-01-23-31-48 +.. gh-issue: 95191 +.. nonce: U7vryB +.. section: IDLE + +Include prompts when saving Shell (interactive input and output). + +.. + +.. date: 2022-07-31-22-15-14 +.. gh-issue: 95511 +.. nonce: WX6PmB +.. section: IDLE + +Fix the Shell context menu copy-with-prompts bug of copying an extra line +when one selects whole lines. + +.. + +.. date: 2022-07-30-15-10-39 +.. gh-issue: 95471 +.. nonce: z3scVG +.. section: IDLE + +In the Edit menu, move ``Select All`` and add a new separator. + +.. + +.. date: 2022-07-29-11-08-52 +.. gh-issue: 95411 +.. nonce: dazlqH +.. section: IDLE + +Enable using IDLE's module browser with .pyw files. + +.. + +.. date: 2022-07-28-18-56-57 +.. gh-issue: 89610 +.. nonce: hcosiM +.. section: IDLE + +Add .pyi as a recognized extension for IDLE on macOS. This allows opening +stub files by double clicking on them in the Finder. + +.. + +.. date: 2022-10-07-22-06-11 +.. gh-issue: 68686 +.. nonce: 6KNIQ4 +.. section: Tools/Demos + +Remove ptags and eptags scripts. + +.. + +.. date: 2022-09-30-18-35-11 +.. gh-issue: 97681 +.. nonce: -KO1Ba +.. section: Tools/Demos + +Remove the ``Tools/demo/`` directory which contained old demo scripts. A +copy can be found in the `old-demos project +`_. Patch by Victor Stinner. + +.. + +.. date: 2022-09-30-14-30-12 +.. gh-issue: 97669 +.. nonce: gvbgcg +.. section: Tools/Demos + +Remove outdated example scripts of the ``Tools/scripts/`` directory. A copy +can be found in the `old-demos project +`_. Patch by Victor Stinner. + +.. + +.. date: 2022-08-29-17-25-13 +.. gh-issue: 95853 +.. nonce: Ce17cT +.. section: Tools/Demos + +The ``wasm_build.py`` script now pre-builds Emscripten ports, checks for +broken EMSDK versions, and warns about pkg-config env vars. + +.. + +.. date: 2022-08-10-17-08-43 +.. gh-issue: 95853 +.. nonce: HCjC2m +.. section: Tools/Demos + +The new tool ``Tools/wasm/wasm_builder.py`` automates configure, compile, +and test steps for building CPython on WebAssembly platforms. + +.. + +.. date: 2022-08-05-23-25-59 +.. gh-issue: 95731 +.. nonce: N2KohU +.. section: Tools/Demos + +Fix handling of module docstrings in :file:`Tools/i18n/pygettext.py`. + +.. + +.. date: 2022-07-04-10-02-02 +.. gh-issue: 93939 +.. nonce: U6sW6H +.. section: Tools/Demos + +Add script ``Tools/scripts/check_modules.py`` to check and validate builtin +and shared extension modules. The script also handles ``Modules/Setup`` and +will eventually replace ``setup.py``. + +.. + +.. date: 2022-07-04-01-37-42 +.. gh-issue: 94538 +.. nonce: 1rgy1Y +.. section: Tools/Demos + +Fix Argument Clinic output to custom file destinations. Patch by Erlend E. +Aasland. + +.. + +.. date: 2022-06-29-22-47-11 +.. gh-issue: 94430 +.. nonce: hdov8L +.. section: Tools/Demos + +Allow parameters named ``module`` and ``self`` with custom C names in +Argument Clinic. Patch by Erlend E. Aasland + +.. + +.. date: 2022-06-19-14-56-33 +.. gh-issue: 86087 +.. nonce: R8MkRy +.. section: Tools/Demos + +The ``Tools/scripts/parseentities.py`` script used to parse HTML4 entities +has been removed. + +.. + +.. date: 2022-10-18-16-16-27 +.. gh-issue: 98393 +.. nonce: 55u4BF +.. section: C API + +The :c:func:`PyUnicode_FSDecoder` function no longer accepts bytes-like +paths, like :class:`bytearray` and :class:`memoryview` types: only the exact +:class:`bytes` type is accepted for bytes strings. Patch by Victor Stinner. + +.. + +.. date: 2022-10-05-10-43-32 +.. gh-issue: 91051 +.. nonce: ODDRsQ +.. section: C API + +Add :c:func:`PyType_Watch` and related APIs to allow callbacks on +:c:func:`PyType_Modified`. + +.. + +.. date: 2022-10-03-20-33-24 +.. gh-issue: 95756 +.. nonce: SSmXlG +.. section: C API + +Lazily create and cache ``co_`` attributes for better performance for code +getters. + +.. + +.. date: 2022-09-20-01-04-57 +.. gh-issue: 96512 +.. nonce: msZTjF +.. section: C API + +Configuration for the :ref:`integer string conversion length limitation +` now lives in the PyConfig C API struct. + +.. + +.. date: 2022-08-16-16-54-42 +.. gh-issue: 95589 +.. nonce: 6xE1ar +.. section: C API + +Extensions classes that set ``tp_dictoffset`` and ``tp_weaklistoffset`` lose +the support for multiple inheritance, but are now safe. Extension classes +should use :const:`Py_TPFLAGS_MANAGED_DICT` and +:const:`Py_TPFLAGS_MANAGED_WEAKREF` instead. + +.. + +.. date: 2022-08-08-14-36-31 +.. gh-issue: 95781 +.. nonce: W_G8YW +.. section: C API + +An unrecognized format character in :c:func:`PyUnicode_FromFormat` and +:c:func:`PyUnicode_FromFormatV` now sets a :exc:`SystemError`. In previous +versions it caused all the rest of the format string to be copied as-is to +the result string, and any extra arguments discarded. + +.. + +.. date: 2022-08-03-14-39-08 +.. gh-issue: 92678 +.. nonce: ozFTEx +.. section: C API + +Restore the 3.10 behavior for multiple inheritance of C extension classes +that store their dictionary at the end of the struct. + +.. + +.. date: 2022-08-03-13-01-57 +.. gh-issue: 92678 +.. nonce: DLwONN +.. section: C API + +Support C extensions using managed dictionaries by setting the +``Py_TPFLAGS_MANAGED_DICT`` flag. + +.. + +.. date: 2022-08-01-16-21-39 +.. gh-issue: 93274 +.. nonce: QoDHEu +.. section: C API + +API for implementing vectorcall (:c:data:`Py_TPFLAGS_HAVE_VECTORCALL`, +:c:func:`PyVectorcall_NARGS` and :c:func:`PyVectorcall_Call`) was added to +the limited API and stable ABI. + +.. + +.. date: 2022-07-31-21-58-27 +.. gh-issue: 95504 +.. nonce: wy7B1F +.. section: C API + +Fix sign placement when specifying width or precision in +:c:func:`PyUnicode_FromFormat` and :c:func:`PyUnicode_FromFormatV`. Patch by +Philip Georgi. + +.. + +.. date: 2022-07-29-15-24-45 +.. gh-issue: 93012 +.. nonce: -DdGEy +.. section: C API + +The :const:`Py_TPFLAGS_HAVE_VECTORCALL` flag is now removed from a class +when the class's :py:meth:`~object.__call__` method is reassigned. This +makes vectorcall safe to use with mutable types (i.e. heap types without the +:const:`immutable ` flag). Mutable types that do +not override :c:member:`~PyTypeObject.tp_call` now inherit the +:const:`Py_TPFLAGS_HAVE_VECTORCALL` flag. + +.. + +.. date: 2022-07-29-10-41-59 +.. gh-issue: 95388 +.. nonce: aiRSgr +.. section: C API + +Creating :c:data:`immutable types ` with mutable +bases is deprecated and is planned to be disabled in Python 3.14. + +.. + +.. date: 2022-07-25-15-54-27 +.. gh-issue: 92678 +.. nonce: ziZpxz +.. section: C API + +Adds unstable C-API functions ``_PyObject_VisitManagedDict`` and +``_PyObject_ClearManagedDict`` to allow C extensions to allow the VM to +manage their object's dictionaries. + +.. + +.. date: 2022-07-19-22-37-40 +.. gh-issue: 94936 +.. nonce: LGlmKv +.. section: C API + +Added :c:func:`PyCode_GetVarnames`, :c:func:`PyCode_GetCellvars` and +:c:func:`PyCode_GetFreevars` for accessing ``co_varnames``, ``co_cellvars`` +and ``co_freevars`` respectively via the C API. + +.. + +.. date: 2022-07-17-18-21-40 +.. gh-issue: 94930 +.. nonce: gPFGDL +.. section: C API + +Fix ``SystemError`` raised when :c:func:`PyArg_ParseTupleAndKeywords` is +used with ``#`` in ``(...)`` but without ``PY_SSIZE_T_CLEAN`` defined. + +.. + +.. date: 2022-07-12-17-39-32 +.. gh-issue: 94731 +.. nonce: 9CPJNU +.. section: C API + +Python again uses C-style casts for most casting operations when compiled +with C++. This may trigger compiler warnings, if they are enabled with e.g. +``-Wold-style-cast`` or ``-Wzero-as-null-pointer-constant`` options for +``g++``. + +.. + +.. date: 2022-06-17-13-41-38 +.. gh-issue: 93937 +.. nonce: uKVTEh +.. section: C API + +The following frame functions and type are now directly available with +``#include ``, it's no longer needed to add ``#include +``: + +* :c:func:`PyFrame_Check` +* :c:func:`PyFrame_GetBack` +* :c:func:`PyFrame_GetBuiltins` +* :c:func:`PyFrame_GetGenerator` +* :c:func:`PyFrame_GetGlobals` +* :c:func:`PyFrame_GetLasti` +* :c:func:`PyFrame_GetLocals` +* :c:type:`PyFrame_Type` + +Patch by Victor Stinner. + +.. + +.. date: 2022-06-13-21-37-31 +.. gh-issue: 91321 +.. nonce: DgJFvS +.. section: C API + +Fix the compatibility of the Python C API with C++ older than C++11. Patch +by Victor Stinner. + +.. + +.. date: 2022-06-10-23-41-48 +.. gh-issue: 91731 +.. nonce: fhYUQG +.. section: C API + +Avoid defining the ``static_assert`` when compiling with C++ 11, where this +is a keyword and redefining it can lead to undefined behavior. Patch by +Pablo Galindo + +.. + +.. date: 2022-06-10-16-50-27 +.. gh-issue: 89546 +.. nonce: mX1f10 +.. section: C API + +:c:func:`PyType_FromMetaclass` (and other ``PyType_From*`` functions) now +check that offsets and the base class's +:c:member:`~PyTypeObject.tp_basicsize` fit in the new class's +``tp_basicsize``. + +.. + +.. date: 2022-06-06-16-04-14 +.. gh-issue: 93503 +.. nonce: MHJTu8 +.. section: C API + +Add two new public functions to the public C-API, +:c:func:`PyEval_SetProfileAllThreads` and +:c:func:`PyEval_SetTraceAllThreads`, that allow to set tracing and profiling +functions in all running threads in addition to the calling one. Also, two +analogous functions to the :mod:`threading` module +(:func:`threading.setprofile_all_threads` and +:func:`threading.settrace_all_threads`) that allow to do the same from +Python. Patch by Pablo Galindo + +.. + +.. date: 2022-06-04-13-15-41 +.. gh-issue: 93442 +.. nonce: 4M4NDb +.. section: C API + +Add C++ overloads for _Py_CAST_impl() to handle 0/NULL. This will allow C++ +extensions that pass 0 or NULL to macros using _Py_CAST() to continue to +compile. + +.. + +.. date: 2022-06-03-14-54-41 +.. gh-issue: 93466 +.. nonce: DDtH0X +.. section: C API + +Slot IDs in PyType_Spec may not be repeated. The documentation was updated +to mention this. For some cases of repeated slots, PyType_FromSpec and +related functions will now raise an exception. + +.. + +.. date: 2022-05-23-15-22-18 +.. gh-issue: 92898 +.. nonce: Qjc9d3 +.. section: C API + +Fix C++ compiler warnings when casting function arguments to ``PyObject*``. +Patch by Serge Guelton. + +.. + +.. date: 2022-05-23-13-33-18 +.. gh-issue: 93103 +.. nonce: ooD3Eb +.. section: C API + +Deprecate global configuration variables, like +:c:var:`Py_IgnoreEnvironmentFlag`, in the documentation: the +:c:func:`Py_InitializeFromConfig` API should be instead. Patch by Victor +Stinner. + +.. + +.. date: 2022-05-23-12-31-04 +.. gh-issue: 77782 +.. nonce: ugC8dn +.. section: C API + +Deprecate global configuration variable like +:c:var:`Py_IgnoreEnvironmentFlag`: the :c:func:`Py_InitializeFromConfig` API +should be instead. Patch by Victor Stinner. + +.. + +.. date: 2022-05-19-18-05-51 +.. gh-issue: 92913 +.. nonce: Ass1Hv +.. section: C API + +Ensures changes to :c:member:`PyConfig.module_search_paths` are ignored +unless :c:member:`PyConfig.module_search_paths_set` is set + +.. + +.. date: 2022-05-13-18-17-48 +.. gh-issue: 92781 +.. nonce: TVDr3- +.. section: C API + +Avoid mixing declarations and code in the C API to fix the compiler warning: +"ISO C90 forbids mixed declarations and code" +[-Werror=declaration-after-statement]. Patch by Victor Stinner. + +.. + +.. date: 2022-05-11-02-33-10 +.. gh-issue: 92651 +.. nonce: FIXLf0 +.. section: C API + +Remove the ``token.h`` header file. There was never any public tokenizer C +API. The ``token.h`` header file was only designed to be used by Python +internals. Patch by Victor Stinner. + +.. + +.. date: 2022-05-10-12-35-42 +.. gh-issue: 92536 +.. nonce: cAoRCZ +.. section: C API + +Remove legacy Unicode APIs based on ``Py_UNICODE*``. + +.. + +.. date: 2022-05-09-23-16-38 +.. gh-issue: 85858 +.. nonce: VIcNDL +.. section: C API + +Remove the ``PyUnicode_InternImmortal()`` function and the +``SSTATE_INTERNED_IMMORTAL`` macro. Patch by Victor Stinner. + +.. + +.. date: 2022-05-03-19-35-37 +.. gh-issue: 92193 +.. nonce: 61VoFL +.. section: C API + +Add new function :c:func:`PyFunction_SetVectorcall` to the C API which sets +the vectorcall field of a given :c:type:`PyFunctionObject`. + +Warning: extensions using this API must preserve the behavior of the +unaltered function! + +.. + +.. date: 2022-04-13-16-10-55 +.. gh-issue: 59121 +.. nonce: -B7mKp +.. section: C API + +Fixed an assert that prevented ``PyRun_InteractiveOne`` from providing +tracebacks when parsing from the provided FD. + +.. + +.. bpo: 45383 +.. date: 2021-10-05-21-59-43 +.. nonce: TVClgf +.. section: C API + +The :c:func:`PyType_FromSpec` API will now find and use a metaclass based on +the provided bases. An error will be raised if there is a metaclass +conflict. diff --git a/Misc/NEWS.d/next/Build/2018-08-21-11-10-18.bpo-34449.Z3qm3c.rst b/Misc/NEWS.d/next/Build/2018-08-21-11-10-18.bpo-34449.Z3qm3c.rst deleted file mode 100644 index 53b75aee9cc2..000000000000 --- a/Misc/NEWS.d/next/Build/2018-08-21-11-10-18.bpo-34449.Z3qm3c.rst +++ /dev/null @@ -1 +0,0 @@ -Drop invalid compiler switch ``-fPIC`` for HP aCC on HP-UX. Patch by Michael Osipov. diff --git a/Misc/NEWS.d/next/Build/2022-05-12-10-19-15.gh-issue-90473.-syvqK.rst b/Misc/NEWS.d/next/Build/2022-05-12-10-19-15.gh-issue-90473.-syvqK.rst deleted file mode 100644 index 29ce3de1f213..000000000000 --- a/Misc/NEWS.d/next/Build/2022-05-12-10-19-15.gh-issue-90473.-syvqK.rst +++ /dev/null @@ -1 +0,0 @@ -Disable pymalloc and increase stack size on ``wasm32-wasi``. diff --git a/Misc/NEWS.d/next/Build/2022-05-25-05-46-00.gh-issue-93202.T37jtj.rst b/Misc/NEWS.d/next/Build/2022-05-25-05-46-00.gh-issue-93202.T37jtj.rst deleted file mode 100644 index 6018e400c15d..000000000000 --- a/Misc/NEWS.d/next/Build/2022-05-25-05-46-00.gh-issue-93202.T37jtj.rst +++ /dev/null @@ -1,4 +0,0 @@ -Python now always use the ``%zu`` and ``%zd`` printf formats to format a -``size_t`` or ``Py_ssize_t`` number. Building Python 3.12 requires a C11 -compiler, so these printf formats are now always supported. Patch by Victor -Stinner. diff --git a/Misc/NEWS.d/next/Build/2022-05-25-13-56-00.gh-issue-93207.B9Rubf.rst b/Misc/NEWS.d/next/Build/2022-05-25-13-56-00.gh-issue-93207.B9Rubf.rst deleted file mode 100644 index cd462bb232f0..000000000000 --- a/Misc/NEWS.d/next/Build/2022-05-25-13-56-00.gh-issue-93207.B9Rubf.rst +++ /dev/null @@ -1,3 +0,0 @@ -``va_start()`` with two parameters, like ``va_start(args, format),`` -is now required to build Python. ``va_start()`` is no longer called with a single parameter. -Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Build/2022-05-31-18-04-58.gh-issue-69093.6lSa0C.rst b/Misc/NEWS.d/next/Build/2022-05-31-18-04-58.gh-issue-69093.6lSa0C.rst deleted file mode 100644 index b061d6c2186c..000000000000 --- a/Misc/NEWS.d/next/Build/2022-05-31-18-04-58.gh-issue-69093.6lSa0C.rst +++ /dev/null @@ -1 +0,0 @@ -Fix ``Modules/Setup.stdlib.in`` rule for ``_sqlite3`` extension. diff --git a/Misc/NEWS.d/next/Build/2022-06-04-12-53-53.gh-issue-93491.ehM211.rst b/Misc/NEWS.d/next/Build/2022-06-04-12-53-53.gh-issue-93491.ehM211.rst deleted file mode 100644 index b3560fac81d2..000000000000 --- a/Misc/NEWS.d/next/Build/2022-06-04-12-53-53.gh-issue-93491.ehM211.rst +++ /dev/null @@ -1 +0,0 @@ -``configure`` now detects and reports :pep:`11` support tiers. diff --git a/Misc/NEWS.d/next/Build/2022-06-08-14-28-03.gh-issue-93584.0xfHOK.rst b/Misc/NEWS.d/next/Build/2022-06-08-14-28-03.gh-issue-93584.0xfHOK.rst deleted file mode 100644 index 07ca5fad592b..000000000000 --- a/Misc/NEWS.d/next/Build/2022-06-08-14-28-03.gh-issue-93584.0xfHOK.rst +++ /dev/null @@ -1,2 +0,0 @@ -Address race condition in ``Makefile`` when installing a PGO build. All -``test`` and ``install`` targets now depend on ``all`` target. diff --git a/Misc/NEWS.d/next/Build/2022-06-25-23-25-47.gh-issue-94280.YhEyW_.rst b/Misc/NEWS.d/next/Build/2022-06-25-23-25-47.gh-issue-94280.YhEyW_.rst deleted file mode 100644 index 1199e842177d..000000000000 --- a/Misc/NEWS.d/next/Build/2022-06-25-23-25-47.gh-issue-94280.YhEyW_.rst +++ /dev/null @@ -1,3 +0,0 @@ -Updated pegen regeneration script on Windows to find and use Python 3.9 or -higher. Prior to this, pegen regeneration already required 3.9 or higher, -but the script may have used lower versions of Python. diff --git a/Misc/NEWS.d/next/Build/2022-06-27-11-57-15.gh-issue-93939.rv7s8W.rst b/Misc/NEWS.d/next/Build/2022-06-27-11-57-15.gh-issue-93939.rv7s8W.rst deleted file mode 100644 index f9ecf5022e24..000000000000 --- a/Misc/NEWS.d/next/Build/2022-06-27-11-57-15.gh-issue-93939.rv7s8W.rst +++ /dev/null @@ -1,2 +0,0 @@ -The ``2to3``, ``idle``, and ``pydoc`` scripts are now generated and installed by -``Makefile`` instead of ``setup.py``. diff --git a/Misc/NEWS.d/next/Build/2022-06-28-09-42-10.gh-issue-93939._VWxKW.rst b/Misc/NEWS.d/next/Build/2022-06-28-09-42-10.gh-issue-93939._VWxKW.rst deleted file mode 100644 index ab873bc839f4..000000000000 --- a/Misc/NEWS.d/next/Build/2022-06-28-09-42-10.gh-issue-93939._VWxKW.rst +++ /dev/null @@ -1,2 +0,0 @@ -C extension modules are now built by ``configure`` and ``make`` -instead of ``distutils`` and ``setup.py``. diff --git a/Misc/NEWS.d/next/Build/2022-06-29-08-58-31.gh-issue-94404.3MadM6.rst b/Misc/NEWS.d/next/Build/2022-06-29-08-58-31.gh-issue-94404.3MadM6.rst deleted file mode 100644 index c7c47533c54a..000000000000 --- a/Misc/NEWS.d/next/Build/2022-06-29-08-58-31.gh-issue-94404.3MadM6.rst +++ /dev/null @@ -1,3 +0,0 @@ -``makesetup`` now works around an issue with sed on macOS and uses correct -CFLAGS for object files that end up in a shared extension. Module CFLAGS -are used before PY_STDMODULE_CFLAGS to avoid clashes with system headers. diff --git a/Misc/NEWS.d/next/Build/2022-06-30-09-57-39.gh-issue-90005.9-pQyR.rst b/Misc/NEWS.d/next/Build/2022-06-30-09-57-39.gh-issue-90005.9-pQyR.rst deleted file mode 100644 index 9b14f767847d..000000000000 --- a/Misc/NEWS.d/next/Build/2022-06-30-09-57-39.gh-issue-90005.9-pQyR.rst +++ /dev/null @@ -1 +0,0 @@ -``_dbm`` module dependencies are now detected by configure. diff --git a/Misc/NEWS.d/next/Build/2022-06-30-17-00-54.gh-issue-90005.iiq5qD.rst b/Misc/NEWS.d/next/Build/2022-06-30-17-00-54.gh-issue-90005.iiq5qD.rst deleted file mode 100644 index 62f40b8f95f6..000000000000 --- a/Misc/NEWS.d/next/Build/2022-06-30-17-00-54.gh-issue-90005.iiq5qD.rst +++ /dev/null @@ -1 +0,0 @@ -Fix building ``_ctypes`` extension without ``pkg-config``. diff --git a/Misc/NEWS.d/next/Build/2022-06-30-17-18-23.gh-issue-90005.EIOOla.rst b/Misc/NEWS.d/next/Build/2022-06-30-17-18-23.gh-issue-90005.EIOOla.rst deleted file mode 100644 index 90a2dd486c19..000000000000 --- a/Misc/NEWS.d/next/Build/2022-06-30-17-18-23.gh-issue-90005.EIOOla.rst +++ /dev/null @@ -1,5 +0,0 @@ -Dependencies of :mod:`readline` and :mod:`curses` module are now detected in -``configure`` script with ``pkg-config``. Only ``ncurses`` / ``ncursesw`` -are detected automatically. The old ``curses`` library is not configured -automatically. Workaround for missing ``termcap`` or ``tinfo`` library -has been removed. diff --git a/Misc/NEWS.d/next/Build/2022-07-08-10-28-23.gh-issue-94682.ZtGt_0.rst b/Misc/NEWS.d/next/Build/2022-07-08-10-28-23.gh-issue-94682.ZtGt_0.rst deleted file mode 100644 index 60717a15bcc2..000000000000 --- a/Misc/NEWS.d/next/Build/2022-07-08-10-28-23.gh-issue-94682.ZtGt_0.rst +++ /dev/null @@ -1 +0,0 @@ -Build and test with OpenSSL 1.1.1q diff --git a/Misc/NEWS.d/next/Build/2022-07-12-13-39-18.gh-issue-94773.koHKm5.rst b/Misc/NEWS.d/next/Build/2022-07-12-13-39-18.gh-issue-94773.koHKm5.rst deleted file mode 100644 index ed7e40c91103..000000000000 --- a/Misc/NEWS.d/next/Build/2022-07-12-13-39-18.gh-issue-94773.koHKm5.rst +++ /dev/null @@ -1,2 +0,0 @@ -``deepfreeze.py`` now supports code object with frozensets that contain -incompatible, unsortable types. diff --git a/Misc/NEWS.d/next/Build/2022-07-13-10-13-10.gh-issue-94801.3xUB24.rst b/Misc/NEWS.d/next/Build/2022-07-13-10-13-10.gh-issue-94801.3xUB24.rst deleted file mode 100644 index 5caf84f96da1..000000000000 --- a/Misc/NEWS.d/next/Build/2022-07-13-10-13-10.gh-issue-94801.3xUB24.rst +++ /dev/null @@ -1,2 +0,0 @@ -``configure`` now uses custom flags like ``ZLIB_CFLAGS`` and ``ZLIB_LIBS`` -when searching for headers and libraries. diff --git a/Misc/NEWS.d/next/Build/2022-07-14-02-45-44.gh-issue-94841.lLRTdf.rst b/Misc/NEWS.d/next/Build/2022-07-14-02-45-44.gh-issue-94841.lLRTdf.rst deleted file mode 100644 index f7ad4f88a51d..000000000000 --- a/Misc/NEWS.d/next/Build/2022-07-14-02-45-44.gh-issue-94841.lLRTdf.rst +++ /dev/null @@ -1 +0,0 @@ -Fix the possible performance regression of :c:func:`PyObject_Free` compiled with MSVC version 1932. diff --git a/Misc/NEWS.d/next/Build/2022-07-14-11-13-26.gh-issue-94847.s3Kr5p.rst b/Misc/NEWS.d/next/Build/2022-07-14-11-13-26.gh-issue-94847.s3Kr5p.rst deleted file mode 100644 index a6d1e7277da4..000000000000 --- a/Misc/NEWS.d/next/Build/2022-07-14-11-13-26.gh-issue-94847.s3Kr5p.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixed ``_decimal`` module build issue on GCC when compiling with LTO and -pydebug. Debug builds no longer force inlining of functions. diff --git a/Misc/NEWS.d/next/Build/2022-07-21-09-17-01.gh-issue-95085.E9x2S_.rst b/Misc/NEWS.d/next/Build/2022-07-21-09-17-01.gh-issue-95085.E9x2S_.rst deleted file mode 100644 index 02dbd2b8b311..000000000000 --- a/Misc/NEWS.d/next/Build/2022-07-21-09-17-01.gh-issue-95085.E9x2S_.rst +++ /dev/null @@ -1,2 +0,0 @@ -Platforms ``wasm32-unknown-emscripten`` and ``wasm32-unknown-wasi`` have -been promoted to :pep:`11` tier 3 platform support. diff --git a/Misc/NEWS.d/next/Build/2022-07-23-21-39-09.gh-issue-95174.7cYMZR.rst b/Misc/NEWS.d/next/Build/2022-07-23-21-39-09.gh-issue-95174.7cYMZR.rst deleted file mode 100644 index 72ce183ac832..000000000000 --- a/Misc/NEWS.d/next/Build/2022-07-23-21-39-09.gh-issue-95174.7cYMZR.rst +++ /dev/null @@ -1 +0,0 @@ -Python now skips missing :mod:`socket` functions and methods on WASI. WASI can only create sockets from existing fd / accept and has no netdb. diff --git a/Misc/NEWS.d/next/Build/2022-07-25-08-59-35.gh-issue-95174.g8woUW.rst b/Misc/NEWS.d/next/Build/2022-07-25-08-59-35.gh-issue-95174.g8woUW.rst deleted file mode 100644 index 05f29955072c..000000000000 --- a/Misc/NEWS.d/next/Build/2022-07-25-08-59-35.gh-issue-95174.g8woUW.rst +++ /dev/null @@ -1,2 +0,0 @@ -Python now detects missing ``dup`` function in WASI and works around some -missing :mod:`errno`, :mod:`select`, and :mod:`socket` constants. diff --git a/Misc/NEWS.d/next/Build/2022-07-25-09-48-43.gh-issue-95145.ZNS3dj.rst b/Misc/NEWS.d/next/Build/2022-07-25-09-48-43.gh-issue-95145.ZNS3dj.rst deleted file mode 100644 index c751b5e3adc4..000000000000 --- a/Misc/NEWS.d/next/Build/2022-07-25-09-48-43.gh-issue-95145.ZNS3dj.rst +++ /dev/null @@ -1,2 +0,0 @@ -wasm32-wasi builds no longer depend on WASIX's pthread stubs. Python now has -its own stubbed pthread API. diff --git a/Misc/NEWS.d/next/Build/2022-07-26-18-13-34.gh-issue-94801.9fREfy.rst b/Misc/NEWS.d/next/Build/2022-07-26-18-13-34.gh-issue-94801.9fREfy.rst deleted file mode 100644 index a58be30e81b0..000000000000 --- a/Misc/NEWS.d/next/Build/2022-07-26-18-13-34.gh-issue-94801.9fREfy.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a regression in ``configure`` script that caused some header checks to -ignore custom ``CPPFLAGS``. The regression was introduced in :gh:`94802`. diff --git a/Misc/NEWS.d/next/Build/2022-08-04-15-29-35.gh-issue-93744.svRuqm.rst b/Misc/NEWS.d/next/Build/2022-08-04-15-29-35.gh-issue-93744.svRuqm.rst deleted file mode 100644 index fa9ade25718f..000000000000 --- a/Misc/NEWS.d/next/Build/2022-08-04-15-29-35.gh-issue-93744.svRuqm.rst +++ /dev/null @@ -1,3 +0,0 @@ -Remove the ``configure --with-cxx-main`` build option: it didn't work for -many years. Remove the ``MAINCC`` variable from ``configure`` and -``Makefile``. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Build/2022-08-12-13-06-03.gh-issue-90536.qMpF6p.rst b/Misc/NEWS.d/next/Build/2022-08-12-13-06-03.gh-issue-90536.qMpF6p.rst deleted file mode 100644 index 4605e03915ee..000000000000 --- a/Misc/NEWS.d/next/Build/2022-08-12-13-06-03.gh-issue-90536.qMpF6p.rst +++ /dev/null @@ -1,2 +0,0 @@ -Use the BOLT post-link optimizer to improve performance, particularly on -medium-to-large applications. diff --git a/Misc/NEWS.d/next/Build/2022-08-15-10-56-07.gh-issue-95973.Bsswsc.rst b/Misc/NEWS.d/next/Build/2022-08-15-10-56-07.gh-issue-95973.Bsswsc.rst deleted file mode 100644 index d03bc5205ead..000000000000 --- a/Misc/NEWS.d/next/Build/2022-08-15-10-56-07.gh-issue-95973.Bsswsc.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add a new ``--with-dsymutil`` configure option to to link debug information -in macOS. Patch by Pablo Galindo. diff --git a/Misc/NEWS.d/next/Build/2022-08-26-11-09-11.gh-issue-84461.Nsdn_R.rst b/Misc/NEWS.d/next/Build/2022-08-26-11-09-11.gh-issue-84461.Nsdn_R.rst deleted file mode 100644 index 134e9645159a..000000000000 --- a/Misc/NEWS.d/next/Build/2022-08-26-11-09-11.gh-issue-84461.Nsdn_R.rst +++ /dev/null @@ -1,3 +0,0 @@ -``wasm32-emscripten`` platform no longer builds :mod:`resource` module, -:func:`~os.getresuid`, :func:`~os.getresgid`, and their setters. The APIs -are stubs and not functional. diff --git a/Misc/NEWS.d/next/Build/2022-08-26-11-50-03.gh-issue-96269.x_J5h0.rst b/Misc/NEWS.d/next/Build/2022-08-26-11-50-03.gh-issue-96269.x_J5h0.rst deleted file mode 100644 index adb605fede5d..000000000000 --- a/Misc/NEWS.d/next/Build/2022-08-26-11-50-03.gh-issue-96269.x_J5h0.rst +++ /dev/null @@ -1,3 +0,0 @@ -Shared module targets now depend on new ``MODULE_DEPS`` variable, which -includes ``EXPORTSYMS``. This fixes a build order issue on unsupported AIX -platform. diff --git a/Misc/NEWS.d/next/Build/2022-09-11-14-23-49.gh-issue-96729.W4uBWL.rst b/Misc/NEWS.d/next/Build/2022-09-11-14-23-49.gh-issue-96729.W4uBWL.rst deleted file mode 100644 index b67cd200e2d3..000000000000 --- a/Misc/NEWS.d/next/Build/2022-09-11-14-23-49.gh-issue-96729.W4uBWL.rst +++ /dev/null @@ -1,2 +0,0 @@ -Ensure that Windows releases built with ``Tools\msi\buildrelease.bat`` are -upgradable to and from official Python releases. diff --git a/Misc/NEWS.d/next/Build/2022-09-12-18-34-51.gh-issue-85936.tX4VCU.rst b/Misc/NEWS.d/next/Build/2022-09-12-18-34-51.gh-issue-85936.tX4VCU.rst deleted file mode 100644 index 302b863a3b1e..000000000000 --- a/Misc/NEWS.d/next/Build/2022-09-12-18-34-51.gh-issue-85936.tX4VCU.rst +++ /dev/null @@ -1,2 +0,0 @@ -CPython now uses the ThinLTO option as the default policy if the Clang -compiler accepts the flag. Patch by Dong-hee Na. diff --git a/Misc/NEWS.d/next/Build/2022-09-17-11-19-24.gh-issue-96883.p_gr62.rst b/Misc/NEWS.d/next/Build/2022-09-17-11-19-24.gh-issue-96883.p_gr62.rst deleted file mode 100644 index 2258ce8ab9d5..000000000000 --- a/Misc/NEWS.d/next/Build/2022-09-17-11-19-24.gh-issue-96883.p_gr62.rst +++ /dev/null @@ -1,2 +0,0 @@ -``wasm32-emscripten`` builds for browsers now include -:mod:`concurrent.futures` for :mod:`asyncio` and :mod:`unittest.mock`. diff --git a/Misc/NEWS.d/next/Build/2022-09-20-12-43-44.gh-issue-96761.IF29kR.rst b/Misc/NEWS.d/next/Build/2022-09-20-12-43-44.gh-issue-96761.IF29kR.rst deleted file mode 100644 index 18f75ac48910..000000000000 --- a/Misc/NEWS.d/next/Build/2022-09-20-12-43-44.gh-issue-96761.IF29kR.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix the build process of clang compiler for :program:`_bootstrap_python` if -LTO optimization is applied. Patch by Matthias G?rgens and Dong-hee Na. diff --git a/Misc/NEWS.d/next/C API/2021-10-05-21-59-43.bpo-45383.TVClgf.rst b/Misc/NEWS.d/next/C API/2021-10-05-21-59-43.bpo-45383.TVClgf.rst deleted file mode 100644 index ca1b7a43d294..000000000000 --- a/Misc/NEWS.d/next/C API/2021-10-05-21-59-43.bpo-45383.TVClgf.rst +++ /dev/null @@ -1,3 +0,0 @@ -The :c:func:`PyType_FromSpec` API will now find and use a metaclass -based on the provided bases. -An error will be raised if there is a metaclass conflict. diff --git a/Misc/NEWS.d/next/C API/2022-04-13-16-10-55.gh-issue-59121.-B7mKp.rst b/Misc/NEWS.d/next/C API/2022-04-13-16-10-55.gh-issue-59121.-B7mKp.rst deleted file mode 100644 index d52866ea08f7..000000000000 --- a/Misc/NEWS.d/next/C API/2022-04-13-16-10-55.gh-issue-59121.-B7mKp.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed an assert that prevented ``PyRun_InteractiveOne`` from providing tracebacks when parsing from the provided FD. diff --git a/Misc/NEWS.d/next/C API/2022-05-03-19-35-37.gh-issue-92193.61VoFL.rst b/Misc/NEWS.d/next/C API/2022-05-03-19-35-37.gh-issue-92193.61VoFL.rst deleted file mode 100644 index e0755bb01994..000000000000 --- a/Misc/NEWS.d/next/C API/2022-05-03-19-35-37.gh-issue-92193.61VoFL.rst +++ /dev/null @@ -1,5 +0,0 @@ -Add new function :c:func:`PyFunction_SetVectorcall` to the C API -which sets the vectorcall field of a given :c:type:`PyFunctionObject`. - -Warning: extensions using this API must preserve the behavior -of the unaltered function! diff --git a/Misc/NEWS.d/next/C API/2022-05-09-23-16-38.gh-issue-85858.VIcNDL.rst b/Misc/NEWS.d/next/C API/2022-05-09-23-16-38.gh-issue-85858.VIcNDL.rst deleted file mode 100644 index c175d1efee38..000000000000 --- a/Misc/NEWS.d/next/C API/2022-05-09-23-16-38.gh-issue-85858.VIcNDL.rst +++ /dev/null @@ -1,2 +0,0 @@ -Remove the ``PyUnicode_InternImmortal()`` function and the -``SSTATE_INTERNED_IMMORTAL`` macro. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/C API/2022-05-10-12-35-42.gh-issue-92536.cAoRCZ.rst b/Misc/NEWS.d/next/C API/2022-05-10-12-35-42.gh-issue-92536.cAoRCZ.rst deleted file mode 100644 index a0b1bc69e281..000000000000 --- a/Misc/NEWS.d/next/C API/2022-05-10-12-35-42.gh-issue-92536.cAoRCZ.rst +++ /dev/null @@ -1 +0,0 @@ -Remove legacy Unicode APIs based on ``Py_UNICODE*``. diff --git a/Misc/NEWS.d/next/C API/2022-05-11-02-33-10.gh-issue-92651.FIXLf0.rst b/Misc/NEWS.d/next/C API/2022-05-11-02-33-10.gh-issue-92651.FIXLf0.rst deleted file mode 100644 index 60a8818e46b7..000000000000 --- a/Misc/NEWS.d/next/C API/2022-05-11-02-33-10.gh-issue-92651.FIXLf0.rst +++ /dev/null @@ -1,3 +0,0 @@ -Remove the ``token.h`` header file. There was never any public tokenizer C -API. The ``token.h`` header file was only designed to be used by Python -internals. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/C API/2022-05-13-18-17-48.gh-issue-92781.TVDr3-.rst b/Misc/NEWS.d/next/C API/2022-05-13-18-17-48.gh-issue-92781.TVDr3-.rst deleted file mode 100644 index 6442ba619450..000000000000 --- a/Misc/NEWS.d/next/C API/2022-05-13-18-17-48.gh-issue-92781.TVDr3-.rst +++ /dev/null @@ -1,3 +0,0 @@ -Avoid mixing declarations and code in the C API to fix the compiler warning: -"ISO C90 forbids mixed declarations and code" -[-Werror=declaration-after-statement]. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/C API/2022-05-19-18-05-51.gh-issue-92913.Ass1Hv.rst b/Misc/NEWS.d/next/C API/2022-05-19-18-05-51.gh-issue-92913.Ass1Hv.rst deleted file mode 100644 index c448c64029d8..000000000000 --- a/Misc/NEWS.d/next/C API/2022-05-19-18-05-51.gh-issue-92913.Ass1Hv.rst +++ /dev/null @@ -1,2 +0,0 @@ -Ensures changes to :c:member:`PyConfig.module_search_paths` are ignored -unless :c:member:`PyConfig.module_search_paths_set` is set diff --git a/Misc/NEWS.d/next/C API/2022-05-23-12-31-04.gh-issue-77782.ugC8dn.rst b/Misc/NEWS.d/next/C API/2022-05-23-12-31-04.gh-issue-77782.ugC8dn.rst deleted file mode 100644 index d212f6b977ef..000000000000 --- a/Misc/NEWS.d/next/C API/2022-05-23-12-31-04.gh-issue-77782.ugC8dn.rst +++ /dev/null @@ -1,3 +0,0 @@ -Deprecate global configuration variable like -:c:var:`Py_IgnoreEnvironmentFlag`: the :c:func:`Py_InitializeFromConfig` API -should be instead. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/C API/2022-05-23-13-33-18.gh-issue-93103.ooD3Eb.rst b/Misc/NEWS.d/next/C API/2022-05-23-13-33-18.gh-issue-93103.ooD3Eb.rst deleted file mode 100644 index 404f0089cd0b..000000000000 --- a/Misc/NEWS.d/next/C API/2022-05-23-13-33-18.gh-issue-93103.ooD3Eb.rst +++ /dev/null @@ -1,4 +0,0 @@ -Deprecate global configuration variables, like -:c:var:`Py_IgnoreEnvironmentFlag`, in the documentation: the -:c:func:`Py_InitializeFromConfig` API should be instead. Patch by Victor -Stinner. diff --git a/Misc/NEWS.d/next/C API/2022-05-23-15-22-18.gh-issue-92898.Qjc9d3.rst b/Misc/NEWS.d/next/C API/2022-05-23-15-22-18.gh-issue-92898.Qjc9d3.rst deleted file mode 100644 index 01eca1db1f18..000000000000 --- a/Misc/NEWS.d/next/C API/2022-05-23-15-22-18.gh-issue-92898.Qjc9d3.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix C++ compiler warnings when casting function arguments to ``PyObject*``. -Patch by Serge Guelton. diff --git a/Misc/NEWS.d/next/C API/2022-06-03-14-54-41.gh-issue-93466.DDtH0X.rst b/Misc/NEWS.d/next/C API/2022-06-03-14-54-41.gh-issue-93466.DDtH0X.rst deleted file mode 100644 index 0bb65ea2b387..000000000000 --- a/Misc/NEWS.d/next/C API/2022-06-03-14-54-41.gh-issue-93466.DDtH0X.rst +++ /dev/null @@ -1,3 +0,0 @@ -Slot IDs in PyType_Spec may not be repeated. The documentation was updated -to mention this. For some cases of repeated slots, PyType_FromSpec and -related functions will now raise an exception. diff --git a/Misc/NEWS.d/next/C API/2022-06-04-13-15-41.gh-issue-93442.4M4NDb.rst b/Misc/NEWS.d/next/C API/2022-06-04-13-15-41.gh-issue-93442.4M4NDb.rst deleted file mode 100644 index f48ed37c8144..000000000000 --- a/Misc/NEWS.d/next/C API/2022-06-04-13-15-41.gh-issue-93442.4M4NDb.rst +++ /dev/null @@ -1,3 +0,0 @@ -Add C++ overloads for _Py_CAST_impl() to handle 0/NULL. This will allow C++ -extensions that pass 0 or NULL to macros using _Py_CAST() to continue to -compile. diff --git a/Misc/NEWS.d/next/C API/2022-06-06-16-04-14.gh-issue-93503.MHJTu8.rst b/Misc/NEWS.d/next/C API/2022-06-06-16-04-14.gh-issue-93503.MHJTu8.rst deleted file mode 100644 index 3dd292cd7780..000000000000 --- a/Misc/NEWS.d/next/C API/2022-06-06-16-04-14.gh-issue-93503.MHJTu8.rst +++ /dev/null @@ -1,7 +0,0 @@ -Add two new public functions to the public C-API, -:c:func:`PyEval_SetProfileAllThreads` and :c:func:`PyEval_SetTraceAllThreads`, -that allow to set tracing and profiling functions in all running threads in -addition to the calling one. Also, two analogous functions to the -:mod:`threading` module (:func:`threading.setprofile_all_threads` and -:func:`threading.settrace_all_threads`) that allow to do the same from Python. -Patch by Pablo Galindo diff --git a/Misc/NEWS.d/next/C API/2022-06-10-16-50-27.gh-issue-89546.mX1f10.rst b/Misc/NEWS.d/next/C API/2022-06-10-16-50-27.gh-issue-89546.mX1f10.rst deleted file mode 100644 index 8e6b6d95c7b4..000000000000 --- a/Misc/NEWS.d/next/C API/2022-06-10-16-50-27.gh-issue-89546.mX1f10.rst +++ /dev/null @@ -1,4 +0,0 @@ -:c:func:`PyType_FromMetaclass` (and other ``PyType_From*`` functions) now -check that offsets and the base class's -:c:member:`~PyTypeObject.tp_basicsize` fit in the new class's -``tp_basicsize``. diff --git a/Misc/NEWS.d/next/C API/2022-06-10-23-41-48.gh-issue-91731.fhYUQG.rst b/Misc/NEWS.d/next/C API/2022-06-10-23-41-48.gh-issue-91731.fhYUQG.rst deleted file mode 100644 index 185671ca4fcf..000000000000 --- a/Misc/NEWS.d/next/C API/2022-06-10-23-41-48.gh-issue-91731.fhYUQG.rst +++ /dev/null @@ -1,3 +0,0 @@ -Avoid defining the ``static_assert`` when compiling with C++ 11, where this -is a keyword and redefining it can lead to undefined behavior. Patch by -Pablo Galindo diff --git a/Misc/NEWS.d/next/C API/2022-06-13-21-37-31.gh-issue-91321.DgJFvS.rst b/Misc/NEWS.d/next/C API/2022-06-13-21-37-31.gh-issue-91321.DgJFvS.rst deleted file mode 100644 index 57c39bc8d83c..000000000000 --- a/Misc/NEWS.d/next/C API/2022-06-13-21-37-31.gh-issue-91321.DgJFvS.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix the compatibility of the Python C API with C++ older than C++11. Patch by -Victor Stinner. diff --git a/Misc/NEWS.d/next/C API/2022-06-17-13-41-38.gh-issue-93937.uKVTEh.rst b/Misc/NEWS.d/next/C API/2022-06-17-13-41-38.gh-issue-93937.uKVTEh.rst deleted file mode 100644 index c0a0745aa0dd..000000000000 --- a/Misc/NEWS.d/next/C API/2022-06-17-13-41-38.gh-issue-93937.uKVTEh.rst +++ /dev/null @@ -1,14 +0,0 @@ -The following frame functions and type are now directly available with -``#include ``, it's no longer needed to add ``#include -``: - -* :c:func:`PyFrame_Check` -* :c:func:`PyFrame_GetBack` -* :c:func:`PyFrame_GetBuiltins` -* :c:func:`PyFrame_GetGenerator` -* :c:func:`PyFrame_GetGlobals` -* :c:func:`PyFrame_GetLasti` -* :c:func:`PyFrame_GetLocals` -* :c:type:`PyFrame_Type` - -Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/C API/2022-07-12-17-39-32.gh-issue-94731.9CPJNU.rst b/Misc/NEWS.d/next/C API/2022-07-12-17-39-32.gh-issue-94731.9CPJNU.rst deleted file mode 100644 index a96b002915c2..000000000000 --- a/Misc/NEWS.d/next/C API/2022-07-12-17-39-32.gh-issue-94731.9CPJNU.rst +++ /dev/null @@ -1,3 +0,0 @@ -Python again uses C-style casts for most casting operations when compiled -with C++. This may trigger compiler warnings, if they are enabled with e.g. -``-Wold-style-cast`` or ``-Wzero-as-null-pointer-constant`` options for ``g++``. diff --git a/Misc/NEWS.d/next/C API/2022-07-17-18-21-40.gh-issue-94930.gPFGDL.rst b/Misc/NEWS.d/next/C API/2022-07-17-18-21-40.gh-issue-94930.gPFGDL.rst deleted file mode 100644 index 5b79d757b1e4..000000000000 --- a/Misc/NEWS.d/next/C API/2022-07-17-18-21-40.gh-issue-94930.gPFGDL.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix ``SystemError`` raised when :c:func:`PyArg_ParseTupleAndKeywords` is -used with ``#`` in ``(...)`` but without ``PY_SSIZE_T_CLEAN`` defined. diff --git a/Misc/NEWS.d/next/C API/2022-07-19-22-37-40.gh-issue-94936.LGlmKv.rst b/Misc/NEWS.d/next/C API/2022-07-19-22-37-40.gh-issue-94936.LGlmKv.rst deleted file mode 100644 index abef9bb376c8..000000000000 --- a/Misc/NEWS.d/next/C API/2022-07-19-22-37-40.gh-issue-94936.LGlmKv.rst +++ /dev/null @@ -1,3 +0,0 @@ -Added :c:func:`PyCode_GetVarnames`, :c:func:`PyCode_GetCellvars` and -:c:func:`PyCode_GetFreevars` for accessing ``co_varnames``, ``co_cellvars`` -and ``co_freevars`` respectively via the C API. diff --git a/Misc/NEWS.d/next/C API/2022-07-25-15-54-27.gh-issue-92678.ziZpxz.rst b/Misc/NEWS.d/next/C API/2022-07-25-15-54-27.gh-issue-92678.ziZpxz.rst deleted file mode 100644 index 52473c9dfab9..000000000000 --- a/Misc/NEWS.d/next/C API/2022-07-25-15-54-27.gh-issue-92678.ziZpxz.rst +++ /dev/null @@ -1,3 +0,0 @@ -Adds unstable C-API functions ``_PyObject_VisitManagedDict`` and -``_PyObject_ClearManagedDict`` to allow C extensions to allow the VM to -manage their object's dictionaries. diff --git a/Misc/NEWS.d/next/C API/2022-07-29-10-41-59.gh-issue-95388.aiRSgr.rst b/Misc/NEWS.d/next/C API/2022-07-29-10-41-59.gh-issue-95388.aiRSgr.rst deleted file mode 100644 index c389d13db6af..000000000000 --- a/Misc/NEWS.d/next/C API/2022-07-29-10-41-59.gh-issue-95388.aiRSgr.rst +++ /dev/null @@ -1,2 +0,0 @@ -Creating :c:data:`immutable types ` with mutable -bases is deprecated and is planned to be disabled in Python 3.14. diff --git a/Misc/NEWS.d/next/C API/2022-07-29-15-24-45.gh-issue-93012.-DdGEy.rst b/Misc/NEWS.d/next/C API/2022-07-29-15-24-45.gh-issue-93012.-DdGEy.rst deleted file mode 100644 index 199c2d1fc197..000000000000 --- a/Misc/NEWS.d/next/C API/2022-07-29-15-24-45.gh-issue-93012.-DdGEy.rst +++ /dev/null @@ -1,6 +0,0 @@ -The :const:`Py_TPFLAGS_HAVE_VECTORCALL` flag is now removed from a class -when the class's :py:meth:`~object.__call__` method is reassigned. This -makes vectorcall safe to use with mutable types (i.e. heap types without the -:const:`immutable ` flag). Mutable types that do -not override :c:member:`~PyTypeObject.tp_call` now inherit the -:const:`Py_TPFLAGS_HAVE_VECTORCALL` flag. diff --git a/Misc/NEWS.d/next/C API/2022-07-31-21-58-27.gh-issue-95504.wy7B1F.rst b/Misc/NEWS.d/next/C API/2022-07-31-21-58-27.gh-issue-95504.wy7B1F.rst deleted file mode 100644 index 955bdd4c7494..000000000000 --- a/Misc/NEWS.d/next/C API/2022-07-31-21-58-27.gh-issue-95504.wy7B1F.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix sign placement when specifying width or precision in -:c:func:`PyUnicode_FromFormat` and :c:func:`PyUnicode_FromFormatV`. -Patch by Philip Georgi. diff --git a/Misc/NEWS.d/next/C API/2022-08-01-16-21-39.gh-issue-93274.QoDHEu.rst b/Misc/NEWS.d/next/C API/2022-08-01-16-21-39.gh-issue-93274.QoDHEu.rst deleted file mode 100644 index da6cce4a7b28..000000000000 --- a/Misc/NEWS.d/next/C API/2022-08-01-16-21-39.gh-issue-93274.QoDHEu.rst +++ /dev/null @@ -1,3 +0,0 @@ -API for implementing vectorcall (:c:data:`Py_TPFLAGS_HAVE_VECTORCALL`, -:c:func:`PyVectorcall_NARGS` and :c:func:`PyVectorcall_Call`) was added to -the limited API and stable ABI. diff --git a/Misc/NEWS.d/next/C API/2022-08-03-13-01-57.gh-issue-92678.DLwONN.rst b/Misc/NEWS.d/next/C API/2022-08-03-13-01-57.gh-issue-92678.DLwONN.rst deleted file mode 100644 index a3a209f5e413..000000000000 --- a/Misc/NEWS.d/next/C API/2022-08-03-13-01-57.gh-issue-92678.DLwONN.rst +++ /dev/null @@ -1,2 +0,0 @@ -Support C extensions using managed dictionaries by setting the -``Py_TPFLAGS_MANAGED_DICT`` flag. diff --git a/Misc/NEWS.d/next/C API/2022-08-03-14-39-08.gh-issue-92678.ozFTEx.rst b/Misc/NEWS.d/next/C API/2022-08-03-14-39-08.gh-issue-92678.ozFTEx.rst deleted file mode 100644 index 6bf3d4b1abbf..000000000000 --- a/Misc/NEWS.d/next/C API/2022-08-03-14-39-08.gh-issue-92678.ozFTEx.rst +++ /dev/null @@ -1,2 +0,0 @@ -Restore the 3.10 behavior for multiple inheritance of C extension classes -that store their dictionary at the end of the struct. diff --git a/Misc/NEWS.d/next/C API/2022-08-08-14-36-31.gh-issue-95781.W_G8YW.rst b/Misc/NEWS.d/next/C API/2022-08-08-14-36-31.gh-issue-95781.W_G8YW.rst deleted file mode 100644 index eb2fd7e9da3d..000000000000 --- a/Misc/NEWS.d/next/C API/2022-08-08-14-36-31.gh-issue-95781.W_G8YW.rst +++ /dev/null @@ -1,4 +0,0 @@ -An unrecognized format character in :c:func:`PyUnicode_FromFormat` and -:c:func:`PyUnicode_FromFormatV` now sets a :exc:`SystemError`. -In previous versions it caused all the rest of the format string to be -copied as-is to the result string, and any extra arguments discarded. diff --git a/Misc/NEWS.d/next/C API/2022-08-16-16-54-42.gh-issue-95589.6xE1ar.rst b/Misc/NEWS.d/next/C API/2022-08-16-16-54-42.gh-issue-95589.6xE1ar.rst deleted file mode 100644 index 696e3c80db62..000000000000 --- a/Misc/NEWS.d/next/C API/2022-08-16-16-54-42.gh-issue-95589.6xE1ar.rst +++ /dev/null @@ -1,4 +0,0 @@ -Extensions classes that set ``tp_dictoffset`` and ``tp_weaklistoffset`` -lose the support for multiple inheritance, but are now safe. Extension -classes should use :const:`Py_TPFLAGS_MANAGED_DICT` and -:const:`Py_TPFLAGS_MANAGED_WEAKREF` instead. diff --git a/Misc/NEWS.d/next/C API/2022-09-20-01-04-57.gh-issue-96512.msZTjF.rst b/Misc/NEWS.d/next/C API/2022-09-20-01-04-57.gh-issue-96512.msZTjF.rst deleted file mode 100644 index 787bee3ee23b..000000000000 --- a/Misc/NEWS.d/next/C API/2022-09-20-01-04-57.gh-issue-96512.msZTjF.rst +++ /dev/null @@ -1,2 +0,0 @@ -Configuration for the :ref:`integer string conversion length limitation -` now lives in the PyConfig C API struct. diff --git a/Misc/NEWS.d/next/C API/2022-10-03-20-33-24.gh-issue-95756.SSmXlG.rst b/Misc/NEWS.d/next/C API/2022-10-03-20-33-24.gh-issue-95756.SSmXlG.rst deleted file mode 100644 index b5c78c16e86d..000000000000 --- a/Misc/NEWS.d/next/C API/2022-10-03-20-33-24.gh-issue-95756.SSmXlG.rst +++ /dev/null @@ -1 +0,0 @@ -Lazily create and cache ``co_`` attributes for better performance for code getters. diff --git a/Misc/NEWS.d/next/C API/2022-10-05-10-43-32.gh-issue-91051.ODDRsQ.rst b/Misc/NEWS.d/next/C API/2022-10-05-10-43-32.gh-issue-91051.ODDRsQ.rst deleted file mode 100644 index c18e2d61f397..000000000000 --- a/Misc/NEWS.d/next/C API/2022-10-05-10-43-32.gh-issue-91051.ODDRsQ.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add :c:func:`PyType_Watch` and related APIs to allow callbacks on -:c:func:`PyType_Modified`. diff --git a/Misc/NEWS.d/next/C API/2022-10-18-16-16-27.gh-issue-98393.55u4BF.rst b/Misc/NEWS.d/next/C API/2022-10-18-16-16-27.gh-issue-98393.55u4BF.rst deleted file mode 100644 index 658f587348a3..000000000000 --- a/Misc/NEWS.d/next/C API/2022-10-18-16-16-27.gh-issue-98393.55u4BF.rst +++ /dev/null @@ -1,3 +0,0 @@ -The :c:func:`PyUnicode_FSDecoder` function no longer accepts bytes-like -paths, like :class:`bytearray` and :class:`memoryview` types: only the exact -:class:`bytes` type is accepted for bytes strings. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-11-15-02-08-43.bpo-42316.LqdkWK.rst b/Misc/NEWS.d/next/Core and Builtins/2020-11-15-02-08-43.bpo-42316.LqdkWK.rst deleted file mode 100644 index ea997800bf07..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-11-15-02-08-43.bpo-42316.LqdkWK.rst +++ /dev/null @@ -1 +0,0 @@ -Document some places where an assignment expression needs parentheses. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-01-02-14-53-59.bpo-46142.WayjgT.rst b/Misc/NEWS.d/next/Core and Builtins/2022-01-02-14-53-59.bpo-46142.WayjgT.rst deleted file mode 100644 index 3c62c5428994..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-01-02-14-53-59.bpo-46142.WayjgT.rst +++ /dev/null @@ -1,3 +0,0 @@ -Make ``--help`` output shorter by moving some info to the new -``--help-env`` and ``--help-xoptions`` command-line options. -Also add ``--help-all`` option to print complete usage. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-03-22-13-12-27.bpo-47091.tJcy-P.rst b/Misc/NEWS.d/next/Core and Builtins/2022-03-22-13-12-27.bpo-47091.tJcy-P.rst deleted file mode 100644 index 72a39b5ebc71..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-03-22-13-12-27.bpo-47091.tJcy-P.rst +++ /dev/null @@ -1 +0,0 @@ -Improve performance of repetition of :class:`list` and :class:`tuple` by using ``memcpy`` to copy data and performing the reference increments in one step. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-04-15-22-12-53.gh-issue-91578.rDOtyK.rst b/Misc/NEWS.d/next/Core and Builtins/2022-04-15-22-12-53.gh-issue-91578.rDOtyK.rst deleted file mode 100644 index 4dc738ab9051..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-04-15-22-12-53.gh-issue-91578.rDOtyK.rst +++ /dev/null @@ -1 +0,0 @@ -Updates the error message for abstract class. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-04-16-15-37-55.gh-issue-91399.trLbK6.rst b/Misc/NEWS.d/next/Core and Builtins/2022-04-16-15-37-55.gh-issue-91399.trLbK6.rst deleted file mode 100644 index d1e6c0988292..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-04-16-15-37-55.gh-issue-91399.trLbK6.rst +++ /dev/null @@ -1 +0,0 @@ -Removed duplicate '{0, 0, 0, 0, 0, 0}' entry in 'Objects/unicodetype_db.h'. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-04-24-02-22-10.gh-issue-91432.YPJAK6.rst b/Misc/NEWS.d/next/Core and Builtins/2022-04-24-02-22-10.gh-issue-91432.YPJAK6.rst deleted file mode 100644 index 081dc0f5c334..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-04-24-02-22-10.gh-issue-91432.YPJAK6.rst +++ /dev/null @@ -1 +0,0 @@ -Specialized the :opcode:`FOR_ITER` opcode using the PEP 659 machinery diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-03-20-12-18.gh-issue-92261.aigLnb.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-03-20-12-18.gh-issue-92261.aigLnb.rst deleted file mode 100644 index df0228e273d8..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-05-03-20-12-18.gh-issue-92261.aigLnb.rst +++ /dev/null @@ -1 +0,0 @@ -Fix hang when trying to iterate over a ``typing.Union``. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-08-19-43-31.gh-issue-88750.1BjJg-.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-08-19-43-31.gh-issue-88750.1BjJg-.rst deleted file mode 100644 index bc8d41397c00..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-05-08-19-43-31.gh-issue-88750.1BjJg-.rst +++ /dev/null @@ -1,2 +0,0 @@ -The deprecated debug build only ``PYTHONTHREADDEBUG`` environment variable -no longer does anything. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-10-11-34-35.gh-issue-92619.u0V0lY.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-10-11-34-35.gh-issue-92619.u0V0lY.rst deleted file mode 100644 index dfc9c0d1327f..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-05-10-11-34-35.gh-issue-92619.u0V0lY.rst +++ /dev/null @@ -1 +0,0 @@ -Make the compiler duplicate an exit block only if none of its instructions have a lineno (previously only the first instruction in the block was checked, leading to unnecessarily duplicated blocks). diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-11-09-16-54.gh-issue-91102.lenv9h.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-11-09-16-54.gh-issue-91102.lenv9h.rst deleted file mode 100644 index b2bdf9d5322f..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-05-11-09-16-54.gh-issue-91102.lenv9h.rst +++ /dev/null @@ -1 +0,0 @@ -:meth:`_warnings.warn_explicit` is ported to Argument Clinic. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-12-13-23-19.gh-issue-92236.sDRzUe.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-12-13-23-19.gh-issue-92236.sDRzUe.rst deleted file mode 100644 index fe482d505c67..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-05-12-13-23-19.gh-issue-92236.sDRzUe.rst +++ /dev/null @@ -1,2 +0,0 @@ -Remove spurious "LINE" event when starting a generator or coroutine, visible -tracing functions implemented in C. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-13-00-57-18.gh-issue-92658.YdhFE2.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-13-00-57-18.gh-issue-92658.YdhFE2.rst deleted file mode 100644 index 887b3d615966..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-05-13-00-57-18.gh-issue-92658.YdhFE2.rst +++ /dev/null @@ -1 +0,0 @@ -Add support for connecting and binding to Hyper-V sockets on Windows Hyper-V hosts and guests. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-13-12-36-10.gh-issue-92777.Odo4vP.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-13-12-36-10.gh-issue-92777.Odo4vP.rst deleted file mode 100644 index 19416590a8e9..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-05-13-12-36-10.gh-issue-92777.Odo4vP.rst +++ /dev/null @@ -1 +0,0 @@ -Specialize ``LOAD_METHOD`` for objects with lazy dictionaries. Patch by Ken Jin. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-14-13-22-11.gh-issue-92804.rAqpI2.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-14-13-22-11.gh-issue-92804.rAqpI2.rst deleted file mode 100644 index 7a5fd3f6568e..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-05-14-13-22-11.gh-issue-92804.rAqpI2.rst +++ /dev/null @@ -1 +0,0 @@ -Fix memory leak in ``memoryview`` iterator as it was not finalized at exit. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-15-15-25-05.gh-issue-90473.MoPHYW.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-15-15-25-05.gh-issue-90473.MoPHYW.rst deleted file mode 100644 index 1f9f45a511fb..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-05-15-15-25-05.gh-issue-90473.MoPHYW.rst +++ /dev/null @@ -1 +0,0 @@ -Decrease default recursion limit on WASI to address limited call stack size. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-17-20-41-43.gh-issue-92858.eIXJTn.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-17-20-41-43.gh-issue-92858.eIXJTn.rst deleted file mode 100644 index fa91d941b175..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-05-17-20-41-43.gh-issue-92858.eIXJTn.rst +++ /dev/null @@ -1 +0,0 @@ -Improve error message for some suites with syntax error before ':' diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-18-08-32-33.gh-issue-92914.tJUeTD.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-18-08-32-33.gh-issue-92914.tJUeTD.rst deleted file mode 100644 index 1242a15c029d..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-05-18-08-32-33.gh-issue-92914.tJUeTD.rst +++ /dev/null @@ -1 +0,0 @@ -Always round the allocated size for lists up to the nearest even number. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-18-12-55-35.gh-issue-90690.TKuoTa.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-18-12-55-35.gh-issue-90690.TKuoTa.rst deleted file mode 100644 index 6c5aa91dfb9d..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-05-18-12-55-35.gh-issue-90690.TKuoTa.rst +++ /dev/null @@ -1,2 +0,0 @@ -The PRECALL instruction has been removed. It offered only a small advantage -for specialization and is not needed in the vast majority of cases. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-18-18-34-45.gh-issue-92930.kpYPOb.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-18-18-34-45.gh-issue-92930.kpYPOb.rst deleted file mode 100644 index cd5d7b3214ea..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-05-18-18-34-45.gh-issue-92930.kpYPOb.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed a crash in ``_pickle.c`` from mutating collections during ``__reduce__`` or ``persistent_id``. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-19-13-25-50.gh-issue-92955.kmNV33.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-19-13-25-50.gh-issue-92955.kmNV33.rst deleted file mode 100644 index 09f03e520c43..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-05-19-13-25-50.gh-issue-92955.kmNV33.rst +++ /dev/null @@ -1 +0,0 @@ -Fix memory leak in code object's lines and positions iterators as they were not finalized at exit. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-19-15-29-53.gh-issue-89914.8bAffH.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-19-15-29-53.gh-issue-89914.8bAffH.rst deleted file mode 100644 index d2156f8bbf3d..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-05-19-15-29-53.gh-issue-89914.8bAffH.rst +++ /dev/null @@ -1,2 +0,0 @@ -The operand of the ``YIELD_VALUE`` instruction is set to the stack depth. -This is done to help frame handling on ``yield`` and may assist debuggers. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-20-09-25-34.gh-issue-93021.k3Aji2.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-20-09-25-34.gh-issue-93021.k3Aji2.rst deleted file mode 100644 index 8fdd8dfb4229..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-05-20-09-25-34.gh-issue-93021.k3Aji2.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix the :attr:`__text_signature__` for :meth:`__get__` methods implemented -in C. Patch by Jelle Zijlstra. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-20-13-32-24.gh-issue-93012.e9B-pv.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-20-13-32-24.gh-issue-93012.e9B-pv.rst deleted file mode 100644 index 8de0f000647d..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-05-20-13-32-24.gh-issue-93012.e9B-pv.rst +++ /dev/null @@ -1,8 +0,0 @@ -Added the new function :c:func:`PyType_FromMetaclass`, which generalizes the -existing :c:func:`PyType_FromModuleAndSpec` using an additional metaclass -argument. This is useful for language binding tools, where it can be used to -intercept type-related operations like subclassing or static attribute access -by specifying a metaclass with custom slots. - -Importantly, :c:func:`PyType_FromMetaclass` is available in the Limited API, -which provides a path towards migrating more binding tools onto the Stable ABI. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-21-23-21-37.gh-issue-93065.5I18WC.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-21-23-21-37.gh-issue-93065.5I18WC.rst deleted file mode 100644 index ea801653f750..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-05-21-23-21-37.gh-issue-93065.5I18WC.rst +++ /dev/null @@ -1,5 +0,0 @@ -Fix contextvars HAMT implementation to handle iteration over deep trees. - -The bug was discovered and fixed by Eli Libman. See -`MagicStack/immutables#84 `_ -for more details. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-22-02-37-50.gh-issue-93061.r70Imp.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-22-02-37-50.gh-issue-93061.r70Imp.rst deleted file mode 100644 index d41e59028ad5..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-05-22-02-37-50.gh-issue-93061.r70Imp.rst +++ /dev/null @@ -1 +0,0 @@ -Backward jumps after ``async for`` loops are no longer given dubious line numbers. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-23-18-36-07.gh-issue-93143.X1Yqxm.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-23-18-36-07.gh-issue-93143.X1Yqxm.rst deleted file mode 100644 index 03994bcfdb56..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-05-23-18-36-07.gh-issue-93143.X1Yqxm.rst +++ /dev/null @@ -1 +0,0 @@ -Avoid ``NULL`` checks for uninitialized local variables by determining at compile time which variables must be initialized. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-24-14-35-48.gh-issue-93040.9X6Ofu.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-24-14-35-48.gh-issue-93040.9X6Ofu.rst deleted file mode 100644 index b2e527446ea7..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-05-24-14-35-48.gh-issue-93040.9X6Ofu.rst +++ /dev/null @@ -1 +0,0 @@ -Wraps unused parameters in ``Objects/obmalloc.c`` with ``Py_UNUSED``. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-25-04-07-22.gh-issue-91924.-UyO4q.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-25-04-07-22.gh-issue-91924.-UyO4q.rst deleted file mode 100644 index 44866a03cf48..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-05-25-04-07-22.gh-issue-91924.-UyO4q.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix ``__lltrace__`` debug feature if the stdout encoding is not UTF-8. Patch -by Victor Stinner. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-25-12-30-12.gh-issue-84694.5sjy2w.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-25-12-30-12.gh-issue-84694.5sjy2w.rst deleted file mode 100644 index c062d28b2948..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-05-25-12-30-12.gh-issue-84694.5sjy2w.rst +++ /dev/null @@ -1,2 +0,0 @@ -The ``--experimental-isolated-subinterpreters`` configure option and -``EXPERIMENTAL_ISOLATED_SUBINTERPRETERS`` macro have been removed. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-25-21-56-25.gh-issue-93223.gTOGVZ.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-25-21-56-25.gh-issue-93223.gTOGVZ.rst deleted file mode 100644 index cac30e11215b..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-05-25-21-56-25.gh-issue-93223.gTOGVZ.rst +++ /dev/null @@ -1 +0,0 @@ -When a bytecode instruction jumps to an unconditional jump instruction, the first instruction can often be optimized to target the unconditional jump's target directly. For tracing reasons, this would previously only occur if both instructions have the same line number. This also now occurs if the unconditional jump is artificial, i.e., if it has no associated line number. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-30-10-22-46.gh-issue-93345.gi1A4L.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-30-10-22-46.gh-issue-93345.gi1A4L.rst deleted file mode 100644 index 4cdb37cfe469..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-05-30-10-22-46.gh-issue-93345.gi1A4L.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a crash in substitution of a ``TypeVar`` in nested generic alias after -``TypeVarTuple``. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-30-14-50-03.gh-issue-93283.XDO2ZQ.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-30-14-50-03.gh-issue-93283.XDO2ZQ.rst deleted file mode 100644 index 550e86988b25..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-05-30-14-50-03.gh-issue-93283.XDO2ZQ.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve error message for invalid syntax of conversion character in f-string -expressions. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-30-15-35-42.gh-issue-93354.RZk8gs.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-30-15-35-42.gh-issue-93354.RZk8gs.rst deleted file mode 100644 index dcfe6a9b6ba3..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-05-30-15-35-42.gh-issue-93354.RZk8gs.rst +++ /dev/null @@ -1,3 +0,0 @@ -Use exponential backoff for specialization counters in the interpreter. Can -reduce the number of failed specializations significantly and avoid slowdown -for those parts of a program that are not suitable for specialization. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-30-15-51-11.gh-issue-93356.l5wnzW.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-30-15-51-11.gh-issue-93356.l5wnzW.rst deleted file mode 100644 index 9bb58468197e..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-05-30-15-51-11.gh-issue-93356.l5wnzW.rst +++ /dev/null @@ -1 +0,0 @@ -Code for exception handlers is emitted at the end of the code unit's bytecode. This avoids one jump when no exception is raised. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-30-19-00-38.gh-issue-93359.zXV3A0.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-30-19-00-38.gh-issue-93359.zXV3A0.rst deleted file mode 100644 index 36e5e52390d7..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-05-30-19-00-38.gh-issue-93359.zXV3A0.rst +++ /dev/null @@ -1,2 +0,0 @@ -Ensure that custom :mod:`ast` nodes without explicit end positions can be -compiled. Patch by Pablo Galindo. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-31-16-36-30.gh-issue-93382.Jf6gAj.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-31-16-36-30.gh-issue-93382.Jf6gAj.rst deleted file mode 100644 index 1fe821edf5a1..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-05-31-16-36-30.gh-issue-93382.Jf6gAj.rst +++ /dev/null @@ -1,2 +0,0 @@ -Cache the result of :c:func:`PyCode_GetCode` function to restore the O(1) -lookup of the :attr:`~types.CodeType.co_code` attribute. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-01-17-47-40.gh-issue-93418.24dJuc.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-01-17-47-40.gh-issue-93418.24dJuc.rst deleted file mode 100644 index 74ad06bfeee7..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-06-01-17-47-40.gh-issue-93418.24dJuc.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixed an assert where an f-string has an equal sign '=' following an -expression, but there's no trailing brace. For example, f"{i=". diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-02-08-28-55.gh-issue-93429.DZTWHx.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-02-08-28-55.gh-issue-93429.DZTWHx.rst deleted file mode 100644 index 02efedaa9645..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-06-02-08-28-55.gh-issue-93429.DZTWHx.rst +++ /dev/null @@ -1 +0,0 @@ -``LOAD_METHOD`` instruction has been removed. It was merged back into ``LOAD_ATTR``. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-02-23-00-08.gh-issue-93444.m63DIs.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-02-23-00-08.gh-issue-93444.m63DIs.rst deleted file mode 100644 index 23cc1bd3e0b4..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-06-02-23-00-08.gh-issue-93444.m63DIs.rst +++ /dev/null @@ -1 +0,0 @@ -Removed redundant fields from the compiler's basicblock struct: ``b_nofallthrough``, ``b_exit``, ``b_return``. They can be easily calculated from the opcode of the last instruction of the block. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-06-14-28-24.gh-issue-93533.lnC0CC.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-06-14-28-24.gh-issue-93533.lnC0CC.rst deleted file mode 100644 index 2d8ac7068af6..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-06-06-14-28-24.gh-issue-93533.lnC0CC.rst +++ /dev/null @@ -1 +0,0 @@ -Reduce the size of the inline cache for ``LOAD_METHOD`` by 2 bytes. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-09-09-08-29.gh-issue-93621.-_Pn1d.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-09-09-08-29.gh-issue-93621.-_Pn1d.rst deleted file mode 100644 index 388540982fd1..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-06-09-09-08-29.gh-issue-93621.-_Pn1d.rst +++ /dev/null @@ -1 +0,0 @@ -Change order of bytecode instructions emitted for :keyword:`with` and :keyword:`async with` to reduce the number of entries in the exception table. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-09-19-19-02.gh-issue-93461.5DqP1e.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-09-19-19-02.gh-issue-93461.5DqP1e.rst deleted file mode 100644 index f6ed14887eae..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-06-09-19-19-02.gh-issue-93461.5DqP1e.rst +++ /dev/null @@ -1,6 +0,0 @@ -:func:`importlib.invalidate_caches` now drops entries from -:data:`sys.path_importer_cache` with a relative path as name. This solves a -caching issue when a process changes its current working directory. - -``FileFinder`` no longer inserts a dot in the path, e.g. -``/egg/./spam`` is now ``/egg/spam``. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-10-10-31-18.gh-issue-93662.-7RSC1.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-10-10-31-18.gh-issue-93662.-7RSC1.rst deleted file mode 100644 index e444a00cf7ec..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-06-10-10-31-18.gh-issue-93662.-7RSC1.rst +++ /dev/null @@ -1,2 +0,0 @@ -Make sure that the end column offsets are correct in multi-line method -calls. Previously, the end column could precede the column offset. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-10-12-03-17.gh-issue-93671.idkQqG.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-10-12-03-17.gh-issue-93671.idkQqG.rst deleted file mode 100644 index a77571533595..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-06-10-12-03-17.gh-issue-93671.idkQqG.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix some exponential backtrace case happening with deeply nested sequence -patterns in match statements. Patch by Pablo Galindo diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-10-16-57-35.gh-issue-93678.1WBnHt.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-10-16-57-35.gh-issue-93678.1WBnHt.rst deleted file mode 100644 index 24a0d1042d81..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-06-10-16-57-35.gh-issue-93678.1WBnHt.rst +++ /dev/null @@ -1 +0,0 @@ -Refactor the compiler to reduce boilerplate and repetition. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-12-19-31-56.gh-issue-89828.bq02M7.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-12-19-31-56.gh-issue-89828.bq02M7.rst deleted file mode 100644 index 14ca99e1458c..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-06-12-19-31-56.gh-issue-89828.bq02M7.rst +++ /dev/null @@ -1,2 +0,0 @@ -:class:`types.GenericAlias` no longer relays the ``__class__`` attribute. -For example, ``isinstance(list[int], type)`` no longer returns ``True``. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-13-10-48-09.gh-issue-93516.yJSait.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-13-10-48-09.gh-issue-93516.yJSait.rst deleted file mode 100644 index 5c22c7a67b6e..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-06-13-10-48-09.gh-issue-93516.yJSait.rst +++ /dev/null @@ -1,2 +0,0 @@ -Lazily create a table mapping bytecode offsets to line numbers to speed up -calculation of line numbers when tracing. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-13-13-55-34.gh-issue-93516.HILrDl.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-13-13-55-34.gh-issue-93516.HILrDl.rst deleted file mode 100644 index a324c2dbcbe8..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-06-13-13-55-34.gh-issue-93516.HILrDl.rst +++ /dev/null @@ -1,2 +0,0 @@ -Store offset of first traceable instruction in code object to avoid having -to recompute it for each instruction when tracing. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-15-11-16-13.gh-issue-93841.06zqX3.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-15-11-16-13.gh-issue-93841.06zqX3.rst deleted file mode 100644 index 179d3808e3b4..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-06-15-11-16-13.gh-issue-93841.06zqX3.rst +++ /dev/null @@ -1,3 +0,0 @@ -When built with ``-enable-pystats``, ``sys._stats_on()``, -``sys._stats_off()``, ``sys._stats_clear()`` and ``sys._stats_dump()`` -functions have been added to enable gathering stats for parts of programs. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-15-16-45-53.gh-issue-93678.1I_ZT3.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-15-16-45-53.gh-issue-93678.1I_ZT3.rst deleted file mode 100644 index 3c99fd2ecf66..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-06-15-16-45-53.gh-issue-93678.1I_ZT3.rst +++ /dev/null @@ -1 +0,0 @@ -Refactor compiler optimisation code so that it no longer needs the ``struct assembler`` and ``struct compiler`` passed around. Instead, each function takes the CFG and other data that it actually needs. This will make it possible to test this code directly. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-16-16-53-22.gh-issue-93911.RDwIiK.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-16-16-53-22.gh-issue-93911.RDwIiK.rst deleted file mode 100644 index 9efa994c1916..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-06-16-16-53-22.gh-issue-93911.RDwIiK.rst +++ /dev/null @@ -1 +0,0 @@ -Specialize ``LOAD_ATTR`` for ``property()`` attributes. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-17-16-30-24.gh-issue-93955.LmiAe9.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-17-16-30-24.gh-issue-93955.LmiAe9.rst deleted file mode 100644 index 3b2f0e8c32d7..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-06-17-16-30-24.gh-issue-93955.LmiAe9.rst +++ /dev/null @@ -1 +0,0 @@ -Improve performance of attribute lookups on objects with custom ``__getattribute__`` and ``__getattr__``. Patch by Ken Jin. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-18-17-00-33.gh-issue-93911.y286of.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-18-17-00-33.gh-issue-93911.y286of.rst deleted file mode 100644 index 7fc8f6a2d492..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-06-18-17-00-33.gh-issue-93911.y286of.rst +++ /dev/null @@ -1 +0,0 @@ -Specialize ``LOAD_ATTR`` for objects with custom ``__getattribute__``. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-20-13-48-57.gh-issue-94021.o78q3G.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-20-13-48-57.gh-issue-94021.o78q3G.rst deleted file mode 100644 index 0724c517b2ba..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-06-20-13-48-57.gh-issue-94021.o78q3G.rst +++ /dev/null @@ -1 +0,0 @@ -Fix unreachable code warning in ``Python/specialize.c``. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-23-12-10-39.gh-issue-94163.SqAfQq.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-23-12-10-39.gh-issue-94163.SqAfQq.rst deleted file mode 100644 index 3f82943cbfbe..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-06-23-12-10-39.gh-issue-94163.SqAfQq.rst +++ /dev/null @@ -1,5 +0,0 @@ -Add :opcode:`BINARY_SLICE` and :opcode:`STORE_SLICE` instructions for more efficient handling -and better specialization of slicing operations, where the slice is explicit -in the source code. - - diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-24-14-06-20.gh-issue-93883.8jVQQ4.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-24-14-06-20.gh-issue-93883.8jVQQ4.rst deleted file mode 100644 index 53345577036a..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-06-24-14-06-20.gh-issue-93883.8jVQQ4.rst +++ /dev/null @@ -1 +0,0 @@ -Revise the display strategy of traceback enhanced error locations. The indicators are only shown when the location doesn't span the whole line. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-25-10-19-43.gh-issue-87995.aMDHnp.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-25-10-19-43.gh-issue-87995.aMDHnp.rst deleted file mode 100644 index 4154ebce2349..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-06-25-10-19-43.gh-issue-87995.aMDHnp.rst +++ /dev/null @@ -1,2 +0,0 @@ -:class:`types.MappingProxyType` instances are now hashable if the underlying -mapping is hashable. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-26-14-37-03.gh-issue-94192.ab7tn7.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-26-14-37-03.gh-issue-94192.ab7tn7.rst deleted file mode 100644 index ebd8b04e4509..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-06-26-14-37-03.gh-issue-94192.ab7tn7.rst +++ /dev/null @@ -1 +0,0 @@ -Fix error for dictionary literals with invalid expression as value. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-28-10-08-06.gh-issue-94262.m-HWUZ.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-28-10-08-06.gh-issue-94262.m-HWUZ.rst deleted file mode 100644 index 7ba39bbcfe21..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-06-28-10-08-06.gh-issue-94262.m-HWUZ.rst +++ /dev/null @@ -1,3 +0,0 @@ -Don't create frame objects for incomplete frames. Prevents the creation of -generators and closures from being observable to Python and C extensions, -restoring the behavior of 3.10 and earlier. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-28-12-41-17.gh-issue-88116.A7fEl_.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-28-12-41-17.gh-issue-88116.A7fEl_.rst deleted file mode 100644 index a8347cff09f3..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-06-28-12-41-17.gh-issue-88116.A7fEl_.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix an issue when reading line numbers from code objects if the encoded line -numbers are close to ``INT_MIN``. Patch by Pablo Galindo diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-28-14-20-36.gh-issue-94360.DiEnen.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-28-14-20-36.gh-issue-94360.DiEnen.rst deleted file mode 100644 index 0a74ba38b0ac..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-06-28-14-20-36.gh-issue-94360.DiEnen.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixed a tokenizer crash when reading encoded files with syntax errors from -``stdin`` with non utf-8 encoded text. Patch by Pablo Galindo diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-29-15-45-04.gh-issue-94329.olUQyk.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-29-15-45-04.gh-issue-94329.olUQyk.rst deleted file mode 100644 index afd31b6e4dc4..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-06-29-15-45-04.gh-issue-94329.olUQyk.rst +++ /dev/null @@ -1,2 +0,0 @@ -Compile and run code with unpacking of extremely large sequences (1000s of elements). -Such code failed to compile. It now compiles and runs correctly. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-29-22-18-36.gh-issue-91719.3APYYI.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-29-22-18-36.gh-issue-91719.3APYYI.rst deleted file mode 100644 index 0d085e887783..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-06-29-22-18-36.gh-issue-91719.3APYYI.rst +++ /dev/null @@ -1,2 +0,0 @@ -Reload ``opcode`` when raising ``unknown opcode error`` in the interpreter main loop, -for C compilers to generate dispatching code independently. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-30-15-07-26.gh-issue-94438.btzHSk.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-30-15-07-26.gh-issue-94438.btzHSk.rst deleted file mode 100644 index b08dd8f2ad16..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-06-30-15-07-26.gh-issue-94438.btzHSk.rst +++ /dev/null @@ -1,2 +0,0 @@ -Account for instructions that can push NULL to the stack when setting line -number in a frame. Prevents some (unlikely) crashes. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-07-01-20-00-19.gh-issue-94485.mo5st7.rst b/Misc/NEWS.d/next/Core and Builtins/2022-07-01-20-00-19.gh-issue-94485.mo5st7.rst deleted file mode 100644 index 14d90b7e764a..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-07-01-20-00-19.gh-issue-94485.mo5st7.rst +++ /dev/null @@ -1,2 +0,0 @@ -Line number of a module's ``RESUME`` instruction is set to 0 as specified in -:pep:`626`. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-07-06-14-02-26.gh-issue-92228.44Cbly.rst b/Misc/NEWS.d/next/Core and Builtins/2022-07-06-14-02-26.gh-issue-92228.44Cbly.rst deleted file mode 100644 index 458ad897cefc..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-07-06-14-02-26.gh-issue-92228.44Cbly.rst +++ /dev/null @@ -1 +0,0 @@ -Disable the compiler's inline-small-exit-blocks optimization for exit blocks that are associated with source code lines. This fixes a bug where the debugger cannot tell where an exception handler ends and the following code block begins. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-07-07-21-13-25.gh-issue-94215._Sv9Ms.rst b/Misc/NEWS.d/next/Core and Builtins/2022-07-07-21-13-25.gh-issue-94215._Sv9Ms.rst deleted file mode 100644 index 07af472fbdca..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-07-07-21-13-25.gh-issue-94215._Sv9Ms.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix an issue where exceptions raised by line-tracing events would cause -frames to be left in an invalid state, possibly resulting in a hard crash of -the interpreter. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-07-08-11-44-45.gh-issue-93252.i2358c.rst b/Misc/NEWS.d/next/Core and Builtins/2022-07-08-11-44-45.gh-issue-93252.i2358c.rst deleted file mode 100644 index 1cc2d8560e53..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-07-08-11-44-45.gh-issue-93252.i2358c.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix an issue that caused internal frames to outlive failed Python function -calls, possibly resulting in memory leaks or hard interpreter crashes. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-07-08-16-44-11.gh-issue-94694.VkL2CM.rst b/Misc/NEWS.d/next/Core and Builtins/2022-07-08-16-44-11.gh-issue-94694.VkL2CM.rst deleted file mode 100644 index 6434788140f4..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-07-08-16-44-11.gh-issue-94694.VkL2CM.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix an issue that could cause code with multi-line method lookups to have -misleading or incorrect column offset information. In some cases (when -compiling a hand-built AST) this could have resulted in a hard crash of the -interpreter. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-07-14-10-07-53.gh-issue-90699.x3aG9m.rst b/Misc/NEWS.d/next/Core and Builtins/2022-07-14-10-07-53.gh-issue-90699.x3aG9m.rst deleted file mode 100644 index 795f4df987eb..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-07-14-10-07-53.gh-issue-90699.x3aG9m.rst +++ /dev/null @@ -1 +0,0 @@ -Fix reference counting bug in :meth:`bool.__repr__`. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-07-15-16-15-04.gh-issue-91153.HiBmtt.rst b/Misc/NEWS.d/next/Core and Builtins/2022-07-15-16-15-04.gh-issue-91153.HiBmtt.rst deleted file mode 100644 index 2caa0170f75b..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-07-15-16-15-04.gh-issue-91153.HiBmtt.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix an issue where a :class:`bytearray` item assignment could crash if it's -resized by the new value's :meth:`__index__` method. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-07-15-22-16-08.gh-issue-94822.zRRzBN.rst b/Misc/NEWS.d/next/Core and Builtins/2022-07-15-22-16-08.gh-issue-94822.zRRzBN.rst deleted file mode 100644 index 5b24918e4977..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-07-15-22-16-08.gh-issue-94822.zRRzBN.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix an issue where lookups of metaclass descriptors may be ignored when an -identically-named attribute also exists on the class itself. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-07-15-22-47-44.gh-issue-94893.YiJYcW.rst b/Misc/NEWS.d/next/Core and Builtins/2022-07-15-22-47-44.gh-issue-94893.YiJYcW.rst deleted file mode 100644 index 6384ef92c654..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-07-15-22-47-44.gh-issue-94893.YiJYcW.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix an issue where frame object manipulations could corrupt inline bytecode -caches. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-07-16-08-14-17.gh-issue-94869.eRwMsX.rst b/Misc/NEWS.d/next/Core and Builtins/2022-07-16-08-14-17.gh-issue-94869.eRwMsX.rst deleted file mode 100644 index 2ccf91b0cd99..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-07-16-08-14-17.gh-issue-94869.eRwMsX.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix the column offsets for some expressions in multi-line f-strings -:mod:`ast` nodes. Patch by Pablo Galindo. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-07-17-15-54-29.gh-issue-91256.z7i7Q5.rst b/Misc/NEWS.d/next/Core and Builtins/2022-07-17-15-54-29.gh-issue-91256.z7i7Q5.rst deleted file mode 100644 index 802a614fd48d..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-07-17-15-54-29.gh-issue-91256.z7i7Q5.rst +++ /dev/null @@ -1 +0,0 @@ -Ensures the program name is known for help text during interpreter startup. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-07-18-04-48-34.gh-issue-94947.df9gUw.rst b/Misc/NEWS.d/next/Core and Builtins/2022-07-18-04-48-34.gh-issue-94947.df9gUw.rst deleted file mode 100644 index 360ea67048fe..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-07-18-04-48-34.gh-issue-94947.df9gUw.rst +++ /dev/null @@ -1 +0,0 @@ -:func:`ast.parse` will no longer parse assignment expressions when passed ``feature_version`` less than ``(3, 8)``. Patch by Shantanu Jain. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-07-18-05-10-29.gh-issue-94949.OsZ7_s.rst b/Misc/NEWS.d/next/Core and Builtins/2022-07-18-05-10-29.gh-issue-94949.OsZ7_s.rst deleted file mode 100644 index bc452d434da0..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-07-18-05-10-29.gh-issue-94949.OsZ7_s.rst +++ /dev/null @@ -1 +0,0 @@ -:func:`ast.parse` will no longer parse parenthesized context managers when passed ``feature_version`` less than ``(3, 9)``. Patch by Shantanu Jain. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-07-18-14-19-21.gh-issue-94739.NQJQi7.rst b/Misc/NEWS.d/next/Core and Builtins/2022-07-18-14-19-21.gh-issue-94739.NQJQi7.rst deleted file mode 100644 index 7476892c423b..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-07-18-14-19-21.gh-issue-94739.NQJQi7.rst +++ /dev/null @@ -1 +0,0 @@ -Allow jumping within, out of, and across exception handlers in the debugger. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-07-19-04-34-56.gh-issue-94996.dV564A.rst b/Misc/NEWS.d/next/Core and Builtins/2022-07-19-04-34-56.gh-issue-94996.dV564A.rst deleted file mode 100644 index 90c9ada079e0..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-07-19-04-34-56.gh-issue-94996.dV564A.rst +++ /dev/null @@ -1 +0,0 @@ -:func:`ast.parse` will no longer parse function definitions with positional-only params when passed ``feature_version`` less than ``(3, 8)``. Patch by Shantanu Jain. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-07-19-09-41-55.gh-issue-94938.xYBlM7.rst b/Misc/NEWS.d/next/Core and Builtins/2022-07-19-09-41-55.gh-issue-94938.xYBlM7.rst deleted file mode 100644 index cc4feae685f2..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-07-19-09-41-55.gh-issue-94938.xYBlM7.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix error detection in some builtin functions when keyword argument name is -an instance of a str subclass with overloaded ``__eq__`` and ``__hash__``. -Previously it could cause SystemError or other undesired behavior. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-07-19-16-30-59.gh-issue-94036._6Utkm.rst b/Misc/NEWS.d/next/Core and Builtins/2022-07-19-16-30-59.gh-issue-94036._6Utkm.rst deleted file mode 100644 index b0f036773626..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-07-19-16-30-59.gh-issue-94036._6Utkm.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix incorrect source location info for some multi-line attribute accesses -and method calls. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-07-20-09-04-55.gh-issue-95023.bs-xd7.rst b/Misc/NEWS.d/next/Core and Builtins/2022-07-20-09-04-55.gh-issue-95023.bs-xd7.rst deleted file mode 100644 index bf0558ba79c7..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-07-20-09-04-55.gh-issue-95023.bs-xd7.rst +++ /dev/null @@ -1 +0,0 @@ -Implement :func:`os.setns` and :func:`os.unshare` for Linux. Patch by Noam Cohen. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-07-20-13-46-01.gh-issue-91409.dhL8Zo.rst b/Misc/NEWS.d/next/Core and Builtins/2022-07-20-13-46-01.gh-issue-91409.dhL8Zo.rst deleted file mode 100644 index 2bc0d8224c6a..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-07-20-13-46-01.gh-issue-91409.dhL8Zo.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix incorrect source location info caused by certain optimizations in the -bytecode compiler. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-07-21-17-54-52.gh-issue-95113.NnSLpT.rst b/Misc/NEWS.d/next/Core and Builtins/2022-07-21-17-54-52.gh-issue-95113.NnSLpT.rst deleted file mode 100644 index c2ff6c90ac8c..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-07-21-17-54-52.gh-issue-95113.NnSLpT.rst +++ /dev/null @@ -1,4 +0,0 @@ -Replace all ``EXTENDED_ARG_QUICK`` instructions with basic -:opcode:`EXTENDED_ARG` instructions in unquickened code. Consumers of -non-adaptive bytecode should be able to handle extended arguments the same -way they were handled in CPython 3.10 and older. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-07-21-19-19-20.gh-issue-95060.4xdT1f.rst b/Misc/NEWS.d/next/Core and Builtins/2022-07-21-19-19-20.gh-issue-95060.4xdT1f.rst deleted file mode 100644 index 160999e82bf0..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-07-21-19-19-20.gh-issue-95060.4xdT1f.rst +++ /dev/null @@ -1,2 +0,0 @@ -Undocumented ``PyCode_Addr2Location`` function now properly returns when -``addrq`` argument is less than zero. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-07-22-12-53-34.gh-issue-94438.hNqACc.rst b/Misc/NEWS.d/next/Core and Builtins/2022-07-22-12-53-34.gh-issue-94438.hNqACc.rst deleted file mode 100644 index 2a7249a833c2..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-07-22-12-53-34.gh-issue-94438.hNqACc.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix an issue that caused extended opcode arguments and some conditional pops -to be ignored when calculating valid jump targets for assignments to the -``f_lineno`` attribute of frame objects. In some cases, this could cause -inconsistent internal state, resulting in a hard crash of the interpreter. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-07-23-19-16-25.gh-issue-93351.0Jyvu-.rst b/Misc/NEWS.d/next/Core and Builtins/2022-07-23-19-16-25.gh-issue-93351.0Jyvu-.rst deleted file mode 100644 index 97cf8055ac54..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-07-23-19-16-25.gh-issue-93351.0Jyvu-.rst +++ /dev/null @@ -1,3 +0,0 @@ -:class:`ast.AST` node positions are now validated when provided to -:func:`compile` and other related functions. If invalid positions are -detected, a :exc:`ValueError` will be raised. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-07-24-00-27-47.gh-issue-95185.ghYTZx.rst b/Misc/NEWS.d/next/Core and Builtins/2022-07-24-00-27-47.gh-issue-95185.ghYTZx.rst deleted file mode 100644 index de156bab2f51..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-07-24-00-27-47.gh-issue-95185.ghYTZx.rst +++ /dev/null @@ -1,3 +0,0 @@ -Prevented crashes in the AST constructor when compiling some absurdly long -expressions like ``"+0"*1000000``. :exc:`RecursionError` is now raised -instead. Patch by Pablo Galindo diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-07-26-09-31-12.gh-issue-93678.W8vvgT.rst b/Misc/NEWS.d/next/Core and Builtins/2022-07-26-09-31-12.gh-issue-93678.W8vvgT.rst deleted file mode 100644 index 6ff816a172cc..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-07-26-09-31-12.gh-issue-93678.W8vvgT.rst +++ /dev/null @@ -1 +0,0 @@ -Add cfg_builder struct and refactor the relevant code so that a cfg can be constructed without an instance of the compiler struct. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-07-26-12-59-03.gh-issue-95245.GHWczn.rst b/Misc/NEWS.d/next/Core and Builtins/2022-07-26-12-59-03.gh-issue-95245.GHWczn.rst deleted file mode 100644 index d6dccc8fcad0..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-07-26-12-59-03.gh-issue-95245.GHWczn.rst +++ /dev/null @@ -1,2 +0,0 @@ -Merge managed dict and values pointer into a single tagged pointer to save -one word in the pre-header. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-07-27-14-05-07.gh-issue-95324.28Q5u7.rst b/Misc/NEWS.d/next/Core and Builtins/2022-07-27-14-05-07.gh-issue-95324.28Q5u7.rst deleted file mode 100644 index 250385270e94..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-07-27-14-05-07.gh-issue-95324.28Q5u7.rst +++ /dev/null @@ -1,2 +0,0 @@ -Emit a warning in debug mode if an object does not call -:c:func:`PyObject_GC_UnTrack` before deallocation. Patch by Pablo Galindo. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-07-27-14-21-57.gh-issue-90081.HVAS5x.rst b/Misc/NEWS.d/next/Core and Builtins/2022-07-27-14-21-57.gh-issue-90081.HVAS5x.rst deleted file mode 100644 index a3be34c175af..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-07-27-14-21-57.gh-issue-90081.HVAS5x.rst +++ /dev/null @@ -1,2 +0,0 @@ -Run Python code in tracer/profiler function at full speed. Fixes slowdown in -earlier versions of 3.11. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-07-28-08-33-31.gh-issue-95355.yN4XVk.rst b/Misc/NEWS.d/next/Core and Builtins/2022-07-28-08-33-31.gh-issue-95355.yN4XVk.rst deleted file mode 100644 index 6a289991e0d6..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-07-28-08-33-31.gh-issue-95355.yN4XVk.rst +++ /dev/null @@ -1 +0,0 @@ -``_PyPegen_Parser_New`` now properly detects token memory allocation errors. Patch by Honglin Zhu. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-07-28-19-07-06.gh-issue-87092.73IPS1.rst b/Misc/NEWS.d/next/Core and Builtins/2022-07-28-19-07-06.gh-issue-87092.73IPS1.rst deleted file mode 100644 index d4cc4bb9afc2..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-07-28-19-07-06.gh-issue-87092.73IPS1.rst +++ /dev/null @@ -1 +0,0 @@ -Create a 'jump target label' abstraction in the compiler so that the compiler's codegen stage does not work directly with basic blocks. This prepares the code for changes to the underlying CFG generation mechanism. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-07-31-03-22-58.gh-issue-91146.Y2Hziy.rst b/Misc/NEWS.d/next/Core and Builtins/2022-07-31-03-22-58.gh-issue-91146.Y2Hziy.rst deleted file mode 100644 index 9172ca298e80..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-07-31-03-22-58.gh-issue-91146.Y2Hziy.rst +++ /dev/null @@ -1,2 +0,0 @@ -Reduce allocation size of :class:`list` from :meth:`str.split` -and :meth:`str.rsplit`. Patch by Dong-hee Na and Inada Naoki. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-07-31-13-23-12.gh-issue-95150.67FXVo.rst b/Misc/NEWS.d/next/Core and Builtins/2022-07-31-13-23-12.gh-issue-95150.67FXVo.rst deleted file mode 100644 index c3db4714188b..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-07-31-13-23-12.gh-issue-95150.67FXVo.rst +++ /dev/null @@ -1,3 +0,0 @@ -Update code object hashing and equality to consider all debugging and -exception handling tables. This fixes an issue where certain non-identical -code objects could be "deduplicated" during compilation. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-08-04-18-46-54.gh-issue-95605.FbpCoG.rst b/Misc/NEWS.d/next/Core and Builtins/2022-08-04-18-46-54.gh-issue-95605.FbpCoG.rst deleted file mode 100644 index 49441c6b3118..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-08-04-18-46-54.gh-issue-95605.FbpCoG.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix misleading contents of error message when converting an all-whitespace -string to :class:`float`. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-08-11-09-19-55.gh-issue-95876.YpQfoV.rst b/Misc/NEWS.d/next/Core and Builtins/2022-08-11-09-19-55.gh-issue-95876.YpQfoV.rst deleted file mode 100644 index 96b69015a586..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-08-11-09-19-55.gh-issue-95876.YpQfoV.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix format string in ``_PyPegen_raise_error_known_location`` that can lead -to memory corruption on some 64bit systems. The function was building a -tuple with ``i`` (int) instead of ``n`` (Py_ssize_t) for Py_ssize_t -arguments. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-08-11-11-01-56.gh-issue-95818.iClLdl.rst b/Misc/NEWS.d/next/Core and Builtins/2022-08-11-11-01-56.gh-issue-95818.iClLdl.rst deleted file mode 100644 index 1e243f5614f1..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-08-11-11-01-56.gh-issue-95818.iClLdl.rst +++ /dev/null @@ -1 +0,0 @@ -Skip over incomplete frames in :c:func:`PyThreadState_GetFrame`. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-08-12-13-04-25.gh-issue-95922.YNCtyX.rst b/Misc/NEWS.d/next/Core and Builtins/2022-08-12-13-04-25.gh-issue-95922.YNCtyX.rst deleted file mode 100644 index 277d35deab39..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-08-12-13-04-25.gh-issue-95922.YNCtyX.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixed bug where the compiler's ``eliminate_empty_basic_blocks`` function -ignores the last block of the code unit. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-08-12-18-13-49.gh-issue-91210.AWMSLj.rst b/Misc/NEWS.d/next/Core and Builtins/2022-08-12-18-13-49.gh-issue-91210.AWMSLj.rst deleted file mode 100644 index f17d6ce5763f..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-08-12-18-13-49.gh-issue-91210.AWMSLj.rst +++ /dev/null @@ -1 +0,0 @@ -Improve error message when a parameter without a default value follows one with a default value, and show the same message, even when the non-default/default sequence is preceded by positional-only parameters. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-08-14-10-04-44.gh-issue-95977.gCTZb9.rst b/Misc/NEWS.d/next/Core and Builtins/2022-08-14-10-04-44.gh-issue-95977.gCTZb9.rst deleted file mode 100644 index b265c770233a..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-08-14-10-04-44.gh-issue-95977.gCTZb9.rst +++ /dev/null @@ -1 +0,0 @@ -Optimized calling :meth:`~object.__get__` with vectorcall. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-08-15-11-58-05.gh-issue-90997.bWwV8Q.rst b/Misc/NEWS.d/next/Core and Builtins/2022-08-15-11-58-05.gh-issue-90997.bWwV8Q.rst deleted file mode 100644 index 8db714e59e15..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-08-15-11-58-05.gh-issue-90997.bWwV8Q.rst +++ /dev/null @@ -1,3 +0,0 @@ -Compile virtual :keyword:`try`/:keyword:`except` blocks to handle exceptions -raised during :meth:`~generator.close` or :meth:`~generator.throw` calls -through a suspended frame. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-08-15-12-41-14.gh-issue-95245.N4gOUV.rst b/Misc/NEWS.d/next/Core and Builtins/2022-08-15-12-41-14.gh-issue-95245.N4gOUV.rst deleted file mode 100644 index 4449ddd8ded8..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-08-15-12-41-14.gh-issue-95245.N4gOUV.rst +++ /dev/null @@ -1,3 +0,0 @@ -Reduces the size of a "simple" Python object from 8 to 6 words by moving the -weakreflist pointer into the pre-header directly before the object's -dict/values pointer. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-08-15-20-52-41.gh-issue-93678.X7GuIJ.rst b/Misc/NEWS.d/next/Core and Builtins/2022-08-15-20-52-41.gh-issue-93678.X7GuIJ.rst deleted file mode 100644 index 9e2b90ba07a4..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-08-15-20-52-41.gh-issue-93678.X7GuIJ.rst +++ /dev/null @@ -1 +0,0 @@ -Added test a harness for direct unit tests of the compiler's optimization stage. The ``_testinternalcapi.optimize_cfg()`` function runs the optimiser on a sequence of instructions. The ``CfgOptimizationTestCase`` class in ``test.support`` has utilities for invoking the optimizer and checking the output. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-08-15-21-08-11.gh-issue-96005.6eoc8k.rst b/Misc/NEWS.d/next/Core and Builtins/2022-08-15-21-08-11.gh-issue-96005.6eoc8k.rst deleted file mode 100644 index 06e414bca0f9..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-08-15-21-08-11.gh-issue-96005.6eoc8k.rst +++ /dev/null @@ -1,4 +0,0 @@ -On WASI :data:`~errno.ENOTCAPABLE` is now mapped to :exc:`PermissionError`. -The :mod:`errno` modules exposes the new error number. ``getpath.py`` now -ignores :exc:`PermissionError` when it cannot open landmark files -``pybuilddir.txt`` and ``pyenv.cfg``. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-08-18-13-47-59.gh-issue-96046.5Hqbka.rst b/Misc/NEWS.d/next/Core and Builtins/2022-08-18-13-47-59.gh-issue-96046.5Hqbka.rst deleted file mode 100644 index b8cb52d4b4ec..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-08-18-13-47-59.gh-issue-96046.5Hqbka.rst +++ /dev/null @@ -1,4 +0,0 @@ -:c:func:`PyType_Ready` now initializes ``ht_cached_keys`` and performs -additional checks to ensure that type objects are properly configured. This -avoids crashes in 3rd party packages that don't use regular API to create -new types. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-08-19-06-51-17.gh-issue-96071.mVgPAo.rst b/Misc/NEWS.d/next/Core and Builtins/2022-08-19-06-51-17.gh-issue-96071.mVgPAo.rst deleted file mode 100644 index 37653ffac124..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-08-19-06-51-17.gh-issue-96071.mVgPAo.rst +++ /dev/null @@ -1 +0,0 @@ -Fix a deadlock in :c:func:`PyGILState_Ensure` when allocating new thread state. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-08-20-18-36-40.gh-issue-96143.nh3GFM.rst b/Misc/NEWS.d/next/Core and Builtins/2022-08-20-18-36-40.gh-issue-96143.nh3GFM.rst deleted file mode 100644 index 30f44fd453a5..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-08-20-18-36-40.gh-issue-96143.nh3GFM.rst +++ /dev/null @@ -1,7 +0,0 @@ -Add a new ``-X perf`` Python command line option as well as -:func:`sys.activate_stack_trampoline` and :func:`sys.deactivate_stack_trampoline` -function in the :mod:`sys` module that allows to set/unset the interpreter in a -way that the Linux ``perf`` profiler can detect Python calls. The new -:func:`sys.is_stack_trampoline_active` function allows to query the state of the -perf trampoline. Design by Pablo Galindo. Patch by Pablo Galindo and Christian Heimes -with contributions from Gregory P. Smith [Google] and Mark Shannon. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-08-22-21-33-28.gh-issue-96187.W_6SRG.rst b/Misc/NEWS.d/next/Core and Builtins/2022-08-22-21-33-28.gh-issue-96187.W_6SRG.rst deleted file mode 100644 index fd194faa6854..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-08-22-21-33-28.gh-issue-96187.W_6SRG.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixed a bug that caused ``_PyCode_GetExtra`` to return garbage for negative -indexes. Patch by Pablo Galindo diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-08-24-14-30-26.gh-issue-96237.msif5f.rst b/Misc/NEWS.d/next/Core and Builtins/2022-08-24-14-30-26.gh-issue-96237.msif5f.rst deleted file mode 100644 index cb8a1c0eb7c2..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-08-24-14-30-26.gh-issue-96237.msif5f.rst +++ /dev/null @@ -1,5 +0,0 @@ -The internal field ``_PyInterpreterFrame.f_func`` is renamed to -``_PyInterpreterFrame.f_funcobj`` and may be any object. The ``f_globals`` -and ``f_builtin`` fields may hold junk values. - -It is safest to treat the ``_PyInterpreterFrame`` struct as opaque. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-08-25-10-19-34.gh-issue-96268.AbYrLB.rst b/Misc/NEWS.d/next/Core and Builtins/2022-08-25-10-19-34.gh-issue-96268.AbYrLB.rst deleted file mode 100644 index 987d85ff3bab..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-08-25-10-19-34.gh-issue-96268.AbYrLB.rst +++ /dev/null @@ -1,2 +0,0 @@ -Loading a file with invalid UTF-8 will now report the broken character at -the correct location. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-08-26-18-46-32.gh-issue-93554.QEaCcK.rst b/Misc/NEWS.d/next/Core and Builtins/2022-08-26-18-46-32.gh-issue-93554.QEaCcK.rst deleted file mode 100644 index dff12aef721b..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-08-26-18-46-32.gh-issue-93554.QEaCcK.rst +++ /dev/null @@ -1,16 +0,0 @@ -Change the jump opcodes so that all conditional jumps are forward jumps. -Backward jumps are converted by the assembler into a conditional forward -jump whose target is the fallthrough block (and with a reversed condition), -followed by an unconditional backward jump. For example: - -``POP_JUMP_IF_TRUE BACKWARD_TARGET`` becomes ``POP_JUMP_IF_FALSE NEXT_BLOCK; -JUMP BACKWARD_TARGET``. - -All the directed conditional jump opcodes were removed: -``POP_JUMP_FORWARD_IF_TRUE``, ``POP_JUMP_BACKWARD_IF_TRUE``, -``POP_JUMP_FORWARD_IF_FALSE``, ``POP_JUMP_BACKWARD_IF_FALSE``, -``POP_JUMP_FORWARD_IF_NONE``, ``POP_JUMP_BACKWARD_IF_NONE``, -``POP_JUMP_FORWARD_IF_NOT_NONE``, ``POP_JUMP_BACKWARD_IF_NOT_NONE``. - -The corresponding opcodes without direction are no longer pseudo-instructions, -and they implement the forward conditional jumps. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-08-28-10-51-19.gh-issue-96352.jTLD2d.rst b/Misc/NEWS.d/next/Core and Builtins/2022-08-28-10-51-19.gh-issue-96352.jTLD2d.rst deleted file mode 100644 index 25ab9678715a..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-08-28-10-51-19.gh-issue-96352.jTLD2d.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix :exc:`AttributeError` missing ``name`` and ``obj`` attributes in -:meth:`object.__getattribute__`. Patch by Philip Georgi. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-08-29-00-37-21.gh-issue-96364.c-IVyb.rst b/Misc/NEWS.d/next/Core and Builtins/2022-08-29-00-37-21.gh-issue-96364.c-IVyb.rst deleted file mode 100644 index 8872f9a5a498..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-08-29-00-37-21.gh-issue-96364.c-IVyb.rst +++ /dev/null @@ -1 +0,0 @@ -Fix text signatures of ``list.__getitem__`` and ``dict.__getitem__``. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-08-29-13-06-58.gh-issue-95196.eGRR4b.rst b/Misc/NEWS.d/next/Core and Builtins/2022-08-29-13-06-58.gh-issue-95196.eGRR4b.rst deleted file mode 100644 index 37534fa17525..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-08-29-13-06-58.gh-issue-95196.eGRR4b.rst +++ /dev/null @@ -1 +0,0 @@ -Disable incorrect pickling of the C implemented classmethod descriptors. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-08-31-18-46-13.gh-issue-96348.xzCoTP.rst b/Misc/NEWS.d/next/Core and Builtins/2022-08-31-18-46-13.gh-issue-96348.xzCoTP.rst deleted file mode 100644 index 5d3bd17b5786..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-08-31-18-46-13.gh-issue-96348.xzCoTP.rst +++ /dev/null @@ -1,2 +0,0 @@ -Emit a DeprecationWarning when :meth:`~generator.throw`, :meth:`~coroutine.throw` or :meth:`~agen.athrow` -are called with more than one argument. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-02-16-47-52.gh-issue-93911.vF-GWe.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-02-16-47-52.gh-issue-93911.vF-GWe.rst deleted file mode 100644 index b8dc0435377b..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-02-16-47-52.gh-issue-93911.vF-GWe.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix an issue that could prevent :opcode:`LOAD_ATTR` from specializing -properly when accessing properties. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-05-09-56-32.gh-issue-91079.H4-DdU.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-05-09-56-32.gh-issue-91079.H4-DdU.rst deleted file mode 100644 index 64606ac74a49..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-05-09-56-32.gh-issue-91079.H4-DdU.rst +++ /dev/null @@ -1,3 +0,0 @@ -Separate Python recursion checking from C recursion checking which reduces -the chance of C stack overflow and allows the recursion limit to be -increased safely. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-05-15-07-25.gh-issue-96582.HEsL5s.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-05-15-07-25.gh-issue-96582.HEsL5s.rst deleted file mode 100644 index 162f7baadf49..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-05-15-07-25.gh-issue-96582.HEsL5s.rst +++ /dev/null @@ -1 +0,0 @@ -Fix possible ``NULL`` pointer dereference in ``_PyThread_CurrentFrames``. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-05-16-43-44.gh-issue-96569.9lmTCC.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-05-16-43-44.gh-issue-96569.9lmTCC.rst deleted file mode 100644 index 4734d3d6ded1..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-05-16-43-44.gh-issue-96569.9lmTCC.rst +++ /dev/null @@ -1 +0,0 @@ -Remove two cases of undefined behavoir, by adding NULL checks. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-05-19-20-44.gh-issue-96587.bVxhX2.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-05-19-20-44.gh-issue-96587.bVxhX2.rst deleted file mode 100644 index 37e9dcbb11f0..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-05-19-20-44.gh-issue-96587.bVxhX2.rst +++ /dev/null @@ -1,2 +0,0 @@ -Correctly raise ``SyntaxError`` on exception groups (:pep:`654`) on python -versions prior to 3.11 diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-06-11-19-03.gh-issue-90230.YOtzs5.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-06-11-19-03.gh-issue-90230.YOtzs5.rst deleted file mode 100644 index aac48e7d792f..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-06-11-19-03.gh-issue-90230.YOtzs5.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix compiler warnings and test failures when building with -``--enable-pystats``. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-06-14-26-36.gh-issue-96612.P4ZbeY.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-06-14-26-36.gh-issue-96612.P4ZbeY.rst deleted file mode 100644 index 52e92703c9c4..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-06-14-26-36.gh-issue-96612.P4ZbeY.rst +++ /dev/null @@ -1 +0,0 @@ -Make sure that incomplete frames do not show up in tracemalloc traces. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-06-16-22-13.gh-issue-96611.14wIX8.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-06-16-22-13.gh-issue-96611.14wIX8.rst deleted file mode 100644 index 08bd409bc9f9..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-06-16-22-13.gh-issue-96611.14wIX8.rst +++ /dev/null @@ -1,2 +0,0 @@ -When loading a file with invalid UTF-8 inside a multi-line string, a correct -SyntaxError is emitted. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-06-16-54-49.gh-issue-96572.8DRsaW.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-06-16-54-49.gh-issue-96572.8DRsaW.rst deleted file mode 100644 index 44cceb46c28c..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-06-16-54-49.gh-issue-96572.8DRsaW.rst +++ /dev/null @@ -1 +0,0 @@ -Fix use after free in trace refs build mode. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-07-12-02-11.gh-issue-96636.YvN-K6.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-07-12-02-11.gh-issue-96636.YvN-K6.rst deleted file mode 100644 index e0fbd8761aa3..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-07-12-02-11.gh-issue-96636.YvN-K6.rst +++ /dev/null @@ -1,3 +0,0 @@ -Ensure that tracing, ``sys.setrace()``, is turned on immediately. In -pre-release versions of 3.11, some tracing events might have been lost when -turning on tracing in a ``__del__`` method or interrupt. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-07-13-38-37.gh-issue-96641.wky0Fc.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-07-13-38-37.gh-issue-96641.wky0Fc.rst deleted file mode 100644 index 51faca8716fb..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-07-13-38-37.gh-issue-96641.wky0Fc.rst +++ /dev/null @@ -1 +0,0 @@ -Do not expose ``KeyWrapper`` in :mod:`_functools`. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-08-20-58-10.gh-issue-64373.AfCi36.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-08-20-58-10.gh-issue-64373.AfCi36.rst deleted file mode 100644 index e7e13cb3a00c..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-08-20-58-10.gh-issue-64373.AfCi36.rst +++ /dev/null @@ -1 +0,0 @@ -Convert :mod:`_functools` to argument clinic. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-09-13-13-27.gh-issue-96678.vMxi9F.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-09-13-13-27.gh-issue-96678.vMxi9F.rst deleted file mode 100644 index 575b52be2940..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-09-13-13-27.gh-issue-96678.vMxi9F.rst +++ /dev/null @@ -1 +0,0 @@ -Fix case of undefined behavior in ceval.c diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-11-00-37-50.gh-issue-90751.VE8-zf.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-11-00-37-50.gh-issue-90751.VE8-zf.rst deleted file mode 100644 index 0908f1cc066f..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-11-00-37-50.gh-issue-90751.VE8-zf.rst +++ /dev/null @@ -1,2 +0,0 @@ -:class:`memoryview` now supports half-floats. -Patch by Dong-hee Na and Antoine Pitrou. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-11-12-43-43.gh-issue-96751.anRT6a.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-11-12-43-43.gh-issue-96751.anRT6a.rst deleted file mode 100644 index fb5b73e1ac77..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-11-12-43-43.gh-issue-96751.anRT6a.rst +++ /dev/null @@ -1 +0,0 @@ -Remove dead code from ``CALL_FUNCTION_EX`` opcode. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-12-15-15-04.gh-issue-90997.sZO8c9.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-12-15-15-04.gh-issue-90997.sZO8c9.rst deleted file mode 100644 index 4a43e2babcde..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-12-15-15-04.gh-issue-90997.sZO8c9.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve the performance of reading and writing inline bytecode caches on -some platforms. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-12-16-58-22.gh-issue-96754.0GRme5.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-12-16-58-22.gh-issue-96754.0GRme5.rst deleted file mode 100644 index beac84ee822a..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-12-16-58-22.gh-issue-96754.0GRme5.rst +++ /dev/null @@ -1,3 +0,0 @@ -Make sure that all frame objects created are created from valid interpreter -frames. Prevents the possibility of invalid frames in backtraces and signal -handlers. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-13-12-06-46.gh-issue-96678.NqGFyb.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-13-12-06-46.gh-issue-96678.NqGFyb.rst deleted file mode 100644 index bdd33c8d2ca9..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-13-12-06-46.gh-issue-96678.NqGFyb.rst +++ /dev/null @@ -1 +0,0 @@ -Fix undefined behaviour in C code of null pointer arithmetic. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-13-21-45-07.gh-issue-95778.Oll4_5.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-13-21-45-07.gh-issue-95778.Oll4_5.rst deleted file mode 100644 index f202afc1f259..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-13-21-45-07.gh-issue-95778.Oll4_5.rst +++ /dev/null @@ -1,2 +0,0 @@ -The ``PyLong_FromString`` function was refactored to make it more maintainable -and extensible. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-16-12-36-13.gh-issue-96864.PLU3i8.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-16-12-36-13.gh-issue-96864.PLU3i8.rst deleted file mode 100644 index c0d41ae7d21e..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-16-12-36-13.gh-issue-96864.PLU3i8.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a possible assertion failure, fatal error, or :exc:`SystemError` if a -line tracing event raises an exception while opcode tracing is enabled. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-16-16-54-35.gh-issue-96387.GRzewg.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-16-16-54-35.gh-issue-96387.GRzewg.rst deleted file mode 100644 index 611ab94bc636..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-16-16-54-35.gh-issue-96387.GRzewg.rst +++ /dev/null @@ -1,5 +0,0 @@ -At Python exit, sometimes a thread holding the GIL can wait forever for a -thread (usually a daemon thread) which requested to drop the GIL, whereas -the thread already exited. To fix the race condition, the thread which -requested the GIL drop now resets its request before exiting. Issue -discovered and analyzed by Mingliang ZHAO. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-16-19-02-40.gh-issue-95778.cJmnst.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-16-19-02-40.gh-issue-95778.cJmnst.rst deleted file mode 100644 index ebf63778a605..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-16-19-02-40.gh-issue-95778.cJmnst.rst +++ /dev/null @@ -1,3 +0,0 @@ -When :exc:`ValueError` is raised if an integer is larger than the limit, -mention the :func:`sys.set_int_max_str_digits` function in the error message. -Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-18-08-47-40.gh-issue-96821.Co2iOq.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-18-08-47-40.gh-issue-96821.Co2iOq.rst deleted file mode 100644 index 4fd0532e827d..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-18-08-47-40.gh-issue-96821.Co2iOq.rst +++ /dev/null @@ -1 +0,0 @@ -Fix undefined behaviour in ``_testcapimodule.c``. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-19-03-35-01.gh-issue-96821.izK6JA.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-19-03-35-01.gh-issue-96821.izK6JA.rst deleted file mode 100644 index 73d0c76f0297..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-19-03-35-01.gh-issue-96821.izK6JA.rst +++ /dev/null @@ -1 +0,0 @@ -Fix undefined behaviour in ``audioop.c``. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-20-11-06-45.gh-issue-95921.dkcRQn.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-20-11-06-45.gh-issue-95921.dkcRQn.rst deleted file mode 100644 index 0c8b704c9510..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-20-11-06-45.gh-issue-95921.dkcRQn.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix overly-broad source position information for chained comparisons used as -branching conditions. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-21-14-38-31.gh-issue-96848.WuoLzU.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-21-14-38-31.gh-issue-96848.WuoLzU.rst deleted file mode 100644 index a9b04ce87d4d..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-21-14-38-31.gh-issue-96848.WuoLzU.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix command line parsing: reject :option:`-X int_max_str_digits <-X>` option -with no value (invalid) when the :envvar:`PYTHONINTMAXSTRDIGITS` environment -variable is set to a valid limit. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-21-16-06-37.gh-issue-96975.BmE0XY.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-21-16-06-37.gh-issue-96975.BmE0XY.rst deleted file mode 100644 index e6fcb84d7bff..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-21-16-06-37.gh-issue-96975.BmE0XY.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a crash occurring when :c:func:`PyEval_GetFrame` is called while the -topmost Python frame is in a partially-initialized state. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-27-11-59-13.gh-issue-96670.XrBBit.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-27-11-59-13.gh-issue-96670.XrBBit.rst deleted file mode 100644 index ba8e2bbaf62b..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-27-11-59-13.gh-issue-96670.XrBBit.rst +++ /dev/null @@ -1,2 +0,0 @@ -The parser now raises :exc:`SyntaxError` when parsing source code containing -null bytes. Patch by Pablo Galindo diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-29-15-19-29.gh-issue-94526.wq5m6T.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-29-15-19-29.gh-issue-94526.wq5m6T.rst deleted file mode 100644 index 59e389a64ee0..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-29-15-19-29.gh-issue-94526.wq5m6T.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix the Python path configuration used to initialized :data:`sys.path` at -Python startup. Paths are no longer encoded to UTF-8/strict to avoid encoding -errors if it contains surrogate characters (bytes paths are decoded with the -surrogateescape error handler). Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-30-13-26-58.gh-issue-97670.n61vMR.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-30-13-26-58.gh-issue-97670.n61vMR.rst deleted file mode 100644 index 50b47871a5fd..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-09-30-13-26-58.gh-issue-97670.n61vMR.rst +++ /dev/null @@ -1,6 +0,0 @@ -Remove the :func:`sys.getdxp` function and the ``Tools/scripts/analyze_dxp.py`` -script. DXP stands for "dynamic execution pairs". They were related to -``DYNAMIC_EXECUTION_PROFILE`` and ``DXPAIRS`` macros which have been removed in -Python 3.11. Python can now be built with :option:`./configure --enable-pystats -<--enable-pystats>` to gather statistics on Python opcodes. Patch by Victor -Stinner. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-01-08-55-09.gh-issue-97591.pw6kkH.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-01-08-55-09.gh-issue-97591.pw6kkH.rst deleted file mode 100644 index 6f07529f15bb..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-10-01-08-55-09.gh-issue-97591.pw6kkH.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixed a missing incref/decref pair in ``Exception.__setstate__()``. -Patch by Ofey Chan. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-03-13-35-48.gh-issue-97752.0xTjJY.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-03-13-35-48.gh-issue-97752.0xTjJY.rst deleted file mode 100644 index c65635070348..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-10-03-13-35-48.gh-issue-97752.0xTjJY.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix possible data corruption or crashes when accessing the ``f_back`` member -of newly-created generator or coroutine frames. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-03-16-12-39.gh-issue-91052.MsYL9d.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-03-16-12-39.gh-issue-91052.MsYL9d.rst deleted file mode 100644 index c7db4da494fe..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-10-03-16-12-39.gh-issue-91052.MsYL9d.rst +++ /dev/null @@ -1 +0,0 @@ -Add API for subscribing to modification events on selected dictionaries. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-04-02-00-10.gh-issue-97779.f3N1hI.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-04-02-00-10.gh-issue-97779.f3N1hI.rst deleted file mode 100644 index 611521808865..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-10-04-02-00-10.gh-issue-97779.f3N1hI.rst +++ /dev/null @@ -1 +0,0 @@ -Ensure that all Python frame objects are backed by "complete" frames. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-04-14-04-40.gh-issue-86298.QVM7G1.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-04-14-04-40.gh-issue-86298.QVM7G1.rst deleted file mode 100644 index 6e349d56c99f..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-10-04-14-04-40.gh-issue-86298.QVM7G1.rst +++ /dev/null @@ -1,3 +0,0 @@ -In cases where ``warnings.warn_explicit()`` consults the module's loader, an -``DeprecationWarning`` is issued when ``m.__loader__`` differs from -``m.__spec__.loader``. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-04-17-02-18.gh-issue-97850.E3QTRA.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-04-17-02-18.gh-issue-97850.E3QTRA.rst deleted file mode 100644 index f880d9663842..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-10-04-17-02-18.gh-issue-97850.E3QTRA.rst +++ /dev/null @@ -1 +0,0 @@ -Long deprecated, ``module_repr()`` should now be completely eradicated. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-05-00-37-27.gh-issue-65961.z0Ys0y.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-05-00-37-27.gh-issue-65961.z0Ys0y.rst deleted file mode 100644 index 0c034263c1a8..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-10-05-00-37-27.gh-issue-65961.z0Ys0y.rst +++ /dev/null @@ -1,5 +0,0 @@ -When ``__package__`` is different than ``__spec__.parent``, raise a -``DeprecationWarning`` instead of ``ImportWarning``. - -Also remove ``importlib.util.set_package()`` which was scheduled for -removal. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-05-11-37-15.gh-issue-97922.Zu9Bge.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-05-11-37-15.gh-issue-97922.Zu9Bge.rst deleted file mode 100644 index bf78709362f4..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-10-05-11-37-15.gh-issue-97922.Zu9Bge.rst +++ /dev/null @@ -1,5 +0,0 @@ -The Garbage Collector now runs only on the eval breaker mechanism of the -Python bytecode evaluation loop instead on object allocations. The GC can -also run when :c:func:`PyErr_CheckSignals` is called so C extensions that -need to run for a long time without executing any Python code also have a -chance to execute the GC periodically. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-05-17-02-22.gh-issue-97943.LYAWlE.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-05-17-02-22.gh-issue-97943.LYAWlE.rst deleted file mode 100644 index 9b4a421a9d47..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-10-05-17-02-22.gh-issue-97943.LYAWlE.rst +++ /dev/null @@ -1,2 +0,0 @@ -Bugfix: :func:`PyFunction_GetAnnotations` should return a borrowed -reference. It was returning a new reference. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-06-02-11-34.gh-issue-97002.Zvsk71.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-06-02-11-34.gh-issue-97002.Zvsk71.rst deleted file mode 100644 index 1f577e02e1fd..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-10-06-02-11-34.gh-issue-97002.Zvsk71.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix an issue where several frame objects could be backed by the same -interpreter frame, possibly leading to corrupted memory and hard crashes of -the interpreter. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-06-06-36-29.gh-issue-97912.jGRJpa.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-06-06-36-29.gh-issue-97912.jGRJpa.rst deleted file mode 100644 index bd3d221252b2..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-10-06-06-36-29.gh-issue-97912.jGRJpa.rst +++ /dev/null @@ -1 +0,0 @@ -The compiler now avoids quadratic behavior when finding which instructions should use the :opcode:`LOAD_FAST_CHECK` opcode. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-06-14-14-28.gh-issue-97955.Nq5VXD.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-06-14-14-28.gh-issue-97955.Nq5VXD.rst deleted file mode 100644 index e21794df4f18..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-10-06-14-14-28.gh-issue-97955.Nq5VXD.rst +++ /dev/null @@ -1 +0,0 @@ -Migrate :mod:`zoneinfo` to Argument Clinic. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-06-15-45-57.gh-issue-96078.fS-6mU.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-06-15-45-57.gh-issue-96078.fS-6mU.rst deleted file mode 100644 index d1f949c6e13a..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-10-06-15-45-57.gh-issue-96078.fS-6mU.rst +++ /dev/null @@ -1,2 +0,0 @@ -:func:`os.sched_yield` now release the GIL while calling sched_yield(2). -Patch by Dong-hee Na. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-06-20-41-29.gh-issue-97973.gB-xWi.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-06-20-41-29.gh-issue-97973.gB-xWi.rst deleted file mode 100644 index a0095a61ec32..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-10-06-20-41-29.gh-issue-97973.gB-xWi.rst +++ /dev/null @@ -1 +0,0 @@ -Modify the tokenizer to return all necessary information the parser needs to set location information in the AST nodes, so that the parser does not have to calculate those doing pointer arithmetic. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-06-23-13-34.gh-issue-97997.JQaJKF.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-06-23-13-34.gh-issue-97997.JQaJKF.rst deleted file mode 100644 index 5cb5e2126638..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-10-06-23-13-34.gh-issue-97997.JQaJKF.rst +++ /dev/null @@ -1 +0,0 @@ -Add running column offset to the tokenizer state to avoid calculating AST column information with pointer arithmetic. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-13-23-23-01.gh-issue-98254.bC8IKt.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-13-23-23-01.gh-issue-98254.bC8IKt.rst deleted file mode 100644 index af5d93ff24e9..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-10-13-23-23-01.gh-issue-98254.bC8IKt.rst +++ /dev/null @@ -1,3 +0,0 @@ -Modules from the standard library are now potentially suggested as part of the -error messages displayed by the interpreter when an :exc:`NameError` is raised -to the top level. Patch by Pablo Galindo diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-18-14-11-32.gh-issue-98390.H1sxJu.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-18-14-11-32.gh-issue-98390.H1sxJu.rst deleted file mode 100644 index 6dac72b905c9..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-10-18-14-11-32.gh-issue-98390.H1sxJu.rst +++ /dev/null @@ -1 +0,0 @@ -Fix location of sub-expressions of boolean expressions, by reducing their scope to that of the sub-expression. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-18-16-17-44.gh-issue-98398.x4rYK_.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-18-16-17-44.gh-issue-98398.x4rYK_.rst deleted file mode 100644 index 35d33c90a690..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-10-18-16-17-44.gh-issue-98398.x4rYK_.rst +++ /dev/null @@ -1 +0,0 @@ -Fix source location of 'assert' bytecodes. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-19-18-03-28.gh-issue-98354.GRGta3.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-19-18-03-28.gh-issue-98354.GRGta3.rst deleted file mode 100644 index a600f3e927a3..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-10-19-18-03-28.gh-issue-98354.GRGta3.rst +++ /dev/null @@ -1 +0,0 @@ -Added unicode check for ``name`` attribute of ``spec`` argument passed in :func:`_imp.create_builtin` function. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-19-20-53-38.gh-issue-98461.iNmPDV.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-19-20-53-38.gh-issue-98461.iNmPDV.rst deleted file mode 100644 index 6289f208609e..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-10-19-20-53-38.gh-issue-98461.iNmPDV.rst +++ /dev/null @@ -1 +0,0 @@ -Fix source location in bytecode for list, set and dict comprehensions as well as generator expressions. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-19-23-48-46.gh-issue-98374.eOBh8M.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-19-23-48-46.gh-issue-98374.eOBh8M.rst deleted file mode 100644 index 56a41e3883d1..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-10-19-23-48-46.gh-issue-98374.eOBh8M.rst +++ /dev/null @@ -1,2 +0,0 @@ -Suppress ImportError for invalid query for help() command. Patch by Dong-hee -Na. diff --git a/Misc/NEWS.d/next/Documentation/2017-12-10-19-13-39.bpo-13553.gQbZs4.rst b/Misc/NEWS.d/next/Documentation/2017-12-10-19-13-39.bpo-13553.gQbZs4.rst deleted file mode 100644 index 23d3c1555e37..000000000000 --- a/Misc/NEWS.d/next/Documentation/2017-12-10-19-13-39.bpo-13553.gQbZs4.rst +++ /dev/null @@ -1 +0,0 @@ -Document tkinter.Tk args. diff --git a/Misc/NEWS.d/next/Documentation/2019-09-12-08-28-17.bpo-38056.6ktYkc.rst b/Misc/NEWS.d/next/Documentation/2019-09-12-08-28-17.bpo-38056.6ktYkc.rst deleted file mode 100644 index 2e6b70fd84b6..000000000000 --- a/Misc/NEWS.d/next/Documentation/2019-09-12-08-28-17.bpo-38056.6ktYkc.rst +++ /dev/null @@ -1 +0,0 @@ -Overhaul the :ref:`error-handlers` documentation in :mod:`codecs`. diff --git a/Misc/NEWS.d/next/Documentation/2021-04-01-08-09-34.bpo-43689.mqCfLe.rst b/Misc/NEWS.d/next/Documentation/2021-04-01-08-09-34.bpo-43689.mqCfLe.rst deleted file mode 100644 index 5cc13d7068c9..000000000000 --- a/Misc/NEWS.d/next/Documentation/2021-04-01-08-09-34.bpo-43689.mqCfLe.rst +++ /dev/null @@ -1 +0,0 @@ -The ``Differ`` documentation now also mentions other whitespace characters, which make it harder to understand the diff output. diff --git a/Misc/NEWS.d/next/Documentation/2022-01-13-16-03-15.bpo-40838.k3NVCf.rst b/Misc/NEWS.d/next/Documentation/2022-01-13-16-03-15.bpo-40838.k3NVCf.rst deleted file mode 100644 index 0f071ab64dbe..000000000000 --- a/Misc/NEWS.d/next/Documentation/2022-01-13-16-03-15.bpo-40838.k3NVCf.rst +++ /dev/null @@ -1,2 +0,0 @@ -Document that :func:`inspect.getdoc`, :func:`inspect.getmodule`, and -:func:`inspect.getsourcefile` might return ``None``. diff --git a/Misc/NEWS.d/next/Documentation/2022-03-30-17-56-01.bpo-47161.gesHfS.rst b/Misc/NEWS.d/next/Documentation/2022-03-30-17-56-01.bpo-47161.gesHfS.rst deleted file mode 100644 index 6b552daa7c13..000000000000 --- a/Misc/NEWS.d/next/Documentation/2022-03-30-17-56-01.bpo-47161.gesHfS.rst +++ /dev/null @@ -1,2 +0,0 @@ -Document that :class:`pathlib.PurePath` does not collapse -initial double slashes because they denote UNC paths. diff --git a/Misc/NEWS.d/next/Documentation/2022-05-18-23-58-26.gh-issue-92240.bHvYiz.rst b/Misc/NEWS.d/next/Documentation/2022-05-18-23-58-26.gh-issue-92240.bHvYiz.rst deleted file mode 100644 index 53b2a66c9779..000000000000 --- a/Misc/NEWS.d/next/Documentation/2022-05-18-23-58-26.gh-issue-92240.bHvYiz.rst +++ /dev/null @@ -1,2 +0,0 @@ -Added release dates for -"What's New in Python 3.X" for 3.0, 3.1, 3.2, 3.8 and 3.10 diff --git a/Misc/NEWS.d/next/Documentation/2022-05-20-18-42-10.gh-issue-93031.c2RdJe.rst b/Misc/NEWS.d/next/Documentation/2022-05-20-18-42-10.gh-issue-93031.c2RdJe.rst deleted file mode 100644 index c46b45d2433c..000000000000 --- a/Misc/NEWS.d/next/Documentation/2022-05-20-18-42-10.gh-issue-93031.c2RdJe.rst +++ /dev/null @@ -1 +0,0 @@ -Update tutorial introduction output to use 3.10+ SyntaxError invalid range. diff --git a/Misc/NEWS.d/next/Documentation/2022-05-26-11-33-23.gh-issue-86438.kEGGmK.rst b/Misc/NEWS.d/next/Documentation/2022-05-26-11-33-23.gh-issue-86438.kEGGmK.rst deleted file mode 100644 index 75abfdd63b8b..000000000000 --- a/Misc/NEWS.d/next/Documentation/2022-05-26-11-33-23.gh-issue-86438.kEGGmK.rst +++ /dev/null @@ -1,3 +0,0 @@ -Clarify that :option:`-W` and :envvar:`PYTHONWARNINGS` are matched literally -and case-insensitively, rather than as regular expressions, in -:mod:`warnings`. diff --git a/Misc/NEWS.d/next/Documentation/2022-05-26-14-51-25.gh-issue-88831.5Cccr5.rst b/Misc/NEWS.d/next/Documentation/2022-05-26-14-51-25.gh-issue-88831.5Cccr5.rst deleted file mode 100644 index 983bea981a9b..000000000000 --- a/Misc/NEWS.d/next/Documentation/2022-05-26-14-51-25.gh-issue-88831.5Cccr5.rst +++ /dev/null @@ -1 +0,0 @@ -Augmented documentation of asyncio.create_task(). Clarified the need to keep strong references to tasks and added a code snippet detailing how to to this. diff --git a/Misc/NEWS.d/next/Documentation/2022-05-29-21-22-54.gh-issue-86986.lFXw8j.rst b/Misc/NEWS.d/next/Documentation/2022-05-29-21-22-54.gh-issue-86986.lFXw8j.rst deleted file mode 100644 index 1db028c30f67..000000000000 --- a/Misc/NEWS.d/next/Documentation/2022-05-29-21-22-54.gh-issue-86986.lFXw8j.rst +++ /dev/null @@ -1 +0,0 @@ -The minimum Sphinx version required to build the documentation is now 3.2. diff --git a/Misc/NEWS.d/next/Documentation/2022-06-15-12-12-49.gh-issue-87260.epyI7D.rst b/Misc/NEWS.d/next/Documentation/2022-06-15-12-12-49.gh-issue-87260.epyI7D.rst deleted file mode 100644 index 4c6cee86ca11..000000000000 --- a/Misc/NEWS.d/next/Documentation/2022-06-15-12-12-49.gh-issue-87260.epyI7D.rst +++ /dev/null @@ -1 +0,0 @@ -Align :mod:`sqlite3` argument specs with the actual implementation. diff --git a/Misc/NEWS.d/next/Documentation/2022-06-16-10-10-59.gh-issue-61162.1ypkG8.rst b/Misc/NEWS.d/next/Documentation/2022-06-16-10-10-59.gh-issue-61162.1ypkG8.rst deleted file mode 100644 index c8b3a2222321..000000000000 --- a/Misc/NEWS.d/next/Documentation/2022-06-16-10-10-59.gh-issue-61162.1ypkG8.rst +++ /dev/null @@ -1 +0,0 @@ -Clarify :mod:`sqlite3` behavior when :ref:`sqlite3-connection-context-manager`. diff --git a/Misc/NEWS.d/next/Documentation/2022-06-19-18-18-22.gh-issue-86128.39DDTD.rst b/Misc/NEWS.d/next/Documentation/2022-06-19-18-18-22.gh-issue-86128.39DDTD.rst deleted file mode 100644 index bab006856dee..000000000000 --- a/Misc/NEWS.d/next/Documentation/2022-06-19-18-18-22.gh-issue-86128.39DDTD.rst +++ /dev/null @@ -1 +0,0 @@ -Document a limitation in ThreadPoolExecutor where its exit handler is executed before any handlers in atexit. diff --git a/Misc/NEWS.d/next/Documentation/2022-07-07-08-42-05.gh-issue-94321.pmCIPb.rst b/Misc/NEWS.d/next/Documentation/2022-07-07-08-42-05.gh-issue-94321.pmCIPb.rst deleted file mode 100644 index c1a8dcd85353..000000000000 --- a/Misc/NEWS.d/next/Documentation/2022-07-07-08-42-05.gh-issue-94321.pmCIPb.rst +++ /dev/null @@ -1,2 +0,0 @@ -Document the :pep:`246` style protocol type -:class:`sqlite3.PrepareProtocol`. diff --git a/Misc/NEWS.d/next/Documentation/2022-07-29-09-04-02.gh-issue-95415.LKTyw6.rst b/Misc/NEWS.d/next/Documentation/2022-07-29-09-04-02.gh-issue-95415.LKTyw6.rst deleted file mode 100644 index ece36bc4d1ce..000000000000 --- a/Misc/NEWS.d/next/Documentation/2022-07-29-09-04-02.gh-issue-95415.LKTyw6.rst +++ /dev/null @@ -1,2 +0,0 @@ -Use consistent syntax for platform availability. The directive now supports -a content body and emits a warning when it encounters an unknown platform. diff --git a/Misc/NEWS.d/next/Documentation/2022-07-29-23-02-19.gh-issue-95451.-tgB93.rst b/Misc/NEWS.d/next/Documentation/2022-07-29-23-02-19.gh-issue-95451.-tgB93.rst deleted file mode 100644 index 3a7b8a122b7a..000000000000 --- a/Misc/NEWS.d/next/Documentation/2022-07-29-23-02-19.gh-issue-95451.-tgB93.rst +++ /dev/null @@ -1,3 +0,0 @@ -Update library documentation with -:ref:`availability information ` -on WebAssembly platforms ``wasm32-emscripten`` and ``wasm32-wasi``. diff --git a/Misc/NEWS.d/next/Documentation/2022-07-30-00-23-11.gh-issue-95454.we7AFm.rst b/Misc/NEWS.d/next/Documentation/2022-07-30-00-23-11.gh-issue-95454.we7AFm.rst deleted file mode 100644 index 6440c23fd500..000000000000 --- a/Misc/NEWS.d/next/Documentation/2022-07-30-00-23-11.gh-issue-95454.we7AFm.rst +++ /dev/null @@ -1,2 +0,0 @@ -Replaced incorrectly written true/false values -in documentiation. Patch by Robert O'Shea diff --git a/Misc/NEWS.d/next/Documentation/2022-08-03-13-35-08.gh-issue-91207.eJ4pPf.rst b/Misc/NEWS.d/next/Documentation/2022-08-03-13-35-08.gh-issue-91207.eJ4pPf.rst deleted file mode 100644 index 8c7391f7edf7..000000000000 --- a/Misc/NEWS.d/next/Documentation/2022-08-03-13-35-08.gh-issue-91207.eJ4pPf.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix stylesheet not working in Windows CHM htmlhelp docs -and add warning that they are deprecated. -Contributed by C.A.M. Gerlach. diff --git a/Misc/NEWS.d/next/Documentation/2022-08-12-01-12-52.gh-issue-95588.PA0FI7.rst b/Misc/NEWS.d/next/Documentation/2022-08-12-01-12-52.gh-issue-95588.PA0FI7.rst deleted file mode 100644 index c070bbc19517..000000000000 --- a/Misc/NEWS.d/next/Documentation/2022-08-12-01-12-52.gh-issue-95588.PA0FI7.rst +++ /dev/null @@ -1,6 +0,0 @@ -Clarified the conflicting advice given in the :mod:`ast` documentation about -:func:`ast.literal_eval` being "safe" for use on untrusted input while at -the same time warning that it can crash the process. The latter statement is -true and is deemed unfixable without a large amount of work unsuitable for a -bugfix. So we keep the warning and no longer claim that ``literal_eval`` is -safe. diff --git a/Misc/NEWS.d/next/Documentation/2022-08-13-20-34-51.gh-issue-95957.W9ZZAx.rst b/Misc/NEWS.d/next/Documentation/2022-08-13-20-34-51.gh-issue-95957.W9ZZAx.rst deleted file mode 100644 index c617bd42abd9..000000000000 --- a/Misc/NEWS.d/next/Documentation/2022-08-13-20-34-51.gh-issue-95957.W9ZZAx.rst +++ /dev/null @@ -1,2 +0,0 @@ -What's New 3.11 now has instructions for how to provide compiler and -linker flags for Tcl/Tk and OpenSSL on RHEL 7 and CentOS 7. diff --git a/Misc/NEWS.d/next/Documentation/2022-08-19-17-07-45.gh-issue-96098.nDp43u.rst b/Misc/NEWS.d/next/Documentation/2022-08-19-17-07-45.gh-issue-96098.nDp43u.rst deleted file mode 100644 index 5ead20bbb535..000000000000 --- a/Misc/NEWS.d/next/Documentation/2022-08-19-17-07-45.gh-issue-96098.nDp43u.rst +++ /dev/null @@ -1,3 +0,0 @@ -Improve discoverability of the higher level concurrent.futures module by -providing clearer links from the lower level threading and multiprocessing -modules. diff --git a/Misc/NEWS.d/next/Documentation/2022-09-01-17-03-04.gh-issue-96432.1EJ1-4.rst b/Misc/NEWS.d/next/Documentation/2022-09-01-17-03-04.gh-issue-96432.1EJ1-4.rst deleted file mode 100644 index c4d296e626b1..000000000000 --- a/Misc/NEWS.d/next/Documentation/2022-09-01-17-03-04.gh-issue-96432.1EJ1-4.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fraction literals now support whitespace around the forward slash, -``Fraction('2 / 3')``. diff --git a/Misc/NEWS.d/next/Documentation/2022-10-02-10-58-52.gh-issue-97741.39l023.rst b/Misc/NEWS.d/next/Documentation/2022-10-02-10-58-52.gh-issue-97741.39l023.rst deleted file mode 100644 index 8da9c92f6fd8..000000000000 --- a/Misc/NEWS.d/next/Documentation/2022-10-02-10-58-52.gh-issue-97741.39l023.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix ``!`` in c domain ref target syntax via a ``conf.py`` patch, so it works -as intended to disable ref target resolution. diff --git a/Misc/NEWS.d/next/Documentation/2022-10-11-09-40-50.gh-issue-86404.dEAb8W.rst b/Misc/NEWS.d/next/Documentation/2022-10-11-09-40-50.gh-issue-86404.dEAb8W.rst deleted file mode 100644 index de7b09216711..000000000000 --- a/Misc/NEWS.d/next/Documentation/2022-10-11-09-40-50.gh-issue-86404.dEAb8W.rst +++ /dev/null @@ -1,3 +0,0 @@ -Deprecated tools ``make suspicious`` and ``rstlint.py`` are now removed. -They have been replaced by `spinx-lint -`_. diff --git a/Misc/NEWS.d/next/Documentation/2022-10-16-17-34-45.gh-issue-85525.DvkD0v.rst b/Misc/NEWS.d/next/Documentation/2022-10-16-17-34-45.gh-issue-85525.DvkD0v.rst deleted file mode 100644 index 292e16998acd..000000000000 --- a/Misc/NEWS.d/next/Documentation/2022-10-16-17-34-45.gh-issue-85525.DvkD0v.rst +++ /dev/null @@ -1 +0,0 @@ -Remove extra row diff --git a/Misc/NEWS.d/next/IDLE/2022-07-28-18-56-57.gh-issue-89610.hcosiM.rst b/Misc/NEWS.d/next/IDLE/2022-07-28-18-56-57.gh-issue-89610.hcosiM.rst deleted file mode 100644 index 0d283711e3e8..000000000000 --- a/Misc/NEWS.d/next/IDLE/2022-07-28-18-56-57.gh-issue-89610.hcosiM.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add .pyi as a recognized extension for IDLE on macOS. This allows opening -stub files by double clicking on them in the Finder. diff --git a/Misc/NEWS.d/next/IDLE/2022-07-29-11-08-52.gh-issue-95411.dazlqH.rst b/Misc/NEWS.d/next/IDLE/2022-07-29-11-08-52.gh-issue-95411.dazlqH.rst deleted file mode 100644 index 94ca8b2c2ea9..000000000000 --- a/Misc/NEWS.d/next/IDLE/2022-07-29-11-08-52.gh-issue-95411.dazlqH.rst +++ /dev/null @@ -1 +0,0 @@ -Enable using IDLE's module browser with .pyw files. diff --git a/Misc/NEWS.d/next/IDLE/2022-07-30-15-10-39.gh-issue-95471.z3scVG.rst b/Misc/NEWS.d/next/IDLE/2022-07-30-15-10-39.gh-issue-95471.z3scVG.rst deleted file mode 100644 index 73a9d8058965..000000000000 --- a/Misc/NEWS.d/next/IDLE/2022-07-30-15-10-39.gh-issue-95471.z3scVG.rst +++ /dev/null @@ -1 +0,0 @@ -In the Edit menu, move ``Select All`` and add a new separator. diff --git a/Misc/NEWS.d/next/IDLE/2022-07-31-22-15-14.gh-issue-95511.WX6PmB.rst b/Misc/NEWS.d/next/IDLE/2022-07-31-22-15-14.gh-issue-95511.WX6PmB.rst deleted file mode 100644 index 803fa5f2a2ab..000000000000 --- a/Misc/NEWS.d/next/IDLE/2022-07-31-22-15-14.gh-issue-95511.WX6PmB.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix the Shell context menu copy-with-prompts bug of copying an extra line -when one selects whole lines. diff --git a/Misc/NEWS.d/next/IDLE/2022-08-01-23-31-48.gh-issue-95191.U7vryB.rst b/Misc/NEWS.d/next/IDLE/2022-08-01-23-31-48.gh-issue-95191.U7vryB.rst deleted file mode 100644 index 94d3dbbd529f..000000000000 --- a/Misc/NEWS.d/next/IDLE/2022-08-01-23-31-48.gh-issue-95191.U7vryB.rst +++ /dev/null @@ -1 +0,0 @@ -Include prompts when saving Shell (interactive input and output). diff --git a/Misc/NEWS.d/next/IDLE/2022-08-04-20-07-51.gh-issue-65802.xnThWe.rst b/Misc/NEWS.d/next/IDLE/2022-08-04-20-07-51.gh-issue-65802.xnThWe.rst deleted file mode 100644 index a62a784b6e69..000000000000 --- a/Misc/NEWS.d/next/IDLE/2022-08-04-20-07-51.gh-issue-65802.xnThWe.rst +++ /dev/null @@ -1 +0,0 @@ -Document handling of extensions in Save As dialogs. diff --git a/Misc/NEWS.d/next/IDLE/2022-10-15-21-20-40.gh-issue-97527.otAHJM.rst b/Misc/NEWS.d/next/IDLE/2022-10-15-21-20-40.gh-issue-97527.otAHJM.rst deleted file mode 100644 index e7fda8974194..000000000000 --- a/Misc/NEWS.d/next/IDLE/2022-10-15-21-20-40.gh-issue-97527.otAHJM.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix a bug in the previous bugfix that caused IDLE to not start when run with -3.10.8, 3.12.0a1, and at least Microsoft Python 3.10.2288.0 installed -without the Lib/test package. 3.11.0 was never affected. diff --git a/Misc/NEWS.d/next/Library/2017-07-31-13-35-28.bpo-26253.8v_sCs.rst b/Misc/NEWS.d/next/Library/2017-07-31-13-35-28.bpo-26253.8v_sCs.rst deleted file mode 100644 index fa0dc95b7d62..000000000000 --- a/Misc/NEWS.d/next/Library/2017-07-31-13-35-28.bpo-26253.8v_sCs.rst +++ /dev/null @@ -1,2 +0,0 @@ -Allow adjustable compression level for tarfile streams in -:func:`tarfile.open`. diff --git a/Misc/NEWS.d/next/Library/2018-09-23-07-47-29.bpo-32990.2FVVTU.rst b/Misc/NEWS.d/next/Library/2018-09-23-07-47-29.bpo-32990.2FVVTU.rst deleted file mode 100644 index 7d7f7e3faaec..000000000000 --- a/Misc/NEWS.d/next/Library/2018-09-23-07-47-29.bpo-32990.2FVVTU.rst +++ /dev/null @@ -1,2 +0,0 @@ -Support reading wave files with the ``WAVE_FORMAT_EXTENSIBLE`` format in the -:mod:`wave` module. diff --git a/Misc/NEWS.d/next/Library/2018-09-28-22-18-03.bpo-34828.5Zyi_S.rst b/Misc/NEWS.d/next/Library/2018-09-28-22-18-03.bpo-34828.5Zyi_S.rst deleted file mode 100644 index b0e10a158b5b..000000000000 --- a/Misc/NEWS.d/next/Library/2018-09-28-22-18-03.bpo-34828.5Zyi_S.rst +++ /dev/null @@ -1 +0,0 @@ -:meth:`sqlite3.Connection.iterdump` now handles databases that use ``AUTOINCREMENT`` in one or more tables. diff --git a/Misc/NEWS.d/next/Library/2019-09-25-00-37-51.bpo-38267.X9Jb5V.rst b/Misc/NEWS.d/next/Library/2019-09-25-00-37-51.bpo-38267.X9Jb5V.rst deleted file mode 100644 index b842fdcb73e9..000000000000 --- a/Misc/NEWS.d/next/Library/2019-09-25-00-37-51.bpo-38267.X9Jb5V.rst +++ /dev/null @@ -1,3 +0,0 @@ -Add *timeout* parameter to :meth:`asyncio.loop.shutdown_default_executor`. -The default value is ``None``, which means the executor will be given an unlimited amount of time. -When called from :class:`asyncio.Runner` or :func:`asyncio.run`, the default timeout is 5 minutes. diff --git a/Misc/NEWS.d/next/Library/2019-11-04-22-21-27.bpo-38693.w_OAov.rst b/Misc/NEWS.d/next/Library/2019-11-04-22-21-27.bpo-38693.w_OAov.rst deleted file mode 100644 index a81e9220a8e6..000000000000 --- a/Misc/NEWS.d/next/Library/2019-11-04-22-21-27.bpo-38693.w_OAov.rst +++ /dev/null @@ -1 +0,0 @@ -:mod:`importlib` now uses f-strings internally instead of ``str.format``. diff --git a/Misc/NEWS.d/next/Library/2020-01-09-01-57-12.bpo-39264.GsBL9-.rst b/Misc/NEWS.d/next/Library/2020-01-09-01-57-12.bpo-39264.GsBL9-.rst deleted file mode 100644 index 5f9ffdffce5c..000000000000 --- a/Misc/NEWS.d/next/Library/2020-01-09-01-57-12.bpo-39264.GsBL9-.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fixed :meth:`collections.UserDict.get` to not call -:meth:`__missing__` when a value is not found. This matches the behavior of -:class:`dict`. Patch by Bar Harel. diff --git a/Misc/NEWS.d/next/Library/2020-07-08-20-32-13.bpo-41246.2trYf3.rst b/Misc/NEWS.d/next/Library/2020-07-08-20-32-13.bpo-41246.2trYf3.rst deleted file mode 100644 index 17b884e777e9..000000000000 --- a/Misc/NEWS.d/next/Library/2020-07-08-20-32-13.bpo-41246.2trYf3.rst +++ /dev/null @@ -1,3 +0,0 @@ -Give the same callback function for when the overlapped operation is done to -the functions ``recv``, ``recv_into``, ``recvfrom``, ``sendto``, ``send`` -and ``sendfile`` inside ``IocpProactor``. diff --git a/Misc/NEWS.d/next/Library/2020-09-28-04-56-04.bpo-14243.YECnxv.rst b/Misc/NEWS.d/next/Library/2020-09-28-04-56-04.bpo-14243.YECnxv.rst deleted file mode 100644 index 267535452ef1..000000000000 --- a/Misc/NEWS.d/next/Library/2020-09-28-04-56-04.bpo-14243.YECnxv.rst +++ /dev/null @@ -1 +0,0 @@ -The :class:`tempfile.NamedTemporaryFile` function has a new optional parameter *delete_on_close* diff --git a/Misc/NEWS.d/next/Library/2020-10-15-18-37-12.bpo-42047.XDdoSF.rst b/Misc/NEWS.d/next/Library/2020-10-15-18-37-12.bpo-42047.XDdoSF.rst deleted file mode 100644 index 4c23763cf8d8..000000000000 --- a/Misc/NEWS.d/next/Library/2020-10-15-18-37-12.bpo-42047.XDdoSF.rst +++ /dev/null @@ -1 +0,0 @@ -Add :func:`threading.get_native_id` support for DragonFly BSD. Patch by David Carlier. diff --git a/Misc/NEWS.d/next/Library/2021-05-22-07-58-59.bpo-42627.EejtD0.rst b/Misc/NEWS.d/next/Library/2021-05-22-07-58-59.bpo-42627.EejtD0.rst deleted file mode 100644 index f165b9ced05d..000000000000 --- a/Misc/NEWS.d/next/Library/2021-05-22-07-58-59.bpo-42627.EejtD0.rst +++ /dev/null @@ -1 +0,0 @@ -Fix incorrect parsing of Windows registry proxy settings diff --git a/Misc/NEWS.d/next/Library/2021-08-27-18-07-35.bpo-44173.oW92Ev.rst b/Misc/NEWS.d/next/Library/2021-08-27-18-07-35.bpo-44173.oW92Ev.rst deleted file mode 100644 index abc98266afb0..000000000000 --- a/Misc/NEWS.d/next/Library/2021-08-27-18-07-35.bpo-44173.oW92Ev.rst +++ /dev/null @@ -1 +0,0 @@ -Enable fast seeking of uncompressed unencrypted :class:`zipfile.ZipExtFile` diff --git a/Misc/NEWS.d/next/Library/2021-08-29-19-59-16.bpo-45046.eGq0NC.rst b/Misc/NEWS.d/next/Library/2021-08-29-19-59-16.bpo-45046.eGq0NC.rst deleted file mode 100644 index 8072afaf445c..000000000000 --- a/Misc/NEWS.d/next/Library/2021-08-29-19-59-16.bpo-45046.eGq0NC.rst +++ /dev/null @@ -1,7 +0,0 @@ -Add support of context managers in :mod:`unittest`: methods -:meth:`~unittest.TestCase.enterContext` and -:meth:`~unittest.TestCase.enterClassContext` of class -:class:`~unittest.TestCase`, method -:meth:`~unittest.IsolatedAsyncioTestCase.enterAsyncContext` of class -:class:`~unittest.IsolatedAsyncioTestCase` and function -:func:`unittest.enterModuleContext`. diff --git a/Misc/NEWS.d/next/Library/2021-12-27-15-32-15.bpo-45924.0ZpHX2.rst b/Misc/NEWS.d/next/Library/2021-12-27-15-32-15.bpo-45924.0ZpHX2.rst deleted file mode 100644 index 5cda22737adb..000000000000 --- a/Misc/NEWS.d/next/Library/2021-12-27-15-32-15.bpo-45924.0ZpHX2.rst +++ /dev/null @@ -1 +0,0 @@ -Fix :mod:`asyncio` incorrect traceback when future's exception is raised multiple times. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Library/2022-01-03-15-07-06.bpo-46197.Z0djv6.rst b/Misc/NEWS.d/next/Library/2022-01-03-15-07-06.bpo-46197.Z0djv6.rst deleted file mode 100644 index 7a3b2d59dfaf..000000000000 --- a/Misc/NEWS.d/next/Library/2022-01-03-15-07-06.bpo-46197.Z0djv6.rst +++ /dev/null @@ -1 +0,0 @@ -Fix :mod:`ensurepip` environment isolation for subprocess running ``pip``. diff --git a/Misc/NEWS.d/next/Library/2022-01-09-14-23-00.bpo-28249.4dzB80.rst b/Misc/NEWS.d/next/Library/2022-01-09-14-23-00.bpo-28249.4dzB80.rst deleted file mode 100644 index b5f1312d7686..000000000000 --- a/Misc/NEWS.d/next/Library/2022-01-09-14-23-00.bpo-28249.4dzB80.rst +++ /dev/null @@ -1,2 +0,0 @@ -Set :attr:`doctest.DocTest.lineno` to ``None`` when object does not have -:attr:`__doc__`. diff --git a/Misc/NEWS.d/next/Library/2022-01-14-10-49-20.bpo-46364.SzhlU9.rst b/Misc/NEWS.d/next/Library/2022-01-14-10-49-20.bpo-46364.SzhlU9.rst deleted file mode 100644 index d547ffc6f97e..000000000000 --- a/Misc/NEWS.d/next/Library/2022-01-14-10-49-20.bpo-46364.SzhlU9.rst +++ /dev/null @@ -1 +0,0 @@ -Restrict use of sockets instead of pipes for stdin of subprocesses created by :mod:`asyncio` to AIX platform only. diff --git a/Misc/NEWS.d/next/Library/2022-02-05-18-46-54.bpo-46642.YI6nHQ.rst b/Misc/NEWS.d/next/Library/2022-02-05-18-46-54.bpo-46642.YI6nHQ.rst deleted file mode 100644 index 2d2815c1e4b0..000000000000 --- a/Misc/NEWS.d/next/Library/2022-02-05-18-46-54.bpo-46642.YI6nHQ.rst +++ /dev/null @@ -1 +0,0 @@ -Improve error message when trying to subclass an instance of :data:`typing.TypeVar`, :data:`typing.ParamSpec`, :data:`typing.TypeVarTuple`, etc. Based on patch by Gregory Beauregard. diff --git a/Misc/NEWS.d/next/Library/2022-02-09-23-44-27.bpo-45393.9v5Y8U.rst b/Misc/NEWS.d/next/Library/2022-02-09-23-44-27.bpo-45393.9v5Y8U.rst deleted file mode 100644 index 0a239b07d76b..000000000000 --- a/Misc/NEWS.d/next/Library/2022-02-09-23-44-27.bpo-45393.9v5Y8U.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix the formatting for ``await x`` and ``not x`` in the operator precedence -table when using the :func:`help` system. diff --git a/Misc/NEWS.d/next/Library/2022-02-15-12-40-48.bpo-46755.zePJfx.rst b/Misc/NEWS.d/next/Library/2022-02-15-12-40-48.bpo-46755.zePJfx.rst deleted file mode 100644 index 399caf725359..000000000000 --- a/Misc/NEWS.d/next/Library/2022-02-15-12-40-48.bpo-46755.zePJfx.rst +++ /dev/null @@ -1,2 +0,0 @@ -In :class:`QueueHandler`, clear ``stack_info`` from :class:`LogRecord` to -prevent stack trace from being written twice. diff --git a/Misc/NEWS.d/next/Library/2022-02-21-01-37-00.bpo-42777.nWK3E6.rst b/Misc/NEWS.d/next/Library/2022-02-21-01-37-00.bpo-42777.nWK3E6.rst deleted file mode 100644 index 24912380fb59..000000000000 --- a/Misc/NEWS.d/next/Library/2022-02-21-01-37-00.bpo-42777.nWK3E6.rst +++ /dev/null @@ -1 +0,0 @@ -Implement :meth:`pathlib.Path.is_mount` for Windows paths. diff --git a/Misc/NEWS.d/next/Library/2022-03-08-04-46-44.bpo-46951.SWAz97.rst b/Misc/NEWS.d/next/Library/2022-03-08-04-46-44.bpo-46951.SWAz97.rst deleted file mode 100644 index cd7601aa8c4d..000000000000 --- a/Misc/NEWS.d/next/Library/2022-03-08-04-46-44.bpo-46951.SWAz97.rst +++ /dev/null @@ -1 +0,0 @@ -Order the contents of zipapp archives, to make builds more reproducible. diff --git a/Misc/NEWS.d/next/Library/2022-03-16-14-24-14.bpo-47025.qtT3CE.rst b/Misc/NEWS.d/next/Library/2022-03-16-14-24-14.bpo-47025.qtT3CE.rst deleted file mode 100644 index 1c7c7ace9706..000000000000 --- a/Misc/NEWS.d/next/Library/2022-03-16-14-24-14.bpo-47025.qtT3CE.rst +++ /dev/null @@ -1 +0,0 @@ -Drop support for :class:`bytes` on :attr:`sys.path`. diff --git a/Misc/NEWS.d/next/Library/2022-03-19-04-41-42.bpo-47063.nwRfUo.rst b/Misc/NEWS.d/next/Library/2022-03-19-04-41-42.bpo-47063.nwRfUo.rst deleted file mode 100644 index b889d3c65207..000000000000 --- a/Misc/NEWS.d/next/Library/2022-03-19-04-41-42.bpo-47063.nwRfUo.rst +++ /dev/null @@ -1 +0,0 @@ -Add an index_pages parameter to support using non-default index page names. diff --git a/Misc/NEWS.d/next/Library/2022-03-22-18-28-55.bpo-35540.nyijX9.rst b/Misc/NEWS.d/next/Library/2022-03-22-18-28-55.bpo-35540.nyijX9.rst deleted file mode 100644 index b7aeee6c8c8f..000000000000 --- a/Misc/NEWS.d/next/Library/2022-03-22-18-28-55.bpo-35540.nyijX9.rst +++ /dev/null @@ -1 +0,0 @@ -Fix :func:`dataclasses.asdict` crash when :class:`collections.defaultdict` is present in the attributes. diff --git a/Misc/NEWS.d/next/Library/2022-04-01-09-43-54.bpo-32547.NIUiNC.rst b/Misc/NEWS.d/next/Library/2022-04-01-09-43-54.bpo-32547.NIUiNC.rst deleted file mode 100644 index 4599b73cc342..000000000000 --- a/Misc/NEWS.d/next/Library/2022-04-01-09-43-54.bpo-32547.NIUiNC.rst +++ /dev/null @@ -1 +0,0 @@ -The constructors for :class:`~csv.DictWriter` and :class:`~csv.DictReader` now coerce the ``fieldnames`` argument to a :class:`list` if it is an iterator. diff --git a/Misc/NEWS.d/next/Library/2022-04-01-12-35-44.gh-issue-90005.pvaLHQ.rst b/Misc/NEWS.d/next/Library/2022-04-01-12-35-44.gh-issue-90005.pvaLHQ.rst deleted file mode 100644 index ef6a881a4d09..000000000000 --- a/Misc/NEWS.d/next/Library/2022-04-01-12-35-44.gh-issue-90005.pvaLHQ.rst +++ /dev/null @@ -1 +0,0 @@ -:mod:`ctypes` dependency ``libffi`` is now detected with ``pkg-config``. diff --git a/Misc/NEWS.d/next/Library/2022-04-03-11-25-02.bpo-41287.8CTdwf.rst b/Misc/NEWS.d/next/Library/2022-04-03-11-25-02.bpo-41287.8CTdwf.rst deleted file mode 100644 index ef80ec664c4a..000000000000 --- a/Misc/NEWS.d/next/Library/2022-04-03-11-25-02.bpo-41287.8CTdwf.rst +++ /dev/null @@ -1 +0,0 @@ -Fix handling of the ``doc`` argument in subclasses of :func:`property`. diff --git a/Misc/NEWS.d/next/Library/2022-04-03-19-40-09.bpo-39064.76PbIz.rst b/Misc/NEWS.d/next/Library/2022-04-03-19-40-09.bpo-39064.76PbIz.rst deleted file mode 100644 index 34d31527e332..000000000000 --- a/Misc/NEWS.d/next/Library/2022-04-03-19-40-09.bpo-39064.76PbIz.rst +++ /dev/null @@ -1,2 +0,0 @@ -:class:`zipfile.ZipFile` now raises :exc:`zipfile.BadZipFile` instead of ``ValueError`` when reading a -corrupt zip file in which the central directory offset is negative. diff --git a/Misc/NEWS.d/next/Library/2022-04-08-22-12-11.bpo-47231.lvyglt.rst b/Misc/NEWS.d/next/Library/2022-04-08-22-12-11.bpo-47231.lvyglt.rst deleted file mode 100644 index ee05c5e28567..000000000000 --- a/Misc/NEWS.d/next/Library/2022-04-08-22-12-11.bpo-47231.lvyglt.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed an issue with inconsistent trailing slashes in tarfile longname directories. diff --git a/Misc/NEWS.d/next/Library/2022-04-11-16-55-41.gh-issue-91456.DK3KKl.rst b/Misc/NEWS.d/next/Library/2022-04-11-16-55-41.gh-issue-91456.DK3KKl.rst deleted file mode 100644 index a4c853149bdf..000000000000 --- a/Misc/NEWS.d/next/Library/2022-04-11-16-55-41.gh-issue-91456.DK3KKl.rst +++ /dev/null @@ -1,3 +0,0 @@ -Deprecate current default auto() behavior: In 3.13 the default will be for -for auto() to always return the largest member value incremented by -1, and to raise if incompatible value types are used. diff --git a/Misc/NEWS.d/next/Library/2022-04-12-18-05-40.gh-issue-91447.N_Fs4H.rst b/Misc/NEWS.d/next/Library/2022-04-12-18-05-40.gh-issue-91447.N_Fs4H.rst deleted file mode 100644 index 6f9be2d3e9be..000000000000 --- a/Misc/NEWS.d/next/Library/2022-04-12-18-05-40.gh-issue-91447.N_Fs4H.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix findtext in the xml module to only give an empty string when the text -attribute is set to None. diff --git a/Misc/NEWS.d/next/Library/2022-04-14-08-37-16.gh-issue-91524.g8PiIu.rst b/Misc/NEWS.d/next/Library/2022-04-14-08-37-16.gh-issue-91524.g8PiIu.rst deleted file mode 100644 index b3f01755eaa3..000000000000 --- a/Misc/NEWS.d/next/Library/2022-04-14-08-37-16.gh-issue-91524.g8PiIu.rst +++ /dev/null @@ -1,3 +0,0 @@ -Speed up the regular expression substitution (functions :func:`re.sub` and -:func:`re.subn` and corresponding :class:`re.Pattern` methods) for -replacement strings containing group references by 2--3 times. diff --git a/Misc/NEWS.d/next/Library/2022-04-15-11-29-38.gh-issue-91539.7WgVuA.rst b/Misc/NEWS.d/next/Library/2022-04-15-11-29-38.gh-issue-91539.7WgVuA.rst deleted file mode 100644 index 16d61f1b9110..000000000000 --- a/Misc/NEWS.d/next/Library/2022-04-15-11-29-38.gh-issue-91539.7WgVuA.rst +++ /dev/null @@ -1 +0,0 @@ -Improve performance of ``urllib.request.getproxies_environment`` when there are many environment variables diff --git a/Misc/NEWS.d/next/Library/2022-04-15-13-16-25.gh-issue-91581.9OGsrN.rst b/Misc/NEWS.d/next/Library/2022-04-15-13-16-25.gh-issue-91581.9OGsrN.rst deleted file mode 100644 index 1c3008f42557..000000000000 --- a/Misc/NEWS.d/next/Library/2022-04-15-13-16-25.gh-issue-91581.9OGsrN.rst +++ /dev/null @@ -1,6 +0,0 @@ -Remove an unhandled error case in the C implementation of calls to -:meth:`datetime.fromtimestamp ` with no time -zone (i.e. getting a local time from an epoch timestamp). This should have no -user-facing effect other than giving a possibly more accurate error message -when called with timestamps that fall on 10000-01-01 in the local time. Patch -by Paul Ganssle. diff --git a/Misc/NEWS.d/next/Library/2022-04-15-17-38-55.gh-issue-91577.Ah7cLL.rst b/Misc/NEWS.d/next/Library/2022-04-15-17-38-55.gh-issue-91577.Ah7cLL.rst deleted file mode 100644 index 0f44f34011f9..000000000000 --- a/Misc/NEWS.d/next/Library/2022-04-15-17-38-55.gh-issue-91577.Ah7cLL.rst +++ /dev/null @@ -1 +0,0 @@ -Move imports in :class:`~multiprocessing.SharedMemory` methods to module level so that they can be executed late in python finalization. diff --git a/Misc/NEWS.d/next/Library/2022-04-15-22-07-36.gh-issue-90622.0C6l8h.rst b/Misc/NEWS.d/next/Library/2022-04-15-22-07-36.gh-issue-90622.0C6l8h.rst deleted file mode 100644 index 5db0a1bbe721..000000000000 --- a/Misc/NEWS.d/next/Library/2022-04-15-22-07-36.gh-issue-90622.0C6l8h.rst +++ /dev/null @@ -1,4 +0,0 @@ -Worker processes for :class:`concurrent.futures.ProcessPoolExecutor` are no -longer spawned on demand (a feature added in 3.9) when the multiprocessing -context start method is ``"fork"`` as that can lead to deadlocks in the -child processes due to a fork happening while threads are running. diff --git a/Misc/NEWS.d/next/Library/2022-04-21-19-14-29.gh-issue-91760.54AR-m.rst b/Misc/NEWS.d/next/Library/2022-04-21-19-14-29.gh-issue-91760.54AR-m.rst deleted file mode 100644 index ac3e7cdd4bac..000000000000 --- a/Misc/NEWS.d/next/Library/2022-04-21-19-14-29.gh-issue-91760.54AR-m.rst +++ /dev/null @@ -1,5 +0,0 @@ -Apply more strict rules for numerical group references and group names in -regular expressions. Only sequence of ASCII digits is now accepted as -a numerical reference. The group name in -bytes patterns and replacement strings can now only contain ASCII letters -and digits and underscore. diff --git a/Misc/NEWS.d/next/Library/2022-04-24-22-26-45.gh-issue-81790.M5Rvpm.rst b/Misc/NEWS.d/next/Library/2022-04-24-22-26-45.gh-issue-81790.M5Rvpm.rst deleted file mode 100644 index 8894493e9741..000000000000 --- a/Misc/NEWS.d/next/Library/2022-04-24-22-26-45.gh-issue-81790.M5Rvpm.rst +++ /dev/null @@ -1,2 +0,0 @@ -:func:`os.path.splitdrive` now understands DOS device paths with UNC -links (beginning ``\\?\UNC\``). Contributed by Barney Gale. diff --git a/Misc/NEWS.d/next/Library/2022-04-25-10-23-01.gh-issue-91810.DOHa6B.rst b/Misc/NEWS.d/next/Library/2022-04-25-10-23-01.gh-issue-91810.DOHa6B.rst deleted file mode 100644 index 0711f8466b81..000000000000 --- a/Misc/NEWS.d/next/Library/2022-04-25-10-23-01.gh-issue-91810.DOHa6B.rst +++ /dev/null @@ -1,5 +0,0 @@ -:class:`~xml.etree.ElementTree.ElementTree` method -:meth:`~xml.etree.ElementTree.ElementTree.write` and function -:func:`~xml.etree.ElementTree.tostring` now use the text file's encoding -("UTF-8" if not available) instead of locale encoding in XML declaration -when ``encoding="unicode"`` is specified. diff --git a/Misc/NEWS.d/next/Library/2022-04-26-18-37-24.gh-issue-91968.fuuH1_.rst b/Misc/NEWS.d/next/Library/2022-04-26-18-37-24.gh-issue-91968.fuuH1_.rst deleted file mode 100644 index f16f5d3a668b..000000000000 --- a/Misc/NEWS.d/next/Library/2022-04-26-18-37-24.gh-issue-91968.fuuH1_.rst +++ /dev/null @@ -1 +0,0 @@ -Add ``SO_RTABLE`` and ``SO_USER_COOKIE`` constants to :mod:`socket`. diff --git a/Misc/NEWS.d/next/Library/2022-05-06-13-00-57.gh-issue-92391.s-Lase.rst b/Misc/NEWS.d/next/Library/2022-05-06-13-00-57.gh-issue-92391.s-Lase.rst deleted file mode 100644 index e042671dae81..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-06-13-00-57.gh-issue-92391.s-Lase.rst +++ /dev/null @@ -1,3 +0,0 @@ -Add :meth:`~object.__class_getitem__` to :class:`csv.DictReader` and -:class:`csv.DictWriter`, allowing them to be parameterized at runtime. -Patch by Marc Mueller. diff --git a/Misc/NEWS.d/next/Library/2022-05-08-18-51-14.gh-issue-89336.TL6ip7.rst b/Misc/NEWS.d/next/Library/2022-05-08-18-51-14.gh-issue-89336.TL6ip7.rst deleted file mode 100644 index b4c58c0e48b2..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-08-18-51-14.gh-issue-89336.TL6ip7.rst +++ /dev/null @@ -1,4 +0,0 @@ -Removed :mod:`configparser` module APIs: -the ``SafeConfigParser`` class alias, the ``ParsingError.filename`` -property and parameter, and the ``ConfigParser.readfp`` method, all -of which were deprecated since Python 3.2. diff --git a/Misc/NEWS.d/next/Library/2022-05-08-19-21-14.gh-issue-84131.rG5kI7.rst b/Misc/NEWS.d/next/Library/2022-05-08-19-21-14.gh-issue-84131.rG5kI7.rst deleted file mode 100644 index 4a930bde0115..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-08-19-21-14.gh-issue-84131.rG5kI7.rst +++ /dev/null @@ -1,3 +0,0 @@ -The :class:`pathlib.Path` deprecated method ``link_to`` has been removed. -Use 3.10's :meth:`~pathlib.Path.hardlink_to` method instead as its semantics -are consistent with that of :meth:`~pathlib.Path.symlink_to`. diff --git a/Misc/NEWS.d/next/Library/2022-05-09-01-27-25.gh-issue-92531.vV7S_O.rst b/Misc/NEWS.d/next/Library/2022-05-09-01-27-25.gh-issue-92531.vV7S_O.rst deleted file mode 100644 index 574fa6c4d979..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-09-01-27-25.gh-issue-92531.vV7S_O.rst +++ /dev/null @@ -1,3 +0,0 @@ -The statistics.median_grouped() function now always return a float. -Formerly, it did not convert the input type when for sequences of length -one. diff --git a/Misc/NEWS.d/next/Library/2022-05-09-09-28-02.gh-issue-92530.M4Q1RS.rst b/Misc/NEWS.d/next/Library/2022-05-09-09-28-02.gh-issue-92530.M4Q1RS.rst deleted file mode 100644 index 8bb8ca0488c9..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-09-09-28-02.gh-issue-92530.M4Q1RS.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix an issue that occurred after interrupting -:func:`threading.Condition.notify`. diff --git a/Misc/NEWS.d/next/Library/2022-05-09-11-55-04.gh-issue-92547.CzVZft.rst b/Misc/NEWS.d/next/Library/2022-05-09-11-55-04.gh-issue-92547.CzVZft.rst deleted file mode 100644 index 52626974c401..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-09-11-55-04.gh-issue-92547.CzVZft.rst +++ /dev/null @@ -1,6 +0,0 @@ -Remove undocumented :mod:`sqlite3` features deprecated in Python 3.10: - -* ``sqlite3.enable_shared_cache()`` -* ``sqlite3.OptimizedUnicode`` - -Patch by Erlend E. Aasland. diff --git a/Misc/NEWS.d/next/Library/2022-05-09-21-31-41.gh-issue-92445.tJosdm.rst b/Misc/NEWS.d/next/Library/2022-05-09-21-31-41.gh-issue-92445.tJosdm.rst deleted file mode 100644 index 16bad6d34b1c..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-09-21-31-41.gh-issue-92445.tJosdm.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix a bug in :mod:`argparse` where ``nargs="*"`` would raise an error instead of returning -an empty list when 0 arguments were supplied if choice was also defined in -``parser.add_argument``. diff --git a/Misc/NEWS.d/next/Library/2022-05-09-22-27-11.gh-issue-92591.V7RCk2.rst b/Misc/NEWS.d/next/Library/2022-05-09-22-27-11.gh-issue-92591.V7RCk2.rst deleted file mode 100644 index cd9b598d1dbc..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-09-22-27-11.gh-issue-92591.V7RCk2.rst +++ /dev/null @@ -1,3 +0,0 @@ -Allow :mod:`logging` filters to return a :class:`logging.LogRecord` instance -so that filters attached to :class:`logging.Handler`\ s can enrich records without -side effects on other handlers. diff --git a/Misc/NEWS.d/next/Library/2022-05-10-07-57-27.gh-issue-92550.Rk_UzM.rst b/Misc/NEWS.d/next/Library/2022-05-10-07-57-27.gh-issue-92550.Rk_UzM.rst deleted file mode 100644 index 1f0fde31108a..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-10-07-57-27.gh-issue-92550.Rk_UzM.rst +++ /dev/null @@ -1 +0,0 @@ -Fix :meth:`pathlib.Path.rglob` for empty pattern. diff --git a/Misc/NEWS.d/next/Library/2022-05-10-16-30-40.gh-issue-90385.1_wBRQ.rst b/Misc/NEWS.d/next/Library/2022-05-10-16-30-40.gh-issue-90385.1_wBRQ.rst deleted file mode 100644 index 24aa4403f8a6..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-10-16-30-40.gh-issue-90385.1_wBRQ.rst +++ /dev/null @@ -1 +0,0 @@ -Add :meth:`pathlib.Path.walk` as an alternative to :func:`os.walk`. diff --git a/Misc/NEWS.d/next/Library/2022-05-11-10-06-31.gh-issue-86388.7ivUtT.rst b/Misc/NEWS.d/next/Library/2022-05-11-10-06-31.gh-issue-86388.7ivUtT.rst deleted file mode 100644 index 13eb5d122b28..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-11-10-06-31.gh-issue-86388.7ivUtT.rst +++ /dev/null @@ -1,5 +0,0 @@ -Removed randrange() functionality deprecated since Python 3.10. Formerly, -randrange(10.0) losslessly converted to randrange(10). Now, it raises a -TypeError. Also, the exception raised for non-integral values such as -randrange(10.5) or randrange('10') has been changed from ValueError to -TypeError. diff --git a/Misc/NEWS.d/next/Library/2022-05-11-14-34-09.gh-issue-91581.glkou2.rst b/Misc/NEWS.d/next/Library/2022-05-11-14-34-09.gh-issue-91581.glkou2.rst deleted file mode 100644 index 846f57844a67..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-11-14-34-09.gh-issue-91581.glkou2.rst +++ /dev/null @@ -1,5 +0,0 @@ -:meth:`~datetime.datetime.utcfromtimestamp` no longer attempts to resolve -``fold`` in the pure Python implementation, since the fold is never 1 in UTC. -In addition to being slightly faster in the common case, this also prevents -some errors when the timestamp is close to :attr:`datetime.min -`. Patch by Paul Ganssle. diff --git a/Misc/NEWS.d/next/Library/2022-05-11-19-33-27.gh-issue-92671.KE4v6a.rst b/Misc/NEWS.d/next/Library/2022-05-11-19-33-27.gh-issue-92671.KE4v6a.rst deleted file mode 100644 index b50677ab5ca1..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-11-19-33-27.gh-issue-92671.KE4v6a.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed :func:`ast.unparse` for empty tuples in the assignment target context. diff --git a/Misc/NEWS.d/next/Library/2022-05-12-15-19-00.gh-issue-92734.d0wjDt.rst b/Misc/NEWS.d/next/Library/2022-05-12-15-19-00.gh-issue-92734.d0wjDt.rst deleted file mode 100644 index a2fcd1ed3dc7..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-12-15-19-00.gh-issue-92734.d0wjDt.rst +++ /dev/null @@ -1 +0,0 @@ -Allow multi-element reprs emitted by :mod:`reprlib` to be pretty-printed using configurable indentation. diff --git a/Misc/NEWS.d/next/Library/2022-05-14-09-01-38.gh-issue-89325.ys-2BZ.rst b/Misc/NEWS.d/next/Library/2022-05-14-09-01-38.gh-issue-89325.ys-2BZ.rst deleted file mode 100644 index 175869624f75..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-14-09-01-38.gh-issue-89325.ys-2BZ.rst +++ /dev/null @@ -1,6 +0,0 @@ -Removed many old deprecated :mod:`unittest` features: -:class:`~unittest.TestCase` method aliases, undocumented and broken -:class:`~unittest.TestCase` method ``assertDictContainsSubset``, -undocumented :meth:`TestLoader.loadTestsFromModule -` parameter *use_load_tests*, and -an underscored alias of the :class:`~unittest.TextTestResult` class. diff --git a/Misc/NEWS.d/next/Library/2022-05-14-11-41-23.gh-issue-90473.kPdOZl.rst b/Misc/NEWS.d/next/Library/2022-05-14-11-41-23.gh-issue-90473.kPdOZl.rst deleted file mode 100644 index bf5ee542182e..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-14-11-41-23.gh-issue-90473.kPdOZl.rst +++ /dev/null @@ -1,2 +0,0 @@ -:mod:`subprocess` now fails early on Emscripten and WASI platforms to work -around missing :func:`os.pipe` on WASI. diff --git a/Misc/NEWS.d/next/Library/2022-05-16-14-35-39.gh-issue-92839.owSMyo.rst b/Misc/NEWS.d/next/Library/2022-05-16-14-35-39.gh-issue-92839.owSMyo.rst deleted file mode 100644 index b425bd9c47bc..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-16-14-35-39.gh-issue-92839.owSMyo.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed crash resulting from calling bisect.insort() or bisect.insort_left() with the key argument not equal to None. diff --git a/Misc/NEWS.d/next/Library/2022-05-17-06-27-39.gh-issue-92869.t8oBkw.rst b/Misc/NEWS.d/next/Library/2022-05-17-06-27-39.gh-issue-92869.t8oBkw.rst deleted file mode 100644 index 7787f3419de6..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-17-06-27-39.gh-issue-92869.t8oBkw.rst +++ /dev/null @@ -1,2 +0,0 @@ -Added :class:`~ctypes.c_time_t` to :mod:`ctypes`, which has the same size as -the :c:type:`time_t` type in C. diff --git a/Misc/NEWS.d/next/Library/2022-05-18-17-18-41.gh-issue-91922.DwWIsJ.rst b/Misc/NEWS.d/next/Library/2022-05-18-17-18-41.gh-issue-91922.DwWIsJ.rst deleted file mode 100644 index 30f7bba11560..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-18-17-18-41.gh-issue-91922.DwWIsJ.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix function :func:`sqlite.connect` and the :class:`sqlite.Connection` -constructor on non-UTF-8 locales. Also, they now support bytes paths -non-decodable with the current FS encoding. diff --git a/Misc/NEWS.d/next/Library/2022-05-18-21-04-09.gh-issue-87901.lnf041.rst b/Misc/NEWS.d/next/Library/2022-05-18-21-04-09.gh-issue-87901.lnf041.rst deleted file mode 100644 index 3488541eb3d7..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-18-21-04-09.gh-issue-87901.lnf041.rst +++ /dev/null @@ -1,2 +0,0 @@ -Removed the ``encoding`` argument from :func:`os.popen` that was added in -3.11b1. diff --git a/Misc/NEWS.d/next/Library/2022-05-19-13-33-18.gh-issue-92675.ZeerMZ.rst b/Misc/NEWS.d/next/Library/2022-05-19-13-33-18.gh-issue-92675.ZeerMZ.rst deleted file mode 100644 index 6adc024fc541..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-19-13-33-18.gh-issue-92675.ZeerMZ.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix :func:`venv.ensure_directories` to accept :class:`pathlib.Path` arguments -in addition to :class:`str` paths. Patch by David Foster. diff --git a/Misc/NEWS.d/next/Library/2022-05-19-17-49-58.gh-issue-92932.o2peTh.rst b/Misc/NEWS.d/next/Library/2022-05-19-17-49-58.gh-issue-92932.o2peTh.rst deleted file mode 100644 index cb76ac5cbd60..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-19-17-49-58.gh-issue-92932.o2peTh.rst +++ /dev/null @@ -1,3 +0,0 @@ -Now :func:`~dis.dis` and :func:`~dis.get_instructions` handle operand values -for instructions prefixed by ``EXTENDED_ARG_QUICK``. -Patch by Sam Gross and Dong-hee Na. diff --git a/Misc/NEWS.d/next/Library/2022-05-19-22-34-42.gh-issue-92986.e6uKxj.rst b/Misc/NEWS.d/next/Library/2022-05-19-22-34-42.gh-issue-92986.e6uKxj.rst deleted file mode 100644 index 691c0dd3759f..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-19-22-34-42.gh-issue-92986.e6uKxj.rst +++ /dev/null @@ -1 +0,0 @@ -Fix :func:`ast.unparse` when ``ImportFrom.level`` is None diff --git a/Misc/NEWS.d/next/Library/2022-05-20-15-52-43.gh-issue-93010.WF-cAc.rst b/Misc/NEWS.d/next/Library/2022-05-20-15-52-43.gh-issue-93010.WF-cAc.rst deleted file mode 100644 index 24208b5160ed..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-20-15-52-43.gh-issue-93010.WF-cAc.rst +++ /dev/null @@ -1 +0,0 @@ -In a very special case, the email package tried to append the nonexistent ``InvalidHeaderError`` to the defect list. It should have been ``InvalidHeaderDefect``. diff --git a/Misc/NEWS.d/next/Library/2022-05-21-13-16-16.gh-issue-93044.eJ_XkZ.rst b/Misc/NEWS.d/next/Library/2022-05-21-13-16-16.gh-issue-93044.eJ_XkZ.rst deleted file mode 100644 index c9df8676bcdd..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-21-13-16-16.gh-issue-93044.eJ_XkZ.rst +++ /dev/null @@ -1,2 +0,0 @@ -No longer convert the database argument of :func:`sqlite3.connect` to bytes -before passing it to the factory. diff --git a/Misc/NEWS.d/next/Library/2022-05-22-16-08-01.gh-issue-89973.jc-Q4g.rst b/Misc/NEWS.d/next/Library/2022-05-22-16-08-01.gh-issue-89973.jc-Q4g.rst deleted file mode 100644 index 7e61fd7d46a0..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-22-16-08-01.gh-issue-89973.jc-Q4g.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix :exc:`re.error` raised in :mod:`fnmatch` if the pattern contains a -character range with upper bound lower than lower bound (e.g. ``[c-a]``). -Now such ranges are interpreted as empty ranges. diff --git a/Misc/NEWS.d/next/Library/2022-05-22-23-46-18.gh-issue-93033.wZfiL-.rst b/Misc/NEWS.d/next/Library/2022-05-22-23-46-18.gh-issue-93033.wZfiL-.rst deleted file mode 100644 index 3cee530339fb..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-22-23-46-18.gh-issue-93033.wZfiL-.rst +++ /dev/null @@ -1 +0,0 @@ -Search in some strings (platform dependent i.e [U+0xFFFF, U+0x0100] on Windows or [U+0xFFFFFFFF, U+0x00010000] on Linux 64-bit) are now up to 10 times faster. diff --git a/Misc/NEWS.d/next/Library/2022-05-24-10-59-02.gh-issue-92728.zxTifq.rst b/Misc/NEWS.d/next/Library/2022-05-24-10-59-02.gh-issue-92728.zxTifq.rst deleted file mode 100644 index b39609be2c4c..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-24-10-59-02.gh-issue-92728.zxTifq.rst +++ /dev/null @@ -1,3 +0,0 @@ -The :func:`re.template` function and the corresponding :const:`re.TEMPLATE` -and :const:`re.T` flags are restored after they were removed in 3.11.0b1, -but they are now deprecated, so they might be removed from Python 3.13. diff --git a/Misc/NEWS.d/next/Library/2022-05-24-11-19-04.gh-issue-74696.-cnf-A.rst b/Misc/NEWS.d/next/Library/2022-05-24-11-19-04.gh-issue-74696.-cnf-A.rst deleted file mode 100644 index 5b2e460e9ea0..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-24-11-19-04.gh-issue-74696.-cnf-A.rst +++ /dev/null @@ -1,2 +0,0 @@ -:func:`shutil.make_archive` no longer temporarily changes the current -working directory during creation of standard ``.zip`` or tar archives. diff --git a/Misc/NEWS.d/next/Library/2022-05-25-00-21-28.gh-issue-91513.9VyCT4.rst b/Misc/NEWS.d/next/Library/2022-05-25-00-21-28.gh-issue-91513.9VyCT4.rst deleted file mode 100644 index f9f93767ed17..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-25-00-21-28.gh-issue-91513.9VyCT4.rst +++ /dev/null @@ -1 +0,0 @@ -Added ``taskName`` attribute to :mod:`logging` module for use with :mod:`asyncio` tasks. diff --git a/Misc/NEWS.d/next/Library/2022-05-25-02-45-41.gh-issue-90817.yxANgU.rst b/Misc/NEWS.d/next/Library/2022-05-25-02-45-41.gh-issue-90817.yxANgU.rst deleted file mode 100644 index 06937e886917..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-25-02-45-41.gh-issue-90817.yxANgU.rst +++ /dev/null @@ -1,3 +0,0 @@ -The :func:`locale.resetlocale` function is deprecated and will be removed in -Python 3.13. Use ``locale.setlocale(locale.LC_ALL, "")`` instead. Patch by -Victor Stinner. diff --git a/Misc/NEWS.d/next/Library/2022-05-25-15-57-39.gh-issue-90155.YMstB5.rst b/Misc/NEWS.d/next/Library/2022-05-25-15-57-39.gh-issue-90155.YMstB5.rst deleted file mode 100644 index 8def76914eda..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-25-15-57-39.gh-issue-90155.YMstB5.rst +++ /dev/null @@ -1 +0,0 @@ -Fix broken :class:`asyncio.Semaphore` when acquire is cancelled. diff --git a/Misc/NEWS.d/next/Library/2022-05-25-22-09-38.gh-issue-92886.ylwDSc.rst b/Misc/NEWS.d/next/Library/2022-05-25-22-09-38.gh-issue-92886.ylwDSc.rst deleted file mode 100644 index 7854381de30f..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-25-22-09-38.gh-issue-92886.ylwDSc.rst +++ /dev/null @@ -1 +0,0 @@ -Replace ``assert`` statements with ``raise AssertionError()`` in :class:`~wsgiref.BaseHandler` so that the tested behaviour is maintained running with optimizations ``(-O)``. diff --git a/Misc/NEWS.d/next/Library/2022-05-26-08-41-34.gh-issue-93243.uw6x5z.rst b/Misc/NEWS.d/next/Library/2022-05-26-08-41-34.gh-issue-93243.uw6x5z.rst deleted file mode 100644 index f03ed7b5efc5..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-26-08-41-34.gh-issue-93243.uw6x5z.rst +++ /dev/null @@ -1 +0,0 @@ -The :mod:`smtpd` module was removed per the schedule in :pep:`594`. diff --git a/Misc/NEWS.d/next/Library/2022-05-26-09-24-41.gh-issue-93162.W1VuhU.rst b/Misc/NEWS.d/next/Library/2022-05-26-09-24-41.gh-issue-93162.W1VuhU.rst deleted file mode 100644 index 4d916a1df5e0..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-26-09-24-41.gh-issue-93162.W1VuhU.rst +++ /dev/null @@ -1,4 +0,0 @@ -Add the ability for :func:`logging.config.dictConfig` to usefully configure -:class:`~logging.handlers.QueueHandler` and :class:`~logging.handlers.QueueListener` -as a pair, and add :func:`logging.getHandlerByName` and :func:`logging.getHandlerNames` -APIs to allow access to handlers by name. diff --git a/Misc/NEWS.d/next/Library/2022-05-26-23-10-55.gh-issue-93156.4XfDVN.rst b/Misc/NEWS.d/next/Library/2022-05-26-23-10-55.gh-issue-93156.4XfDVN.rst deleted file mode 100644 index 165baa08aaab..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-26-23-10-55.gh-issue-93156.4XfDVN.rst +++ /dev/null @@ -1,2 +0,0 @@ -Accessing the :attr:`pathlib.PurePath.parents` sequence of an absolute path -using negative index values produced incorrect results. diff --git a/Misc/NEWS.d/next/Library/2022-05-27-10-52-06.gh-issue-85308.K6r-tJ.rst b/Misc/NEWS.d/next/Library/2022-05-27-10-52-06.gh-issue-85308.K6r-tJ.rst deleted file mode 100644 index 4574264dd4d4..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-27-10-52-06.gh-issue-85308.K6r-tJ.rst +++ /dev/null @@ -1,4 +0,0 @@ -Changed :class:`argparse.ArgumentParser` to use :term:`filesystem encoding -and error handler` instead of default text encoding to read arguments from -file (e.g. ``fromfile_prefix_chars`` option). This change affects Windows; -argument file should be encoded with UTF-8 instead of ANSI Codepage. diff --git a/Misc/NEWS.d/next/Library/2022-05-27-13-18-18.gh-issue-93297.e2zuHz.rst b/Misc/NEWS.d/next/Library/2022-05-27-13-18-18.gh-issue-93297.e2zuHz.rst deleted file mode 100644 index a8e4cd93d304..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-27-13-18-18.gh-issue-93297.e2zuHz.rst +++ /dev/null @@ -1 +0,0 @@ -Make asyncio task groups prevent child tasks from being GCed diff --git a/Misc/NEWS.d/next/Library/2022-05-27-22-17-11.gh-issue-88123.mkYl5q.rst b/Misc/NEWS.d/next/Library/2022-05-27-22-17-11.gh-issue-88123.mkYl5q.rst deleted file mode 100644 index 46bd37a85a7c..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-27-22-17-11.gh-issue-88123.mkYl5q.rst +++ /dev/null @@ -1,2 +0,0 @@ -Implement Enum __contains__ that returns True or False to replace the -deprecated behaviour that would sometimes raise a TypeError. diff --git a/Misc/NEWS.d/next/Library/2022-05-28-08-02-55.gh-issue-93312.HY0Uzj.rst b/Misc/NEWS.d/next/Library/2022-05-28-08-02-55.gh-issue-93312.HY0Uzj.rst deleted file mode 100644 index f11d04f63532..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-28-08-02-55.gh-issue-93312.HY0Uzj.rst +++ /dev/null @@ -1,3 +0,0 @@ -Add :data:`os.PIDFD_NONBLOCK` flag to open a file descriptor -for a process with :func:`os.pidfd_open` in non-blocking mode. -Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Library/2022-05-30-21-42-50.gh-issue-83658.01Ntx0.rst b/Misc/NEWS.d/next/Library/2022-05-30-21-42-50.gh-issue-83658.01Ntx0.rst deleted file mode 100644 index a18730954098..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-30-21-42-50.gh-issue-83658.01Ntx0.rst +++ /dev/null @@ -1 +0,0 @@ -Make :class:`multiprocessing.Pool` raise an exception if ``maxtasksperchild`` is not ``None`` or a positive int. diff --git a/Misc/NEWS.d/next/Library/2022-05-31-14-58-40.gh-issue-93353.9Hvm6o.rst b/Misc/NEWS.d/next/Library/2022-05-31-14-58-40.gh-issue-93353.9Hvm6o.rst deleted file mode 100644 index 67be3c68f47c..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-31-14-58-40.gh-issue-93353.9Hvm6o.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix the :func:`importlib.resources.as_file` context manager to remove the -temporary file if destroyed late during Python finalization: keep a local -reference to the :func:`os.remove` function. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Library/2022-06-01-11-24-13.gh-issue-91162.NxvU_u.rst b/Misc/NEWS.d/next/Library/2022-06-01-11-24-13.gh-issue-91162.NxvU_u.rst deleted file mode 100644 index 09fa47c0d238..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-01-11-24-13.gh-issue-91162.NxvU_u.rst +++ /dev/null @@ -1,5 +0,0 @@ -Support splitting of unpacked arbitrary-length tuple over ``TypeVar`` and -``TypeVarTuple`` parameters. For example: - -* ``A[T, *Ts][*tuple[int, ...]]`` -> ``A[int, *tuple[int, ...]]`` -* ``A[*Ts, T][*tuple[int, ...]]`` -> ``A[*tuple[int, ...], int]`` diff --git a/Misc/NEWS.d/next/Library/2022-06-02-08-40-58.gh-issue-91810.Gtk44w.rst b/Misc/NEWS.d/next/Library/2022-06-02-08-40-58.gh-issue-91810.Gtk44w.rst deleted file mode 100644 index e40005886afc..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-02-08-40-58.gh-issue-91810.Gtk44w.rst +++ /dev/null @@ -1,2 +0,0 @@ -Suppress writing an XML declaration in open files in ``ElementTree.write()`` -with ``encoding='unicode'`` and ``xml_declaration=None``. diff --git a/Misc/NEWS.d/next/Library/2022-06-03-22-13-28.gh-issue-93370.tjfu9L.rst b/Misc/NEWS.d/next/Library/2022-06-03-22-13-28.gh-issue-93370.tjfu9L.rst deleted file mode 100644 index bd5315038003..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-03-22-13-28.gh-issue-93370.tjfu9L.rst +++ /dev/null @@ -1 +0,0 @@ -Deprecate :data:`sqlite3.version` and :data:`sqlite3.version_info`. diff --git a/Misc/NEWS.d/next/Library/2022-06-04-00-11-54.gh-issue-93475.vffFw1.rst b/Misc/NEWS.d/next/Library/2022-06-04-00-11-54.gh-issue-93475.vffFw1.rst deleted file mode 100644 index efe7ff3e9b4f..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-04-00-11-54.gh-issue-93475.vffFw1.rst +++ /dev/null @@ -1,2 +0,0 @@ -Expose ``FICLONE`` and ``FICLONERANGE`` constants in :mod:`fcntl`. Patch by -Illia Volochii. diff --git a/Misc/NEWS.d/next/Library/2022-06-05-22-22-42.gh-issue-93421.43UO_8.rst b/Misc/NEWS.d/next/Library/2022-06-05-22-22-42.gh-issue-93421.43UO_8.rst deleted file mode 100644 index 9e1d6554e0ab..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-05-22-22-42.gh-issue-93421.43UO_8.rst +++ /dev/null @@ -1,3 +0,0 @@ -Update :data:`sqlite3.Cursor.rowcount` when a DML statement has run to -completion. This fixes the row count for SQL queries like -``UPDATE ... RETURNING``. Patch by Erlend E. Aasland. diff --git a/Misc/NEWS.d/next/Library/2022-06-06-12-58-27.gh-issue-79579.e8rB-M.rst b/Misc/NEWS.d/next/Library/2022-06-06-12-58-27.gh-issue-79579.e8rB-M.rst deleted file mode 100644 index 82b1a1c28a60..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-06-12-58-27.gh-issue-79579.e8rB-M.rst +++ /dev/null @@ -1,2 +0,0 @@ -:mod:`sqlite3` now correctly detects DML queries with leading comments. -Patch by Erlend E. Aasland. diff --git a/Misc/NEWS.d/next/Library/2022-06-06-13-19-43.gh-issue-93521._vE8m9.rst b/Misc/NEWS.d/next/Library/2022-06-06-13-19-43.gh-issue-93521._vE8m9.rst deleted file mode 100644 index 3a3ff4736d29..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-06-13-19-43.gh-issue-93521._vE8m9.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fixed a case where dataclasses would try to add ``__weakref__`` into the -``__slots__`` for a dataclass that specified ``weakref_slot=True`` when it was -already defined in one of its bases. This resulted in a ``TypeError`` upon the -new class being created. diff --git a/Misc/NEWS.d/next/Library/2022-06-07-14-53-46.gh-issue-90549.T4FMKY.rst b/Misc/NEWS.d/next/Library/2022-06-07-14-53-46.gh-issue-90549.T4FMKY.rst deleted file mode 100644 index 6ebdc394900e..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-07-14-53-46.gh-issue-90549.T4FMKY.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a multiprocessing bug where a global named resource (such as a semaphore) -could leak when a child process is spawned (as opposed to forked). diff --git a/Misc/NEWS.d/next/Library/2022-06-08-20-11-02.gh-issue-90494.LIZT85.rst b/Misc/NEWS.d/next/Library/2022-06-08-20-11-02.gh-issue-90494.LIZT85.rst deleted file mode 100644 index 95416768793e..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-08-20-11-02.gh-issue-90494.LIZT85.rst +++ /dev/null @@ -1,3 +0,0 @@ -:func:`copy.copy` and :func:`copy.deepcopy` now always raise a TypeError if -``__reduce__()`` returns a tuple with length 6 instead of silently ignore -the 6th item or produce incorrect result. diff --git a/Misc/NEWS.d/next/Library/2022-06-09-10-12-55.gh-issue-90473.683m_C.rst b/Misc/NEWS.d/next/Library/2022-06-09-10-12-55.gh-issue-90473.683m_C.rst deleted file mode 100644 index b053a8e9a081..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-09-10-12-55.gh-issue-90473.683m_C.rst +++ /dev/null @@ -1,2 +0,0 @@ -Emscripten and WASI have no home directory and cannot provide :pep:`370` -user site directory. diff --git a/Misc/NEWS.d/next/Library/2022-06-09-14-44-21.gh-issue-93626.sfghs46.rst b/Misc/NEWS.d/next/Library/2022-06-09-14-44-21.gh-issue-93626.sfghs46.rst deleted file mode 100644 index c6fa103706e9..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-09-14-44-21.gh-issue-93626.sfghs46.rst +++ /dev/null @@ -1 +0,0 @@ -Set ``__future__.annotations`` to have a ``None`` mandatoryRelease to indicate that it is currently 'TBD'. diff --git a/Misc/NEWS.d/next/Library/2022-06-09-17-15-26.gh-issue-91389.OE4vS5.rst b/Misc/NEWS.d/next/Library/2022-06-09-17-15-26.gh-issue-91389.OE4vS5.rst deleted file mode 100644 index 0a126551e411..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-09-17-15-26.gh-issue-91389.OE4vS5.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix an issue where :mod:`dis` utilities could report missing or incorrect -position information in the presence of ``CACHE`` entries. diff --git a/Misc/NEWS.d/next/Library/2022-06-11-13-32-17.gh-issue-79512.A1KTDr.rst b/Misc/NEWS.d/next/Library/2022-06-11-13-32-17.gh-issue-79512.A1KTDr.rst deleted file mode 100644 index 5393fb52e93c..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-11-13-32-17.gh-issue-79512.A1KTDr.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fixed names and ``__module__`` value of :mod:`weakref` classes -:class:`~weakref.ReferenceType`, :class:`~weakref.ProxyType`, -:class:`~weakref.CallableProxyType`. It makes them pickleable. diff --git a/Misc/NEWS.d/next/Library/2022-06-15-21-20-02.gh-issue-93820.FAMLY8.rst b/Misc/NEWS.d/next/Library/2022-06-15-21-20-02.gh-issue-93820.FAMLY8.rst deleted file mode 100644 index e06d897e7d8e..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-15-21-20-02.gh-issue-93820.FAMLY8.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixed a regression when :func:`copy.copy`-ing :class:`enum.Flag` with -multiple flag members. diff --git a/Misc/NEWS.d/next/Library/2022-06-15-21-28-16.gh-issue-83499.u3DQJ-.rst b/Misc/NEWS.d/next/Library/2022-06-15-21-28-16.gh-issue-83499.u3DQJ-.rst deleted file mode 100644 index 6b32b238dfde..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-15-21-28-16.gh-issue-83499.u3DQJ-.rst +++ /dev/null @@ -1 +0,0 @@ -Fix double closing of file description in :mod:`tempfile`. diff --git a/Misc/NEWS.d/next/Library/2022-06-15-21-35-11.gh-issue-91404.39TZzW.rst b/Misc/NEWS.d/next/Library/2022-06-15-21-35-11.gh-issue-91404.39TZzW.rst deleted file mode 100644 index e20b15c7b758..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-15-21-35-11.gh-issue-91404.39TZzW.rst +++ /dev/null @@ -1,3 +0,0 @@ -Revert the :mod:`re` memory leak when a match is terminated by a signal or -memory allocation failure as the implemented fix caused a major performance -regression. diff --git a/Misc/NEWS.d/next/Library/2022-06-16-09-24-50.gh-issue-93847.kuv8bN.rst b/Misc/NEWS.d/next/Library/2022-06-16-09-24-50.gh-issue-93847.kuv8bN.rst deleted file mode 100644 index c6947575e67e..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-16-09-24-50.gh-issue-93847.kuv8bN.rst +++ /dev/null @@ -1 +0,0 @@ -Fix repr of enum of generic aliases. diff --git a/Misc/NEWS.d/next/Library/2022-06-16-11-16-53.gh-issue-93820.00X0Y5.rst b/Misc/NEWS.d/next/Library/2022-06-16-11-16-53.gh-issue-93820.00X0Y5.rst deleted file mode 100644 index 70bb1e6c0cd7..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-16-11-16-53.gh-issue-93820.00X0Y5.rst +++ /dev/null @@ -1 +0,0 @@ -Pickle :class:`enum.Flag` by name. diff --git a/Misc/NEWS.d/next/Library/2022-06-17-12-02-30.gh-issue-93858.R49ARc.rst b/Misc/NEWS.d/next/Library/2022-06-17-12-02-30.gh-issue-93858.R49ARc.rst deleted file mode 100644 index 508ba626bab4..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-17-12-02-30.gh-issue-93858.R49ARc.rst +++ /dev/null @@ -1 +0,0 @@ -Prevent error when activating venv in nested fish instances. diff --git a/Misc/NEWS.d/next/Library/2022-06-17-16-00-55.gh-issue-93963.8YYZ-2.rst b/Misc/NEWS.d/next/Library/2022-06-17-16-00-55.gh-issue-93963.8YYZ-2.rst deleted file mode 100644 index 0973982dfeef..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-17-16-00-55.gh-issue-93963.8YYZ-2.rst +++ /dev/null @@ -1,2 +0,0 @@ -Officially deprecate from ``importlib.abc`` classes moved to -``importlib.resources.abc``. diff --git a/Misc/NEWS.d/next/Library/2022-06-18-15-06-54.gh-issue-93973.4y6UQT.rst b/Misc/NEWS.d/next/Library/2022-06-18-15-06-54.gh-issue-93973.4y6UQT.rst deleted file mode 100644 index a3e68ce4fab9..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-18-15-06-54.gh-issue-93973.4y6UQT.rst +++ /dev/null @@ -1 +0,0 @@ -Add keyword argument ``all_errors`` to ``asyncio.create_connection`` so that multiple connection errors can be raised as an ``ExceptionGroup``. diff --git a/Misc/NEWS.d/next/Library/2022-06-20-23-14-43.gh-issue-94028.UofEcX.rst b/Misc/NEWS.d/next/Library/2022-06-20-23-14-43.gh-issue-94028.UofEcX.rst deleted file mode 100644 index 5775b2276d70..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-20-23-14-43.gh-issue-94028.UofEcX.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix a regression in the :mod:`sqlite3` where statement objects were not -properly cleared and reset after use in cursor iters. The regression was -introduced by PR 27884 in Python 3.11a1. Patch by Erlend E. Aasland. diff --git a/Misc/NEWS.d/next/Library/2022-06-21-11-40-31.gh-issue-84753.FW1pxO.rst b/Misc/NEWS.d/next/Library/2022-06-21-11-40-31.gh-issue-84753.FW1pxO.rst deleted file mode 100644 index eeae2edf7161..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-21-11-40-31.gh-issue-84753.FW1pxO.rst +++ /dev/null @@ -1,7 +0,0 @@ -:func:`inspect.iscoroutinefunction`, :func:`inspect.isgeneratorfunction`, -and :func:`inspect.isasyncgenfunction` now properly return ``True`` for -duck-typed function-like objects like instances of -:class:`unittest.mock.AsyncMock`. - -This makes :func:`inspect.iscoroutinefunction` consistent with the -behavior of :func:`asyncio.iscoroutinefunction`. Patch by Mehdi ABAAKOUK. diff --git a/Misc/NEWS.d/next/Library/2022-06-22-11-16-11.gh-issue-94101.V9vDG8.rst b/Misc/NEWS.d/next/Library/2022-06-22-11-16-11.gh-issue-94101.V9vDG8.rst deleted file mode 100644 index bcef0ca07470..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-22-11-16-11.gh-issue-94101.V9vDG8.rst +++ /dev/null @@ -1,3 +0,0 @@ -Manual instantiation of :class:`ssl.SSLSession` objects is no longer allowed -as it lead to misconfigured instances that crashed the interpreter when -attributes where accessed on them. diff --git a/Misc/NEWS.d/next/Library/2022-06-23-13-12-05.gh-issue-91742.sNytVX.rst b/Misc/NEWS.d/next/Library/2022-06-23-13-12-05.gh-issue-91742.sNytVX.rst deleted file mode 100644 index 30c92363b10b..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-23-13-12-05.gh-issue-91742.sNytVX.rst +++ /dev/null @@ -1 +0,0 @@ -Fix :mod:`pdb` crash after jump caused by a null pointer dereference. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Library/2022-06-23-14-35-10.gh-issue-94169.jeba90.rst b/Misc/NEWS.d/next/Library/2022-06-23-14-35-10.gh-issue-94169.jeba90.rst deleted file mode 100644 index 40c1fc10bc0e..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-23-14-35-10.gh-issue-94169.jeba90.rst +++ /dev/null @@ -1,4 +0,0 @@ -Remove ``io.OpenWrapper`` and ``_pyio.OpenWrapper``, deprecated in Python -3.10: just use :func:`open` instead. The :func:`open` (:func:`io.open`) -function is a built-in function. Since Python 3.10, :func:`_pyio.open` is -also a static method. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Library/2022-06-24-08-49-47.gh-issue-94182.Wknau0.rst b/Misc/NEWS.d/next/Library/2022-06-24-08-49-47.gh-issue-94182.Wknau0.rst deleted file mode 100644 index c7be8640ef1f..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-24-08-49-47.gh-issue-94182.Wknau0.rst +++ /dev/null @@ -1 +0,0 @@ -run the :class:`asyncio.PidfdChildWatcher` on the running loop, this allows event loops to run subprocesses when there is no default event loop running on the main thread diff --git a/Misc/NEWS.d/next/Library/2022-06-24-09-41-41.gh-issue-94196.r2KyfS.rst b/Misc/NEWS.d/next/Library/2022-06-24-09-41-41.gh-issue-94196.r2KyfS.rst deleted file mode 100644 index e22776f1b45e..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-24-09-41-41.gh-issue-94196.r2KyfS.rst +++ /dev/null @@ -1,4 +0,0 @@ -:mod:`gzip`: Remove the ``filename`` attribute of :class:`gzip.GzipFile`, -deprecated since Python 2.6, use the :attr:`~gzip.GzipFile.name` attribute -instead. In write mode, the ``filename`` attribute added ``'.gz'`` file -extension if it was not present. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Library/2022-06-24-10-18-59.gh-issue-94199.kYOo8g.rst b/Misc/NEWS.d/next/Library/2022-06-24-10-18-59.gh-issue-94199.kYOo8g.rst deleted file mode 100644 index f3a9a35e8fca..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-24-10-18-59.gh-issue-94199.kYOo8g.rst +++ /dev/null @@ -1,5 +0,0 @@ -:mod:`hashlib`: Remove the pure Python implementation of -:func:`hashlib.pbkdf2_hmac()`, deprecated in Python 3.10. Python 3.10 and -newer requires OpenSSL 1.1.1 (:pep:`644`): this OpenSSL version provides -a C implementation of :func:`~hashlib.pbkdf2_hmac()` which is faster. Patch -by Victor Stinner. diff --git a/Misc/NEWS.d/next/Library/2022-06-24-10-29-19.gh-issue-94199.pfehmz.rst b/Misc/NEWS.d/next/Library/2022-06-24-10-29-19.gh-issue-94199.pfehmz.rst deleted file mode 100644 index ed325c0f6886..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-24-10-29-19.gh-issue-94199.pfehmz.rst +++ /dev/null @@ -1,3 +0,0 @@ -Remove the :func:`ssl.RAND_pseudo_bytes` function, deprecated in Python 3.6: -use :func:`os.urandom` or :func:`ssl.RAND_bytes` instead. Patch by Victor -Stinner. diff --git a/Misc/NEWS.d/next/Library/2022-06-24-10-39-56.gh-issue-94199.MIuckY.rst b/Misc/NEWS.d/next/Library/2022-06-24-10-39-56.gh-issue-94199.MIuckY.rst deleted file mode 100644 index e1fb163d55d5..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-24-10-39-56.gh-issue-94199.MIuckY.rst +++ /dev/null @@ -1,7 +0,0 @@ -Remove the :func:`ssl.wrap_socket` function, deprecated in Python 3.7: instead, -create a :class:`ssl.SSLContext` object and call its -:class:`ssl.SSLContext.wrap_socket` method. Any package that still uses -:func:`ssl.wrap_socket` is broken and insecure. The function neither sends a -SNI TLS extension nor validates server hostname. Code is subject to `CWE-295 -`_: Improper Certificate -Validation. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Library/2022-06-24-14-25-26.gh-issue-94214.03pXR5.rst b/Misc/NEWS.d/next/Library/2022-06-24-14-25-26.gh-issue-94214.03pXR5.rst deleted file mode 100644 index 7dccc0abd4af..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-24-14-25-26.gh-issue-94214.03pXR5.rst +++ /dev/null @@ -1 +0,0 @@ -Document the ``context`` object used in the ``venv.EnvBuilder`` class, and add the new environment's library path to it. diff --git a/Misc/NEWS.d/next/Library/2022-06-24-17-11-33.gh-issue-94199.7releN.rst b/Misc/NEWS.d/next/Library/2022-06-24-17-11-33.gh-issue-94199.7releN.rst deleted file mode 100644 index 68bd283b9907..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-24-17-11-33.gh-issue-94199.7releN.rst +++ /dev/null @@ -1,4 +0,0 @@ -Remove the :func:`ssl.match_hostname` function. The -:func:`ssl.match_hostname` was deprecated in Python 3.7. OpenSSL performs -hostname matching since Python 3.7, Python no longer uses the -:func:`ssl.match_hostname` function. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Library/2022-06-24-18-20-42.gh-issue-94226.8ZL4Fm.rst b/Misc/NEWS.d/next/Library/2022-06-24-18-20-42.gh-issue-94226.8ZL4Fm.rst deleted file mode 100644 index 099f945c23f2..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-24-18-20-42.gh-issue-94226.8ZL4Fm.rst +++ /dev/null @@ -1,2 +0,0 @@ -Remove the :func:`locale.format` function, deprecated in Python 3.7: use -:func:`locale.format_string` instead. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Library/2022-06-24-19-16-09.gh-issue-93096.r1_oIc.rst b/Misc/NEWS.d/next/Library/2022-06-24-19-16-09.gh-issue-93096.r1_oIc.rst deleted file mode 100644 index 536a9d7cab1b..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-24-19-16-09.gh-issue-93096.r1_oIc.rst +++ /dev/null @@ -1,3 +0,0 @@ -Removed undocumented ``-t`` argument of ``python -m base64``. Use -``python -m unittest test.test_base64.LegacyBase64TestCase.test_encodebytes`` -instead. diff --git a/Misc/NEWS.d/next/Library/2022-06-24-19-23-59.gh-issue-94207.VhS1eS.rst b/Misc/NEWS.d/next/Library/2022-06-24-19-23-59.gh-issue-94207.VhS1eS.rst deleted file mode 100644 index 3d38524ac0e8..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-24-19-23-59.gh-issue-94207.VhS1eS.rst +++ /dev/null @@ -1,2 +0,0 @@ -Made :class:`_struct.Struct` GC-tracked in order to fix a reference leak in -the :mod:`_struct` module. diff --git a/Misc/NEWS.d/next/Library/2022-06-24-19-40-40.gh-issue-93096.3RlK2d.rst b/Misc/NEWS.d/next/Library/2022-06-24-19-40-40.gh-issue-93096.3RlK2d.rst deleted file mode 100644 index f7d9e33eb414..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-24-19-40-40.gh-issue-93096.3RlK2d.rst +++ /dev/null @@ -1,2 +0,0 @@ -Removed undocumented ``python -m codecs``. Use ``python -m unittest -test.test_codecs.EncodedFileTest`` instead. diff --git a/Misc/NEWS.d/next/Library/2022-06-24-20-00-57.gh-issue-94216.hxnQPu.rst b/Misc/NEWS.d/next/Library/2022-06-24-20-00-57.gh-issue-94216.hxnQPu.rst deleted file mode 100644 index ae3c2e7e71f3..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-24-20-00-57.gh-issue-94216.hxnQPu.rst +++ /dev/null @@ -1 +0,0 @@ -The :mod:`dis` module now has the opcodes for pseudo instructions (those which are used by the compiler during code generation but then removed or replaced by real opcodes before the final bytecode is emitted). diff --git a/Misc/NEWS.d/next/Library/2022-06-25-09-12-23.gh-issue-74696.fxC9ua.rst b/Misc/NEWS.d/next/Library/2022-06-25-09-12-23.gh-issue-74696.fxC9ua.rst deleted file mode 100644 index 48beaff59a16..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-25-09-12-23.gh-issue-74696.fxC9ua.rst +++ /dev/null @@ -1,2 +0,0 @@ -:func:`shutil.make_archive` now passes the *root_dir* argument to custom -archivers which support it. diff --git a/Misc/NEWS.d/next/Library/2022-06-25-13-38-53.gh-issue-93259.FAGw-2.rst b/Misc/NEWS.d/next/Library/2022-06-25-13-38-53.gh-issue-93259.FAGw-2.rst deleted file mode 100644 index d346b65836b7..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-25-13-38-53.gh-issue-93259.FAGw-2.rst +++ /dev/null @@ -1,2 +0,0 @@ -Now raise ``ValueError`` when ``None`` or an empty string are passed to -``Distribution.from_name`` (and other callers). diff --git a/Misc/NEWS.d/next/Library/2022-06-25-16-27-02.gh-issue-94254.beP16v.rst b/Misc/NEWS.d/next/Library/2022-06-25-16-27-02.gh-issue-94254.beP16v.rst deleted file mode 100644 index 81482bcd4f89..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-25-16-27-02.gh-issue-94254.beP16v.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed types of :mod:`struct` module to be immutable. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Library/2022-06-25-23-44-44.gh-issue-90016.EB409s.rst b/Misc/NEWS.d/next/Library/2022-06-25-23-44-44.gh-issue-90016.EB409s.rst deleted file mode 100644 index 040ba44be2b9..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-25-23-44-44.gh-issue-90016.EB409s.rst +++ /dev/null @@ -1,2 +0,0 @@ -Deprecate :mod:`sqlite3` :ref:`default adapters and converters -`. Patch by Erlend E. Aasland. diff --git a/Misc/NEWS.d/next/Library/2022-06-26-10-59-15.gh-issue-89988.K8rnmt.rst b/Misc/NEWS.d/next/Library/2022-06-26-10-59-15.gh-issue-89988.K8rnmt.rst deleted file mode 100644 index 811a8d6031e0..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-26-10-59-15.gh-issue-89988.K8rnmt.rst +++ /dev/null @@ -1 +0,0 @@ -Fix memory leak in :class:`pickle.Pickler` when looking up :attr:`dispatch_table`. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Library/2022-06-27-10-33-18.gh-issue-94318.jR4_QV.rst b/Misc/NEWS.d/next/Library/2022-06-27-10-33-18.gh-issue-94318.jR4_QV.rst deleted file mode 100644 index 97a7cd8c9e7a..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-27-10-33-18.gh-issue-94318.jR4_QV.rst +++ /dev/null @@ -1 +0,0 @@ -Strip trailing spaces in :mod:`pydoc` text output. diff --git a/Misc/NEWS.d/next/Library/2022-06-28-00-24-48.gh-issue-94352.JY1Ayt.rst b/Misc/NEWS.d/next/Library/2022-06-28-00-24-48.gh-issue-94352.JY1Ayt.rst deleted file mode 100644 index 3a166abdcc32..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-28-00-24-48.gh-issue-94352.JY1Ayt.rst +++ /dev/null @@ -1,3 +0,0 @@ -:func:`shlex.split`: Passing ``None`` for *s* argument now raises an exception, -rather than reading :data:`sys.stdin`. The feature was deprecated in Python -3.9. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Library/2022-06-28-14-29-21.gh-issue-94379.RrgKfh.rst b/Misc/NEWS.d/next/Library/2022-06-28-14-29-21.gh-issue-94379.RrgKfh.rst deleted file mode 100644 index 24eafa1048ab..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-28-14-29-21.gh-issue-94379.RrgKfh.rst +++ /dev/null @@ -1,3 +0,0 @@ -:mod:`zipimport`: Remove ``find_loader()`` and ``find_module()`` methods, -deprecated in Python 3.10: use the ``find_spec()`` method instead. See -:pep:`451` for the rationale. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Library/2022-06-28-14-41-22.gh-issue-94383.CXnquo.rst b/Misc/NEWS.d/next/Library/2022-06-28-14-41-22.gh-issue-94383.CXnquo.rst deleted file mode 100644 index 9ed476b717f3..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-28-14-41-22.gh-issue-94383.CXnquo.rst +++ /dev/null @@ -1,5 +0,0 @@ -:mod:`xml.etree`: Remove the ``ElementTree.Element.copy()`` method of the -pure Python implementation, deprecated in Python 3.10, use the -:func:`copy.copy` function instead. The C implementation of :mod:`xml.etree` -has no ``copy()`` method, only a ``__copy__()`` method. Patch by Victor -Stinner. diff --git a/Misc/NEWS.d/next/Library/2022-06-29-04-42-56.gh-issue-94398.YOq_bJ.rst b/Misc/NEWS.d/next/Library/2022-06-29-04-42-56.gh-issue-94398.YOq_bJ.rst deleted file mode 100644 index c6e7e967d106..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-29-04-42-56.gh-issue-94398.YOq_bJ.rst +++ /dev/null @@ -1 +0,0 @@ -Once a :class:`asyncio.TaskGroup` has started shutting down (i.e., at least one task has failed and the task group has started cancelling the remaining tasks), it should not be possible to add new tasks to the task group. diff --git a/Misc/NEWS.d/next/Library/2022-06-29-09-48-37.gh-issue-92336.otA6c6.rst b/Misc/NEWS.d/next/Library/2022-06-29-09-48-37.gh-issue-92336.otA6c6.rst deleted file mode 100644 index eb74e0ceb744..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-29-09-48-37.gh-issue-92336.otA6c6.rst +++ /dev/null @@ -1 +0,0 @@ -Fix bug where :meth:`linecache.getline` fails on bad files with :exc:`UnicodeDecodeError` or :exc:`SyntaxError`. It now returns an empty string as per the documentation. diff --git a/Misc/NEWS.d/next/Library/2022-07-02-19-46-30.gh-issue-94510.xOatDC.rst b/Misc/NEWS.d/next/Library/2022-07-02-19-46-30.gh-issue-94510.xOatDC.rst deleted file mode 100644 index 55856d575655..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-02-19-46-30.gh-issue-94510.xOatDC.rst +++ /dev/null @@ -1,2 +0,0 @@ -Re-entrant calls to :func:`sys.setprofile` and :func:`sys.settrace` now -raise :exc:`RuntimeError`. Patch by Pablo Galindo. diff --git a/Misc/NEWS.d/next/Library/2022-07-03-16-26-35.gh-issue-78724.XNiJzf.rst b/Misc/NEWS.d/next/Library/2022-07-03-16-26-35.gh-issue-78724.XNiJzf.rst deleted file mode 100644 index 9621e4d3f83d..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-03-16-26-35.gh-issue-78724.XNiJzf.rst +++ /dev/null @@ -1 +0,0 @@ -Fix crash in :class:`struct.Struct` when it was not completely initialized by initializing it in :meth:`~object.__new__``. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Library/2022-07-03-16-41-03.gh-issue-94382.zuVZeM.rst b/Misc/NEWS.d/next/Library/2022-07-03-16-41-03.gh-issue-94382.zuVZeM.rst deleted file mode 100644 index d79300778f76..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-03-16-41-03.gh-issue-94382.zuVZeM.rst +++ /dev/null @@ -1 +0,0 @@ -Port static types of ``_multiprocessing`` module to heap types. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Library/2022-07-05-17-22-00.gh-issue-94343.kf4H5r.rst b/Misc/NEWS.d/next/Library/2022-07-05-17-22-00.gh-issue-94343.kf4H5r.rst deleted file mode 100644 index f666c2b0ec12..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-05-17-22-00.gh-issue-94343.kf4H5r.rst +++ /dev/null @@ -1 +0,0 @@ -Allow setting the attributes of ``reprlib.Repr`` during object initialization diff --git a/Misc/NEWS.d/next/Library/2022-07-06-06-02-02.gh-issue-93896.vIgWGr.rst b/Misc/NEWS.d/next/Library/2022-07-06-06-02-02.gh-issue-93896.vIgWGr.rst deleted file mode 100644 index 2283e14de9a9..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-06-06-02-02.gh-issue-93896.vIgWGr.rst +++ /dev/null @@ -1 +0,0 @@ -Fix :func:`asyncio.run` and :class:`unittest.IsolatedAsyncioTestCase` to always the set event loop as it was done in Python 3.10 and earlier. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Library/2022-07-06-14-45-12.gh-issue-93910.iZcp67.rst b/Misc/NEWS.d/next/Library/2022-07-06-14-45-12.gh-issue-93910.iZcp67.rst deleted file mode 100644 index 2e589118e3ef..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-06-14-45-12.gh-issue-93910.iZcp67.rst +++ /dev/null @@ -1,3 +0,0 @@ -The ability to access the other values of an enum on an enum (e.g. -``Color.RED.BLUE``) has been restored in order to fix a performance -regression. diff --git a/Misc/NEWS.d/next/Library/2022-07-06-14-57-33.gh-issue-94619.PRqKVX.rst b/Misc/NEWS.d/next/Library/2022-07-06-14-57-33.gh-issue-94619.PRqKVX.rst deleted file mode 100644 index 987ea6b045af..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-06-14-57-33.gh-issue-94619.PRqKVX.rst +++ /dev/null @@ -1 +0,0 @@ -Remove the long-deprecated ``module_repr()`` from :mod:`importlib`. diff --git a/Misc/NEWS.d/next/Library/2022-07-06-16-01-08.gh-issue-94607.Q6RYfz.rst b/Misc/NEWS.d/next/Library/2022-07-06-16-01-08.gh-issue-94607.Q6RYfz.rst deleted file mode 100644 index 3bbb9172f261..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-06-16-01-08.gh-issue-94607.Q6RYfz.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix subclassing complex generics with type variables in :mod:`typing`. Previously an error message saying ``Some type variables ... are not listed in Generic[...]`` was shown. -:mod:`typing` no longer populates ``__parameters__`` with the ``__parameters__`` of a Python class. diff --git a/Misc/NEWS.d/next/Library/2022-07-06-21-24-03.gh-issue-92546.s5Upkh.rst b/Misc/NEWS.d/next/Library/2022-07-06-21-24-03.gh-issue-92546.s5Upkh.rst deleted file mode 100644 index 0ea676ef5b0d..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-06-21-24-03.gh-issue-92546.s5Upkh.rst +++ /dev/null @@ -1,2 +0,0 @@ -An undocumented ``python -m pprint`` benchmark is moved into ``pprint`` -suite of pyperformance. Patch by Oleg Iarygin. diff --git a/Misc/NEWS.d/next/Library/2022-07-06-22-41-51.gh-issue-94309._XswsX.rst b/Misc/NEWS.d/next/Library/2022-07-06-22-41-51.gh-issue-94309._XswsX.rst deleted file mode 100644 index b1d45586e9c4..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-06-22-41-51.gh-issue-94309._XswsX.rst +++ /dev/null @@ -1 +0,0 @@ -Deprecate aliases :class:`typing.Hashable` and :class:`typing.Sized` diff --git a/Misc/NEWS.d/next/Library/2022-07-07-15-46-55.gh-issue-94637.IYEiUM.rst b/Misc/NEWS.d/next/Library/2022-07-07-15-46-55.gh-issue-94637.IYEiUM.rst deleted file mode 100644 index 20cbbcd5088b..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-07-15-46-55.gh-issue-94637.IYEiUM.rst +++ /dev/null @@ -1,3 +0,0 @@ -:meth:`SSLContext.set_default_verify_paths` now releases the GIL around -``SSL_CTX_set_default_verify_paths`` call. The function call performs I/O -and CPU intensive work. diff --git a/Misc/NEWS.d/next/Library/2022-07-08-08-39-35.gh-issue-88050.0aOC_m.rst b/Misc/NEWS.d/next/Library/2022-07-08-08-39-35.gh-issue-88050.0aOC_m.rst deleted file mode 100644 index 43c0765d940d..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-08-08-39-35.gh-issue-88050.0aOC_m.rst +++ /dev/null @@ -1 +0,0 @@ -Fix :mod:`asyncio` subprocess transport to kill process cleanly when process is blocked and avoid ``RuntimeError`` when loop is closed. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Library/2022-07-08-17-49-12.gh-issue-87822.F9dzkf.rst b/Misc/NEWS.d/next/Library/2022-07-08-17-49-12.gh-issue-87822.F9dzkf.rst deleted file mode 100644 index 7b27f5df45ba..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-08-17-49-12.gh-issue-87822.F9dzkf.rst +++ /dev/null @@ -1 +0,0 @@ -When called with ``capture_locals=True``, the :mod:`traceback` module functions swallow exceptions raised from calls to ``repr()`` on local variables of frames. This is in order to prioritize the original exception over rendering errors. An indication of the failure is printed in place of the missing value. (Patch by Simon-Martin Schroeder). diff --git a/Misc/NEWS.d/next/Library/2022-07-09-08-55-04.gh-issue-74116.0XwYC1.rst b/Misc/NEWS.d/next/Library/2022-07-09-08-55-04.gh-issue-74116.0XwYC1.rst deleted file mode 100644 index 33782598745b..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-09-08-55-04.gh-issue-74116.0XwYC1.rst +++ /dev/null @@ -1 +0,0 @@ -Allow :meth:`asyncio.StreamWriter.drain` to be awaited concurrently by multiple tasks. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Library/2022-07-09-15-17-02.gh-issue-81620.L0O_bV.rst b/Misc/NEWS.d/next/Library/2022-07-09-15-17-02.gh-issue-81620.L0O_bV.rst deleted file mode 100644 index b4ccea4924ff..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-09-15-17-02.gh-issue-81620.L0O_bV.rst +++ /dev/null @@ -1 +0,0 @@ -Add random.binomialvariate(). diff --git a/Misc/NEWS.d/next/Library/2022-07-11-10-41-48.gh-issue-94736.EbsgeK.rst b/Misc/NEWS.d/next/Library/2022-07-11-10-41-48.gh-issue-94736.EbsgeK.rst deleted file mode 100644 index 3080672ecdfb..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-11-10-41-48.gh-issue-94736.EbsgeK.rst +++ /dev/null @@ -1 +0,0 @@ -Fix crash when deallocating an instance of a subclass of ``_multiprocessing.SemLock``. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Library/2022-07-14-00-43-52.gh-issue-94821.e17ghU.rst b/Misc/NEWS.d/next/Library/2022-07-14-00-43-52.gh-issue-94821.e17ghU.rst deleted file mode 100644 index bf7885aef8cb..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-14-00-43-52.gh-issue-94821.e17ghU.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix binding of unix socket to empty address on Linux to use an available -address from the abstract namespace, instead of "\0". diff --git a/Misc/NEWS.d/next/Library/2022-07-15-08-13-51.gh-issue-94857.9_KvZJ.rst b/Misc/NEWS.d/next/Library/2022-07-15-08-13-51.gh-issue-94857.9_KvZJ.rst deleted file mode 100644 index e684415595d1..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-15-08-13-51.gh-issue-94857.9_KvZJ.rst +++ /dev/null @@ -1 +0,0 @@ -Fix refleak in ``_io.TextIOWrapper.reconfigure``. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Library/2022-07-17-22-31-32.gh-issue-90085.c4FWcS.rst b/Misc/NEWS.d/next/Library/2022-07-17-22-31-32.gh-issue-90085.c4FWcS.rst deleted file mode 100644 index 37952adc8f1a..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-17-22-31-32.gh-issue-90085.c4FWcS.rst +++ /dev/null @@ -1,3 +0,0 @@ -Remove ``-c/--clock`` and ``-t/--time`` CLI options of :mod:`timeit`. -The options had been deprecated since Python 3.3 and the functionality -was removed in Python 3.7. Patch by Shantanu Jain. diff --git a/Misc/NEWS.d/next/Library/2022-07-19-15-37-11.gh-issue-95005.iRmZ74.rst b/Misc/NEWS.d/next/Library/2022-07-19-15-37-11.gh-issue-95005.iRmZ74.rst deleted file mode 100644 index 787f3146ab77..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-19-15-37-11.gh-issue-95005.iRmZ74.rst +++ /dev/null @@ -1,2 +0,0 @@ -Replace :c:expr:`_PyAccu` with :c:expr:`_PyUnicodeWriter` in JSON encoder -and StringIO and remove the :c:expr:`_PyAccu` implementation. diff --git a/Misc/NEWS.d/next/Library/2022-07-20-00-23-58.gh-issue-77617.XGaqSQ.rst b/Misc/NEWS.d/next/Library/2022-07-20-00-23-58.gh-issue-77617.XGaqSQ.rst deleted file mode 100644 index 1cbaa7dfe15e..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-20-00-23-58.gh-issue-77617.XGaqSQ.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add :mod:`sqlite3` :ref:`command-line interface `. -Patch by Erlend Aasland. diff --git a/Misc/NEWS.d/next/Library/2022-07-20-22-49-48.gh-issue-95066.TuCu0E.rst b/Misc/NEWS.d/next/Library/2022-07-20-22-49-48.gh-issue-95066.TuCu0E.rst deleted file mode 100644 index 05ae4a6a2761..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-20-22-49-48.gh-issue-95066.TuCu0E.rst +++ /dev/null @@ -1 +0,0 @@ -Replaced assert with exception in :func:`ast.parse`, when ``feature_version`` has an invalid major version. Patch by Shantanu Jain. diff --git a/Misc/NEWS.d/next/Library/2022-07-21-19-55-49.gh-issue-95105.BIX2Km.rst b/Misc/NEWS.d/next/Library/2022-07-21-19-55-49.gh-issue-95105.BIX2Km.rst deleted file mode 100644 index 58af62b1edc8..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-21-19-55-49.gh-issue-95105.BIX2Km.rst +++ /dev/null @@ -1 +0,0 @@ -:meth:`wsgiref.types.InputStream.__iter__` should return ``Iterator[bytes]``, not ``Iterable[bytes]``. Patch by Shantanu Jain. diff --git a/Misc/NEWS.d/next/Library/2022-07-21-22-59-22.gh-issue-95109.usxA9r.rst b/Misc/NEWS.d/next/Library/2022-07-21-22-59-22.gh-issue-95109.usxA9r.rst deleted file mode 100644 index 40196dd214a2..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-21-22-59-22.gh-issue-95109.usxA9r.rst +++ /dev/null @@ -1 +0,0 @@ -Ensure that timeouts scheduled with :class:`asyncio.Timeout` that have already expired are delivered promptly. diff --git a/Misc/NEWS.d/next/Library/2022-07-22-00-58-49.gh-issue-95077.4Z6CNC.rst b/Misc/NEWS.d/next/Library/2022-07-22-00-58-49.gh-issue-95077.4Z6CNC.rst deleted file mode 100644 index 09f350067cd3..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-22-00-58-49.gh-issue-95077.4Z6CNC.rst +++ /dev/null @@ -1 +0,0 @@ -Add deprecation warning for enum ``member.member`` access (e.g. ``Color.RED.BLUE``). diff --git a/Misc/NEWS.d/next/Library/2022-07-22-09-09-08.gh-issue-91212.53O8Ab.rst b/Misc/NEWS.d/next/Library/2022-07-22-09-09-08.gh-issue-91212.53O8Ab.rst deleted file mode 100644 index 8552f51196b5..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-22-09-09-08.gh-issue-91212.53O8Ab.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed flickering of the turtle window when the tracer is turned off. Patch by Shin-myoung-serp. diff --git a/Misc/NEWS.d/next/Library/2022-07-22-17-19-57.gh-issue-93157.RXByAk.rst b/Misc/NEWS.d/next/Library/2022-07-22-17-19-57.gh-issue-93157.RXByAk.rst deleted file mode 100644 index 054b318ec63f..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-22-17-19-57.gh-issue-93157.RXByAk.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix :mod:`fileinput` module didn't support ``errors`` option when -``inplace`` is true. diff --git a/Misc/NEWS.d/next/Library/2022-07-22-21-18-17.gh-issue-95132.n9anlw.rst b/Misc/NEWS.d/next/Library/2022-07-22-21-18-17.gh-issue-95132.n9anlw.rst deleted file mode 100644 index 64666ad84fb4..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-22-21-18-17.gh-issue-95132.n9anlw.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix a :mod:`sqlite3` regression where ``*args`` and ``**kwds`` were -incorrectly relayed from :py:func:`~sqlite3.connect` to the -:class:`~sqlite3.Connection` factory. The regression was introduced in 3.11a1 -with PR 24421 (:gh:`85128`). Patch by Erlend E. Aasland.` diff --git a/Misc/NEWS.d/next/Library/2022-07-23-10-42-05.gh-issue-95166.xw6p3C.rst b/Misc/NEWS.d/next/Library/2022-07-23-10-42-05.gh-issue-95166.xw6p3C.rst deleted file mode 100644 index 34b017078436..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-23-10-42-05.gh-issue-95166.xw6p3C.rst +++ /dev/null @@ -1 +0,0 @@ -Fix :meth:`concurrent.futures.Executor.map` to cancel the currently waiting on future on an error - e.g. TimeoutError or KeyboardInterrupt. diff --git a/Misc/NEWS.d/next/Library/2022-07-23-10-50-05.gh-issue-93899.VT34A5.rst b/Misc/NEWS.d/next/Library/2022-07-23-10-50-05.gh-issue-93899.VT34A5.rst deleted file mode 100644 index e63475f8ba96..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-23-10-50-05.gh-issue-93899.VT34A5.rst +++ /dev/null @@ -1 +0,0 @@ -Fix check for existence of :data:`os.EFD_CLOEXEC`, :data:`os.EFD_NONBLOCK` and :data:`os.EFD_SEMAPHORE` flags on older kernel versions where these flags are not present. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Library/2022-07-24-09-15-35.gh-issue-95194.ERVmqG.rst b/Misc/NEWS.d/next/Library/2022-07-24-09-15-35.gh-issue-95194.ERVmqG.rst deleted file mode 100644 index c69651923b41..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-24-09-15-35.gh-issue-95194.ERVmqG.rst +++ /dev/null @@ -1 +0,0 @@ -Upgrade bundled pip to 22.2. diff --git a/Misc/NEWS.d/next/Library/2022-07-24-12-00-06.gh-issue-95199.-5A64k.rst b/Misc/NEWS.d/next/Library/2022-07-24-12-00-06.gh-issue-95199.-5A64k.rst deleted file mode 100644 index f3d9cf3306b8..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-24-12-00-06.gh-issue-95199.-5A64k.rst +++ /dev/null @@ -1 +0,0 @@ -Upgrade bundled setuptools to 63.2.0. diff --git a/Misc/NEWS.d/next/Library/2022-07-24-12-59-02.gh-issue-95087.VvqXkN.rst b/Misc/NEWS.d/next/Library/2022-07-24-12-59-02.gh-issue-95087.VvqXkN.rst deleted file mode 100644 index 48a5c1af7490..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-24-12-59-02.gh-issue-95087.VvqXkN.rst +++ /dev/null @@ -1 +0,0 @@ -Fix IndexError in parsing invalid date in the :mod:`email` module. diff --git a/Misc/NEWS.d/next/Library/2022-07-24-18-00-42.gh-issue-95097.lu5qNf.rst b/Misc/NEWS.d/next/Library/2022-07-24-18-00-42.gh-issue-95097.lu5qNf.rst deleted file mode 100644 index 2840f057a9c1..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-24-18-00-42.gh-issue-95097.lu5qNf.rst +++ /dev/null @@ -1 +0,0 @@ -Fix :func:`asyncio.run` for :class:`asyncio.Task` implementations without :meth:`~asyncio.Task.uncancel` method. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Library/2022-07-25-15-45-06.gh-issue-95231.i807-g.rst b/Misc/NEWS.d/next/Library/2022-07-25-15-45-06.gh-issue-95231.i807-g.rst deleted file mode 100644 index aa53f2938bc9..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-25-15-45-06.gh-issue-95231.i807-g.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fail gracefully if :data:`~errno.EPERM` or :data:`~errno.ENOSYS` is raised when loading -:mod:`crypt` methods. This may happen when trying to load ``MD5`` on a Linux kernel -with :abbr:`FIPS (Federal Information Processing Standard)` enabled. diff --git a/Misc/NEWS.d/next/Library/2022-07-27-11-35-45.gh-issue-95045.iysT-Q.rst b/Misc/NEWS.d/next/Library/2022-07-27-11-35-45.gh-issue-95045.iysT-Q.rst deleted file mode 100644 index d4ab325e0365..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-27-11-35-45.gh-issue-95045.iysT-Q.rst +++ /dev/null @@ -1 +0,0 @@ -Fix GC crash when deallocating ``_lsprof.Profiler`` by untracking it before calling any callbacks. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Library/2022-07-27-19-43-07.gh-issue-95339.NuVQ68.rst b/Misc/NEWS.d/next/Library/2022-07-27-19-43-07.gh-issue-95339.NuVQ68.rst deleted file mode 100644 index 6674a4a26953..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-27-19-43-07.gh-issue-95339.NuVQ68.rst +++ /dev/null @@ -1 +0,0 @@ -Update bundled pip to 22.2.1. diff --git a/Misc/NEWS.d/next/Library/2022-07-27-19-47-51.gh-issue-83901.OSw06c.rst b/Misc/NEWS.d/next/Library/2022-07-27-19-47-51.gh-issue-83901.OSw06c.rst deleted file mode 100644 index da407905a886..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-27-19-47-51.gh-issue-83901.OSw06c.rst +++ /dev/null @@ -1 +0,0 @@ -Improve :meth:`Signature.bind ` error message for missing keyword-only arguments. diff --git a/Misc/NEWS.d/next/Library/2022-07-28-17-14-38.gh-issue-95385.6YlsDI.rst b/Misc/NEWS.d/next/Library/2022-07-28-17-14-38.gh-issue-95385.6YlsDI.rst deleted file mode 100644 index 89fa9c2b2766..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-28-17-14-38.gh-issue-95385.6YlsDI.rst +++ /dev/null @@ -1 +0,0 @@ -Faster ``json.dumps()`` when sorting of keys is not requested (default). diff --git a/Misc/NEWS.d/next/Library/2022-07-29-20-58-37.gh-issue-94909.YjMusj.rst b/Misc/NEWS.d/next/Library/2022-07-29-20-58-37.gh-issue-94909.YjMusj.rst deleted file mode 100644 index b6d853888101..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-29-20-58-37.gh-issue-94909.YjMusj.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix incorrect joining of relative Windows paths with drives in -:class:`pathlib.PurePath` initializer. diff --git a/Misc/NEWS.d/next/Library/2022-08-03-16-52-32.gh-issue-95289.FMnHlV.rst b/Misc/NEWS.d/next/Library/2022-08-03-16-52-32.gh-issue-95289.FMnHlV.rst deleted file mode 100644 index d802f557217b..000000000000 --- a/Misc/NEWS.d/next/Library/2022-08-03-16-52-32.gh-issue-95289.FMnHlV.rst +++ /dev/null @@ -1 +0,0 @@ -Fix :class:`asyncio.TaskGroup` to propagate exception when :exc:`asyncio.CancelledError` was replaced with another exception by a context manger. Patch by Kumar Aditya and Guido van Rossum. diff --git a/Misc/NEWS.d/next/Library/2022-08-03-21-01-17.gh-issue-95609.xxyjyX.rst b/Misc/NEWS.d/next/Library/2022-08-03-21-01-17.gh-issue-95609.xxyjyX.rst deleted file mode 100644 index 81c02ae900f7..000000000000 --- a/Misc/NEWS.d/next/Library/2022-08-03-21-01-17.gh-issue-95609.xxyjyX.rst +++ /dev/null @@ -1 +0,0 @@ -Update bundled pip to 22.2.2. diff --git a/Misc/NEWS.d/next/Library/2022-08-07-14-56-23.gh-issue-95149.U0c6Ib.rst b/Misc/NEWS.d/next/Library/2022-08-07-14-56-23.gh-issue-95149.U0c6Ib.rst deleted file mode 100644 index 6393444b53fb..000000000000 --- a/Misc/NEWS.d/next/Library/2022-08-07-14-56-23.gh-issue-95149.U0c6Ib.rst +++ /dev/null @@ -1,2 +0,0 @@ -The :class:`HTTPStatus ` enum offers a couple of properties -to indicate the HTTP status category e.g. ``HTTPStatus.OK.is_success``. diff --git a/Misc/NEWS.d/next/Library/2022-08-08-01-42-11.gh-issue-95704.MOPFfX.rst b/Misc/NEWS.d/next/Library/2022-08-08-01-42-11.gh-issue-95704.MOPFfX.rst deleted file mode 100644 index 31f9fc6547d9..000000000000 --- a/Misc/NEWS.d/next/Library/2022-08-08-01-42-11.gh-issue-95704.MOPFfX.rst +++ /dev/null @@ -1,2 +0,0 @@ -When a task catches :exc:`asyncio.CancelledError` and raises some other error, -the other error should generally not silently be suppressed. diff --git a/Misc/NEWS.d/next/Library/2022-08-10-11-54-04.gh-issue-95804.i5FCFK.rst b/Misc/NEWS.d/next/Library/2022-08-10-11-54-04.gh-issue-95804.i5FCFK.rst deleted file mode 100644 index 46434cb46604..000000000000 --- a/Misc/NEWS.d/next/Library/2022-08-10-11-54-04.gh-issue-95804.i5FCFK.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix ``logging`` shutdown handler so it respects -``MemoryHandler.flushOnClose``. diff --git a/Misc/NEWS.d/next/Library/2022-08-10-17-34-07.gh-issue-95861.qv-T5s.rst b/Misc/NEWS.d/next/Library/2022-08-10-17-34-07.gh-issue-95861.qv-T5s.rst deleted file mode 100644 index aae76c74e2fd..000000000000 --- a/Misc/NEWS.d/next/Library/2022-08-10-17-34-07.gh-issue-95861.qv-T5s.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add support for computing Spearman's correlation coefficient to the existing -statistics.correlation() function. diff --git a/Misc/NEWS.d/next/Library/2022-08-11-03-16-48.gh-issue-95865.0IOkFP.rst b/Misc/NEWS.d/next/Library/2022-08-11-03-16-48.gh-issue-95865.0IOkFP.rst deleted file mode 100644 index aa7c73ff1a35..000000000000 --- a/Misc/NEWS.d/next/Library/2022-08-11-03-16-48.gh-issue-95865.0IOkFP.rst +++ /dev/null @@ -1 +0,0 @@ -Speed up :func:`urllib.parse.quote_from_bytes` by replacing a list comprehension with ``map()``. diff --git a/Misc/NEWS.d/next/Library/2022-08-11-18-22-29.gh-issue-95736.LzRZXe.rst b/Misc/NEWS.d/next/Library/2022-08-11-18-22-29.gh-issue-95736.LzRZXe.rst deleted file mode 100644 index abc270fe35ca..000000000000 --- a/Misc/NEWS.d/next/Library/2022-08-11-18-22-29.gh-issue-95736.LzRZXe.rst +++ /dev/null @@ -1 +0,0 @@ -Fix :class:`unittest.IsolatedAsyncioTestCase` to set event loop before calling setup functions. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Library/2022-08-11-18-52-17.gh-issue-95899._Bi4uG.rst b/Misc/NEWS.d/next/Library/2022-08-11-18-52-17.gh-issue-95899._Bi4uG.rst deleted file mode 100644 index d2386cf3ae22..000000000000 --- a/Misc/NEWS.d/next/Library/2022-08-11-18-52-17.gh-issue-95899._Bi4uG.rst +++ /dev/null @@ -1 +0,0 @@ -Fix :class:`asyncio.Runner` to call :func:`asyncio.set_event_loop` only once to avoid calling :meth:`~asyncio.AbstractChildWatcher.attach_loop` multiple times on child watchers. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Library/2022-08-14-18-59-54.gh-issue-69142.6is5Pq.rst b/Misc/NEWS.d/next/Library/2022-08-14-18-59-54.gh-issue-69142.6is5Pq.rst deleted file mode 100644 index 0db8b3730cf5..000000000000 --- a/Misc/NEWS.d/next/Library/2022-08-14-18-59-54.gh-issue-69142.6is5Pq.rst +++ /dev/null @@ -1 +0,0 @@ -Add ``%:z`` strftime format code (generates tzoffset with colons as separator), see :ref:`strftime-strptime-behavior`. diff --git a/Misc/NEWS.d/next/Library/2022-08-18-14-53-53.gh-issue-95463.GpP05c.rst b/Misc/NEWS.d/next/Library/2022-08-18-14-53-53.gh-issue-95463.GpP05c.rst deleted file mode 100644 index 553c55436aab..000000000000 --- a/Misc/NEWS.d/next/Library/2022-08-18-14-53-53.gh-issue-95463.GpP05c.rst +++ /dev/null @@ -1,2 +0,0 @@ -Remove an incompatible change from :issue:`28080` that caused a regression -that ignored the utf8 in ``ZipInfo.flag_bits``. Patch by Pablo Galindo. diff --git a/Misc/NEWS.d/next/Library/2022-08-19-10-19-32.gh-issue-96019.b7uAVP.rst b/Misc/NEWS.d/next/Library/2022-08-19-10-19-32.gh-issue-96019.b7uAVP.rst deleted file mode 100644 index 296963fd8172..000000000000 --- a/Misc/NEWS.d/next/Library/2022-08-19-10-19-32.gh-issue-96019.b7uAVP.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix a bug in the ``makeunicodedata.py`` script leading to about 13 KiB of -space saving in the ``unicodedata`` module, specifically the character -decomposition data. diff --git a/Misc/NEWS.d/next/Library/2022-08-19-18-21-01.gh-issue-96125.ODcF1Y.rst b/Misc/NEWS.d/next/Library/2022-08-19-18-21-01.gh-issue-96125.ODcF1Y.rst deleted file mode 100644 index ba7d26a96582..000000000000 --- a/Misc/NEWS.d/next/Library/2022-08-19-18-21-01.gh-issue-96125.ODcF1Y.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix incorrect condition that causes ``sys.thread_info.name`` to be wrong on -pthread platforms. diff --git a/Misc/NEWS.d/next/Library/2022-08-20-10-31-01.gh-issue-96052.a6FhaD.rst b/Misc/NEWS.d/next/Library/2022-08-20-10-31-01.gh-issue-96052.a6FhaD.rst deleted file mode 100644 index c190fb7dbcb9..000000000000 --- a/Misc/NEWS.d/next/Library/2022-08-20-10-31-01.gh-issue-96052.a6FhaD.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix handling compiler warnings (SyntaxWarning and DeprecationWarning) in -:func:`codeop.compile_command` when checking for incomplete input. -Previously it emitted warnings and raised a SyntaxError. Now it always -returns ``None`` for incomplete input without emitting any warnings. diff --git a/Misc/NEWS.d/next/Library/2022-08-20-12-56-15.gh-issue-96145.8ah3pE.rst b/Misc/NEWS.d/next/Library/2022-08-20-12-56-15.gh-issue-96145.8ah3pE.rst deleted file mode 100644 index 540ec8b71ebf..000000000000 --- a/Misc/NEWS.d/next/Library/2022-08-20-12-56-15.gh-issue-96145.8ah3pE.rst +++ /dev/null @@ -1 +0,0 @@ -Add AttrDict to JSON module for use with object_hook. diff --git a/Misc/NEWS.d/next/Library/2022-08-22-13-54-20.gh-issue-96175.bH7zGU.rst b/Misc/NEWS.d/next/Library/2022-08-22-13-54-20.gh-issue-96175.bH7zGU.rst deleted file mode 100644 index c34eff22b3d4..000000000000 --- a/Misc/NEWS.d/next/Library/2022-08-22-13-54-20.gh-issue-96175.bH7zGU.rst +++ /dev/null @@ -1 +0,0 @@ -Fix unused ``localName`` parameter in the ``Attr`` class in :mod:`xml.dom.minidom`. diff --git a/Misc/NEWS.d/next/Library/2022-08-22-18-42-17.gh-issue-96159.3bFU39.rst b/Misc/NEWS.d/next/Library/2022-08-22-18-42-17.gh-issue-96159.3bFU39.rst deleted file mode 100644 index f64469e563f3..000000000000 --- a/Misc/NEWS.d/next/Library/2022-08-22-18-42-17.gh-issue-96159.3bFU39.rst +++ /dev/null @@ -1 +0,0 @@ -Fix a performance regression in logging TimedRotatingFileHandler. Only check for special files when the rollover time has passed. diff --git a/Misc/NEWS.d/next/Library/2022-08-23-13-30-30.gh-issue-96172.7WTHer.rst b/Misc/NEWS.d/next/Library/2022-08-23-13-30-30.gh-issue-96172.7WTHer.rst deleted file mode 100644 index 1bb57f177887..000000000000 --- a/Misc/NEWS.d/next/Library/2022-08-23-13-30-30.gh-issue-96172.7WTHer.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix a bug in ``unicodedata``: ``east_asian_width`` used to return the wrong -value for unassigned characters; and for yet unassigned, but reserved -characters. diff --git a/Misc/NEWS.d/next/Library/2022-08-27-14-38-49.gh-issue-90467.VOOB0p.rst b/Misc/NEWS.d/next/Library/2022-08-27-14-38-49.gh-issue-90467.VOOB0p.rst deleted file mode 100644 index 282c0e76a8c8..000000000000 --- a/Misc/NEWS.d/next/Library/2022-08-27-14-38-49.gh-issue-90467.VOOB0p.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix :class:`asyncio.streams.StreamReaderProtocol` to keep a strong reference -to the created task, so that it's not garbage collected diff --git a/Misc/NEWS.d/next/Library/2022-08-27-21-26-52.gh-issue-96349.XyYLlO.rst b/Misc/NEWS.d/next/Library/2022-08-27-21-26-52.gh-issue-96349.XyYLlO.rst deleted file mode 100644 index 59eb3517191d..000000000000 --- a/Misc/NEWS.d/next/Library/2022-08-27-21-26-52.gh-issue-96349.XyYLlO.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed a minor performance regression in :func:`threading.Event.__init__` diff --git a/Misc/NEWS.d/next/Library/2022-08-27-23-16-09.gh-issue-96346.jJX14I.rst b/Misc/NEWS.d/next/Library/2022-08-27-23-16-09.gh-issue-96346.jJX14I.rst deleted file mode 100644 index 9883348b9c3e..000000000000 --- a/Misc/NEWS.d/next/Library/2022-08-27-23-16-09.gh-issue-96346.jJX14I.rst +++ /dev/null @@ -1 +0,0 @@ -Use double caching for compiled RE patterns. diff --git a/Misc/NEWS.d/next/Library/2022-08-29-07-04-03.gh-issue-89258.ri7ncj.rst b/Misc/NEWS.d/next/Library/2022-08-29-07-04-03.gh-issue-89258.ri7ncj.rst deleted file mode 100644 index 74300c108c89..000000000000 --- a/Misc/NEWS.d/next/Library/2022-08-29-07-04-03.gh-issue-89258.ri7ncj.rst +++ /dev/null @@ -1,2 +0,0 @@ -Added a :meth:`~logging.Logger.getChildren` method to -:class:`logging.Logger`, to get the immediate child loggers of a logger. diff --git a/Misc/NEWS.d/next/Library/2022-08-29-12-35-28.gh-issue-96073.WaGstf.rst b/Misc/NEWS.d/next/Library/2022-08-29-12-35-28.gh-issue-96073.WaGstf.rst deleted file mode 100644 index 8f20588c4c58..000000000000 --- a/Misc/NEWS.d/next/Library/2022-08-29-12-35-28.gh-issue-96073.WaGstf.rst +++ /dev/null @@ -1 +0,0 @@ -In :mod:`inspect`, fix overeager replacement of "``typing.``" in formatting annotations. diff --git a/Misc/NEWS.d/next/Library/2022-08-29-12-49-30.gh-issue-96142.PdCMez.rst b/Misc/NEWS.d/next/Library/2022-08-29-12-49-30.gh-issue-96142.PdCMez.rst deleted file mode 100644 index 43d1c3de9922..000000000000 --- a/Misc/NEWS.d/next/Library/2022-08-29-12-49-30.gh-issue-96142.PdCMez.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add ``match_args``, ``kw_only``, ``slots``, and ``weakref_slot`` to -``_DataclassParams``. diff --git a/Misc/NEWS.d/next/Library/2022-08-29-15-28-39.gh-issue-96385.uLRTsf.rst b/Misc/NEWS.d/next/Library/2022-08-29-15-28-39.gh-issue-96385.uLRTsf.rst deleted file mode 100644 index 57354826f349..000000000000 --- a/Misc/NEWS.d/next/Library/2022-08-29-15-28-39.gh-issue-96385.uLRTsf.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix ``TypeVarTuple.__typing_prepare_subst__``. ``TypeError`` was not raised -when using more than one ``TypeVarTuple``, like ``[*T, *V]`` in type alias -substitutions. diff --git a/Misc/NEWS.d/next/Library/2022-08-29-16-54-36.gh-issue-96388.dCpJcu.rst b/Misc/NEWS.d/next/Library/2022-08-29-16-54-36.gh-issue-96388.dCpJcu.rst deleted file mode 100644 index 3a35c4734871..000000000000 --- a/Misc/NEWS.d/next/Library/2022-08-29-16-54-36.gh-issue-96388.dCpJcu.rst +++ /dev/null @@ -1,2 +0,0 @@ -Work around missing socket functions in :class:`~socket.socket`'s -``__repr__``. diff --git a/Misc/NEWS.d/next/Library/2022-08-30-11-46-36.gh-issue-95987.CV7_u4.rst b/Misc/NEWS.d/next/Library/2022-08-30-11-46-36.gh-issue-95987.CV7_u4.rst deleted file mode 100644 index 232bba1b9244..000000000000 --- a/Misc/NEWS.d/next/Library/2022-08-30-11-46-36.gh-issue-95987.CV7_u4.rst +++ /dev/null @@ -1 +0,0 @@ -Fix ``repr`` of ``Any`` subclasses. diff --git a/Misc/NEWS.d/next/Library/2022-08-30-12-32-00.gh-issue-96415.6W7ORH.rst b/Misc/NEWS.d/next/Library/2022-08-30-12-32-00.gh-issue-96415.6W7ORH.rst deleted file mode 100644 index 0c93abf6dfcf..000000000000 --- a/Misc/NEWS.d/next/Library/2022-08-30-12-32-00.gh-issue-96415.6W7ORH.rst +++ /dev/null @@ -1 +0,0 @@ -Remove ``types._cell_factory`` from module namespace. diff --git a/Misc/NEWS.d/next/Library/2022-08-31-11-10-21.gh-issue-96079.uqrXdJ.rst b/Misc/NEWS.d/next/Library/2022-08-31-11-10-21.gh-issue-96079.uqrXdJ.rst deleted file mode 100644 index 4cb8d276cbe7..000000000000 --- a/Misc/NEWS.d/next/Library/2022-08-31-11-10-21.gh-issue-96079.uqrXdJ.rst +++ /dev/null @@ -1 +0,0 @@ -In :mod:`typing`, fix missing field ``name`` and incorrect ``__module__`` in _AnnotatedAlias. diff --git a/Misc/NEWS.d/next/Library/2022-09-01-13-54-38.gh-issue-96465.0IJmrH.rst b/Misc/NEWS.d/next/Library/2022-09-01-13-54-38.gh-issue-96465.0IJmrH.rst deleted file mode 100644 index c78d7538ef94..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-01-13-54-38.gh-issue-96465.0IJmrH.rst +++ /dev/null @@ -1 +0,0 @@ -Fraction hashes are now cached. diff --git a/Misc/NEWS.d/next/Library/2022-09-03-18-39-05.gh-issue-96538.W156-D.rst b/Misc/NEWS.d/next/Library/2022-09-03-18-39-05.gh-issue-96538.W156-D.rst deleted file mode 100644 index 22e5b4fc2599..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-03-18-39-05.gh-issue-96538.W156-D.rst +++ /dev/null @@ -1 +0,0 @@ -Speed up ``bisect.bisect()`` functions by taking advantage of type-stability. diff --git a/Misc/NEWS.d/next/Library/2022-09-04-12-32-52.gh-issue-68163.h6TJCc.rst b/Misc/NEWS.d/next/Library/2022-09-04-12-32-52.gh-issue-68163.h6TJCc.rst deleted file mode 100644 index 756f6c9eb9e8..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-04-12-32-52.gh-issue-68163.h6TJCc.rst +++ /dev/null @@ -1 +0,0 @@ -Correct conversion of :class:`numbers.Rational`'s to :class:`float`. diff --git a/Misc/NEWS.d/next/Library/2022-09-07-22-49-37.gh-issue-96652.YqOKxI.rst b/Misc/NEWS.d/next/Library/2022-09-07-22-49-37.gh-issue-96652.YqOKxI.rst deleted file mode 100644 index 1d04db7b2a25..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-07-22-49-37.gh-issue-96652.YqOKxI.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix the faulthandler implementation of ``faulthandler.register(signal, -chain=True)`` if the ``sigaction()`` function is not available: don't call -the previous signal handler if it's NULL. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Library/2022-09-08-20-12-48.gh-issue-46412.r_cfTh.rst b/Misc/NEWS.d/next/Library/2022-09-08-20-12-48.gh-issue-46412.r_cfTh.rst deleted file mode 100644 index 27fcd0328bd2..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-08-20-12-48.gh-issue-46412.r_cfTh.rst +++ /dev/null @@ -1 +0,0 @@ -Improve performance of ``bool(db)`` for large ndb/gdb databases. Previously this would call ``len(db)`` which would iterate over all keys -- the answer (empty or not) is known after the first key. diff --git a/Misc/NEWS.d/next/Library/2022-09-10-16-46-16.gh-issue-96735.0YzJuG.rst b/Misc/NEWS.d/next/Library/2022-09-10-16-46-16.gh-issue-96735.0YzJuG.rst deleted file mode 100644 index a29ada98ac20..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-10-16-46-16.gh-issue-96735.0YzJuG.rst +++ /dev/null @@ -1 +0,0 @@ -Fix undefined behaviour in :func:`struct.unpack`. diff --git a/Misc/NEWS.d/next/Library/2022-09-13-15-12-31.gh-issue-96734.G08vjz.rst b/Misc/NEWS.d/next/Library/2022-09-13-15-12-31.gh-issue-96734.G08vjz.rst deleted file mode 100644 index e5c8a25b4bc6..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-13-15-12-31.gh-issue-96734.G08vjz.rst +++ /dev/null @@ -1 +0,0 @@ -Update :mod:`unicodedata` database to Unicode 15.0.0. diff --git a/Misc/NEWS.d/next/Library/2022-09-15-00-37-33.gh-issue-96741.4b6czN.rst b/Misc/NEWS.d/next/Library/2022-09-15-00-37-33.gh-issue-96741.4b6czN.rst deleted file mode 100644 index e7f53311e589..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-15-00-37-33.gh-issue-96741.4b6czN.rst +++ /dev/null @@ -1 +0,0 @@ -Corrected type annotation for dataclass attribute ``pstats.FunctionProfile.ncalls`` to be ``str``. diff --git a/Misc/NEWS.d/next/Library/2022-09-16-07-53-29.gh-issue-95865.oHjX0A.rst b/Misc/NEWS.d/next/Library/2022-09-16-07-53-29.gh-issue-95865.oHjX0A.rst deleted file mode 100644 index 03a5be722949..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-16-07-53-29.gh-issue-95865.oHjX0A.rst +++ /dev/null @@ -1,3 +0,0 @@ -Reduce :func:`urllib.parse.quote_from_bytes` memory use on large values. - -Contributed by Dennis Sweeney. diff --git a/Misc/NEWS.d/next/Library/2022-09-17-13-15-10.gh-issue-96819.6RfqM7.rst b/Misc/NEWS.d/next/Library/2022-09-17-13-15-10.gh-issue-96819.6RfqM7.rst deleted file mode 100644 index 07b62a883b85..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-17-13-15-10.gh-issue-96819.6RfqM7.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed check in :mod:`multiprocessing.resource_tracker` that guarantees that the length of a write to a pipe is not greater than ``PIPE_BUF``. diff --git a/Misc/NEWS.d/next/Library/2022-09-18-04-51-30.gh-issue-96704.DmamRX.rst b/Misc/NEWS.d/next/Library/2022-09-18-04-51-30.gh-issue-96704.DmamRX.rst deleted file mode 100644 index 6ac99197e685..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-18-04-51-30.gh-issue-96704.DmamRX.rst +++ /dev/null @@ -1 +0,0 @@ -Pass the correct ``contextvars.Context`` when a ``asyncio`` exception handler is called on behalf of a task or callback handle. This adds a new ``Task`` method, ``get_context``, and also a new ``Handle`` method with the same name. If this method is not found on a task object (perhaps because it is a third-party library that does not yet provide this method), the context prevailing at the time the exception handler is called is used. diff --git a/Misc/NEWS.d/next/Library/2022-09-22-11-50-29.gh-issue-85760.DETTPd.rst b/Misc/NEWS.d/next/Library/2022-09-22-11-50-29.gh-issue-85760.DETTPd.rst deleted file mode 100644 index af8ae2026f16..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-22-11-50-29.gh-issue-85760.DETTPd.rst +++ /dev/null @@ -1 +0,0 @@ -Fix race condition in :mod:`asyncio` where :meth:`~asyncio.SubprocessProtocol.process_exited` called before the :meth:`~asyncio.SubprocessProtocol.pipe_data_received` leading to inconsistent output. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Library/2022-09-22-14-35-02.gh-issue-97005.yf21Q7.rst b/Misc/NEWS.d/next/Library/2022-09-22-14-35-02.gh-issue-97005.yf21Q7.rst deleted file mode 100644 index d57999aa29b7..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-22-14-35-02.gh-issue-97005.yf21Q7.rst +++ /dev/null @@ -1 +0,0 @@ -Update bundled libexpat to 2.4.9 diff --git a/Misc/NEWS.d/next/Library/2022-09-24-18-56-23.gh-issue-96865.o9WUkW.rst b/Misc/NEWS.d/next/Library/2022-09-24-18-56-23.gh-issue-96865.o9WUkW.rst deleted file mode 100644 index b054fdeee078..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-24-18-56-23.gh-issue-96865.o9WUkW.rst +++ /dev/null @@ -1,9 +0,0 @@ -fix Flag to use boundary CONFORM - -This restores previous Flag behavior of allowing flags with non-sequential values to be combined; e.g. - - class Skip(Flag): - TWO = 2 - EIGHT = 8 - - Skip.TWO | Skip.EIGHT -> diff --git a/Misc/NEWS.d/next/Library/2022-09-25-20-42-33.gh-issue-73588.uVtjEA.rst b/Misc/NEWS.d/next/Library/2022-09-25-20-42-33.gh-issue-73588.uVtjEA.rst deleted file mode 100644 index d8a0e690e291..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-25-20-42-33.gh-issue-73588.uVtjEA.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix generation of the default name of :class:`tkinter.Checkbutton`. -Previously, checkbuttons in different parent widgets could have the same -short name and share the same state if arguments "name" and "variable" are -not specified. Now they are globally unique. diff --git a/Misc/NEWS.d/next/Library/2022-09-25-23-24-52.gh-issue-97545.HZLSNt.rst b/Misc/NEWS.d/next/Library/2022-09-25-23-24-52.gh-issue-97545.HZLSNt.rst deleted file mode 100644 index a53902ea670b..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-25-23-24-52.gh-issue-97545.HZLSNt.rst +++ /dev/null @@ -1 +0,0 @@ -Make Semaphore run faster. diff --git a/Misc/NEWS.d/next/Library/2022-09-29-08-15-55.gh-issue-97639.JSjWYW.rst b/Misc/NEWS.d/next/Library/2022-09-29-08-15-55.gh-issue-97639.JSjWYW.rst deleted file mode 100644 index 65c3105f3bc3..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-29-08-15-55.gh-issue-97639.JSjWYW.rst +++ /dev/null @@ -1 +0,0 @@ -Remove ``tokenize.NL`` check from :mod:`tabnanny`. diff --git a/Misc/NEWS.d/next/Library/2022-09-29-23-22-24.gh-issue-97592.tpJg_J.rst b/Misc/NEWS.d/next/Library/2022-09-29-23-22-24.gh-issue-97592.tpJg_J.rst deleted file mode 100644 index aa245cf94400..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-29-23-22-24.gh-issue-97592.tpJg_J.rst +++ /dev/null @@ -1 +0,0 @@ -Avoid a crash in the C version of :meth:`asyncio.Future.remove_done_callback` when an evil argument is passed. diff --git a/Misc/NEWS.d/next/Library/2022-09-30-09-22-37.gh-issue-95534.ndEfPj.rst b/Misc/NEWS.d/next/Library/2022-09-30-09-22-37.gh-issue-95534.ndEfPj.rst deleted file mode 100644 index 131d4ed69991..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-30-09-22-37.gh-issue-95534.ndEfPj.rst +++ /dev/null @@ -1 +0,0 @@ -:meth:`gzip.GzipFile.read` reads 10% faster. diff --git a/Misc/NEWS.d/next/Library/2022-09-30-15-56-20.gh-issue-96827.lzy1iw.rst b/Misc/NEWS.d/next/Library/2022-09-30-15-56-20.gh-issue-96827.lzy1iw.rst deleted file mode 100644 index 159ab32ffbfc..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-30-15-56-20.gh-issue-96827.lzy1iw.rst +++ /dev/null @@ -1 +0,0 @@ -Avoid spurious tracebacks from :mod:`asyncio` when default executor cleanup is delayed until after the event loop is closed (e.g. as the result of a keyboard interrupt). diff --git a/Misc/NEWS.d/next/Library/2022-10-03-13-25-19.gh-issue-97781.gCLLef.rst b/Misc/NEWS.d/next/Library/2022-10-03-13-25-19.gh-issue-97781.gCLLef.rst deleted file mode 100644 index 8c36d9c3afd2..000000000000 --- a/Misc/NEWS.d/next/Library/2022-10-03-13-25-19.gh-issue-97781.gCLLef.rst +++ /dev/null @@ -1,5 +0,0 @@ -Removed deprecated interfaces in ``importlib.metadata`` (entry points -accessed as dictionary, implicit dictionary construction of sequence of -``EntryPoint`` objects, mutablility of ``EntryPoints`` result, access of -entry point by index). ``entry_points`` now has a simpler, more -straightforward API (returning ``EntryPoints``). diff --git a/Misc/NEWS.d/next/Library/2022-10-03-14-42-13.gh-issue-97799.Y1iJvf.rst b/Misc/NEWS.d/next/Library/2022-10-03-14-42-13.gh-issue-97799.Y1iJvf.rst deleted file mode 100644 index 71097d29d344..000000000000 --- a/Misc/NEWS.d/next/Library/2022-10-03-14-42-13.gh-issue-97799.Y1iJvf.rst +++ /dev/null @@ -1,2 +0,0 @@ -:mod:`dataclass` now uses :func:`inspect.get_annotations` to examine the -annotations on class objects. diff --git a/Misc/NEWS.d/next/Library/2022-10-04-00-43-43.gh-issue-97008.3rjtt6.rst b/Misc/NEWS.d/next/Library/2022-10-04-00-43-43.gh-issue-97008.3rjtt6.rst deleted file mode 100644 index b41f88d07890..000000000000 --- a/Misc/NEWS.d/next/Library/2022-10-04-00-43-43.gh-issue-97008.3rjtt6.rst +++ /dev/null @@ -1,5 +0,0 @@ -:exc:`NameError` and :exc:`AttributeError` spelling suggestions provided -since :gh:`82711` are now also emitted by the pure Python -:mod:`traceback` module. Tests for those suggestions now exercise both -implementations to ensure they are equivalent. Patch by Carl Friedrich -Bolz-Tereick and ?ukasz Langa. diff --git a/Misc/NEWS.d/next/Library/2022-10-04-07-55-19.gh-issue-97825.mNdv1l.rst b/Misc/NEWS.d/next/Library/2022-10-04-07-55-19.gh-issue-97825.mNdv1l.rst deleted file mode 100644 index 4633dce7b663..000000000000 --- a/Misc/NEWS.d/next/Library/2022-10-04-07-55-19.gh-issue-97825.mNdv1l.rst +++ /dev/null @@ -1 +0,0 @@ -Fixes :exc:`AttributeError` when :meth:`subprocess.check_output` is used with argument ``input=None`` and either of the arguments *encoding* or *errors* are used. diff --git a/Misc/NEWS.d/next/Library/2022-10-04-21-21-41.gh-issue-97837.19q-eg.rst b/Misc/NEWS.d/next/Library/2022-10-04-21-21-41.gh-issue-97837.19q-eg.rst deleted file mode 100644 index b1350c959e2b..000000000000 --- a/Misc/NEWS.d/next/Library/2022-10-04-21-21-41.gh-issue-97837.19q-eg.rst +++ /dev/null @@ -1,7 +0,0 @@ -Change deprecate warning message in :mod:`unittest` from - -``It is deprecated to return a value!=None`` - -to - -``It is deprecated to return a value that is not None from a test case`` diff --git a/Misc/NEWS.d/next/Library/2022-10-05-11-40-02.gh-issue-97850.NzdREm.rst b/Misc/NEWS.d/next/Library/2022-10-05-11-40-02.gh-issue-97850.NzdREm.rst deleted file mode 100644 index 5e759bc0995a..000000000000 --- a/Misc/NEWS.d/next/Library/2022-10-05-11-40-02.gh-issue-97850.NzdREm.rst +++ /dev/null @@ -1,2 +0,0 @@ -Remove deprecated :func:`importlib.utils.set_loader` and -:func:`importlib.utils.module_for_loader` from :mod:`importlib.utils`. diff --git a/Misc/NEWS.d/next/Library/2022-10-05-16-10-24.gh-issue-97930.NPSrzE.rst b/Misc/NEWS.d/next/Library/2022-10-05-16-10-24.gh-issue-97930.NPSrzE.rst deleted file mode 100644 index 860f6adeb201..000000000000 --- a/Misc/NEWS.d/next/Library/2022-10-05-16-10-24.gh-issue-97930.NPSrzE.rst +++ /dev/null @@ -1,3 +0,0 @@ -Apply changes from importlib_resources 5.8 and 5.9: ``Traversable.joinpath`` -provides a concrete implementation. ``as_file`` now supports directories of -resources. diff --git a/Misc/NEWS.d/next/Library/2022-10-05-20-52-17.gh-issue-97646.Q4fVww.rst b/Misc/NEWS.d/next/Library/2022-10-05-20-52-17.gh-issue-97646.Q4fVww.rst deleted file mode 100644 index 6eed16c8e8bb..000000000000 --- a/Misc/NEWS.d/next/Library/2022-10-05-20-52-17.gh-issue-97646.Q4fVww.rst +++ /dev/null @@ -1 +0,0 @@ -Replace deprecated ``application/javascript`` with ``text/javascript`` in :mod:`mimetypes`. See :rfc:`9239`. Patch by Noam Cohen. diff --git a/Misc/NEWS.d/next/Library/2022-10-06-17-59-22.gh-issue-65961.SXlQnI.rst b/Misc/NEWS.d/next/Library/2022-10-06-17-59-22.gh-issue-65961.SXlQnI.rst deleted file mode 100644 index f708a75a5045..000000000000 --- a/Misc/NEWS.d/next/Library/2022-10-06-17-59-22.gh-issue-65961.SXlQnI.rst +++ /dev/null @@ -1,2 +0,0 @@ -Do not rely solely on ``__cached__`` on modules; code will also support -``__spec__.cached``. diff --git a/Misc/NEWS.d/next/Library/2022-10-06-23-42-00.gh-issue-90985.s280JY.rst b/Misc/NEWS.d/next/Library/2022-10-06-23-42-00.gh-issue-90985.s280JY.rst deleted file mode 100644 index 964aa3986331..000000000000 --- a/Misc/NEWS.d/next/Library/2022-10-06-23-42-00.gh-issue-90985.s280JY.rst +++ /dev/null @@ -1 +0,0 @@ -Earlier in 3.11 we deprecated ``asyncio.Task.cancel("message")``. We realized we were too harsh, and have undeprecated it. diff --git a/Misc/NEWS.d/next/Library/2022-10-07-09-52-37.gh-issue-98023.aliEcl.rst b/Misc/NEWS.d/next/Library/2022-10-07-09-52-37.gh-issue-98023.aliEcl.rst deleted file mode 100644 index 1bfd68d4ac7c..000000000000 --- a/Misc/NEWS.d/next/Library/2022-10-07-09-52-37.gh-issue-98023.aliEcl.rst +++ /dev/null @@ -1 +0,0 @@ -Change default child watcher to :class:`~asyncio.PidfdChildWatcher` on Linux systems which supports it. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Library/2022-10-08-06-59-46.gh-issue-94597.TsS0oT.rst b/Misc/NEWS.d/next/Library/2022-10-08-06-59-46.gh-issue-94597.TsS0oT.rst deleted file mode 100644 index f504ccf39ec9..000000000000 --- a/Misc/NEWS.d/next/Library/2022-10-08-06-59-46.gh-issue-94597.TsS0oT.rst +++ /dev/null @@ -1 +0,0 @@ -The child watcher classes :class:`~asyncio.MultiLoopChildWatcher`, :class:`~asyncio.FastChildWatcher` and :class:`~asyncio.SafeChildWatcher` are deprecated and will be removed in Python 3.14. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Library/2022-10-09-12-12-38.gh-issue-87730.ClgP3f.rst b/Misc/NEWS.d/next/Library/2022-10-09-12-12-38.gh-issue-87730.ClgP3f.rst deleted file mode 100644 index 6c63fa4928c6..000000000000 --- a/Misc/NEWS.d/next/Library/2022-10-09-12-12-38.gh-issue-87730.ClgP3f.rst +++ /dev/null @@ -1,3 +0,0 @@ -Wrap network errors consistently in urllib FTP support, so the test suite -doesn't fail when a network is available but the public internet is not -reachable. diff --git a/Misc/NEWS.d/next/Library/2022-10-10-09-52-21.gh-issue-44098.okcqJt.rst b/Misc/NEWS.d/next/Library/2022-10-10-09-52-21.gh-issue-44098.okcqJt.rst deleted file mode 100644 index 4efea4a7c4fc..000000000000 --- a/Misc/NEWS.d/next/Library/2022-10-10-09-52-21.gh-issue-44098.okcqJt.rst +++ /dev/null @@ -1 +0,0 @@ -Release the GIL when creating :class:`mmap.mmap` objects on Unix. diff --git a/Misc/NEWS.d/next/Library/2022-10-12-10-00-40.gh-issue-98178.hspH51.rst b/Misc/NEWS.d/next/Library/2022-10-12-10-00-40.gh-issue-98178.hspH51.rst deleted file mode 100644 index 833a6e6bb3f7..000000000000 --- a/Misc/NEWS.d/next/Library/2022-10-12-10-00-40.gh-issue-98178.hspH51.rst +++ /dev/null @@ -1,4 +0,0 @@ -On macOS, fix a crash in :func:`syslog.syslog` in multi-threaded applications. -On macOS, the libc ``syslog()`` function is not thread-safe, so -:func:`syslog.syslog` no longer releases the GIL to call it. Patch by Victor -Stinner. diff --git a/Misc/NEWS.d/next/Library/2022-10-12-11-20-54.gh-issue-94597.GYJZlb.rst b/Misc/NEWS.d/next/Library/2022-10-12-11-20-54.gh-issue-94597.GYJZlb.rst deleted file mode 100644 index 5ea1358b7d8a..000000000000 --- a/Misc/NEWS.d/next/Library/2022-10-12-11-20-54.gh-issue-94597.GYJZlb.rst +++ /dev/null @@ -1 +0,0 @@ -Deprecated :meth:`asyncio.AbstractEventLoopPolicy.get_child_watcher` and :meth:`asyncio.AbstractEventLoopPolicy.set_child_watcher` methods to be removed in Python 3.14. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Library/2022-10-14-11-46-31.gh-issue-98251.Uxc9al.rst b/Misc/NEWS.d/next/Library/2022-10-14-11-46-31.gh-issue-98251.Uxc9al.rst deleted file mode 100644 index 1a2b6a2537b9..000000000000 --- a/Misc/NEWS.d/next/Library/2022-10-14-11-46-31.gh-issue-98251.Uxc9al.rst +++ /dev/null @@ -1,2 +0,0 @@ -Allow :mod:`venv` to pass along :envvar:`PYTHON*` variables to ``ensurepip`` and ``pip`` when -they do not impact path resolution diff --git a/Misc/NEWS.d/next/Library/2022-10-14-12-29-05.gh-issue-98257.aMSMs2.rst b/Misc/NEWS.d/next/Library/2022-10-14-12-29-05.gh-issue-98257.aMSMs2.rst deleted file mode 100644 index 67f6cb4dbc19..000000000000 --- a/Misc/NEWS.d/next/Library/2022-10-14-12-29-05.gh-issue-98257.aMSMs2.rst +++ /dev/null @@ -1,3 +0,0 @@ -Make :func:`sys.setprofile` and :func:`sys.settrace` functions reentrant. They -can no long fail with: ``RuntimeError("Cannot install a trace function while -another trace function is being installed")``. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Library/2022-10-14-19-57-37.gh-issue-96035.0xcX-p.rst b/Misc/NEWS.d/next/Library/2022-10-14-19-57-37.gh-issue-96035.0xcX-p.rst deleted file mode 100644 index f04a0fd0915e..000000000000 --- a/Misc/NEWS.d/next/Library/2022-10-14-19-57-37.gh-issue-96035.0xcX-p.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix bug in :func:`urllib.parse.urlparse` that causes certain port numbers -containing whitespace, underscores, plus and minus signs, or non-ASCII digits to be -incorrectly accepted. diff --git a/Misc/NEWS.d/next/Library/2022-10-16-06-18-59.gh-issue-98307.b2_CDu.rst b/Misc/NEWS.d/next/Library/2022-10-16-06-18-59.gh-issue-98307.b2_CDu.rst deleted file mode 100644 index 3fe41d53c980..000000000000 --- a/Misc/NEWS.d/next/Library/2022-10-16-06-18-59.gh-issue-98307.b2_CDu.rst +++ /dev/null @@ -1,2 +0,0 @@ -A :meth:`~logging.handlers.SysLogHandler.createSocket` method was added to -:class:`~logging.handlers.SysLogHandler`. diff --git a/Misc/NEWS.d/next/Library/2022-10-16-15-31-50.gh-issue-98331.Y5kPOX.rst b/Misc/NEWS.d/next/Library/2022-10-16-15-31-50.gh-issue-98331.Y5kPOX.rst deleted file mode 100644 index b4cf94310af6..000000000000 --- a/Misc/NEWS.d/next/Library/2022-10-16-15-31-50.gh-issue-98331.Y5kPOX.rst +++ /dev/null @@ -1 +0,0 @@ -Update the bundled copies of pip and setuptools to versions 22.3 and 65.5.0 respectively. diff --git a/Misc/NEWS.d/next/Library/2022-10-17-12-49-02.gh-issue-98363.aFmSP-.rst b/Misc/NEWS.d/next/Library/2022-10-17-12-49-02.gh-issue-98363.aFmSP-.rst deleted file mode 100644 index 9c6e7552a3f4..000000000000 --- a/Misc/NEWS.d/next/Library/2022-10-17-12-49-02.gh-issue-98363.aFmSP-.rst +++ /dev/null @@ -1,2 +0,0 @@ -Added itertools.batched() to batch data into lists of a given length with -the last list possibly being shorter than the others. diff --git a/Misc/NEWS.d/next/Library/2022-10-18-15-41-37.gh-issue-98393.vhPu4L.rst b/Misc/NEWS.d/next/Library/2022-10-18-15-41-37.gh-issue-98393.vhPu4L.rst deleted file mode 100644 index 54e45bb900b2..000000000000 --- a/Misc/NEWS.d/next/Library/2022-10-18-15-41-37.gh-issue-98393.vhPu4L.rst +++ /dev/null @@ -1,3 +0,0 @@ -The :mod:`os` module no longer accepts bytes-like paths, like -:class:`bytearray` and :class:`memoryview` types: only the exact -:class:`bytes` type is accepted for bytes strings. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Library/2022-10-19-09-29-12.gh-issue-97928.xj3im7.rst b/Misc/NEWS.d/next/Library/2022-10-19-09-29-12.gh-issue-97928.xj3im7.rst deleted file mode 100644 index cf33db7548f6..000000000000 --- a/Misc/NEWS.d/next/Library/2022-10-19-09-29-12.gh-issue-97928.xj3im7.rst +++ /dev/null @@ -1,2 +0,0 @@ -:meth:`tkinter.Text.count` raises now an exception for options starting with -"-" instead of silently ignoring them. diff --git a/Misc/NEWS.d/next/Library/2022-10-23-18-30-39.gh-issue-89237.kBui30.rst b/Misc/NEWS.d/next/Library/2022-10-23-18-30-39.gh-issue-89237.kBui30.rst deleted file mode 100644 index 668ea4c7a4ea..000000000000 --- a/Misc/NEWS.d/next/Library/2022-10-23-18-30-39.gh-issue-89237.kBui30.rst +++ /dev/null @@ -1 +0,0 @@ -Fix hang on Windows in ``subprocess.wait_closed()`` in :mod:`asyncio` with :class:`~asyncio.ProactorEventLoop`. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Security/2022-04-27-18-25-30.gh-issue-68966.gjS8zs.rst b/Misc/NEWS.d/next/Security/2022-04-27-18-25-30.gh-issue-68966.gjS8zs.rst deleted file mode 100644 index da81a1f6993d..000000000000 --- a/Misc/NEWS.d/next/Security/2022-04-27-18-25-30.gh-issue-68966.gjS8zs.rst +++ /dev/null @@ -1,4 +0,0 @@ -The deprecated mailcap module now refuses to inject unsafe text (filenames, -MIME types, parameters) into shell commands. Instead of using such text, it -will warn and act as if a match was not found (or for test commands, as if -the test failed). diff --git a/Misc/NEWS.d/next/Security/2022-05-19-08-53-07.gh-issue-92888.TLtR9W.rst b/Misc/NEWS.d/next/Security/2022-05-19-08-53-07.gh-issue-92888.TLtR9W.rst deleted file mode 100644 index 4841b8a90a08..000000000000 --- a/Misc/NEWS.d/next/Security/2022-05-19-08-53-07.gh-issue-92888.TLtR9W.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix ``memoryview`` use after free when accessing the backing buffer in certain cases. - diff --git a/Misc/NEWS.d/next/Security/2022-06-03-12-52-53.gh-issue-79096.YVoxgC.rst b/Misc/NEWS.d/next/Security/2022-06-03-12-52-53.gh-issue-79096.YVoxgC.rst deleted file mode 100644 index 9ec3335dc71b..000000000000 --- a/Misc/NEWS.d/next/Security/2022-06-03-12-52-53.gh-issue-79096.YVoxgC.rst +++ /dev/null @@ -1 +0,0 @@ -LWPCookieJar and MozillaCookieJar create files with file mode 600 instead of 644 (Microsoft Windows is not affected) diff --git a/Misc/NEWS.d/next/Security/2022-06-15-20-09-23.gh-issue-87389.QVaC3f.rst b/Misc/NEWS.d/next/Security/2022-06-15-20-09-23.gh-issue-87389.QVaC3f.rst deleted file mode 100644 index 029d437190de..000000000000 --- a/Misc/NEWS.d/next/Security/2022-06-15-20-09-23.gh-issue-87389.QVaC3f.rst +++ /dev/null @@ -1,3 +0,0 @@ -:mod:`http.server`: Fix an open redirection vulnerability in the HTTP server -when an URI path starts with ``//``. Vulnerability discovered, and initial -fix proposed, by Hamza Avvan. diff --git a/Misc/NEWS.d/next/Security/2022-09-07-10-42-00.gh-issue-97514.Yggdsl.rst b/Misc/NEWS.d/next/Security/2022-09-07-10-42-00.gh-issue-97514.Yggdsl.rst deleted file mode 100644 index 02d95b570520..000000000000 --- a/Misc/NEWS.d/next/Security/2022-09-07-10-42-00.gh-issue-97514.Yggdsl.rst +++ /dev/null @@ -1,15 +0,0 @@ -On Linux the :mod:`multiprocessing` module returns to using filesystem backed -unix domain sockets for communication with the *forkserver* process instead of -the Linux abstract socket namespace. Only code that chooses to use the -:ref:`"forkserver" start method ` is affected. - -Abstract sockets have no permissions and could allow any user on the system in -the same `network namespace -`_ (often the -whole system) to inject code into the multiprocessing *forkserver* process. -This was a potential privilege escalation. Filesystem based socket permissions -restrict this to the *forkserver* process user as was the default in Python 3.8 -and earlier. - -This prevents Linux `CVE-2022-42919 -`_. diff --git a/Misc/NEWS.d/next/Security/2022-09-28-17-09-37.gh-issue-97616.K1e3Xs.rst b/Misc/NEWS.d/next/Security/2022-09-28-17-09-37.gh-issue-97616.K1e3Xs.rst deleted file mode 100644 index 721427fe6465..000000000000 --- a/Misc/NEWS.d/next/Security/2022-09-28-17-09-37.gh-issue-97616.K1e3Xs.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix multiplying a list by an integer (``list *= int``): detect the integer -overflow when the new allocated length is close to the maximum size. Issue -reported by Jordan Limor. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Tests/2022-03-14-23-28-17.bpo-47016.K-t2QX.rst b/Misc/NEWS.d/next/Tests/2022-03-14-23-28-17.bpo-47016.K-t2QX.rst deleted file mode 100644 index 774bfafc021e..000000000000 --- a/Misc/NEWS.d/next/Tests/2022-03-14-23-28-17.bpo-47016.K-t2QX.rst +++ /dev/null @@ -1,2 +0,0 @@ -Create a GitHub Actions workflow for verifying bundled pip and setuptools. -Patch by Illia Volochii and Adam Turner. diff --git a/Misc/NEWS.d/next/Tests/2022-05-08-15-40-41.gh-issue-92514.Xbf5JY.rst b/Misc/NEWS.d/next/Tests/2022-05-08-15-40-41.gh-issue-92514.Xbf5JY.rst deleted file mode 100644 index 6b82196a25e4..000000000000 --- a/Misc/NEWS.d/next/Tests/2022-05-08-15-40-41.gh-issue-92514.Xbf5JY.rst +++ /dev/null @@ -1 +0,0 @@ -Remove unused ``test.support.BasicTestRunner``. Patch by Jelle Zijlstra. diff --git a/Misc/NEWS.d/next/Tests/2022-05-12-05-51-06.gh-issue-92670.7L43Z_.rst b/Misc/NEWS.d/next/Tests/2022-05-12-05-51-06.gh-issue-92670.7L43Z_.rst deleted file mode 100644 index c1349519e7c3..000000000000 --- a/Misc/NEWS.d/next/Tests/2022-05-12-05-51-06.gh-issue-92670.7L43Z_.rst +++ /dev/null @@ -1,3 +0,0 @@ -Skip ``test_shutil.TestCopy.test_copyfile_nonexistent_dir`` test on AIX as the test uses a trailing -slash to force the OS consider the path as a directory, but on AIX the -trailing slash has no effect and is considered as a file. diff --git a/Misc/NEWS.d/next/Tests/2022-05-25-22-34-10.gh-issue-92886.1Lkt8S.rst b/Misc/NEWS.d/next/Tests/2022-05-25-22-34-10.gh-issue-92886.1Lkt8S.rst deleted file mode 100644 index 2b9c1b4d2dd4..000000000000 --- a/Misc/NEWS.d/next/Tests/2022-05-25-22-34-10.gh-issue-92886.1Lkt8S.rst +++ /dev/null @@ -1 +0,0 @@ -Fixing tests that fail when running with optimizations (``-O``) in ``_test_multiprocessing.py`` diff --git a/Misc/NEWS.d/next/Tests/2022-05-25-22-43-11.gh-issue-92886.9HQb9e.rst b/Misc/NEWS.d/next/Tests/2022-05-25-22-43-11.gh-issue-92886.9HQb9e.rst deleted file mode 100644 index 0c5870441c3b..000000000000 --- a/Misc/NEWS.d/next/Tests/2022-05-25-22-43-11.gh-issue-92886.9HQb9e.rst +++ /dev/null @@ -1 +0,0 @@ -Fixing tests that fail when running with optimizations (``-O``) in ``test_sys_settrace.py``. diff --git a/Misc/NEWS.d/next/Tests/2022-05-25-22-53-30.gh-issue-92886.mIfdtz.rst b/Misc/NEWS.d/next/Tests/2022-05-25-22-53-30.gh-issue-92886.mIfdtz.rst deleted file mode 100644 index 014e9e614cca..000000000000 --- a/Misc/NEWS.d/next/Tests/2022-05-25-22-53-30.gh-issue-92886.mIfdtz.rst +++ /dev/null @@ -1 +0,0 @@ -Fixing tests that fail when running with optimizations (``-O``) in ``test_py_compile.py`` diff --git a/Misc/NEWS.d/next/Tests/2022-05-25-23-00-35.gh-issue-92886.Y-vrWj.rst b/Misc/NEWS.d/next/Tests/2022-05-25-23-00-35.gh-issue-92886.Y-vrWj.rst deleted file mode 100644 index 93c1ffe33f28..000000000000 --- a/Misc/NEWS.d/next/Tests/2022-05-25-23-00-35.gh-issue-92886.Y-vrWj.rst +++ /dev/null @@ -1 +0,0 @@ -Fixing tests that fail when running with optimizations (``-O``) in ``test_zipimport.py`` diff --git a/Misc/NEWS.d/next/Tests/2022-05-25-23-07-15.gh-issue-92886.Aki63_.rst b/Misc/NEWS.d/next/Tests/2022-05-25-23-07-15.gh-issue-92886.Aki63_.rst deleted file mode 100644 index 581f6bfea24b..000000000000 --- a/Misc/NEWS.d/next/Tests/2022-05-25-23-07-15.gh-issue-92886.Aki63_.rst +++ /dev/null @@ -1 +0,0 @@ -Fixing tests that fail when running with optimizations (``-O``) in ``test_imaplib.py``. diff --git a/Misc/NEWS.d/next/Tests/2022-06-03-12-22-44.gh-issue-89858.ftBvjE.rst b/Misc/NEWS.d/next/Tests/2022-06-03-12-22-44.gh-issue-89858.ftBvjE.rst deleted file mode 100644 index ef806a93c018..000000000000 --- a/Misc/NEWS.d/next/Tests/2022-06-03-12-22-44.gh-issue-89858.ftBvjE.rst +++ /dev/null @@ -1 +0,0 @@ -Fix ``test_embed`` for out-of-tree builds. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Tests/2022-06-03-14-18-37.gh-issue-90473.7iXVRK.rst b/Misc/NEWS.d/next/Tests/2022-06-03-14-18-37.gh-issue-90473.7iXVRK.rst deleted file mode 100644 index a3165a01111f..000000000000 --- a/Misc/NEWS.d/next/Tests/2022-06-03-14-18-37.gh-issue-90473.7iXVRK.rst +++ /dev/null @@ -1,2 +0,0 @@ -Skip symlink tests on WASI. wasmtime uses ``openat2(2)`` with -``RESOLVE_BENEATH`` flag, which prevents symlinks with absolute paths. diff --git a/Misc/NEWS.d/next/Tests/2022-06-03-16-26-04.gh-issue-57539.HxWgYO.rst b/Misc/NEWS.d/next/Tests/2022-06-03-16-26-04.gh-issue-57539.HxWgYO.rst deleted file mode 100644 index 0734b599f4ad..000000000000 --- a/Misc/NEWS.d/next/Tests/2022-06-03-16-26-04.gh-issue-57539.HxWgYO.rst +++ /dev/null @@ -1 +0,0 @@ -Increase calendar test coverage for :meth:`calendar.LocaleTextCalendar.formatweekday`. diff --git a/Misc/NEWS.d/next/Tests/2022-06-04-12-05-31.gh-issue-90473.RSpjF7.rst b/Misc/NEWS.d/next/Tests/2022-06-04-12-05-31.gh-issue-90473.RSpjF7.rst deleted file mode 100644 index 07d579995c09..000000000000 --- a/Misc/NEWS.d/next/Tests/2022-06-04-12-05-31.gh-issue-90473.RSpjF7.rst +++ /dev/null @@ -1 +0,0 @@ -Skip tests on WASI that require symlinks with absolute paths. diff --git a/Misc/NEWS.d/next/Tests/2022-06-05-10-16-45.gh-issue-90473.QMu7A8.rst b/Misc/NEWS.d/next/Tests/2022-06-05-10-16-45.gh-issue-90473.QMu7A8.rst deleted file mode 100644 index 6c76b7f4990e..000000000000 --- a/Misc/NEWS.d/next/Tests/2022-06-05-10-16-45.gh-issue-90473.QMu7A8.rst +++ /dev/null @@ -1,2 +0,0 @@ -WASI does not have a ``chmod(2)`` syscall. :func:`os.chmod` is now a dummy -function on WASI. Skip all tests that depend on working :func:`os.chmod`. diff --git a/Misc/NEWS.d/next/Tests/2022-06-08-14-17-59.gh-issue-93575.Xb2LNB.rst b/Misc/NEWS.d/next/Tests/2022-06-08-14-17-59.gh-issue-93575.Xb2LNB.rst deleted file mode 100644 index 98d15328a087..000000000000 --- a/Misc/NEWS.d/next/Tests/2022-06-08-14-17-59.gh-issue-93575.Xb2LNB.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix issue with test_unicode test_raiseMemError. The test case now use -``test.support.calcobjsize`` to calculate size of PyUnicode structs. -:func:`sys.getsizeof` may return different size when string has UTF-8 -memory. diff --git a/Misc/NEWS.d/next/Tests/2022-06-08-22-32-56.gh-issue-93616.e5Kkx2.rst b/Misc/NEWS.d/next/Tests/2022-06-08-22-32-56.gh-issue-93616.e5Kkx2.rst deleted file mode 100644 index de8ec52cc88b..000000000000 --- a/Misc/NEWS.d/next/Tests/2022-06-08-22-32-56.gh-issue-93616.e5Kkx2.rst +++ /dev/null @@ -1,2 +0,0 @@ -``test_modulefinder`` now creates a temporary directory in -``ModuleFinderTest.setUp()`` instead of module scope. diff --git a/Misc/NEWS.d/next/Tests/2022-06-10-21-18-14.gh-issue-84461.9TAb26.rst b/Misc/NEWS.d/next/Tests/2022-06-10-21-18-14.gh-issue-84461.9TAb26.rst deleted file mode 100644 index 7cdf5bee7218..000000000000 --- a/Misc/NEWS.d/next/Tests/2022-06-10-21-18-14.gh-issue-84461.9TAb26.rst +++ /dev/null @@ -1,2 +0,0 @@ -``run_tests.py`` now handles cross compiling env vars correctly and pass -``HOSTRUNNER`` to regression tests. diff --git a/Misc/NEWS.d/next/Tests/2022-06-16-17-50-58.gh-issue-93353.JdpATx.rst b/Misc/NEWS.d/next/Tests/2022-06-16-17-50-58.gh-issue-93353.JdpATx.rst deleted file mode 100644 index 4e232948f49e..000000000000 --- a/Misc/NEWS.d/next/Tests/2022-06-16-17-50-58.gh-issue-93353.JdpATx.rst +++ /dev/null @@ -1,2 +0,0 @@ -regrtest now checks if a test leaks temporary files or directories if run -with -jN option. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Tests/2022-06-16-21-38-18.gh-issue-93852.U_Hl6s.rst b/Misc/NEWS.d/next/Tests/2022-06-16-21-38-18.gh-issue-93852.U_Hl6s.rst deleted file mode 100644 index ce86eead0266..000000000000 --- a/Misc/NEWS.d/next/Tests/2022-06-16-21-38-18.gh-issue-93852.U_Hl6s.rst +++ /dev/null @@ -1,4 +0,0 @@ -test_asyncio, test_logging, test_socket and test_socketserver now create -AF_UNIX domains in the current directory to no longer fail with -``OSError("AF_UNIX path too long")`` if the temporary directory (the -:envvar:`TMPDIR` environment variable) is too long. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Tests/2022-06-17-13-27-21.gh-issue-93884.5pvPvl.rst b/Misc/NEWS.d/next/Tests/2022-06-17-13-27-21.gh-issue-93884.5pvPvl.rst deleted file mode 100644 index ce389149aaae..000000000000 --- a/Misc/NEWS.d/next/Tests/2022-06-17-13-27-21.gh-issue-93884.5pvPvl.rst +++ /dev/null @@ -1 +0,0 @@ -Add test cases for :c:func:`PyNumber_ToBase` that take a large number or a non-int object as parameter. diff --git a/Misc/NEWS.d/next/Tests/2022-06-17-13-55-11.gh-issue-93957.X4ovYV.rst b/Misc/NEWS.d/next/Tests/2022-06-17-13-55-11.gh-issue-93957.X4ovYV.rst deleted file mode 100644 index 2719933f6b94..000000000000 --- a/Misc/NEWS.d/next/Tests/2022-06-17-13-55-11.gh-issue-93957.X4ovYV.rst +++ /dev/null @@ -1,2 +0,0 @@ -Provide nicer error reporting from subprocesses in -test_venv.EnsurePipTest.test_with_pip. diff --git a/Misc/NEWS.d/next/Tests/2022-06-17-15-20-09.gh-issue-93951.CW1Vv4.rst b/Misc/NEWS.d/next/Tests/2022-06-17-15-20-09.gh-issue-93951.CW1Vv4.rst deleted file mode 100644 index b627466b4b22..000000000000 --- a/Misc/NEWS.d/next/Tests/2022-06-17-15-20-09.gh-issue-93951.CW1Vv4.rst +++ /dev/null @@ -1 +0,0 @@ -In test_bdb.StateTestCase.test_skip, avoid including auxiliary importers. diff --git a/Misc/NEWS.d/next/Tests/2022-06-20-23-04-52.gh-issue-93839.OE3Ybk.rst b/Misc/NEWS.d/next/Tests/2022-06-20-23-04-52.gh-issue-93839.OE3Ybk.rst deleted file mode 100644 index 121b64b13307..000000000000 --- a/Misc/NEWS.d/next/Tests/2022-06-20-23-04-52.gh-issue-93839.OE3Ybk.rst +++ /dev/null @@ -1,2 +0,0 @@ -Move ``Lib/ctypes/test/`` to ``Lib/test/test_ctypes/``. Patch by Victor -Stinner. diff --git a/Misc/NEWS.d/next/Tests/2022-06-21-17-37-46.gh-issue-54781.BjVAVg.rst b/Misc/NEWS.d/next/Tests/2022-06-21-17-37-46.gh-issue-54781.BjVAVg.rst deleted file mode 100644 index f7ae7b976af9..000000000000 --- a/Misc/NEWS.d/next/Tests/2022-06-21-17-37-46.gh-issue-54781.BjVAVg.rst +++ /dev/null @@ -1,2 +0,0 @@ -Rename test_tk to test_tkinter, and rename test_ttk_guionly to test_ttk. -Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Tests/2022-06-27-08-53-40.gh-issue-94315.MoZT9t.rst b/Misc/NEWS.d/next/Tests/2022-06-27-08-53-40.gh-issue-94315.MoZT9t.rst deleted file mode 100644 index 09d5d7e56ae8..000000000000 --- a/Misc/NEWS.d/next/Tests/2022-06-27-08-53-40.gh-issue-94315.MoZT9t.rst +++ /dev/null @@ -1,2 +0,0 @@ -Tests now check for DAC override capability instead of relying on -:func:`os.geteuid`. diff --git a/Misc/NEWS.d/next/Tests/2022-06-27-21-27-20.gh-issue-94208.VR6HX-.rst b/Misc/NEWS.d/next/Tests/2022-06-27-21-27-20.gh-issue-94208.VR6HX-.rst deleted file mode 100644 index d0f970ad286b..000000000000 --- a/Misc/NEWS.d/next/Tests/2022-06-27-21-27-20.gh-issue-94208.VR6HX-.rst +++ /dev/null @@ -1,2 +0,0 @@ -``test_ssl`` is now checking for supported TLS version and protocols in more -tests. diff --git a/Misc/NEWS.d/next/Tests/2022-07-05-17-53-13.gh-issue-91330.Qys5IL.rst b/Misc/NEWS.d/next/Tests/2022-07-05-17-53-13.gh-issue-91330.Qys5IL.rst deleted file mode 100644 index 6f44dcfd7e66..000000000000 --- a/Misc/NEWS.d/next/Tests/2022-07-05-17-53-13.gh-issue-91330.Qys5IL.rst +++ /dev/null @@ -1,2 +0,0 @@ -Added more tests for :mod:`dataclasses` to cover behavior with data -descriptor-based fields. diff --git a/Misc/NEWS.d/next/Tests/2022-07-08-12-22-00.gh-issue-94675.IiTs5f.rst b/Misc/NEWS.d/next/Tests/2022-07-08-12-22-00.gh-issue-94675.IiTs5f.rst deleted file mode 100644 index d0005d9f6014..000000000000 --- a/Misc/NEWS.d/next/Tests/2022-07-08-12-22-00.gh-issue-94675.IiTs5f.rst +++ /dev/null @@ -1 +0,0 @@ -Add a regression test for :mod:`re` exponentional slowdown when using rjsmin. diff --git a/Misc/NEWS.d/next/Tests/2022-07-24-16-28-31.gh-issue-93963.UB9azu.rst b/Misc/NEWS.d/next/Tests/2022-07-24-16-28-31.gh-issue-93963.UB9azu.rst deleted file mode 100644 index 89ce124c55f2..000000000000 --- a/Misc/NEWS.d/next/Tests/2022-07-24-16-28-31.gh-issue-93963.UB9azu.rst +++ /dev/null @@ -1 +0,0 @@ -Updated tests to use preferred location for ``importlib.resources`` ABCs. diff --git a/Misc/NEWS.d/next/Tests/2022-07-24-17-24-42.gh-issue-95218.zfBLtu.rst b/Misc/NEWS.d/next/Tests/2022-07-24-17-24-42.gh-issue-95218.zfBLtu.rst deleted file mode 100644 index 7326689657a7..000000000000 --- a/Misc/NEWS.d/next/Tests/2022-07-24-17-24-42.gh-issue-95218.zfBLtu.rst +++ /dev/null @@ -1 +0,0 @@ -Move tests for importlib.resources into test_importlib.resources. diff --git a/Misc/NEWS.d/next/Tests/2022-07-24-20-19-05.gh-issue-95212.fHiU4e.rst b/Misc/NEWS.d/next/Tests/2022-07-24-20-19-05.gh-issue-95212.fHiU4e.rst deleted file mode 100644 index 44cea181cc1f..000000000000 --- a/Misc/NEWS.d/next/Tests/2022-07-24-20-19-05.gh-issue-95212.fHiU4e.rst +++ /dev/null @@ -1,2 +0,0 @@ -Make multiprocessing test case ``test_shared_memory_recreate`` -parallel-safe. diff --git a/Misc/NEWS.d/next/Tests/2022-07-26-15-22-19.gh-issue-95280.h8HvbP.rst b/Misc/NEWS.d/next/Tests/2022-07-26-15-22-19.gh-issue-95280.h8HvbP.rst deleted file mode 100644 index 523d9d5f2f8b..000000000000 --- a/Misc/NEWS.d/next/Tests/2022-07-26-15-22-19.gh-issue-95280.h8HvbP.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix problem with ``test_ssl`` ``test_get_ciphers`` on systems that require -perfect forward secrecy (PFS) ciphers. diff --git a/Misc/NEWS.d/next/Tests/2022-08-05-09-57-43.gh-issue-95573.edMdQB.rst b/Misc/NEWS.d/next/Tests/2022-08-05-09-57-43.gh-issue-95573.edMdQB.rst deleted file mode 100644 index 8580556965e1..000000000000 --- a/Misc/NEWS.d/next/Tests/2022-08-05-09-57-43.gh-issue-95573.edMdQB.rst +++ /dev/null @@ -1,6 +0,0 @@ -:source:`Lib/test/test_asyncio/test_ssl.py` exposed a bug in the macOS -kernel where intense concurrent load on non-blocking sockets occasionally -causes :const:`errno.ENOBUFS` ("No buffer space available") to be emitted. -FB11063974 filed with Apple, in the mean time as a workaround buffer size -used in tests on macOS is decreased to avoid intermittent failures. Patch -by Fantix King. diff --git a/Misc/NEWS.d/next/Tests/2022-08-22-14-59-42.gh-issue-95243.DeD66V.rst b/Misc/NEWS.d/next/Tests/2022-08-22-14-59-42.gh-issue-95243.DeD66V.rst deleted file mode 100644 index a9ca1f8b8676..000000000000 --- a/Misc/NEWS.d/next/Tests/2022-08-22-14-59-42.gh-issue-95243.DeD66V.rst +++ /dev/null @@ -1,3 +0,0 @@ -Mitigate the inherent race condition from using find_unused_port() in -testSockName() by trying to find an unused port a few times before failing. -Patch by Ross Burton. diff --git a/Misc/NEWS.d/next/Tests/2022-09-08-18-31-26.gh-issue-96624.5cANM1.rst b/Misc/NEWS.d/next/Tests/2022-09-08-18-31-26.gh-issue-96624.5cANM1.rst deleted file mode 100644 index 2d1bcc03e1c8..000000000000 --- a/Misc/NEWS.d/next/Tests/2022-09-08-18-31-26.gh-issue-96624.5cANM1.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed the failure of repeated runs of ``test.test_unittest`` caused by side effects in ``test_dotted_but_module_not_loaded``. diff --git a/Misc/NEWS.d/next/Tests/2022-10-20-17-49-50.gh-issue-95027.viRpJB.rst b/Misc/NEWS.d/next/Tests/2022-10-20-17-49-50.gh-issue-95027.viRpJB.rst deleted file mode 100644 index 8bf1a9d33573..000000000000 --- a/Misc/NEWS.d/next/Tests/2022-10-20-17-49-50.gh-issue-95027.viRpJB.rst +++ /dev/null @@ -1,4 +0,0 @@ -On Windows, when the Python test suite is run with the ``-jN`` option, the -ANSI code page is now used as the encoding for the stdout temporary file, -rather than using UTF-8 which can lead to decoding errors. Patch by Victor -Stinner. diff --git a/Misc/NEWS.d/next/Tools-Demos/2022-06-19-14-56-33.gh-issue-86087.R8MkRy.rst b/Misc/NEWS.d/next/Tools-Demos/2022-06-19-14-56-33.gh-issue-86087.R8MkRy.rst deleted file mode 100644 index a10d4c768845..000000000000 --- a/Misc/NEWS.d/next/Tools-Demos/2022-06-19-14-56-33.gh-issue-86087.R8MkRy.rst +++ /dev/null @@ -1,2 +0,0 @@ -The ``Tools/scripts/parseentities.py`` script used to parse HTML4 entities -has been removed. diff --git a/Misc/NEWS.d/next/Tools-Demos/2022-06-29-22-47-11.gh-issue-94430.hdov8L.rst b/Misc/NEWS.d/next/Tools-Demos/2022-06-29-22-47-11.gh-issue-94430.hdov8L.rst deleted file mode 100644 index 88aa8d086653..000000000000 --- a/Misc/NEWS.d/next/Tools-Demos/2022-06-29-22-47-11.gh-issue-94430.hdov8L.rst +++ /dev/null @@ -1,2 +0,0 @@ -Allow parameters named ``module`` and ``self`` with custom C names in Argument -Clinic. Patch by Erlend E. Aasland diff --git a/Misc/NEWS.d/next/Tools-Demos/2022-07-04-01-37-42.gh-issue-94538.1rgy1Y.rst b/Misc/NEWS.d/next/Tools-Demos/2022-07-04-01-37-42.gh-issue-94538.1rgy1Y.rst deleted file mode 100644 index e39ae3950c0f..000000000000 --- a/Misc/NEWS.d/next/Tools-Demos/2022-07-04-01-37-42.gh-issue-94538.1rgy1Y.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix Argument Clinic output to custom file destinations. Patch by Erlend E. -Aasland. diff --git a/Misc/NEWS.d/next/Tools-Demos/2022-07-04-10-02-02.gh-issue-93939.U6sW6H.rst b/Misc/NEWS.d/next/Tools-Demos/2022-07-04-10-02-02.gh-issue-93939.U6sW6H.rst deleted file mode 100644 index a129d6800c36..000000000000 --- a/Misc/NEWS.d/next/Tools-Demos/2022-07-04-10-02-02.gh-issue-93939.U6sW6H.rst +++ /dev/null @@ -1,3 +0,0 @@ -Add script ``Tools/scripts/check_modules.py`` to check and validate builtin -and shared extension modules. The script also handles ``Modules/Setup`` and -will eventually replace ``setup.py``. diff --git a/Misc/NEWS.d/next/Tools-Demos/2022-08-05-23-25-59.gh-issue-95731.N2KohU.rst b/Misc/NEWS.d/next/Tools-Demos/2022-08-05-23-25-59.gh-issue-95731.N2KohU.rst deleted file mode 100644 index 6b214616c0a9..000000000000 --- a/Misc/NEWS.d/next/Tools-Demos/2022-08-05-23-25-59.gh-issue-95731.N2KohU.rst +++ /dev/null @@ -1 +0,0 @@ -Fix handling of module docstrings in :file:`Tools/i18n/pygettext.py`. diff --git a/Misc/NEWS.d/next/Tools-Demos/2022-08-10-17-08-43.gh-issue-95853.HCjC2m.rst b/Misc/NEWS.d/next/Tools-Demos/2022-08-10-17-08-43.gh-issue-95853.HCjC2m.rst deleted file mode 100644 index c38db3af425e..000000000000 --- a/Misc/NEWS.d/next/Tools-Demos/2022-08-10-17-08-43.gh-issue-95853.HCjC2m.rst +++ /dev/null @@ -1,2 +0,0 @@ -The new tool ``Tools/wasm/wasm_builder.py`` automates configure, compile, and -test steps for building CPython on WebAssembly platforms. diff --git a/Misc/NEWS.d/next/Tools-Demos/2022-08-29-17-25-13.gh-issue-95853.Ce17cT.rst b/Misc/NEWS.d/next/Tools-Demos/2022-08-29-17-25-13.gh-issue-95853.Ce17cT.rst deleted file mode 100644 index 1cd1ce14fac0..000000000000 --- a/Misc/NEWS.d/next/Tools-Demos/2022-08-29-17-25-13.gh-issue-95853.Ce17cT.rst +++ /dev/null @@ -1,2 +0,0 @@ -The ``wasm_build.py`` script now pre-builds Emscripten ports, checks for -broken EMSDK versions, and warns about pkg-config env vars. diff --git a/Misc/NEWS.d/next/Tools-Demos/2022-09-30-14-30-12.gh-issue-97669.gvbgcg.rst b/Misc/NEWS.d/next/Tools-Demos/2022-09-30-14-30-12.gh-issue-97669.gvbgcg.rst deleted file mode 100644 index 604f20290fc8..000000000000 --- a/Misc/NEWS.d/next/Tools-Demos/2022-09-30-14-30-12.gh-issue-97669.gvbgcg.rst +++ /dev/null @@ -1,3 +0,0 @@ -Remove outdated example scripts of the ``Tools/scripts/`` directory. A copy can -be found in the `old-demos project `_. -Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Tools-Demos/2022-09-30-18-35-11.gh-issue-97681.-KO1Ba.rst b/Misc/NEWS.d/next/Tools-Demos/2022-09-30-18-35-11.gh-issue-97681.-KO1Ba.rst deleted file mode 100644 index 6f1ec12ce0c3..000000000000 --- a/Misc/NEWS.d/next/Tools-Demos/2022-09-30-18-35-11.gh-issue-97681.-KO1Ba.rst +++ /dev/null @@ -1,3 +0,0 @@ -Remove the ``Tools/demo/`` directory which contained old demo scripts. A copy -can be found in the `old-demos project -`_. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Tools-Demos/2022-10-07-22-06-11.gh-issue-68686.6KNIQ4.rst b/Misc/NEWS.d/next/Tools-Demos/2022-10-07-22-06-11.gh-issue-68686.6KNIQ4.rst deleted file mode 100644 index a4289d675703..000000000000 --- a/Misc/NEWS.d/next/Tools-Demos/2022-10-07-22-06-11.gh-issue-68686.6KNIQ4.rst +++ /dev/null @@ -1 +0,0 @@ -Remove ptags and eptags scripts. diff --git a/Misc/NEWS.d/next/Windows/2020-01-10-23-33-03.bpo-38704.2Idtdn.rst b/Misc/NEWS.d/next/Windows/2020-01-10-23-33-03.bpo-38704.2Idtdn.rst deleted file mode 100644 index 519338f27a47..000000000000 --- a/Misc/NEWS.d/next/Windows/2020-01-10-23-33-03.bpo-38704.2Idtdn.rst +++ /dev/null @@ -1 +0,0 @@ -Prevent installation on unsupported Windows versions. diff --git a/Misc/NEWS.d/next/Windows/2022-03-20-15-47-35.bpo-42658.16eXtb.rst b/Misc/NEWS.d/next/Windows/2022-03-20-15-47-35.bpo-42658.16eXtb.rst deleted file mode 100644 index 852cc77676a3..000000000000 --- a/Misc/NEWS.d/next/Windows/2022-03-20-15-47-35.bpo-42658.16eXtb.rst +++ /dev/null @@ -1,3 +0,0 @@ -Support native Windows case-insensitive path comparisons by using -``LCMapStringEx`` instead of :func:`str.lower` in :func:`ntpath.normcase`. -Add ``LCMapStringEx`` to the :mod:`_winapi` module. diff --git a/Misc/NEWS.d/next/Windows/2022-04-12-18-35-20.gh-issue-91061.x40hSK.rst b/Misc/NEWS.d/next/Windows/2022-04-12-18-35-20.gh-issue-91061.x40hSK.rst deleted file mode 100644 index aadc30344202..000000000000 --- a/Misc/NEWS.d/next/Windows/2022-04-12-18-35-20.gh-issue-91061.x40hSK.rst +++ /dev/null @@ -1 +0,0 @@ -Accept os.PathLike for the argument to winsound.PlaySound diff --git a/Misc/NEWS.d/next/Windows/2022-05-05-06-27-59.bpo-46907.IW-uvT.rst b/Misc/NEWS.d/next/Windows/2022-05-05-06-27-59.bpo-46907.IW-uvT.rst deleted file mode 100644 index 420fbd210ef1..000000000000 --- a/Misc/NEWS.d/next/Windows/2022-05-05-06-27-59.bpo-46907.IW-uvT.rst +++ /dev/null @@ -1 +0,0 @@ -Update Windows installer to use SQLite 3.38.4. diff --git a/Misc/NEWS.d/next/Windows/2022-05-16-11-45-06.gh-issue-92841.NQx107.rst b/Misc/NEWS.d/next/Windows/2022-05-16-11-45-06.gh-issue-92841.NQx107.rst deleted file mode 100644 index 5e1897e6ba1b..000000000000 --- a/Misc/NEWS.d/next/Windows/2022-05-16-11-45-06.gh-issue-92841.NQx107.rst +++ /dev/null @@ -1,2 +0,0 @@ -:mod:`asyncio` no longer throws ``RuntimeError: Event loop is closed`` on -interpreter exit after asynchronous socket activity. Patch by Oleg Iarygin. diff --git a/Misc/NEWS.d/next/Windows/2022-05-19-14-01-30.gh-issue-92984.Dsxnlr.rst b/Misc/NEWS.d/next/Windows/2022-05-19-14-01-30.gh-issue-92984.Dsxnlr.rst deleted file mode 100644 index 2d3071b00b76..000000000000 --- a/Misc/NEWS.d/next/Windows/2022-05-19-14-01-30.gh-issue-92984.Dsxnlr.rst +++ /dev/null @@ -1 +0,0 @@ -Explicitly disable incremental linking for non-Debug builds diff --git a/Misc/NEWS.d/next/Windows/2022-05-19-21-44-25.gh-issue-92817.Jrf-Kv.rst b/Misc/NEWS.d/next/Windows/2022-05-19-21-44-25.gh-issue-92817.Jrf-Kv.rst deleted file mode 100644 index 16acba1d6274..000000000000 --- a/Misc/NEWS.d/next/Windows/2022-05-19-21-44-25.gh-issue-92817.Jrf-Kv.rst +++ /dev/null @@ -1,3 +0,0 @@ -Ensures that :file:`py.exe` will prefer an active virtual environment over -default tags specified with environment variables or through a -:file:`py.ini` file. diff --git a/Misc/NEWS.d/next/Windows/2022-05-28-19-36-13.gh-issue-43414.NGMJ3g.rst b/Misc/NEWS.d/next/Windows/2022-05-28-19-36-13.gh-issue-43414.NGMJ3g.rst deleted file mode 100644 index 553e8762d5d1..000000000000 --- a/Misc/NEWS.d/next/Windows/2022-05-28-19-36-13.gh-issue-43414.NGMJ3g.rst +++ /dev/null @@ -1,2 +0,0 @@ -:func:`os.get_terminal_size` now attempts to read the size from any provided -handle, rather than only supporting file descriptors 0, 1 and 2. diff --git a/Misc/NEWS.d/next/Windows/2022-06-15-01-03-52.gh-issue-93824.mR4mxu.rst b/Misc/NEWS.d/next/Windows/2022-06-15-01-03-52.gh-issue-93824.mR4mxu.rst deleted file mode 100644 index cabe983847c8..000000000000 --- a/Misc/NEWS.d/next/Windows/2022-06-15-01-03-52.gh-issue-93824.mR4mxu.rst +++ /dev/null @@ -1,2 +0,0 @@ -Drag and drop of files onto Python files in Windows Explorer has been -enabled for Windows ARM64. diff --git a/Misc/NEWS.d/next/Windows/2022-06-20-22-32-14.gh-issue-94018.bycC3A.rst b/Misc/NEWS.d/next/Windows/2022-06-20-22-32-14.gh-issue-94018.bycC3A.rst deleted file mode 100644 index a2e558b3b4b3..000000000000 --- a/Misc/NEWS.d/next/Windows/2022-06-20-22-32-14.gh-issue-94018.bycC3A.rst +++ /dev/null @@ -1 +0,0 @@ -:mod:`zipfile` will now remove trailing spaces from path components when extracting files on Windows. diff --git a/Misc/NEWS.d/next/Windows/2022-07-12-20-45-43.gh-issue-94772.uNMmdG.rst b/Misc/NEWS.d/next/Windows/2022-07-12-20-45-43.gh-issue-94772.uNMmdG.rst deleted file mode 100644 index bb5ab754484e..000000000000 --- a/Misc/NEWS.d/next/Windows/2022-07-12-20-45-43.gh-issue-94772.uNMmdG.rst +++ /dev/null @@ -1 +0,0 @@ -Fix incorrect handling of shebang lines in py.exe launcher diff --git a/Misc/NEWS.d/next/Windows/2022-07-16-16-18-32.gh-issue-90844.vwITT3.rst b/Misc/NEWS.d/next/Windows/2022-07-16-16-18-32.gh-issue-90844.vwITT3.rst deleted file mode 100644 index 8d9e850a5b5b..000000000000 --- a/Misc/NEWS.d/next/Windows/2022-07-16-16-18-32.gh-issue-90844.vwITT3.rst +++ /dev/null @@ -1,2 +0,0 @@ -Allow virtual environments to correctly launch when they have spaces in the -path. diff --git a/Misc/NEWS.d/next/Windows/2022-07-26-20-33-12.gh-issue-95285.w6fa22.rst b/Misc/NEWS.d/next/Windows/2022-07-26-20-33-12.gh-issue-95285.w6fa22.rst deleted file mode 100644 index 76b38e7803cc..000000000000 --- a/Misc/NEWS.d/next/Windows/2022-07-26-20-33-12.gh-issue-95285.w6fa22.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix :ref:`launcher` handling of command lines where it is only passed a -short executable name. diff --git a/Misc/NEWS.d/next/Windows/2022-07-28-20-21-38.gh-issue-95359.ywMrgu.rst b/Misc/NEWS.d/next/Windows/2022-07-28-20-21-38.gh-issue-95359.ywMrgu.rst deleted file mode 100644 index 513a2be28a9c..000000000000 --- a/Misc/NEWS.d/next/Windows/2022-07-28-20-21-38.gh-issue-95359.ywMrgu.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix :ref:`launcher` handling of :file:`py.ini` commands (it was incorrectly -expecting a ``py_`` prefix on keys) and crashes when reading per-user -configuration file. diff --git a/Misc/NEWS.d/next/Windows/2022-07-30-14-18-33.gh-issue-95445.mjrTaq.rst b/Misc/NEWS.d/next/Windows/2022-07-30-14-18-33.gh-issue-95445.mjrTaq.rst deleted file mode 100644 index 565489ebf909..000000000000 --- a/Misc/NEWS.d/next/Windows/2022-07-30-14-18-33.gh-issue-95445.mjrTaq.rst +++ /dev/null @@ -1 +0,0 @@ -Fixes the unsuccessful removal of the HTML document directory when uninstalling with Windows msi. diff --git a/Misc/NEWS.d/next/Windows/2022-08-03-00-49-46.gh-issue-94399.KvxHc0.rst b/Misc/NEWS.d/next/Windows/2022-08-03-00-49-46.gh-issue-94399.KvxHc0.rst deleted file mode 100644 index a49e99ca2665..000000000000 --- a/Misc/NEWS.d/next/Windows/2022-08-03-00-49-46.gh-issue-94399.KvxHc0.rst +++ /dev/null @@ -1,3 +0,0 @@ -Restores the behaviour of :ref:`launcher` for ``/usr/bin/env`` shebang -lines, which will now search :envvar:`PATH` for an executable matching the -given command. If none is found, the usual search process is used. diff --git a/Misc/NEWS.d/next/Windows/2022-08-04-01-12-27.gh-issue-95587.Fvdv5q.rst b/Misc/NEWS.d/next/Windows/2022-08-04-01-12-27.gh-issue-95587.Fvdv5q.rst deleted file mode 100644 index 1033e892876c..000000000000 --- a/Misc/NEWS.d/next/Windows/2022-08-04-01-12-27.gh-issue-95587.Fvdv5q.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixes some issues where the Windows installer would incorrectly detect -certain features of an existing install when upgrading. diff --git a/Misc/NEWS.d/next/Windows/2022-08-04-18-47-54.gh-issue-95656.VJ1d13.rst b/Misc/NEWS.d/next/Windows/2022-08-04-18-47-54.gh-issue-95656.VJ1d13.rst deleted file mode 100644 index 77fea4c33f7a..000000000000 --- a/Misc/NEWS.d/next/Windows/2022-08-04-18-47-54.gh-issue-95656.VJ1d13.rst +++ /dev/null @@ -1,2 +0,0 @@ -Enable the :meth:`~sqlite3.Connection.enable_load_extension` :mod:`sqlite3` -API. diff --git a/Misc/NEWS.d/next/Windows/2022-08-10-22-46-48.gh-issue-95733.2_urOp.rst b/Misc/NEWS.d/next/Windows/2022-08-10-22-46-48.gh-issue-95733.2_urOp.rst deleted file mode 100644 index 996209211690..000000000000 --- a/Misc/NEWS.d/next/Windows/2022-08-10-22-46-48.gh-issue-95733.2_urOp.rst +++ /dev/null @@ -1,2 +0,0 @@ -Make certain requirements of the Windows Store package optional to allow -installing on earlier updates of Windows. diff --git a/Misc/NEWS.d/next/Windows/2022-08-26-00-11-18.gh-issue-89545.zmJMY_.rst b/Misc/NEWS.d/next/Windows/2022-08-26-00-11-18.gh-issue-89545.zmJMY_.rst deleted file mode 100644 index eeedbf9d6fa8..000000000000 --- a/Misc/NEWS.d/next/Windows/2022-08-26-00-11-18.gh-issue-89545.zmJMY_.rst +++ /dev/null @@ -1 +0,0 @@ -Updates :mod:`platform` code getting the Windows version to use native Windows Management Instrumentation (WMI) queries to determine OS version, type, and architecture. diff --git a/Misc/NEWS.d/next/Windows/2022-08-30-12-01-51.gh-issue-94781.OxO-Gr.rst b/Misc/NEWS.d/next/Windows/2022-08-30-12-01-51.gh-issue-94781.OxO-Gr.rst deleted file mode 100644 index 2eaa83fa850d..000000000000 --- a/Misc/NEWS.d/next/Windows/2022-08-30-12-01-51.gh-issue-94781.OxO-Gr.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix :file:`pcbuild.proj` to clean previous instances of output files in ``Python\deepfreeze`` and -``Python\frozen_modules`` directories on Windows. Patch by Charlie Zhao. diff --git a/Misc/NEWS.d/next/Windows/2022-09-05-18-32-47.gh-issue-96559.561sUd.rst b/Misc/NEWS.d/next/Windows/2022-09-05-18-32-47.gh-issue-96559.561sUd.rst deleted file mode 100644 index 275617648f92..000000000000 --- a/Misc/NEWS.d/next/Windows/2022-09-05-18-32-47.gh-issue-96559.561sUd.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fixes the Windows launcher not using the compatible interpretation of -default tags found in configuration files when no tag was passed to the -command. diff --git a/Misc/NEWS.d/next/Windows/2022-09-07-00-11-33.gh-issue-96577.kV4K_1.rst b/Misc/NEWS.d/next/Windows/2022-09-07-00-11-33.gh-issue-96577.kV4K_1.rst deleted file mode 100644 index 6025e5ce4130..000000000000 --- a/Misc/NEWS.d/next/Windows/2022-09-07-00-11-33.gh-issue-96577.kV4K_1.rst +++ /dev/null @@ -1 +0,0 @@ -Fixes a potential buffer overrun in :mod:`msilib`. diff --git a/Misc/NEWS.d/next/Windows/2022-09-23-15-40-04.gh-issue-96965.CsnEGs.rst b/Misc/NEWS.d/next/Windows/2022-09-23-15-40-04.gh-issue-96965.CsnEGs.rst deleted file mode 100644 index de7aff0563e5..000000000000 --- a/Misc/NEWS.d/next/Windows/2022-09-23-15-40-04.gh-issue-96965.CsnEGs.rst +++ /dev/null @@ -1 +0,0 @@ -Update libffi to 3.4.3 diff --git a/Misc/NEWS.d/next/Windows/2022-09-29-22-27-04.gh-issue-97649.bI7OQU.rst b/Misc/NEWS.d/next/Windows/2022-09-29-22-27-04.gh-issue-97649.bI7OQU.rst deleted file mode 100644 index 118f9df7c89d..000000000000 --- a/Misc/NEWS.d/next/Windows/2022-09-29-22-27-04.gh-issue-97649.bI7OQU.rst +++ /dev/null @@ -1 +0,0 @@ -The ``Tools`` directory is no longer installed on Windows diff --git a/Misc/NEWS.d/next/Windows/2022-09-29-23-08-49.gh-issue-90989.no89Q2.rst b/Misc/NEWS.d/next/Windows/2022-09-29-23-08-49.gh-issue-90989.no89Q2.rst deleted file mode 100644 index 786b3435042d..000000000000 --- a/Misc/NEWS.d/next/Windows/2022-09-29-23-08-49.gh-issue-90989.no89Q2.rst +++ /dev/null @@ -1,2 +0,0 @@ -Made :ref:`launcher` install per-user by default (unless an all users -install already exists), and clarify some text in the installer. diff --git a/Misc/NEWS.d/next/Windows/2022-10-02-11-59-23.gh-issue-97728.dIdlPE.rst b/Misc/NEWS.d/next/Windows/2022-10-02-11-59-23.gh-issue-97728.dIdlPE.rst deleted file mode 100644 index 2a6a253a52ae..000000000000 --- a/Misc/NEWS.d/next/Windows/2022-10-02-11-59-23.gh-issue-97728.dIdlPE.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix possible crashes caused by the use of uninitialized variables when pass -invalid arguments in :func:`os.system` on Windows and in Windows-specific -modules (like ``winreg``). diff --git a/Misc/NEWS.d/next/Windows/2022-10-19-19-35-37.gh-issue-98414.FbHZuS.rst b/Misc/NEWS.d/next/Windows/2022-10-19-19-35-37.gh-issue-98414.FbHZuS.rst deleted file mode 100644 index df07b7f547df..000000000000 --- a/Misc/NEWS.d/next/Windows/2022-10-19-19-35-37.gh-issue-98414.FbHZuS.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix :file:`py.exe` launcher handling of ``-V:/`` option when -default preferences have been set in environment variables or configuration -files. diff --git a/Misc/NEWS.d/next/Windows/2022-10-19-20-00-28.gh-issue-98360.O2m6YG.rst b/Misc/NEWS.d/next/Windows/2022-10-19-20-00-28.gh-issue-98360.O2m6YG.rst deleted file mode 100644 index 61c1e5e837fe..000000000000 --- a/Misc/NEWS.d/next/Windows/2022-10-19-20-00-28.gh-issue-98360.O2m6YG.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fixes :mod:`multiprocessing` spawning child processes on Windows from a -virtual environment to ensure that child processes that also use -:mod:`multiprocessing` to spawn more children will recognize that they are -in a virtual environment. diff --git a/Misc/NEWS.d/next/macOS/2022-10-05-15-26-58.gh-issue-97897.Rf-C6u.rst b/Misc/NEWS.d/next/macOS/2022-10-05-15-26-58.gh-issue-97897.Rf-C6u.rst deleted file mode 100644 index 0d21e98b37c5..000000000000 --- a/Misc/NEWS.d/next/macOS/2022-10-05-15-26-58.gh-issue-97897.Rf-C6u.rst +++ /dev/null @@ -1,6 +0,0 @@ -The macOS 13 SDK includes support for the ``mkfifoat`` and ``mknodat`` system calls. -Using the ``dir_fd`` option with either :func:`os.mkfifo` or :func:`os.mknod` could result in a -segfault if cpython is built with the macOS 13 SDK but run on an earlier -version of macOS. Prevent this by adding runtime support for detection of -these system calls ("weaklinking") as is done for other newer syscalls on -macOS. diff --git a/README.rst b/README.rst index 8227ae748d39..577dccde70be 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -This is Python version 3.12.0 alpha 0 +This is Python version 3.12.0 alpha 1 ===================================== .. image:: https://github.com/python/cpython/workflows/Tests/badge.svg From webhook-mailer at python.org Mon Oct 24 23:02:52 2022 From: webhook-mailer at python.org (corona10) Date: Tue, 25 Oct 2022 03:02:52 -0000 Subject: [Python-checkins] =?utf-8?q?=5B3=2E10=5D_gh-98456=3A_Replace_dep?= =?utf-8?q?recated_=60set-output=60_with_up-to-date_vers=E2=80=A6_=28gh-98?= =?utf-8?q?564=29?= Message-ID: https://github.com/python/cpython/commit/25eae0b6c261b8bab4b82fb4e404cd73dbfc15ea commit: 25eae0b6c261b8bab4b82fb4e404cd73dbfc15ea branch: 3.10 author: Dong-hee Na committer: corona10 date: 2022-10-25T12:02:47+09:00 summary: [3.10] gh-98456: Replace deprecated `set-output` with up-to-date vers? (gh-98564) [3.10] gh-98456: Replace deprecated `set-output` with up-to-date version (gh-98457). (cherry picked from commit 1db2a0cb20a1de5231a73fc7381056d725e90535) Co-authored-by: Noam Cohen Co-authored-by: Noam Cohen files: M .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ba23c72586d4..630c238c9918 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -39,8 +39,8 @@ jobs: id: check run: | if [ -z "$GITHUB_BASE_REF" ]; then - echo '::set-output name=run_tests::true' - echo '::set-output name=run_ssl_tests::true' + echo "run_tests=true" >> $GITHUB_OUTPUT + echo "run_ssl_tests=true" >> $GITHUB_OUTPUT else git fetch origin $GITHUB_BASE_REF --depth=1 # git diff "origin/$GITHUB_BASE_REF..." (3 dots) may be more @@ -56,8 +56,8 @@ jobs: # into the PR branch anyway. # # https://github.com/python/core-workflow/issues/373 - git diff --name-only origin/$GITHUB_BASE_REF.. | grep -qvE '(\.rst$|^Doc|^Misc)' && echo '::set-output name=run_tests::true' || true - git diff --name-only origin/$GITHUB_BASE_REF.. | grep -qE '(ssl|hashlib|hmac|^.github)' && echo '::set-output name=run_ssl_tests::true' || true + git diff --name-only origin/$GITHUB_BASE_REF.. | grep -qvE '(\.rst$|^Doc|^Misc)' && echo "run_tests=true" >> $GITHUB_OUTPUT || true + git diff --name-only origin/$GITHUB_BASE_REF.. | grep -qE '(ssl|hashlib|hmac|^.github)' && echo "run_ssl_tests=true" >> $GITHUB_OUTPUT || true fi check_abi: From webhook-mailer at python.org Mon Oct 24 23:03:08 2022 From: webhook-mailer at python.org (corona10) Date: Tue, 25 Oct 2022 03:03:08 -0000 Subject: [Python-checkins] =?utf-8?q?=5B3=2E11=5D_gh-98456=3A_Replace_dep?= =?utf-8?q?recated_=60set-output=60_with_up-to-date_vers=E2=80=A6_=28gh-98?= =?utf-8?q?565=29?= Message-ID: https://github.com/python/cpython/commit/5fb3b6111461f513b9566c9dcc96dff2a1ca8840 commit: 5fb3b6111461f513b9566c9dcc96dff2a1ca8840 branch: 3.11 author: Dong-hee Na committer: corona10 date: 2022-10-25T12:03:02+09:00 summary: [3.11] gh-98456: Replace deprecated `set-output` with up-to-date vers? (gh-98565) [3.11] gh-98456: Replace deprecated `set-output` with up-to-date version (gh-98457). (cherry picked from commit 1db2a0cb20a1de5231a73fc7381056d725e90535) Co-authored-by: Noam Cohen Co-authored-by: Noam Cohen files: M .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cba0eac83ca8..38dbb131575a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -42,8 +42,8 @@ jobs: id: check run: | if [ -z "$GITHUB_BASE_REF" ]; then - echo '::set-output name=run_tests::true' - echo '::set-output name=run_ssl_tests::true' + echo "run_tests=true" >> $GITHUB_OUTPUT + echo "run_ssl_tests=true" >> $GITHUB_OUTPUT else git fetch origin $GITHUB_BASE_REF --depth=1 # git diff "origin/$GITHUB_BASE_REF..." (3 dots) may be more @@ -59,8 +59,8 @@ jobs: # into the PR branch anyway. # # https://github.com/python/core-workflow/issues/373 - git diff --name-only origin/$GITHUB_BASE_REF.. | grep -qvE '(\.rst$|^Doc|^Misc)' && echo '::set-output name=run_tests::true' || true - git diff --name-only origin/$GITHUB_BASE_REF.. | grep -qE '(ssl|hashlib|hmac|^.github)' && echo '::set-output name=run_ssl_tests::true' || true + git diff --name-only origin/$GITHUB_BASE_REF.. | grep -qvE '(\.rst$|^Doc|^Misc)' && echo "run_tests=true" >> $GITHUB_OUTPUT || true + git diff --name-only origin/$GITHUB_BASE_REF.. | grep -qE '(ssl|hashlib|hmac|^.github)' && echo "run_ssl_tests=true" >> $GITHUB_OUTPUT || true fi check_abi: From webhook-mailer at python.org Mon Oct 24 23:34:13 2022 From: webhook-mailer at python.org (gvanrossum) Date: Tue, 25 Oct 2022 03:34:13 -0000 Subject: [Python-checkins] [3.11] GH-89237: fix hang in proactor `subprocess.wait_closed()` (GH-98572) (#98620) Message-ID: https://github.com/python/cpython/commit/8950689dcecbab3229f9630c4f7b142414e5907b commit: 8950689dcecbab3229f9630c4f7b142414e5907b branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: gvanrossum date: 2022-10-24T20:34:08-07:00 summary: [3.11] GH-89237: fix hang in proactor `subprocess.wait_closed()` (GH-98572) (#98620) GH-89237: fix hang in proactor `subprocess.wait_closed()` (GH-98572) (cherry picked from commit ad1dc3ebb6aadaeeeacde13d4ed2d62bf302bf62) Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> files: A Misc/NEWS.d/next/Library/2022-10-23-18-30-39.gh-issue-89237.kBui30.rst M Lib/asyncio/proactor_events.py M Lib/test/test_asyncio/test_proactor_events.py diff --git a/Lib/asyncio/proactor_events.py b/Lib/asyncio/proactor_events.py index ddb9daca0269..2685a3376cfd 100644 --- a/Lib/asyncio/proactor_events.py +++ b/Lib/asyncio/proactor_events.py @@ -60,6 +60,7 @@ def __init__(self, loop, sock, protocol, waiter=None, self._pending_write = 0 self._conn_lost = 0 self._closing = False # Set when close() called. + self._called_connection_lost = False self._eof_written = False if self._server is not None: self._server._attach() @@ -136,7 +137,7 @@ def _force_close(self, exc): self._empty_waiter.set_result(None) else: self._empty_waiter.set_exception(exc) - if self._closing: + if self._closing and self._called_connection_lost: return self._closing = True self._conn_lost += 1 @@ -166,6 +167,7 @@ def _call_connection_lost(self, exc): if server is not None: server._detach() self._server = None + self._called_connection_lost = True def get_write_buffer_size(self): size = self._pending_write diff --git a/Lib/test/test_asyncio/test_proactor_events.py b/Lib/test/test_asyncio/test_proactor_events.py index 7fca0541ee75..7fd8b261cd5e 100644 --- a/Lib/test/test_asyncio/test_proactor_events.py +++ b/Lib/test/test_asyncio/test_proactor_events.py @@ -290,7 +290,12 @@ def test_force_close_idempotent(self): tr._closing = True tr._force_close(None) test_utils.run_briefly(self.loop) - self.assertFalse(self.protocol.connection_lost.called) + # See https://github.com/python/cpython/issues/89237 + # `protocol.connection_lost` should be called even if + # the transport was closed forcefully otherwise + # the resources held by protocol will never be freed + # and waiters will never be notified leading to hang. + self.assertTrue(self.protocol.connection_lost.called) def test_fatal_error_2(self): tr = self.socket_transport() diff --git a/Misc/NEWS.d/next/Library/2022-10-23-18-30-39.gh-issue-89237.kBui30.rst b/Misc/NEWS.d/next/Library/2022-10-23-18-30-39.gh-issue-89237.kBui30.rst new file mode 100644 index 000000000000..668ea4c7a4ea --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-23-18-30-39.gh-issue-89237.kBui30.rst @@ -0,0 +1 @@ +Fix hang on Windows in ``subprocess.wait_closed()`` in :mod:`asyncio` with :class:`~asyncio.ProactorEventLoop`. Patch by Kumar Aditya. From webhook-mailer at python.org Tue Oct 25 06:49:50 2022 From: webhook-mailer at python.org (erlend-aasland) Date: Tue, 25 Oct 2022 10:49:50 -0000 Subject: [Python-checkins] gh-94328: Update macOS installer to use SQLite 3.39.4. (#98639) Message-ID: https://github.com/python/cpython/commit/8aa1e994a530e538a5433c8ada6500ffc1214467 commit: 8aa1e994a530e538a5433c8ada6500ffc1214467 branch: main author: Erlend E. Aasland committer: erlend-aasland date: 2022-10-25T12:49:44+02:00 summary: gh-94328: Update macOS installer to use SQLite 3.39.4. (#98639) files: A Misc/NEWS.d/next/macOS/2022-10-25-10-32-23.gh-issue-94328.W3YNC_.rst M Mac/BuildScript/build-installer.py diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py index 9fd87f3361fd..b789e30946a8 100755 --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -360,9 +360,9 @@ def library_recipes(): ), ), dict( - name="SQLite 3.38.4", - url="https://sqlite.org/2022/sqlite-autoconf-3380400.tar.gz", - checksum="34c0b92a0609ed4ce78582e8dc1ed45a", + name="SQLite 3.39.4", + url="https://sqlite.org/2022/sqlite-autoconf-3390400.tar.gz", + checksum="44b7e6691b0954086f717a6c43b622a5", extra_cflags=('-Os ' '-DSQLITE_ENABLE_FTS5 ' '-DSQLITE_ENABLE_FTS4 ' diff --git a/Misc/NEWS.d/next/macOS/2022-10-25-10-32-23.gh-issue-94328.W3YNC_.rst b/Misc/NEWS.d/next/macOS/2022-10-25-10-32-23.gh-issue-94328.W3YNC_.rst new file mode 100644 index 000000000000..cbef54d17a82 --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2022-10-25-10-32-23.gh-issue-94328.W3YNC_.rst @@ -0,0 +1 @@ +Update macOS installer to SQLite 3.39.4. From webhook-mailer at python.org Tue Oct 25 07:18:07 2022 From: webhook-mailer at python.org (miss-islington) Date: Tue, 25 Oct 2022 11:18:07 -0000 Subject: [Python-checkins] gh-94328: Update macOS installer to use SQLite 3.39.4. (GH-98639) Message-ID: https://github.com/python/cpython/commit/febbb4b819d0ec78b338960cfb99768b2dcb4050 commit: febbb4b819d0ec78b338960cfb99768b2dcb4050 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-25T04:18:01-07:00 summary: gh-94328: Update macOS installer to use SQLite 3.39.4. (GH-98639) (cherry picked from commit 8aa1e994a530e538a5433c8ada6500ffc1214467) Co-authored-by: Erlend E. Aasland files: A Misc/NEWS.d/next/macOS/2022-10-25-10-32-23.gh-issue-94328.W3YNC_.rst M Mac/BuildScript/build-installer.py diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py index dd6bcf5fe7f1..86eed5ff9569 100755 --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -359,9 +359,9 @@ def library_recipes(): ), ), dict( - name="SQLite 3.38.4", - url="https://sqlite.org/2022/sqlite-autoconf-3380400.tar.gz", - checksum="34c0b92a0609ed4ce78582e8dc1ed45a", + name="SQLite 3.39.4", + url="https://sqlite.org/2022/sqlite-autoconf-3390400.tar.gz", + checksum="44b7e6691b0954086f717a6c43b622a5", extra_cflags=('-Os ' '-DSQLITE_ENABLE_FTS5 ' '-DSQLITE_ENABLE_FTS4 ' diff --git a/Misc/NEWS.d/next/macOS/2022-10-25-10-32-23.gh-issue-94328.W3YNC_.rst b/Misc/NEWS.d/next/macOS/2022-10-25-10-32-23.gh-issue-94328.W3YNC_.rst new file mode 100644 index 000000000000..cbef54d17a82 --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2022-10-25-10-32-23.gh-issue-94328.W3YNC_.rst @@ -0,0 +1 @@ +Update macOS installer to SQLite 3.39.4. From webhook-mailer at python.org Tue Oct 25 07:26:44 2022 From: webhook-mailer at python.org (iritkatriel) Date: Tue, 25 Oct 2022 11:26:44 -0000 Subject: [Python-checkins] gh-98461: Fix location of RETURN_VALUE in async generator bytecode. compiler_jump_if no longer needs a pointer to the loc. (GH-98494) Message-ID: https://github.com/python/cpython/commit/a1a8828e42a3ce08374655201fd49ab0137823cc commit: a1a8828e42a3ce08374655201fd49ab0137823cc branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2022-10-25T12:26:26+01:00 summary: gh-98461: Fix location of RETURN_VALUE in async generator bytecode. compiler_jump_if no longer needs a pointer to the loc. (GH-98494) files: M Lib/test/test_compile.py M Python/compile.c diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index a59d692876b6..27f91dbcd63a 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -1283,7 +1283,7 @@ def test_multiline_async_generator_expression(self): self.assertOpcodeSourcePositionIs(compiled_code, 'YIELD_VALUE', line=1, end_line=2, column=1, end_column=8, occurrence=2) self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_VALUE', - line=6, end_line=6, column=23, end_column=30, occurrence=1) + line=1, end_line=6, column=0, end_column=32, occurrence=1) def test_multiline_list_comprehension(self): snippet = """\ diff --git a/Python/compile.c b/Python/compile.c index 676558b0f409..67ccd2239381 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -2873,13 +2873,14 @@ static int compiler_addcompare(struct compiler *c, location loc, static int -compiler_jump_if(struct compiler *c, location *ploc, +compiler_jump_if(struct compiler *c, location loc, expr_ty e, jump_target_label next, int cond) { switch (e->kind) { case UnaryOp_kind: - if (e->v.UnaryOp.op == Not) - return compiler_jump_if(c, ploc, e->v.UnaryOp.operand, next, !cond); + if (e->v.UnaryOp.op == Not) { + return compiler_jump_if(c, loc, e->v.UnaryOp.operand, next, !cond); + } /* fallback to general implementation */ break; case BoolOp_kind: { @@ -2893,11 +2894,13 @@ compiler_jump_if(struct compiler *c, location *ploc, next2 = new_next2; } for (i = 0; i < n; ++i) { - if (!compiler_jump_if(c, ploc, (expr_ty)asdl_seq_GET(s, i), next2, cond2)) + if (!compiler_jump_if(c, loc, (expr_ty)asdl_seq_GET(s, i), next2, cond2)) { return 0; + } } - if (!compiler_jump_if(c, ploc, (expr_ty)asdl_seq_GET(s, n), next, cond)) + if (!compiler_jump_if(c, loc, (expr_ty)asdl_seq_GET(s, n), next, cond)) { return 0; + } if (!SAME_LABEL(next2, next)) { USE_LABEL(c, next2); } @@ -2906,45 +2909,46 @@ compiler_jump_if(struct compiler *c, location *ploc, case IfExp_kind: { NEW_JUMP_TARGET_LABEL(c, end); NEW_JUMP_TARGET_LABEL(c, next2); - if (!compiler_jump_if(c, ploc, e->v.IfExp.test, next2, 0)) + if (!compiler_jump_if(c, loc, e->v.IfExp.test, next2, 0)) { return 0; - if (!compiler_jump_if(c, ploc, e->v.IfExp.body, next, cond)) + } + if (!compiler_jump_if(c, loc, e->v.IfExp.body, next, cond)) { return 0; + } ADDOP_JUMP(c, NO_LOCATION, JUMP, end); USE_LABEL(c, next2); - if (!compiler_jump_if(c, ploc, e->v.IfExp.orelse, next, cond)) + if (!compiler_jump_if(c, loc, e->v.IfExp.orelse, next, cond)) { return 0; + } USE_LABEL(c, end); return 1; } case Compare_kind: { - SET_LOC(c, e); - *ploc = LOC(e); - Py_ssize_t i, n = asdl_seq_LEN(e->v.Compare.ops) - 1; + Py_ssize_t n = asdl_seq_LEN(e->v.Compare.ops) - 1; if (n > 0) { if (!check_compare(c, e)) { return 0; } NEW_JUMP_TARGET_LABEL(c, cleanup); VISIT(c, expr, e->v.Compare.left); - for (i = 0; i < n; i++) { + for (Py_ssize_t i = 0; i < n; i++) { VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, i)); - ADDOP_I(c, *ploc, SWAP, 2); - ADDOP_I(c, *ploc, COPY, 2); - ADDOP_COMPARE(c, *ploc, asdl_seq_GET(e->v.Compare.ops, i)); - ADDOP_JUMP(c, *ploc, POP_JUMP_IF_FALSE, cleanup); + ADDOP_I(c, LOC(e), SWAP, 2); + ADDOP_I(c, LOC(e), COPY, 2); + ADDOP_COMPARE(c, LOC(e), asdl_seq_GET(e->v.Compare.ops, i)); + ADDOP_JUMP(c, LOC(e), POP_JUMP_IF_FALSE, cleanup); } VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, n)); - ADDOP_COMPARE(c, *ploc, asdl_seq_GET(e->v.Compare.ops, n)); - ADDOP_JUMP(c, *ploc, cond ? POP_JUMP_IF_TRUE : POP_JUMP_IF_FALSE, next); + ADDOP_COMPARE(c, LOC(e), asdl_seq_GET(e->v.Compare.ops, n)); + ADDOP_JUMP(c, LOC(e), cond ? POP_JUMP_IF_TRUE : POP_JUMP_IF_FALSE, next); NEW_JUMP_TARGET_LABEL(c, end); ADDOP_JUMP(c, NO_LOCATION, JUMP, end); USE_LABEL(c, cleanup); - ADDOP(c, *ploc, POP_TOP); + ADDOP(c, LOC(e), POP_TOP); if (!cond) { ADDOP_JUMP(c, NO_LOCATION, JUMP, next); } @@ -2973,8 +2977,7 @@ compiler_ifexp(struct compiler *c, expr_ty e) NEW_JUMP_TARGET_LABEL(c, end); NEW_JUMP_TARGET_LABEL(c, next); - location loc = LOC(e); - if (!compiler_jump_if(c, &loc, e->v.IfExp.test, next, 0)) { + if (!compiler_jump_if(c, LOC(e), e->v.IfExp.test, next, 0)) { return 0; } VISIT(c, expr, e->v.IfExp.body); @@ -3059,8 +3062,7 @@ compiler_if(struct compiler *c, stmt_ty s) else { next = end; } - location loc = LOC(s); - if (!compiler_jump_if(c, &loc, s->v.If.test, next, 0)) { + if (!compiler_jump_if(c, LOC(s), s->v.If.test, next, 0)) { return 0; } VISIT_SEQ(c, stmt, s->v.If.body); @@ -3167,25 +3169,22 @@ compiler_async_for(struct compiler *c, stmt_ty s) static int compiler_while(struct compiler *c, stmt_ty s) { - location loc = LOC(s); NEW_JUMP_TARGET_LABEL(c, loop); NEW_JUMP_TARGET_LABEL(c, body); NEW_JUMP_TARGET_LABEL(c, end); NEW_JUMP_TARGET_LABEL(c, anchor); USE_LABEL(c, loop); - if (!compiler_push_fblock(c, loc, WHILE_LOOP, loop, end, NULL)) { + if (!compiler_push_fblock(c, LOC(s), WHILE_LOOP, loop, end, NULL)) { return 0; } - if (!compiler_jump_if(c, &loc, s->v.While.test, anchor, 0)) { + if (!compiler_jump_if(c, LOC(s), s->v.While.test, anchor, 0)) { return 0; } USE_LABEL(c, body); VISIT_SEQ(c, stmt, s->v.While.body); - SET_LOC(c, s); - loc = LOC(s); - if (!compiler_jump_if(c, &loc, s->v.While.test, body, 1)) { + if (!compiler_jump_if(c, LOC(s), s->v.While.test, body, 1)) { return 0; } @@ -3986,8 +3985,7 @@ compiler_assert(struct compiler *c, stmt_ty s) return 1; } NEW_JUMP_TARGET_LABEL(c, end); - location loc = LOC(s); - if (!compiler_jump_if(c, &loc, s->v.Assert.test, end, 1)) { + if (!compiler_jump_if(c, LOC(s), s->v.Assert.test, end, 1)) { return 0; } ADDOP(c, LOC(s), LOAD_ASSERTION_ERROR); @@ -4017,18 +4015,13 @@ compiler_stmt_expr(struct compiler *c, location loc, expr_ty value) } VISIT(c, expr, value); - /* Mark POP_TOP as artificial */ - UNSET_LOC(c); - ADDOP(c, NO_LOCATION, POP_TOP); + ADDOP(c, NO_LOCATION, POP_TOP); /* artificial */ return 1; } static int compiler_visit_stmt(struct compiler *c, stmt_ty s) { - Py_ssize_t i, n; - /* Always assign a lineno to the next instruction for a stmt. */ - SET_LOC(c, s); switch (s->kind) { case FunctionDef_kind: @@ -4042,12 +4035,11 @@ compiler_visit_stmt(struct compiler *c, stmt_ty s) break; case Assign_kind: { - n = asdl_seq_LEN(s->v.Assign.targets); + Py_ssize_t n = asdl_seq_LEN(s->v.Assign.targets); VISIT(c, expr, s->v.Assign.value); - location loc = LOC(s); - for (i = 0; i < n; i++) { + for (Py_ssize_t i = 0; i < n; i++) { if (i < n - 1) { - ADDOP_I(c, loc, COPY, 1); + ADDOP_I(c, LOC(s), COPY, 1); } VISIT(c, expr, (expr_ty)asdl_seq_GET(s->v.Assign.targets, i)); @@ -4068,7 +4060,7 @@ compiler_visit_stmt(struct compiler *c, stmt_ty s) return compiler_match(c, s); case Raise_kind: { - n = 0; + Py_ssize_t n = 0; if (s->v.Raise.exc) { VISIT(c, expr, s->v.Raise.exc); n++; @@ -4077,8 +4069,7 @@ compiler_visit_stmt(struct compiler *c, stmt_ty s) n++; } } - location loc = LOC(s); - ADDOP_I(c, loc, RAISE_VARARGS, (int)n); + ADDOP_I(c, LOC(s), RAISE_VARARGS, (int)n); break; } case Try_kind: @@ -4096,24 +4087,20 @@ compiler_visit_stmt(struct compiler *c, stmt_ty s) break; case Expr_kind: { - location loc = LOC(s); - return compiler_stmt_expr(c, loc, s->v.Expr.value); + return compiler_stmt_expr(c, LOC(s), s->v.Expr.value); } case Pass_kind: { - location loc = LOC(s); - ADDOP(c, loc, NOP); + ADDOP(c, LOC(s), NOP); break; } case Break_kind: { - location loc = LOC(s); - return compiler_break(c, loc); + return compiler_break(c, LOC(s)); } case Continue_kind: { - location loc = LOC(s); - return compiler_continue(c, loc); + return compiler_continue(c, LOC(s)); } case With_kind: return compiler_with(c, s, 0); @@ -5275,7 +5262,7 @@ compiler_sync_comprehension_generator(struct compiler *c, location loc, Py_ssize_t n = asdl_seq_LEN(gen->ifs); for (Py_ssize_t i = 0; i < n; i++) { expr_ty e = (expr_ty)asdl_seq_GET(gen->ifs, i); - if (!compiler_jump_if(c, &loc, e, if_cleanup, 0)) { + if (!compiler_jump_if(c, loc, e, if_cleanup, 0)) { return 0; } } @@ -5374,7 +5361,7 @@ compiler_async_comprehension_generator(struct compiler *c, location loc, Py_ssize_t n = asdl_seq_LEN(gen->ifs); for (Py_ssize_t i = 0; i < n; i++) { expr_ty e = (expr_ty)asdl_seq_GET(gen->ifs, i); - if (!compiler_jump_if(c, &loc, e, if_cleanup, 0)) { + if (!compiler_jump_if(c, loc, e, if_cleanup, 0)) { return 0; } } @@ -7109,7 +7096,7 @@ compiler_match_inner(struct compiler *c, stmt_ty s, pattern_context *pc) // NOTE: Returning macros are safe again. if (m->guard) { RETURN_IF_FALSE(ensure_fail_pop(c, pc, 0)); - RETURN_IF_FALSE(compiler_jump_if(c, &loc, m->guard, pc->fail_pop[0], 0)); + RETURN_IF_FALSE(compiler_jump_if(c, loc, m->guard, pc->fail_pop[0], 0)); } // Success! Pop the subject off, we're done with it: if (i != cases - has_default - 1) { @@ -7138,7 +7125,7 @@ compiler_match_inner(struct compiler *c, stmt_ty s, pattern_context *pc) ADDOP(c, loc, NOP); } if (m->guard) { - RETURN_IF_FALSE(compiler_jump_if(c, &loc, m->guard, end, 0)); + RETURN_IF_FALSE(compiler_jump_if(c, loc, m->guard, end, 0)); } VISIT_SEQ(c, stmt, m->body); } From webhook-mailer at python.org Tue Oct 25 08:23:44 2022 From: webhook-mailer at python.org (erlend-aasland) Date: Tue, 25 Oct 2022 12:23:44 -0000 Subject: [Python-checkins] [3.10] gh-94328: Update macOS installer to use SQLite 3.39.4. (GH-98639) (#98647) Message-ID: https://github.com/python/cpython/commit/9387b7c1b3b852e90307804871df62c1f39cf7e2 commit: 9387b7c1b3b852e90307804871df62c1f39cf7e2 branch: 3.10 author: Erlend E. Aasland committer: erlend-aasland date: 2022-10-25T14:23:38+02:00 summary: [3.10] gh-94328: Update macOS installer to use SQLite 3.39.4. (GH-98639) (#98647) [3.10] gh-94328: Update macOS installer to use SQLite 3.39.4. (GH-98639). (cherry picked from commit 8aa1e994a530e538a5433c8ada6500ffc1214467) Co-authored-by: Erlend E. Aasland files: A Misc/NEWS.d/next/macOS/2022-10-25-10-32-23.gh-issue-94328.W3YNC_.rst M Mac/BuildScript/build-installer.py diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py index 67a6e4b2cf77..a200fb3fc942 100755 --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -359,9 +359,9 @@ def library_recipes(): ), ), dict( - name="SQLite 3.37.2", - url="https://sqlite.org/2022/sqlite-autoconf-3370200.tar.gz", - checksum='683cc5312ee74e71079c14d24b7a6d27', + name="SQLite 3.39.4", + url="https://sqlite.org/2022/sqlite-autoconf-3390400.tar.gz", + checksum="44b7e6691b0954086f717a6c43b622a5", extra_cflags=('-Os ' '-DSQLITE_ENABLE_FTS5 ' '-DSQLITE_ENABLE_FTS4 ' diff --git a/Misc/NEWS.d/next/macOS/2022-10-25-10-32-23.gh-issue-94328.W3YNC_.rst b/Misc/NEWS.d/next/macOS/2022-10-25-10-32-23.gh-issue-94328.W3YNC_.rst new file mode 100644 index 000000000000..cbef54d17a82 --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2022-10-25-10-32-23.gh-issue-94328.W3YNC_.rst @@ -0,0 +1 @@ +Update macOS installer to SQLite 3.39.4. From webhook-mailer at python.org Tue Oct 25 09:20:27 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Tue, 25 Oct 2022 13:20:27 -0000 Subject: [Python-checkins] gh-95913: Prepare Improved Modules in 3.11 WhatsNew for final edits (#98631) Message-ID: https://github.com/python/cpython/commit/dd13b23e49b8c49bc751fe5ed470773a2d60b7d1 commit: dd13b23e49b8c49bc751fe5ed470773a2d60b7d1 branch: main author: C.A.M. Gerlach committer: JelleZijlstra date: 2022-10-25T06:19:44-07:00 summary: gh-95913: Prepare Improved Modules in 3.11 WhatsNew for final edits (#98631) * Add two line breaks and ref target labels to remaining subsections * Fix a few out of order Improved Modules * Fix a few minor textual formatting issues in sections * Fix remaining Sphinx warnings in the Improved Modules section files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index deec42006850..cc8437f1709a 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -614,12 +614,18 @@ asyncio These are primarily intended for internal use, notably by :class:`~asyncio.TaskGroup`. + +.. _whatsnew311-contextlib: + contextlib ---------- -Added non parallel-safe :func:`~contextlib.chdir` context manager to change -the current working directory and then restore it on exit. Simple wrapper -around :func:`~os.chdir`. (Contributed by Filipe La?ns in :issue:`25625`) +* Added non parallel-safe :func:`~contextlib.chdir` context manager to change + the current working directory and then restore it on exit. Simple wrapper + around :func:`~os.chdir`. (Contributed by Filipe La?ns in :issue:`25625`) + + +.. _whatsnew311-dataclasses: dataclasses ----------- @@ -629,11 +635,15 @@ dataclasses :class:`dict`, :class:`list` or :class:`set`. (Contributed by Eric V. Smith in :issue:`44674`.) + +.. _whatsnew311-datetime: + datetime -------- * Add :attr:`datetime.UTC`, a convenience alias for :attr:`datetime.timezone.utc`. (Contributed by Kabir Kwatra in :gh:`91973`.) + * :meth:`datetime.date.fromisoformat`, :meth:`datetime.time.fromisoformat` and :meth:`datetime.datetime.fromisoformat` can now be used to parse most ISO 8601 formats (barring only those that support fractional hours and minutes). @@ -658,7 +668,7 @@ enum (used by :func:`str`, :func:`format` and :term:`f-string`\s). * Changed :class:`~enum.IntEnum`, :class:`~enum.IntFlag` and :class:`~enum.StrEnum` - to now inherit from :class:`ReprEnum`, + to now inherit from :class:`~enum.ReprEnum`, so their :func:`str` output now matches :func:`format` (both ``str(AnIntEnum.ONE)`` and ``format(AnIntEnum.ONE)`` return ``'1'``, whereas before ``str(AnIntEnum.ONE)`` returned ``'AnIntEnum.ONE'``. @@ -708,6 +718,18 @@ enum inverted flags are coerced to their positive equivalent. +.. _whatsnew311-fcntl: + +fcntl +----- + +* On FreeBSD, the :data:`!F_DUP2FD` and :data:`!F_DUP2FD_CLOEXEC` flags respectively + are supported, the former equals to ``dup2`` usage while the latter set + the ``FD_CLOEXEC`` flag in addition. + + +.. _whatsnew311-fractions: + fractions --------- @@ -718,6 +740,9 @@ fractions that an ``isinstance(some_fraction, typing.SupportsInt)`` check passes. (Contributed by Mark Dickinson in :issue:`44547`.) + +.. _whatsnew311-functools: + functools --------- @@ -748,6 +773,9 @@ functools (Contributed by Yurii Karabas in :issue:`46014`.) + +.. _whatsnew311-hashlib: + hashlib ------- @@ -766,6 +794,9 @@ hashlib of files or file-like objects. (Contributed by Christian Heimes in :gh:`89313`.) + +.. _whatsnew311-idle: + IDLE and idlelib ---------------- @@ -803,6 +834,9 @@ inspect (Contributed by Pablo Galindo in :gh:`88116`.) + +.. _whatsnew311-locale: + locale ------ @@ -830,6 +864,8 @@ logging (Contributed by Kirill Pinchuk in :gh:`88457`.) +.. _whatsnew311-math: + math ---- @@ -849,6 +885,8 @@ math (Contributed by Victor Stinner in :issue:`46917`.) +.. _whatsnew311-operator: + operator -------- @@ -857,6 +895,8 @@ operator (Contributed by Antony Lee in :issue:`44019`.) +.. _whatsnew311-os: + os -- @@ -865,6 +905,8 @@ os (Contributed by Dong-hee Na in :issue:`44611`.) +.. _whatsnew311-pathlib: + pathlib ------- @@ -873,6 +915,9 @@ pathlib :data:`~os.sep` or :data:`~os.altsep`. (Contributed by Eisuke Kawasima in :issue:`22276` and :issue:`33392`.) + +.. _whatsnew311-re: + re -- @@ -880,6 +925,9 @@ re ``?+``, ``{m,n}+``) are now supported in regular expressions. (Contributed by Jeffrey C. Jacobs and Serhiy Storchaka in :issue:`433030`.) + +.. _whatsnew311-shutil: + shutil ------ @@ -887,6 +935,8 @@ shutil (Contributed by Serhiy Storchaka in :issue:`46245`.) +.. _whatsnew311-socket: + socket ------ @@ -898,6 +948,9 @@ socket instead of only raising the last error. (Contributed by Irit Katriel in :issue:`29980`.) + +.. _whatsnew311-sqlite3: + sqlite3 ------- @@ -961,13 +1014,15 @@ string (Contributed by Ben Kehoe in :gh:`90465`.) +.. _whatsnew311-sys: + sys --- * :func:`sys.exc_info` now derives the ``type`` and ``traceback`` fields from the ``value`` (the exception instance), so when an exception is modified while it is being handled, the changes are reflected in - the results of subsequent calls to :func:`exc_info`. + the results of subsequent calls to :func:`!exc_info`. (Contributed by Irit Katriel in :issue:`45711`.) * Add :func:`sys.exception` which returns the active exception instance @@ -978,6 +1033,8 @@ sys (Contributed by Victor Stinner in :gh:`57684`.) +.. _whatsnew311-sysconfig: + sysconfig --------- @@ -1008,6 +1065,8 @@ tempfile (Contributed by Carey Metcalfe in :gh:`70363`.) +.. _whatsnew311-threading: + threading --------- @@ -1019,6 +1078,8 @@ threading (Contributed by Victor Stinner in :issue:`41710`.) +.. _whatsnew311-time: + time ---- @@ -1036,6 +1097,18 @@ time (Contributed by Benjamin Sz?ke, Dong-hee Na, Eryk Sun and Victor Stinner in :issue:`21302` and :issue:`45429`.) +.. _whatsnew311-tkinter: + +tkinter +------- + +* Added method ``info_patchlevel()`` which returns the exact version of + the Tcl library as a named tuple similar to :data:`sys.version_info`. + (Contributed by Serhiy Storchaka in :gh:`91827`.) + + +.. _whatsnew311-traceback: + traceback --------- @@ -1049,6 +1122,8 @@ traceback (Contributed by Irit Katriel in :issue:`33809`.) +.. _whatsnew311-typing: + typing ------ @@ -1089,7 +1164,7 @@ For major changes, see :ref:`new-feat-related-type-hints-311`. to clear all registered overloads of a function. (Contributed by Jelle Zijlstra in :gh:`89263`.) -* The :meth:`__init__` method of :class:`~typing.Protocol` subclasses +* The :meth:`~object.__init__` method of :class:`~typing.Protocol` subclasses is now preserved. (Contributed by Adrian Garcia Badarasco in :gh:`88970`.) * The representation of empty tuple types (``Tuple[()]``) is simplified. @@ -1118,19 +1193,16 @@ For major changes, see :ref:`new-feat-related-type-hints-311`. by Nikita Sobolev in :gh:`90729`.) -tkinter -------- - -* Added method ``info_patchlevel()`` which returns the exact version of - the Tcl library as a named tuple similar to :data:`sys.version_info`. - (Contributed by Serhiy Storchaka in :gh:`91827`.) - +.. _whatsnew311-unicodedata: unicodedata ----------- -* The Unicode database has been updated to version 14.0.0. (Contributed by Benjamin Peterson in :issue:`45190`). +* The Unicode database has been updated to version 14.0.0. + (Contributed by Benjamin Peterson in :issue:`45190`). + +.. _whatsnew311-unittest: unittest -------- @@ -1144,6 +1216,8 @@ unittest (Contributed by Serhiy Storchaka in :issue:`45046`.) +.. _whatsnew311-venv: + venv ---- @@ -1157,6 +1231,9 @@ venv Third party code that also creates new virtual environments should do the same. (Contributed by Miro Hron?ok in :issue:`45413`.) + +.. _whatsnew311-warnings: + warnings -------- @@ -1183,14 +1260,6 @@ zipfile (Contributed by Miguel Brito in :gh:`88261`.) -fcntl ------ - -* On FreeBSD, the :attr:`F_DUP2FD` and :attr:`F_DUP2FD_CLOEXEC` flags respectively - are supported, the former equals to ``dup2`` usage while the latter set - the ``FD_CLOEXEC`` flag in addition. - - .. _whatsnew311-optimizations: Optimizations From webhook-mailer at python.org Tue Oct 25 09:22:59 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Tue, 25 Oct 2022 13:22:59 -0000 Subject: [Python-checkins] gh-93696: Locate frozen module source with __file__ (#93697) Message-ID: https://github.com/python/cpython/commit/d91de288e73c67805e4c838b5f770ab7ec3661f9 commit: d91de288e73c67805e4c838b5f770ab7ec3661f9 branch: main author: James Gerity committer: JelleZijlstra date: 2022-10-25T06:22:53-07:00 summary: gh-93696: Locate frozen module source with __file__ (#93697) Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> files: A Misc/NEWS.d/next/Core and Builtins/2022-06-10-16-37-44.gh-issue-93696.65BI2R.rst M Lib/pdb.py M Lib/test/test_pdb.py diff --git a/Lib/pdb.py b/Lib/pdb.py index b0acb1f571d3..78d0ce537f1f 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -1332,6 +1332,12 @@ def do_list(self, arg): if last is None: last = first + 10 filename = self.curframe.f_code.co_filename + # gh-93696: stdlib frozen modules provide a useful __file__ + # this workaround can be removed with the closure of gh-89815 + if filename.startswith("", "exec") + func_code = dummy_mod.co_consts[0] + + mod = type(sys)("gh93696") + mod.func = type(lambda: None)(func_code, mod.__dict__) + mod.__file__ = 'gh93696.py' + + return mod + + mod = _create_fake_frozen_module() + mod.func() + """ + commands = """ + break 20 + continue + step + list + quit + """ + with open('gh93696.py', 'w') as f: + f.write(textwrap.dedent(frozen_src)) + + with open('gh93696_host.py', 'w') as f: + f.write(textwrap.dedent(host_program)) + + self.addCleanup(os_helper.unlink, 'gh93696.py') + self.addCleanup(os_helper.unlink, 'gh93696_host.py') + stdout, stderr = self._run_pdb(["gh93696_host.py"], commands) + # verify that pdb found the source of the "frozen" function + self.assertIn('x = "Sentinel string for gh-93696"', stdout, "Sentinel statement not found") + class ChecklineTests(unittest.TestCase): def setUp(self): linecache.clearcache() # Pdb.checkline() uses linecache.getline() diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-10-16-37-44.gh-issue-93696.65BI2R.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-10-16-37-44.gh-issue-93696.65BI2R.rst new file mode 100644 index 000000000000..8eadab0ad8fb --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-06-10-16-37-44.gh-issue-93696.65BI2R.rst @@ -0,0 +1 @@ +Allow :mod:`pdb` to locate source for frozen modules in the standard library. From webhook-mailer at python.org Tue Oct 25 09:29:59 2022 From: webhook-mailer at python.org (miss-islington) Date: Tue, 25 Oct 2022 13:29:59 -0000 Subject: [Python-checkins] gh-95913: Prepare Improved Modules in 3.11 WhatsNew for final edits (GH-98631) Message-ID: https://github.com/python/cpython/commit/c96c7630c50037d1fc075aa7ca10e03a4d777f80 commit: c96c7630c50037d1fc075aa7ca10e03a4d777f80 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-25T06:29:53-07:00 summary: gh-95913: Prepare Improved Modules in 3.11 WhatsNew for final edits (GH-98631) * Add two line breaks and ref target labels to remaining subsections * Fix a few out of order Improved Modules * Fix a few minor textual formatting issues in sections * Fix remaining Sphinx warnings in the Improved Modules section (cherry picked from commit dd13b23e49b8c49bc751fe5ed470773a2d60b7d1) Co-authored-by: C.A.M. Gerlach files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 3e94c40bca69..8f13bf3fa173 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -615,12 +615,18 @@ asyncio These are primarily intended for internal use, notably by :class:`~asyncio.TaskGroup`. + +.. _whatsnew311-contextlib: + contextlib ---------- -Added non parallel-safe :func:`~contextlib.chdir` context manager to change -the current working directory and then restore it on exit. Simple wrapper -around :func:`~os.chdir`. (Contributed by Filipe La?ns in :issue:`25625`) +* Added non parallel-safe :func:`~contextlib.chdir` context manager to change + the current working directory and then restore it on exit. Simple wrapper + around :func:`~os.chdir`. (Contributed by Filipe La?ns in :issue:`25625`) + + +.. _whatsnew311-dataclasses: dataclasses ----------- @@ -630,11 +636,15 @@ dataclasses :class:`dict`, :class:`list` or :class:`set`. (Contributed by Eric V. Smith in :issue:`44674`.) + +.. _whatsnew311-datetime: + datetime -------- * Add :attr:`datetime.UTC`, a convenience alias for :attr:`datetime.timezone.utc`. (Contributed by Kabir Kwatra in :gh:`91973`.) + * :meth:`datetime.date.fromisoformat`, :meth:`datetime.time.fromisoformat` and :meth:`datetime.datetime.fromisoformat` can now be used to parse most ISO 8601 formats (barring only those that support fractional hours and minutes). @@ -659,7 +669,7 @@ enum (used by :func:`str`, :func:`format` and :term:`f-string`\s). * Changed :class:`~enum.IntEnum`, :class:`~enum.IntFlag` and :class:`~enum.StrEnum` - to now inherit from :class:`ReprEnum`, + to now inherit from :class:`~enum.ReprEnum`, so their :func:`str` output now matches :func:`format` (both ``str(AnIntEnum.ONE)`` and ``format(AnIntEnum.ONE)`` return ``'1'``, whereas before ``str(AnIntEnum.ONE)`` returned ``'AnIntEnum.ONE'``. @@ -709,6 +719,18 @@ enum inverted flags are coerced to their positive equivalent. +.. _whatsnew311-fcntl: + +fcntl +----- + +* On FreeBSD, the :data:`!F_DUP2FD` and :data:`!F_DUP2FD_CLOEXEC` flags respectively + are supported, the former equals to ``dup2`` usage while the latter set + the ``FD_CLOEXEC`` flag in addition. + + +.. _whatsnew311-fractions: + fractions --------- @@ -719,6 +741,9 @@ fractions that an ``isinstance(some_fraction, typing.SupportsInt)`` check passes. (Contributed by Mark Dickinson in :issue:`44547`.) + +.. _whatsnew311-functools: + functools --------- @@ -749,6 +774,9 @@ functools (Contributed by Yurii Karabas in :issue:`46014`.) + +.. _whatsnew311-hashlib: + hashlib ------- @@ -767,6 +795,9 @@ hashlib of files or file-like objects. (Contributed by Christian Heimes in :gh:`89313`.) + +.. _whatsnew311-idle: + IDLE and idlelib ---------------- @@ -804,6 +835,9 @@ inspect (Contributed by Pablo Galindo in :gh:`88116`.) + +.. _whatsnew311-locale: + locale ------ @@ -831,6 +865,8 @@ logging (Contributed by Kirill Pinchuk in :gh:`88457`.) +.. _whatsnew311-math: + math ---- @@ -850,6 +886,8 @@ math (Contributed by Victor Stinner in :issue:`46917`.) +.. _whatsnew311-operator: + operator -------- @@ -858,6 +896,8 @@ operator (Contributed by Antony Lee in :issue:`44019`.) +.. _whatsnew311-os: + os -- @@ -866,6 +906,8 @@ os (Contributed by Dong-hee Na in :issue:`44611`.) +.. _whatsnew311-pathlib: + pathlib ------- @@ -874,6 +916,9 @@ pathlib :data:`~os.sep` or :data:`~os.altsep`. (Contributed by Eisuke Kawasima in :issue:`22276` and :issue:`33392`.) + +.. _whatsnew311-re: + re -- @@ -881,6 +926,9 @@ re ``?+``, ``{m,n}+``) are now supported in regular expressions. (Contributed by Jeffrey C. Jacobs and Serhiy Storchaka in :issue:`433030`.) + +.. _whatsnew311-shutil: + shutil ------ @@ -888,6 +936,8 @@ shutil (Contributed by Serhiy Storchaka in :issue:`46245`.) +.. _whatsnew311-socket: + socket ------ @@ -899,6 +949,9 @@ socket instead of only raising the last error. (Contributed by Irit Katriel in :issue:`29980`.) + +.. _whatsnew311-sqlite3: + sqlite3 ------- @@ -962,13 +1015,15 @@ string (Contributed by Ben Kehoe in :gh:`90465`.) +.. _whatsnew311-sys: + sys --- * :func:`sys.exc_info` now derives the ``type`` and ``traceback`` fields from the ``value`` (the exception instance), so when an exception is modified while it is being handled, the changes are reflected in - the results of subsequent calls to :func:`exc_info`. + the results of subsequent calls to :func:`!exc_info`. (Contributed by Irit Katriel in :issue:`45711`.) * Add :func:`sys.exception` which returns the active exception instance @@ -979,6 +1034,8 @@ sys (Contributed by Victor Stinner in :gh:`57684`.) +.. _whatsnew311-sysconfig: + sysconfig --------- @@ -1009,6 +1066,8 @@ tempfile (Contributed by Carey Metcalfe in :gh:`70363`.) +.. _whatsnew311-threading: + threading --------- @@ -1020,6 +1079,8 @@ threading (Contributed by Victor Stinner in :issue:`41710`.) +.. _whatsnew311-time: + time ---- @@ -1037,6 +1098,18 @@ time (Contributed by Benjamin Sz?ke, Dong-hee Na, Eryk Sun and Victor Stinner in :issue:`21302` and :issue:`45429`.) +.. _whatsnew311-tkinter: + +tkinter +------- + +* Added method ``info_patchlevel()`` which returns the exact version of + the Tcl library as a named tuple similar to :data:`sys.version_info`. + (Contributed by Serhiy Storchaka in :gh:`91827`.) + + +.. _whatsnew311-traceback: + traceback --------- @@ -1050,6 +1123,8 @@ traceback (Contributed by Irit Katriel in :issue:`33809`.) +.. _whatsnew311-typing: + typing ------ @@ -1090,7 +1165,7 @@ For major changes, see :ref:`new-feat-related-type-hints-311`. to clear all registered overloads of a function. (Contributed by Jelle Zijlstra in :gh:`89263`.) -* The :meth:`__init__` method of :class:`~typing.Protocol` subclasses +* The :meth:`~object.__init__` method of :class:`~typing.Protocol` subclasses is now preserved. (Contributed by Adrian Garcia Badarasco in :gh:`88970`.) * The representation of empty tuple types (``Tuple[()]``) is simplified. @@ -1119,19 +1194,16 @@ For major changes, see :ref:`new-feat-related-type-hints-311`. by Nikita Sobolev in :gh:`90729`.) -tkinter -------- - -* Added method ``info_patchlevel()`` which returns the exact version of - the Tcl library as a named tuple similar to :data:`sys.version_info`. - (Contributed by Serhiy Storchaka in :gh:`91827`.) - +.. _whatsnew311-unicodedata: unicodedata ----------- -* The Unicode database has been updated to version 14.0.0. (Contributed by Benjamin Peterson in :issue:`45190`). +* The Unicode database has been updated to version 14.0.0. + (Contributed by Benjamin Peterson in :issue:`45190`). + +.. _whatsnew311-unittest: unittest -------- @@ -1145,6 +1217,8 @@ unittest (Contributed by Serhiy Storchaka in :issue:`45046`.) +.. _whatsnew311-venv: + venv ---- @@ -1158,6 +1232,9 @@ venv Third party code that also creates new virtual environments should do the same. (Contributed by Miro Hron?ok in :issue:`45413`.) + +.. _whatsnew311-warnings: + warnings -------- @@ -1184,14 +1261,6 @@ zipfile (Contributed by Miguel Brito in :gh:`88261`.) -fcntl ------ - -* On FreeBSD, the :attr:`F_DUP2FD` and :attr:`F_DUP2FD_CLOEXEC` flags respectively - are supported, the former equals to ``dup2`` usage while the latter set - the ``FD_CLOEXEC`` flag in addition. - - .. _whatsnew311-optimizations: Optimizations From webhook-mailer at python.org Tue Oct 25 09:33:40 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Tue, 25 Oct 2022 13:33:40 -0000 Subject: [Python-checkins] Use more precise exception types in `assertRaises` in typing tests (#98650) Message-ID: https://github.com/python/cpython/commit/45c89358b71e4638455e75ba6e60b42c511bbc2a commit: 45c89358b71e4638455e75ba6e60b42c511bbc2a branch: main author: Nikita Sobolev committer: JelleZijlstra date: 2022-10-25T06:33:34-07:00 summary: Use more precise exception types in `assertRaises` in typing tests (#98650) files: M Lib/test/test_typing.py diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index ab8e71735c4d..26c3e0294ce6 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -3575,11 +3575,11 @@ class D(C): self.assertEqual(D.__parameters__, ()) - with self.assertRaises(Exception): + with self.assertRaises(TypeError): D[int] - with self.assertRaises(Exception): + with self.assertRaises(TypeError): D[Any] - with self.assertRaises(Exception): + with self.assertRaises(TypeError): D[T] def test_new_with_args(self): From webhook-mailer at python.org Tue Oct 25 09:48:48 2022 From: webhook-mailer at python.org (miss-islington) Date: Tue, 25 Oct 2022 13:48:48 -0000 Subject: [Python-checkins] gh-93696: Locate frozen module source with __file__ (GH-93697) Message-ID: https://github.com/python/cpython/commit/a86a7b827bd679b87f619329d3c3f870fa01ee0a commit: a86a7b827bd679b87f619329d3c3f870fa01ee0a branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-25T06:48:41-07:00 summary: gh-93696: Locate frozen module source with __file__ (GH-93697) Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> (cherry picked from commit d91de288e73c67805e4c838b5f770ab7ec3661f9) Co-authored-by: James Gerity files: A Misc/NEWS.d/next/Core and Builtins/2022-06-10-16-37-44.gh-issue-93696.65BI2R.rst M Lib/pdb.py M Lib/test/test_pdb.py diff --git a/Lib/pdb.py b/Lib/pdb.py index 7ab50b4845d3..7401a675253d 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -1248,6 +1248,12 @@ def do_list(self, arg): if last is None: last = first + 10 filename = self.curframe.f_code.co_filename + # gh-93696: stdlib frozen modules provide a useful __file__ + # this workaround can be removed with the closure of gh-89815 + if filename.startswith("", "exec") + func_code = dummy_mod.co_consts[0] + + mod = type(sys)("gh93696") + mod.func = type(lambda: None)(func_code, mod.__dict__) + mod.__file__ = 'gh93696.py' + + return mod + + mod = _create_fake_frozen_module() + mod.func() + """ + commands = """ + break 20 + continue + step + list + quit + """ + with open('gh93696.py', 'w') as f: + f.write(textwrap.dedent(frozen_src)) + + with open('gh93696_host.py', 'w') as f: + f.write(textwrap.dedent(host_program)) + + self.addCleanup(os_helper.unlink, 'gh93696.py') + self.addCleanup(os_helper.unlink, 'gh93696_host.py') + stdout, stderr = self._run_pdb(["gh93696_host.py"], commands) + # verify that pdb found the source of the "frozen" function + self.assertIn('x = "Sentinel string for gh-93696"', stdout, "Sentinel statement not found") + class ChecklineTests(unittest.TestCase): def setUp(self): linecache.clearcache() # Pdb.checkline() uses linecache.getline() diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-10-16-37-44.gh-issue-93696.65BI2R.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-10-16-37-44.gh-issue-93696.65BI2R.rst new file mode 100644 index 000000000000..8eadab0ad8fb --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-06-10-16-37-44.gh-issue-93696.65BI2R.rst @@ -0,0 +1 @@ +Allow :mod:`pdb` to locate source for frozen modules in the standard library. From webhook-mailer at python.org Tue Oct 25 09:49:40 2022 From: webhook-mailer at python.org (miss-islington) Date: Tue, 25 Oct 2022 13:49:40 -0000 Subject: [Python-checkins] gh-93696: Locate frozen module source with __file__ (GH-93697) Message-ID: https://github.com/python/cpython/commit/65f9c8e6dda177925346b8e846995cd5b1552167 commit: 65f9c8e6dda177925346b8e846995cd5b1552167 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-25T06:49:34-07:00 summary: gh-93696: Locate frozen module source with __file__ (GH-93697) Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> (cherry picked from commit d91de288e73c67805e4c838b5f770ab7ec3661f9) Co-authored-by: James Gerity files: A Misc/NEWS.d/next/Core and Builtins/2022-06-10-16-37-44.gh-issue-93696.65BI2R.rst M Lib/pdb.py M Lib/test/test_pdb.py diff --git a/Lib/pdb.py b/Lib/pdb.py index fe8ddd1abb10..411ce53115e7 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -1332,6 +1332,12 @@ def do_list(self, arg): if last is None: last = first + 10 filename = self.curframe.f_code.co_filename + # gh-93696: stdlib frozen modules provide a useful __file__ + # this workaround can be removed with the closure of gh-89815 + if filename.startswith("", "exec") + func_code = dummy_mod.co_consts[0] + + mod = type(sys)("gh93696") + mod.func = type(lambda: None)(func_code, mod.__dict__) + mod.__file__ = 'gh93696.py' + + return mod + + mod = _create_fake_frozen_module() + mod.func() + """ + commands = """ + break 20 + continue + step + list + quit + """ + with open('gh93696.py', 'w') as f: + f.write(textwrap.dedent(frozen_src)) + + with open('gh93696_host.py', 'w') as f: + f.write(textwrap.dedent(host_program)) + + self.addCleanup(os_helper.unlink, 'gh93696.py') + self.addCleanup(os_helper.unlink, 'gh93696_host.py') + stdout, stderr = self._run_pdb(["gh93696_host.py"], commands) + # verify that pdb found the source of the "frozen" function + self.assertIn('x = "Sentinel string for gh-93696"', stdout, "Sentinel statement not found") + class ChecklineTests(unittest.TestCase): def setUp(self): linecache.clearcache() # Pdb.checkline() uses linecache.getline() diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-10-16-37-44.gh-issue-93696.65BI2R.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-10-16-37-44.gh-issue-93696.65BI2R.rst new file mode 100644 index 000000000000..8eadab0ad8fb --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-06-10-16-37-44.gh-issue-93696.65BI2R.rst @@ -0,0 +1 @@ +Allow :mod:`pdb` to locate source for frozen modules in the standard library. From webhook-mailer at python.org Tue Oct 25 10:06:19 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Tue, 25 Oct 2022 14:06:19 -0000 Subject: [Python-checkins] gh-98623: Fix base classes in `typing.rst` (#98626) Message-ID: https://github.com/python/cpython/commit/5076108872df07592931cd27efac4a4496aba2e8 commit: 5076108872df07592931cd27efac4a4496aba2e8 branch: main author: Nikita Sobolev committer: JelleZijlstra date: 2022-10-25T07:06:13-07:00 summary: gh-98623: Fix base classes in `typing.rst` (#98626) files: M Doc/library/typing.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 886b5ca42dd9..ead7835bfffa 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -2057,7 +2057,7 @@ Abstract Base Classes Corresponding to collections in :mod:`collections.abc` """""""""""""""""""""""""""""""""""""""""""""""""""""" -.. class:: AbstractSet(Sized, Collection[T_co]) +.. class:: AbstractSet(Collection[T_co]) A generic version of :class:`collections.abc.Set`. @@ -2113,7 +2113,7 @@ Corresponding to collections in :mod:`collections.abc` :class:`collections.abc.KeysView` now supports subscripting (``[]``). See :pep:`585` and :ref:`types-genericalias`. -.. class:: Mapping(Sized, Collection[KT], Generic[VT_co]) +.. class:: Mapping(Collection[KT], Generic[KT, VT_co]) A generic version of :class:`collections.abc.Mapping`. This type can be used as follows:: From webhook-mailer at python.org Tue Oct 25 10:13:05 2022 From: webhook-mailer at python.org (miss-islington) Date: Tue, 25 Oct 2022 14:13:05 -0000 Subject: [Python-checkins] Use more precise exception types in `assertRaises` in typing tests (GH-98650) Message-ID: https://github.com/python/cpython/commit/750e5048009e36e7c3ca9f396fc82cbcfaf8bd5e commit: 750e5048009e36e7c3ca9f396fc82cbcfaf8bd5e branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-25T07:12:59-07:00 summary: Use more precise exception types in `assertRaises` in typing tests (GH-98650) (cherry picked from commit 45c89358b71e4638455e75ba6e60b42c511bbc2a) Co-authored-by: Nikita Sobolev files: M Lib/test/test_typing.py diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 3f38e30881d4..34f944416070 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -2405,11 +2405,11 @@ class D(C): self.assertEqual(D.__parameters__, ()) - with self.assertRaises(Exception): + with self.assertRaises(TypeError): D[int] - with self.assertRaises(Exception): + with self.assertRaises(TypeError): D[Any] - with self.assertRaises(Exception): + with self.assertRaises(TypeError): D[T] def test_new_with_args(self): From webhook-mailer at python.org Tue Oct 25 10:13:22 2022 From: webhook-mailer at python.org (miss-islington) Date: Tue, 25 Oct 2022 14:13:22 -0000 Subject: [Python-checkins] gh-98623: Fix base classes in `typing.rst` (GH-98626) Message-ID: https://github.com/python/cpython/commit/4b68e34a6c483582000cea69db526ff266abf61c commit: 4b68e34a6c483582000cea69db526ff266abf61c branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-25T07:13:16-07:00 summary: gh-98623: Fix base classes in `typing.rst` (GH-98626) (cherry picked from commit 5076108872df07592931cd27efac4a4496aba2e8) Co-authored-by: Nikita Sobolev files: M Doc/library/typing.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index d49bae8cc2f3..353e7eb1ca87 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -2057,7 +2057,7 @@ Abstract Base Classes Corresponding to collections in :mod:`collections.abc` """""""""""""""""""""""""""""""""""""""""""""""""""""" -.. class:: AbstractSet(Sized, Collection[T_co]) +.. class:: AbstractSet(Collection[T_co]) A generic version of :class:`collections.abc.Set`. @@ -2113,7 +2113,7 @@ Corresponding to collections in :mod:`collections.abc` :class:`collections.abc.KeysView` now supports subscripting (``[]``). See :pep:`585` and :ref:`types-genericalias`. -.. class:: Mapping(Sized, Collection[KT], Generic[VT_co]) +.. class:: Mapping(Collection[KT], Generic[KT, VT_co]) A generic version of :class:`collections.abc.Mapping`. This type can be used as follows:: From webhook-mailer at python.org Tue Oct 25 10:15:15 2022 From: webhook-mailer at python.org (miss-islington) Date: Tue, 25 Oct 2022 14:15:15 -0000 Subject: [Python-checkins] gh-98623: Fix base classes in `typing.rst` (GH-98626) Message-ID: https://github.com/python/cpython/commit/3e335f2c0de9b7fab542a18d603f5bbdb1fb2ef3 commit: 3e335f2c0de9b7fab542a18d603f5bbdb1fb2ef3 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-25T07:15:07-07:00 summary: gh-98623: Fix base classes in `typing.rst` (GH-98626) (cherry picked from commit 5076108872df07592931cd27efac4a4496aba2e8) Co-authored-by: Nikita Sobolev files: M Doc/library/typing.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index de63735ed0f1..7a93b875c742 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -1752,7 +1752,7 @@ Abstract Base Classes Corresponding to collections in :mod:`collections.abc` """""""""""""""""""""""""""""""""""""""""""""""""""""" -.. class:: AbstractSet(Sized, Collection[T_co]) +.. class:: AbstractSet(Collection[T_co]) A generic version of :class:`collections.abc.Set`. @@ -1808,7 +1808,7 @@ Corresponding to collections in :mod:`collections.abc` :class:`collections.abc.KeysView` now supports subscripting (``[]``). See :pep:`585` and :ref:`types-genericalias`. -.. class:: Mapping(Sized, Collection[KT], Generic[VT_co]) +.. class:: Mapping(Collection[KT], Generic[KT, VT_co]) A generic version of :class:`collections.abc.Mapping`. This type can be used as follows:: From webhook-mailer at python.org Tue Oct 25 10:19:43 2022 From: webhook-mailer at python.org (miss-islington) Date: Tue, 25 Oct 2022 14:19:43 -0000 Subject: [Python-checkins] Use more precise exception types in `assertRaises` in typing tests (GH-98650) Message-ID: https://github.com/python/cpython/commit/abc1a8c61c82860e135b1b1fcb01713f8b911cd8 commit: abc1a8c61c82860e135b1b1fcb01713f8b911cd8 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-25T07:19:37-07:00 summary: Use more precise exception types in `assertRaises` in typing tests (GH-98650) (cherry picked from commit 45c89358b71e4638455e75ba6e60b42c511bbc2a) Co-authored-by: Nikita Sobolev files: M Lib/test/test_typing.py diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 298e374e4cfa..b36804216fa2 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -3560,11 +3560,11 @@ class D(C): self.assertEqual(D.__parameters__, ()) - with self.assertRaises(Exception): + with self.assertRaises(TypeError): D[int] - with self.assertRaises(Exception): + with self.assertRaises(TypeError): D[Any] - with self.assertRaises(Exception): + with self.assertRaises(TypeError): D[T] def test_new_with_args(self): From webhook-mailer at python.org Tue Oct 25 10:45:03 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Tue, 25 Oct 2022 14:45:03 -0000 Subject: [Python-checkins] GH-87390: Add remaining tests for PEP 646 (#98267) Message-ID: https://github.com/python/cpython/commit/cb95cc24efecf32ad035318867b065a2b042d25a commit: cb95cc24efecf32ad035318867b065a2b042d25a branch: main author: Matthew Rahtz committer: JelleZijlstra date: 2022-10-25T07:44:30-07:00 summary: GH-87390: Add remaining tests for PEP 646 (#98267) Co-authored-by: Guido van Rossum files: A Misc/NEWS.d/next/Tests/2022-10-15-07-46-48.gh-issue-87390.asR-Zo.rst M Lib/test/test_genericalias.py M Lib/test/test_typing.py diff --git a/Lib/test/test_genericalias.py b/Lib/test/test_genericalias.py index 1afb7ea4f85d..6b2de724af6b 100644 --- a/Lib/test/test_genericalias.py +++ b/Lib/test/test_genericalias.py @@ -205,23 +205,11 @@ class MyList(list): self.assertEqual(repr(list[str]), 'list[str]') self.assertEqual(repr(list[()]), 'list[()]') self.assertEqual(repr(tuple[int, ...]), 'tuple[int, ...]') - x1 = tuple[ - tuple( # Effectively the same as starring; TODO - tuple[int] - ) - ] + x1 = tuple[*tuple[int]] self.assertEqual(repr(x1), 'tuple[*tuple[int]]') - x2 = tuple[ - tuple( # Ditto TODO - tuple[int, str] - ) - ] + x2 = tuple[*tuple[int, str]] self.assertEqual(repr(x2), 'tuple[*tuple[int, str]]') - x3 = tuple[ - tuple( # Ditto TODO - tuple[int, ...] - ) - ] + x3 = tuple[*tuple[int, ...]] self.assertEqual(repr(x3), 'tuple[*tuple[int, ...]]') self.assertTrue(repr(MyList[int]).endswith('.BaseTest.test_repr..MyList[int]')) self.assertEqual(repr(list[str]()), '[]') # instances should keep their normal repr @@ -275,42 +263,24 @@ def test_parameters(self): self.assertEqual(L5.__args__, (Callable[[K, V], K],)) self.assertEqual(L5.__parameters__, (K, V)) - T1 = tuple[ - tuple( # Ditto TODO - tuple[int] - ) - ] + T1 = tuple[*tuple[int]] self.assertEqual( T1.__args__, - tuple( # Ditto TODO - tuple[int] - ) + (*tuple[int],), ) self.assertEqual(T1.__parameters__, ()) - T2 = tuple[ - tuple( # Ditto TODO - tuple[T] - ) - ] + T2 = tuple[*tuple[T]] self.assertEqual( T2.__args__, - tuple( # Ditto TODO - tuple[T] - ) + (*tuple[T],), ) self.assertEqual(T2.__parameters__, (T,)) - T4 = tuple[ - tuple( # Ditto TODO - tuple[int, str] - ) - ] + T4 = tuple[*tuple[int, str]] self.assertEqual( T4.__args__, - tuple( # Ditto TODO - tuple[int, str] - ) + (*tuple[int, str],), ) self.assertEqual(T4.__parameters__, ()) @@ -345,18 +315,7 @@ def test_equality(self): self.assertEqual(list[int], list[int]) self.assertEqual(dict[str, int], dict[str, int]) self.assertEqual((*tuple[int],)[0], (*tuple[int],)[0]) - self.assertEqual( - tuple[ - tuple( # Effectively the same as starring; TODO - tuple[int] - ) - ], - tuple[ - tuple( # Ditto TODO - tuple[int] - ) - ] - ) + self.assertEqual(tuple[*tuple[int]], tuple[*tuple[int]]) self.assertNotEqual(dict[str, int], dict[str, str]) self.assertNotEqual(list, list[int]) self.assertNotEqual(list[int], list) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 26c3e0294ce6..a3f52b8934d0 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -592,10 +592,9 @@ def test_no_duplicates_if_replacement_not_in_templates(self): class GenericAliasSubstitutionTests(BaseTestCase): """Tests for type variable substitution in generic aliases. - Note that the expected results here are tentative, based on a - still-being-worked-out spec for what we allow at runtime (given that - implementation of *full* substitution logic at runtime would add too much - complexity to typing.py). This spec is currently being discussed at + For variadic cases, these tests should be regarded as the source of truth, + since we hadn't realised the full complexity of variadic substitution + at the time of finalizing PEP 646. For full discussion, see https://github.com/python/cpython/issues/91162. """ @@ -682,9 +681,6 @@ class C(Generic[T1, T2]): pass ('generic[T1, T2]', '[tuple_type[int, ...]]', 'TypeError'), ('generic[T1, T2]', '[tuple_type[int, ...], tuple_type[str, ...]]', 'generic[tuple_type[int, ...], tuple_type[str, ...]]'), - # Should raise TypeError according to the tentative spec: unpacked - # types cannot be used as arguments to aliases that expect a fixed - # number of arguments. ('generic[T1, T2]', '[*tuple_type[int, ...]]', 'TypeError'), ('generic[T1, T2]', '[int, *tuple_type[str, ...]]', 'TypeError'), ('generic[T1, T2]', '[*tuple_type[int, ...], str]', 'TypeError'), @@ -692,10 +688,12 @@ class C(Generic[T1, T2]): pass ('generic[T1, T2]', '[*Ts]', 'TypeError'), ('generic[T1, T2]', '[T, *Ts]', 'TypeError'), ('generic[T1, T2]', '[*Ts, T]', 'TypeError'), - # Should raise TypeError according to the tentative spec: unpacked - # types cannot be used as arguments to generics that expect a fixed - # number of arguments. - # (None of the things in `generics` were defined using *Ts.) + # This one isn't technically valid - none of the things that + # `generic` can be (defined in `generics` above) are variadic, so we + # shouldn't really be able to do `generic[T1, *tuple_type[int, ...]]`. + # So even if type checkers shouldn't allow it, we allow it at + # runtime, in accordance with a general philosophy of "Keep the + # runtime lenient so people can experiment with typing constructs". ('generic[T1, *tuple_type[int, ...]]', '[str]', 'generic[str, *tuple_type[int, ...]]'), ] @@ -757,8 +755,6 @@ class C(Generic[*Ts]): pass generics = ['C', 'tuple', 'Tuple'] tuple_types = ['tuple', 'Tuple'] - # The majority of these have three separate cases for C, tuple and - # Tuple because tuple currently behaves differently. tests = [ # Alias # Args # Expected result ('generic[*Ts]', '[()]', 'generic[()]'), @@ -791,7 +787,11 @@ class C(Generic[*Ts]): pass ('generic[*Ts, list[T]]', '[int, str, bool]', 'generic[int, str, list[bool]]'), ('generic[T, *Ts]', '[*tuple_type[int, ...]]', 'generic[int, *tuple_type[int, ...]]'), + ('generic[T, *Ts]', '[str, *tuple_type[int, ...]]', 'generic[str, *tuple_type[int, ...]]'), + ('generic[T, *Ts]', '[*tuple_type[int, ...], str]', 'generic[int, *tuple_type[int, ...], str]'), ('generic[*Ts, T]', '[*tuple_type[int, ...]]', 'generic[*tuple_type[int, ...], int]'), + ('generic[*Ts, T]', '[str, *tuple_type[int, ...]]', 'generic[str, *tuple_type[int, ...], int]'), + ('generic[*Ts, T]', '[*tuple_type[int, ...], str]', 'generic[*tuple_type[int, ...], str]'), ('generic[T1, *Ts, T2]', '[*tuple_type[int, ...]]', 'generic[int, *tuple_type[int, ...], int]'), ('generic[T, str, *Ts]', '[*tuple_type[int, ...]]', 'generic[int, str, *tuple_type[int, ...]]'), ('generic[*Ts, str, T]', '[*tuple_type[int, ...]]', 'generic[*tuple_type[int, ...], str, int]'), @@ -830,13 +830,19 @@ class C(Generic[*Ts]): pass class UnpackTests(BaseTestCase): def test_accepts_single_type(self): + (*tuple[int],) Unpack[Tuple[int]] def test_rejects_multiple_types(self): with self.assertRaises(TypeError): Unpack[Tuple[int], Tuple[str]] + # We can't do the equivalent for `*` here - + # *(Tuple[int], Tuple[str]) is just plain tuple unpacking, + # which is valid. def test_rejects_multiple_parameterization(self): + with self.assertRaises(TypeError): + (*tuple[int],)[0][tuple[int]] with self.assertRaises(TypeError): Unpack[Tuple[int]][Tuple[int]] @@ -875,19 +881,20 @@ def test_cannot_call_instance(self): def test_unpacked_typevartuple_is_equal_to_itself(self): Ts = TypeVarTuple('Ts') + self.assertEqual((*Ts,)[0], (*Ts,)[0]) self.assertEqual(Unpack[Ts], Unpack[Ts]) def test_parameterised_tuple_is_equal_to_itself(self): Ts = TypeVarTuple('Ts') - self.assertEqual(tuple[Unpack[Ts]], tuple[Unpack[Ts]]) + self.assertEqual(tuple[*Ts], tuple[*Ts]) self.assertEqual(Tuple[Unpack[Ts]], Tuple[Unpack[Ts]]) def tests_tuple_arg_ordering_matters(self): Ts1 = TypeVarTuple('Ts1') Ts2 = TypeVarTuple('Ts2') self.assertNotEqual( - tuple[Unpack[Ts1], Unpack[Ts2]], - tuple[Unpack[Ts2], Unpack[Ts1]], + tuple[*Ts1, *Ts2], + tuple[*Ts2, *Ts1], ) self.assertNotEqual( Tuple[Unpack[Ts1], Unpack[Ts2]], @@ -896,8 +903,8 @@ def tests_tuple_arg_ordering_matters(self): def test_tuple_args_and_parameters_are_correct(self): Ts = TypeVarTuple('Ts') - t1 = tuple[Unpack[Ts]] - self.assertEqual(t1.__args__, (Unpack[Ts],)) + t1 = tuple[*Ts] + self.assertEqual(t1.__args__, (*Ts,)) self.assertEqual(t1.__parameters__, (Ts,)) t2 = Tuple[Unpack[Ts]] self.assertEqual(t2.__args__, (Unpack[Ts],)) @@ -907,128 +914,218 @@ def test_var_substitution(self): Ts = TypeVarTuple('Ts') T = TypeVar('T') T2 = TypeVar('T2') - class G(Generic[Unpack[Ts]]): pass + class G1(Generic[*Ts]): pass + class G2(Generic[Unpack[Ts]]): pass - for A in G, Tuple, tuple: - B = A[Unpack[Ts]] + for A in G1, G2, Tuple, tuple: + B = A[*Ts] self.assertEqual(B[()], A[()]) self.assertEqual(B[float], A[float]) self.assertEqual(B[float, str], A[float, str]) - C = List[A[Unpack[Ts]]] - self.assertEqual(C[()], List[A[()]]) - self.assertEqual(C[float], List[A[float]]) - self.assertEqual(C[float, str], List[A[float, str]]) + C = A[Unpack[Ts]] + self.assertEqual(C[()], A[()]) + self.assertEqual(C[float], A[float]) + self.assertEqual(C[float, str], A[float, str]) + + D = list[A[*Ts]] + self.assertEqual(D[()], list[A[()]]) + self.assertEqual(D[float], list[A[float]]) + self.assertEqual(D[float, str], list[A[float, str]]) + + E = List[A[Unpack[Ts]]] + self.assertEqual(E[()], List[A[()]]) + self.assertEqual(E[float], List[A[float]]) + self.assertEqual(E[float, str], List[A[float, str]]) + + F = A[T, *Ts, T2] + with self.assertRaises(TypeError): + F[()] + with self.assertRaises(TypeError): + F[float] + self.assertEqual(F[float, str], A[float, str]) + self.assertEqual(F[float, str, int], A[float, str, int]) + self.assertEqual(F[float, str, int, bytes], A[float, str, int, bytes]) - D = A[T, Unpack[Ts], T2] + G = A[T, Unpack[Ts], T2] with self.assertRaises(TypeError): - D[()] + G[()] with self.assertRaises(TypeError): - D[float] - self.assertEqual(D[float, str], A[float, str]) - self.assertEqual(D[float, str, int], A[float, str, int]) - self.assertEqual(D[float, str, int, bytes], A[float, str, int, bytes]) + G[float] + self.assertEqual(G[float, str], A[float, str]) + self.assertEqual(G[float, str, int], A[float, str, int]) + self.assertEqual(G[float, str, int, bytes], A[float, str, int, bytes]) - E = Tuple[List[T], A[Unpack[Ts]], List[T2]] + H = tuple[list[T], A[*Ts], list[T2]] with self.assertRaises(TypeError): - E[()] + H[()] with self.assertRaises(TypeError): - E[float] + H[float] if A != Tuple: - self.assertEqual(E[float, str], + self.assertEqual(H[float, str], + tuple[list[float], A[()], list[str]]) + self.assertEqual(H[float, str, int], + tuple[list[float], A[str], list[int]]) + self.assertEqual(H[float, str, int, bytes], + tuple[list[float], A[str, int], list[bytes]]) + + I = Tuple[List[T], A[Unpack[Ts]], List[T2]] + with self.assertRaises(TypeError): + I[()] + with self.assertRaises(TypeError): + I[float] + if A != Tuple: + self.assertEqual(I[float, str], Tuple[List[float], A[()], List[str]]) - self.assertEqual(E[float, str, int], + self.assertEqual(I[float, str, int], Tuple[List[float], A[str], List[int]]) - self.assertEqual(E[float, str, int, bytes], + self.assertEqual(I[float, str, int, bytes], Tuple[List[float], A[str, int], List[bytes]]) def test_bad_var_substitution(self): Ts = TypeVarTuple('Ts') T = TypeVar('T') T2 = TypeVar('T2') - class G(Generic[Unpack[Ts]]): pass + class G1(Generic[*Ts]): pass + class G2(Generic[Unpack[Ts]]): pass - for A in G, Tuple, tuple: + for A in G1, G2, Tuple, tuple: B = A[Ts] with self.assertRaises(TypeError): B[int, str] C = A[T, T2] + with self.assertRaises(TypeError): + C[*Ts] with self.assertRaises(TypeError): C[Unpack[Ts]] - def test_repr_is_correct(self): - Ts = TypeVarTuple('Ts') - T = TypeVar('T') - T2 = TypeVar('T2') - class G(Generic[Unpack[Ts]]): pass - - for A in G, Tuple: - B = A[T, Unpack[Ts], str, T2] + B = A[T, *Ts, str, T2] with self.assertRaises(TypeError): - B[int, Unpack[Ts]] + B[int, *Ts] + with self.assertRaises(TypeError): + B[int, *Ts, *Ts] + C = A[T, Unpack[Ts], str, T2] + with self.assertRaises(TypeError): + C[int, Unpack[Ts]] with self.assertRaises(TypeError): C[int, Unpack[Ts], Unpack[Ts]] def test_repr_is_correct(self): Ts = TypeVarTuple('Ts') + T = TypeVar('T') + T2 = TypeVar('T2') + + class G1(Generic[*Ts]): pass + class G2(Generic[Unpack[Ts]]): pass + self.assertEqual(repr(Ts), 'Ts') + + self.assertEqual(repr((*Ts,)[0]), '*Ts') self.assertEqual(repr(Unpack[Ts]), '*Ts') - self.assertEqual(repr(tuple[Unpack[Ts]]), 'tuple[*Ts]') + + self.assertEqual(repr(tuple[*Ts]), 'tuple[*Ts]') self.assertEqual(repr(Tuple[Unpack[Ts]]), 'typing.Tuple[*Ts]') - self.assertEqual(repr(Unpack[tuple[Unpack[Ts]]]), '*tuple[*Ts]') + + self.assertEqual(repr(*tuple[*Ts]), '*tuple[*Ts]') self.assertEqual(repr(Unpack[Tuple[Unpack[Ts]]]), '*typing.Tuple[*Ts]') def test_variadic_class_repr_is_correct(self): Ts = TypeVarTuple('Ts') - class A(Generic[Unpack[Ts]]): pass + class A(Generic[*Ts]): pass + class B(Generic[Unpack[Ts]]): pass self.assertEndsWith(repr(A[()]), 'A[()]') + self.assertEndsWith(repr(B[()]), 'B[()]') self.assertEndsWith(repr(A[float]), 'A[float]') + self.assertEndsWith(repr(B[float]), 'B[float]') self.assertEndsWith(repr(A[float, str]), 'A[float, str]') - self.assertEndsWith(repr(A[Unpack[tuple[int, ...]]]), + self.assertEndsWith(repr(B[float, str]), 'B[float, str]') + + self.assertEndsWith(repr(A[*tuple[int, ...]]), 'A[*tuple[int, ...]]') - self.assertEndsWith(repr(A[float, Unpack[tuple[int, ...]]]), + self.assertEndsWith(repr(B[Unpack[Tuple[int, ...]]]), + 'B[*typing.Tuple[int, ...]]') + + self.assertEndsWith(repr(A[float, *tuple[int, ...]]), 'A[float, *tuple[int, ...]]') - self.assertEndsWith(repr(A[Unpack[tuple[int, ...]], str]), + self.assertEndsWith(repr(A[float, Unpack[Tuple[int, ...]]]), + 'A[float, *typing.Tuple[int, ...]]') + + self.assertEndsWith(repr(A[*tuple[int, ...], str]), 'A[*tuple[int, ...], str]') - self.assertEndsWith(repr(A[float, Unpack[tuple[int, ...]], str]), + self.assertEndsWith(repr(B[Unpack[Tuple[int, ...]], str]), + 'B[*typing.Tuple[int, ...], str]') + + self.assertEndsWith(repr(A[float, *tuple[int, ...], str]), 'A[float, *tuple[int, ...], str]') + self.assertEndsWith(repr(B[float, Unpack[Tuple[int, ...]], str]), + 'B[float, *typing.Tuple[int, ...], str]') def test_variadic_class_alias_repr_is_correct(self): Ts = TypeVarTuple('Ts') class A(Generic[Unpack[Ts]]): pass - B = A[Unpack[Ts]] + B = A[*Ts] self.assertEndsWith(repr(B), 'A[*Ts]') self.assertEndsWith(repr(B[()]), 'A[()]') self.assertEndsWith(repr(B[float]), 'A[float]') self.assertEndsWith(repr(B[float, str]), 'A[float, str]') - C = A[Unpack[Ts], int] - self.assertEndsWith(repr(C), 'A[*Ts, int]') - self.assertEndsWith(repr(C[()]), 'A[int]') - self.assertEndsWith(repr(C[float]), 'A[float, int]') - self.assertEndsWith(repr(C[float, str]), 'A[float, str, int]') + C = A[Unpack[Ts]] + self.assertEndsWith(repr(C), 'A[*Ts]') + self.assertEndsWith(repr(C[()]), 'A[()]') + self.assertEndsWith(repr(C[float]), 'A[float]') + self.assertEndsWith(repr(C[float, str]), 'A[float, str]') - D = A[int, Unpack[Ts]] - self.assertEndsWith(repr(D), 'A[int, *Ts]') + D = A[*Ts, int] + self.assertEndsWith(repr(D), 'A[*Ts, int]') self.assertEndsWith(repr(D[()]), 'A[int]') - self.assertEndsWith(repr(D[float]), 'A[int, float]') - self.assertEndsWith(repr(D[float, str]), 'A[int, float, str]') - - E = A[int, Unpack[Ts], str] - self.assertEndsWith(repr(E), 'A[int, *Ts, str]') - self.assertEndsWith(repr(E[()]), 'A[int, str]') - self.assertEndsWith(repr(E[float]), 'A[int, float, str]') - self.assertEndsWith(repr(E[float, str]), 'A[int, float, str, str]') - - F = A[Unpack[Ts], Unpack[tuple[str, ...]]] - self.assertEndsWith(repr(F), 'A[*Ts, *tuple[str, ...]]') - self.assertEndsWith(repr(F[()]), 'A[*tuple[str, ...]]') - self.assertEndsWith(repr(F[float]), 'A[float, *tuple[str, ...]]') - self.assertEndsWith(repr(F[float, str]), 'A[float, str, *tuple[str, ...]]') + self.assertEndsWith(repr(D[float]), 'A[float, int]') + self.assertEndsWith(repr(D[float, str]), 'A[float, str, int]') + + E = A[Unpack[Ts], int] + self.assertEndsWith(repr(E), 'A[*Ts, int]') + self.assertEndsWith(repr(E[()]), 'A[int]') + self.assertEndsWith(repr(E[float]), 'A[float, int]') + self.assertEndsWith(repr(E[float, str]), 'A[float, str, int]') + + F = A[int, *Ts] + self.assertEndsWith(repr(F), 'A[int, *Ts]') + self.assertEndsWith(repr(F[()]), 'A[int]') + self.assertEndsWith(repr(F[float]), 'A[int, float]') + self.assertEndsWith(repr(F[float, str]), 'A[int, float, str]') + + G = A[int, Unpack[Ts]] + self.assertEndsWith(repr(G), 'A[int, *Ts]') + self.assertEndsWith(repr(G[()]), 'A[int]') + self.assertEndsWith(repr(G[float]), 'A[int, float]') + self.assertEndsWith(repr(G[float, str]), 'A[int, float, str]') + + H = A[int, *Ts, str] + self.assertEndsWith(repr(H), 'A[int, *Ts, str]') + self.assertEndsWith(repr(H[()]), 'A[int, str]') + self.assertEndsWith(repr(H[float]), 'A[int, float, str]') + self.assertEndsWith(repr(H[float, str]), 'A[int, float, str, str]') + + I = A[int, Unpack[Ts], str] + self.assertEndsWith(repr(I), 'A[int, *Ts, str]') + self.assertEndsWith(repr(I[()]), 'A[int, str]') + self.assertEndsWith(repr(I[float]), 'A[int, float, str]') + self.assertEndsWith(repr(I[float, str]), 'A[int, float, str, str]') + + J = A[*Ts, *tuple[str, ...]] + self.assertEndsWith(repr(J), 'A[*Ts, *tuple[str, ...]]') + self.assertEndsWith(repr(J[()]), 'A[*tuple[str, ...]]') + self.assertEndsWith(repr(J[float]), 'A[float, *tuple[str, ...]]') + self.assertEndsWith(repr(J[float, str]), 'A[float, str, *tuple[str, ...]]') + + K = A[Unpack[Ts], Unpack[Tuple[str, ...]]] + self.assertEndsWith(repr(K), 'A[*Ts, *typing.Tuple[str, ...]]') + self.assertEndsWith(repr(K[()]), 'A[*typing.Tuple[str, ...]]') + self.assertEndsWith(repr(K[float]), 'A[float, *typing.Tuple[str, ...]]') + self.assertEndsWith(repr(K[float, str]), 'A[float, str, *typing.Tuple[str, ...]]') def test_cannot_subclass(self): with self.assertRaisesRegex(TypeError, CANNOT_SUBCLASS_TYPE): @@ -1037,39 +1134,69 @@ class C(TypeVarTuple): pass with self.assertRaisesRegex(TypeError, CANNOT_SUBCLASS_INSTANCE % 'TypeVarTuple'): class C(Ts): pass - with self.assertRaisesRegex(TypeError, r'Cannot subclass \*Ts'): - class C(*Ts): pass with self.assertRaisesRegex(TypeError, CANNOT_SUBCLASS_TYPE): class C(type(Unpack)): pass + with self.assertRaisesRegex(TypeError, CANNOT_SUBCLASS_TYPE): + class C(type(*Ts)): pass with self.assertRaisesRegex(TypeError, CANNOT_SUBCLASS_TYPE): class C(type(Unpack[Ts])): pass with self.assertRaisesRegex(TypeError, r'Cannot subclass typing\.Unpack'): class C(Unpack): pass + with self.assertRaisesRegex(TypeError, r'Cannot subclass \*Ts'): + class C(*Ts): pass with self.assertRaisesRegex(TypeError, r'Cannot subclass \*Ts'): class C(Unpack[Ts]): pass def test_variadic_class_args_are_correct(self): T = TypeVar('T') Ts = TypeVarTuple('Ts') - class A(Generic[Unpack[Ts]]): pass - B = A[()] - self.assertEqual(B.__args__, ()) - C = A[int] - self.assertEqual(C.__args__, (int,)) - D = A[int, str] - self.assertEqual(D.__args__, (int, str)) - E = A[T] - self.assertEqual(E.__args__, (T,)) - F = A[Unpack[Ts]] - self.assertEqual(F.__args__, (Unpack[Ts],)) - G = A[T, Unpack[Ts]] - self.assertEqual(G.__args__, (T, Unpack[Ts])) - H = A[Unpack[Ts], T] - self.assertEqual(H.__args__, (Unpack[Ts], T)) + class A(Generic[*Ts]): pass + class B(Generic[Unpack[Ts]]): pass + + C = A[()] + D = B[()] + self.assertEqual(C.__args__, ()) + self.assertEqual(D.__args__, ()) + + E = A[int] + F = B[int] + self.assertEqual(E.__args__, (int,)) + self.assertEqual(F.__args__, (int,)) + + G = A[int, str] + H = B[int, str] + self.assertEqual(G.__args__, (int, str)) + self.assertEqual(H.__args__, (int, str)) + + I = A[T] + J = B[T] + self.assertEqual(I.__args__, (T,)) + self.assertEqual(J.__args__, (T,)) + + K = A[*Ts] + L = B[Unpack[Ts]] + self.assertEqual(K.__args__, (*Ts,)) + self.assertEqual(L.__args__, (Unpack[Ts],)) + + M = A[T, *Ts] + N = B[T, Unpack[Ts]] + self.assertEqual(M.__args__, (T, *Ts)) + self.assertEqual(N.__args__, (T, Unpack[Ts])) + + O = A[*Ts, T] + P = B[Unpack[Ts], T] + self.assertEqual(O.__args__, (*Ts, T)) + self.assertEqual(P.__args__, (Unpack[Ts], T)) def test_variadic_class_origin_is_correct(self): Ts = TypeVarTuple('Ts') + + class C(Generic[*Ts]): pass + self.assertIs(C[int].__origin__, C) + self.assertIs(C[T].__origin__, C) + self.assertIs(C[Unpack[Ts]].__origin__, C) + class D(Generic[Unpack[Ts]]): pass self.assertIs(D[int].__origin__, D) self.assertIs(D[T].__origin__, D) @@ -1078,21 +1205,21 @@ class D(Generic[Unpack[Ts]]): pass def test_tuple_args_are_correct(self): Ts = TypeVarTuple('Ts') - self.assertEqual(tuple[Unpack[Ts]].__args__, (Unpack[Ts],)) + self.assertEqual(tuple[*Ts].__args__, (*Ts,)) self.assertEqual(Tuple[Unpack[Ts]].__args__, (Unpack[Ts],)) - self.assertEqual(tuple[Unpack[Ts], int].__args__, (Unpack[Ts], int)) + self.assertEqual(tuple[*Ts, int].__args__, (*Ts, int)) self.assertEqual(Tuple[Unpack[Ts], int].__args__, (Unpack[Ts], int)) - self.assertEqual(tuple[int, Unpack[Ts]].__args__, (int, Unpack[Ts])) + self.assertEqual(tuple[int, *Ts].__args__, (int, *Ts)) self.assertEqual(Tuple[int, Unpack[Ts]].__args__, (int, Unpack[Ts])) - self.assertEqual(tuple[int, Unpack[Ts], str].__args__, - (int, Unpack[Ts], str)) + self.assertEqual(tuple[int, *Ts, str].__args__, + (int, *Ts, str)) self.assertEqual(Tuple[int, Unpack[Ts], str].__args__, (int, Unpack[Ts], str)) - self.assertEqual(tuple[Unpack[Ts], int].__args__, (Unpack[Ts], int)) + self.assertEqual(tuple[*Ts, int].__args__, (*Ts, int)) self.assertEqual(Tuple[Unpack[Ts]].__args__, (Unpack[Ts],)) def test_callable_args_are_correct(self): @@ -1102,63 +1229,97 @@ def test_callable_args_are_correct(self): # TypeVarTuple in the arguments - a = Callable[[Unpack[Ts]], None] - self.assertEqual(a.__args__, (Unpack[Ts], type(None))) + a = Callable[[*Ts], None] + b = Callable[[Unpack[Ts]], None] + self.assertEqual(a.__args__, (*Ts, type(None))) + self.assertEqual(b.__args__, (Unpack[Ts], type(None))) - b = Callable[[int, Unpack[Ts]], None] - self.assertEqual(b.__args__, (int, Unpack[Ts], type(None))) + c = Callable[[int, *Ts], None] + d = Callable[[int, Unpack[Ts]], None] + self.assertEqual(c.__args__, (int, *Ts, type(None))) + self.assertEqual(d.__args__, (int, Unpack[Ts], type(None))) - c = Callable[[Unpack[Ts], int], None] - self.assertEqual(c.__args__, (Unpack[Ts], int, type(None))) + e = Callable[[*Ts, int], None] + f = Callable[[Unpack[Ts], int], None] + self.assertEqual(e.__args__, (*Ts, int, type(None))) + self.assertEqual(f.__args__, (Unpack[Ts], int, type(None))) - d = Callable[[str, Unpack[Ts], int], None] - self.assertEqual(d.__args__, (str, Unpack[Ts], int, type(None))) + g = Callable[[str, *Ts, int], None] + h = Callable[[str, Unpack[Ts], int], None] + self.assertEqual(g.__args__, (str, *Ts, int, type(None))) + self.assertEqual(h.__args__, (str, Unpack[Ts], int, type(None))) # TypeVarTuple as the return - e = Callable[[None], Unpack[Ts]] - self.assertEqual(e.__args__, (type(None), Unpack[Ts])) + i = Callable[[None], *Ts] + j = Callable[[None], Unpack[Ts]] + self.assertEqual(i.__args__, (type(None), *Ts)) + self.assertEqual(i.__args__, (type(None), Unpack[Ts])) - f = Callable[[None], tuple[int, Unpack[Ts]]] - self.assertEqual(f.__args__, (type(None), tuple[int, Unpack[Ts]])) + k = Callable[[None], tuple[int, *Ts]] + l = Callable[[None], Tuple[int, Unpack[Ts]]] + self.assertEqual(k.__args__, (type(None), tuple[int, *Ts])) + self.assertEqual(l.__args__, (type(None), Tuple[int, Unpack[Ts]])) - g = Callable[[None], tuple[Unpack[Ts], int]] - self.assertEqual(g.__args__, (type(None), tuple[Unpack[Ts], int])) + m = Callable[[None], tuple[*Ts, int]] + n = Callable[[None], Tuple[Unpack[Ts], int]] + self.assertEqual(m.__args__, (type(None), tuple[*Ts, int])) + self.assertEqual(n.__args__, (type(None), Tuple[Unpack[Ts], int])) - h = Callable[[None], tuple[str, Unpack[Ts], int]] - self.assertEqual(h.__args__, (type(None), tuple[str, Unpack[Ts], int])) + o = Callable[[None], tuple[str, *Ts, int]] + p = Callable[[None], Tuple[str, Unpack[Ts], int]] + self.assertEqual(o.__args__, (type(None), tuple[str, *Ts, int])) + self.assertEqual(p.__args__, (type(None), Tuple[str, Unpack[Ts], int])) # TypeVarTuple in both - i = Callable[[Unpack[Ts]], Unpack[Ts]] - self.assertEqual(i.__args__, (Unpack[Ts], Unpack[Ts])) + q = Callable[[*Ts], *Ts] + r = Callable[[Unpack[Ts]], Unpack[Ts]] + self.assertEqual(q.__args__, (*Ts, *Ts)) + self.assertEqual(r.__args__, (Unpack[Ts], Unpack[Ts])) - j = Callable[[Unpack[Ts1]], Unpack[Ts2]] - self.assertEqual(j.__args__, (Unpack[Ts1], Unpack[Ts2])) + s = Callable[[*Ts1], *Ts2] + u = Callable[[Unpack[Ts1]], Unpack[Ts2]] + self.assertEqual(s.__args__, (*Ts1, *Ts2)) + self.assertEqual(u.__args__, (Unpack[Ts1], Unpack[Ts2])) def test_variadic_class_with_duplicate_typevartuples_fails(self): Ts1 = TypeVarTuple('Ts1') Ts2 = TypeVarTuple('Ts2') + + with self.assertRaises(TypeError): + class C(Generic[*Ts1, *Ts1]): pass with self.assertRaises(TypeError): class C(Generic[Unpack[Ts1], Unpack[Ts1]]): pass + + with self.assertRaises(TypeError): + class C(Generic[*Ts1, *Ts2, *Ts1]): pass with self.assertRaises(TypeError): class C(Generic[Unpack[Ts1], Unpack[Ts2], Unpack[Ts1]]): pass def test_type_concatenation_in_variadic_class_argument_list_succeeds(self): Ts = TypeVarTuple('Ts') class C(Generic[Unpack[Ts]]): pass + + C[int, *Ts] C[int, Unpack[Ts]] + + C[*Ts, int] C[Unpack[Ts], int] + + C[int, *Ts, str] C[int, Unpack[Ts], str] + + C[int, bool, *Ts, float, str] C[int, bool, Unpack[Ts], float, str] def test_type_concatenation_in_tuple_argument_list_succeeds(self): Ts = TypeVarTuple('Ts') - tuple[int, Unpack[Ts]] - tuple[Unpack[Ts], int] - tuple[int, Unpack[Ts], str] - tuple[int, bool, Unpack[Ts], float, str] + tuple[int, *Ts] + tuple[*Ts, int] + tuple[int, *Ts, str] + tuple[int, bool, *Ts, float, str] Tuple[int, Unpack[Ts]] Tuple[Unpack[Ts], int] @@ -1172,6 +1333,8 @@ class C(Generic[Ts]): pass def test_variadic_class_definition_using_concrete_types_fails(self): Ts = TypeVarTuple('Ts') + with self.assertRaises(TypeError): + class F(Generic[*Ts, int]): pass with self.assertRaises(TypeError): class E(Generic[Unpack[Ts], int]): pass @@ -1180,32 +1343,50 @@ def test_variadic_class_with_2_typevars_accepts_2_or_more_args(self): T1 = TypeVar('T1') T2 = TypeVar('T2') - class A(Generic[T1, T2, Unpack[Ts]]): pass + class A(Generic[T1, T2, *Ts]): pass A[int, str] A[int, str, float] A[int, str, float, bool] - class B(Generic[T1, Unpack[Ts], T2]): pass + class B(Generic[T1, T2, Unpack[Ts]]): pass B[int, str] B[int, str, float] B[int, str, float, bool] - class C(Generic[Unpack[Ts], T1, T2]): pass + class C(Generic[T1, *Ts, T2]): pass C[int, str] C[int, str, float] C[int, str, float, bool] + class D(Generic[T1, Unpack[Ts], T2]): pass + D[int, str] + D[int, str, float] + D[int, str, float, bool] + + class E(Generic[*Ts, T1, T2]): pass + E[int, str] + E[int, str, float] + E[int, str, float, bool] + + class F(Generic[Unpack[Ts], T1, T2]): pass + F[int, str] + F[int, str, float] + F[int, str, float, bool] + def test_variadic_args_annotations_are_correct(self): Ts = TypeVarTuple('Ts') + def f(*args: Unpack[Ts]): pass + def g(*args: *Ts): pass self.assertEqual(f.__annotations__, {'args': Unpack[Ts]}) + self.assertEqual(g.__annotations__, {'args': (*Ts,)[0]}) def test_variadic_args_with_ellipsis_annotations_are_correct(self): Ts = TypeVarTuple('Ts') - def a(*args: Unpack[tuple[int, ...]]): pass + def a(*args: *tuple[int, ...]): pass self.assertEqual(a.__annotations__, - {'args': Unpack[tuple[int, ...]]}) + {'args': (*tuple[int, ...],)[0]}) def b(*args: Unpack[Tuple[int, ...]]): pass self.assertEqual(b.__annotations__, @@ -1214,30 +1395,30 @@ def b(*args: Unpack[Tuple[int, ...]]): pass def test_concatenation_in_variadic_args_annotations_are_correct(self): Ts = TypeVarTuple('Ts') - # Unpacking using `Unpack`, native `tuple` type + # Unpacking using `*`, native `tuple` type - def a(*args: Unpack[tuple[int, Unpack[Ts]]]): pass + def a(*args: *tuple[int, *Ts]): pass self.assertEqual( a.__annotations__, - {'args': Unpack[tuple[int, Unpack[Ts]]]}, + {'args': (*tuple[int, *Ts],)[0]}, ) - def b(*args: Unpack[tuple[Unpack[Ts], int]]): pass + def b(*args: *tuple[*Ts, int]): pass self.assertEqual( b.__annotations__, - {'args': Unpack[tuple[Unpack[Ts], int]]}, + {'args': (*tuple[*Ts, int],)[0]}, ) - def c(*args: Unpack[tuple[str, Unpack[Ts], int]]): pass + def c(*args: *tuple[str, *Ts, int]): pass self.assertEqual( c.__annotations__, - {'args': Unpack[tuple[str, Unpack[Ts], int]]}, + {'args': (*tuple[str, *Ts, int],)[0]}, ) - def d(*args: Unpack[tuple[int, bool, Unpack[Ts], float, str]]): pass + def d(*args: *tuple[int, bool, *Ts, float, str]): pass self.assertEqual( d.__annotations__, - {'args': Unpack[tuple[int, bool, Unpack[Ts], float, str]]}, + {'args': (*tuple[int, bool, *Ts, float, str],)[0]}, ) # Unpacking using `Unpack`, `Tuple` type from typing.py @@ -1268,47 +1449,78 @@ def h(*args: Unpack[Tuple[int, bool, Unpack[Ts], float, str]]): pass def test_variadic_class_same_args_results_in_equalty(self): Ts = TypeVarTuple('Ts') - class C(Generic[Unpack[Ts]]): pass + class C(Generic[*Ts]): pass + class D(Generic[Unpack[Ts]]): pass self.assertEqual(C[int], C[int]) + self.assertEqual(D[int], D[int]) Ts1 = TypeVarTuple('Ts1') Ts2 = TypeVarTuple('Ts2') + self.assertEqual( - C[Unpack[Ts1]], - C[Unpack[Ts1]], + C[*Ts1], + C[*Ts1], ) self.assertEqual( - C[Unpack[Ts1], Unpack[Ts2]], - C[Unpack[Ts1], Unpack[Ts2]], + D[Unpack[Ts1]], + D[Unpack[Ts1]], + ) + + self.assertEqual( + C[*Ts1, *Ts2], + C[*Ts1, *Ts2], + ) + self.assertEqual( + D[Unpack[Ts1], Unpack[Ts2]], + D[Unpack[Ts1], Unpack[Ts2]], + ) + + self.assertEqual( + C[int, *Ts1, *Ts2], + C[int, *Ts1, *Ts2], ) self.assertEqual( - C[int, Unpack[Ts1], Unpack[Ts2]], - C[int, Unpack[Ts1], Unpack[Ts2]], + D[int, Unpack[Ts1], Unpack[Ts2]], + D[int, Unpack[Ts1], Unpack[Ts2]], ) def test_variadic_class_arg_ordering_matters(self): Ts = TypeVarTuple('Ts') - class C(Generic[Unpack[Ts]]): pass + class C(Generic[*Ts]): pass + class D(Generic[Unpack[Ts]]): pass self.assertNotEqual( C[int, str], C[str, int], ) + self.assertNotEqual( + D[int, str], + D[str, int], + ) Ts1 = TypeVarTuple('Ts1') Ts2 = TypeVarTuple('Ts2') + + self.assertNotEqual( + C[*Ts1, *Ts2], + C[*Ts2, *Ts1], + ) self.assertNotEqual( - C[Unpack[Ts1], Unpack[Ts2]], - C[Unpack[Ts2], Unpack[Ts1]], + D[Unpack[Ts1], Unpack[Ts2]], + D[Unpack[Ts2], Unpack[Ts1]], ) def test_variadic_class_arg_typevartuple_identity_matters(self): Ts = TypeVarTuple('Ts') - class C(Generic[Unpack[Ts]]): pass Ts1 = TypeVarTuple('Ts1') Ts2 = TypeVarTuple('Ts2') - self.assertNotEqual(C[Unpack[Ts1]], C[Unpack[Ts2]]) + + class C(Generic[*Ts]): pass + class D(Generic[Unpack[Ts]]): pass + + self.assertNotEqual(C[*Ts1], C[*Ts2]) + self.assertNotEqual(D[Unpack[Ts1]], D[Unpack[Ts2]]) class TypeVarTuplePicklingTests(BaseTestCase): @@ -1328,10 +1540,15 @@ def test_pickling_then_unpickling_results_in_same_identity(self, proto): def test_pickling_then_unpickling_unpacked_results_in_same_identity(self, proto): global global_Ts # See explanation at start of class. global_Ts = TypeVarTuple('global_Ts') - unpacked1 = Unpack[global_Ts] + + unpacked1 = (*global_Ts,)[0] unpacked2 = pickle.loads(pickle.dumps(unpacked1, proto)) self.assertIs(unpacked1, unpacked2) + unpacked3 = Unpack[global_Ts] + unpacked4 = pickle.loads(pickle.dumps(unpacked3, proto)) + self.assertIs(unpacked3, unpacked4) + @all_pickle_protocols def test_pickling_then_unpickling_tuple_with_typevartuple_equality( self, proto @@ -1340,17 +1557,19 @@ def test_pickling_then_unpickling_tuple_with_typevartuple_equality( global_T = TypeVar('global_T') global_Ts = TypeVarTuple('global_Ts') - a1 = Tuple[Unpack[global_Ts]] - a2 = pickle.loads(pickle.dumps(a1, proto)) - self.assertEqual(a1, a2) + tuples = [ + tuple[*global_Ts], + Tuple[Unpack[global_Ts]], - a1 = Tuple[T, Unpack[global_Ts]] - a2 = pickle.loads(pickle.dumps(a1, proto)) - self.assertEqual(a1, a2) + tuple[T, *global_Ts], + Tuple[T, Unpack[global_Ts]], - a1 = Tuple[int, Unpack[global_Ts]] - a2 = pickle.loads(pickle.dumps(a1, proto)) - self.assertEqual(a1, a2) + tuple[int, *global_Ts], + Tuple[int, Unpack[global_Ts]], + ] + for t in tuples: + t2 = pickle.loads(pickle.dumps(t, proto)) + self.assertEqual(t, t2) class UnionTests(BaseTestCase): @@ -4936,6 +5155,7 @@ def h(x: collections.abc.Callable[P, int]): ... class GetUtilitiesTestCase(TestCase): def test_get_origin(self): T = TypeVar('T') + Ts = TypeVarTuple('Ts') P = ParamSpec('P') class C(Generic[T]): pass self.assertIs(get_origin(C[int]), C) @@ -4959,6 +5179,10 @@ class C(Generic[T]): pass self.assertIs(get_origin(P.kwargs), P) self.assertIs(get_origin(Required[int]), Required) self.assertIs(get_origin(NotRequired[int]), NotRequired) + self.assertIs(get_origin((*Ts,)[0]), Unpack) + self.assertIs(get_origin(Unpack[Ts]), Unpack) + self.assertIs(get_origin((*tuple[*Ts],)[0]), tuple) + self.assertIs(get_origin(Unpack[Tuple[Unpack[Ts]]]), Unpack) def test_get_args(self): T = TypeVar('T') @@ -5020,8 +5244,12 @@ class C(Generic[T]): pass self.assertEqual(get_args(TypeGuard[int]), (int,)) Ts = TypeVarTuple('Ts') self.assertEqual(get_args(Ts), ()) + self.assertEqual(get_args((*Ts,)[0]), (Ts,)) self.assertEqual(get_args(Unpack[Ts]), (Ts,)) + self.assertEqual(get_args(tuple[*Ts]), (*Ts,)) self.assertEqual(get_args(tuple[Unpack[Ts]]), (Unpack[Ts],)) + self.assertEqual(get_args((*tuple[*Ts],)[0]), (*Ts,)) + self.assertEqual(get_args(Unpack[tuple[Unpack[Ts]]]), (tuple[Unpack[Ts]],)) class CollectionsAbcTests(BaseTestCase): @@ -6699,69 +6927,112 @@ def test_typevar_subst(self): T1 = TypeVar('T1') T2 = TypeVar('T2') - A = Annotated[Tuple[Unpack[Ts]], dec] - self.assertEqual(A[int], Annotated[Tuple[int], dec]) - self.assertEqual(A[str, int], Annotated[Tuple[str, int], dec]) + A = Annotated[tuple[*Ts], dec] + self.assertEqual(A[int], Annotated[tuple[int], dec]) + self.assertEqual(A[str, int], Annotated[tuple[str, int], dec]) with self.assertRaises(TypeError): - Annotated[Unpack[Ts], dec] + Annotated[*Ts, dec] - B = Annotated[Tuple[T, Unpack[Ts]], dec] + B = Annotated[Tuple[Unpack[Ts]], dec] self.assertEqual(B[int], Annotated[Tuple[int], dec]) - self.assertEqual(B[int, str], Annotated[Tuple[int, str], dec]) - self.assertEqual( - B[int, str, float], - Annotated[Tuple[int, str, float], dec] - ) + self.assertEqual(B[str, int], Annotated[Tuple[str, int], dec]) with self.assertRaises(TypeError): - B[()] + Annotated[Unpack[Ts], dec] - C = Annotated[Tuple[Unpack[Ts], T], dec] - self.assertEqual(C[int], Annotated[Tuple[int], dec]) - self.assertEqual(C[int, str], Annotated[Tuple[int, str], dec]) + C = Annotated[tuple[T, *Ts], dec] + self.assertEqual(C[int], Annotated[tuple[int], dec]) + self.assertEqual(C[int, str], Annotated[tuple[int, str], dec]) self.assertEqual( C[int, str, float], - Annotated[Tuple[int, str, float], dec] + Annotated[tuple[int, str, float], dec] ) with self.assertRaises(TypeError): C[()] - D = Annotated[Tuple[T1, Unpack[Ts], T2], dec] + D = Annotated[Tuple[T, Unpack[Ts]], dec] + self.assertEqual(D[int], Annotated[Tuple[int], dec]) self.assertEqual(D[int, str], Annotated[Tuple[int, str], dec]) self.assertEqual( D[int, str, float], Annotated[Tuple[int, str, float], dec] ) + with self.assertRaises(TypeError): + D[()] + + E = Annotated[tuple[*Ts, T], dec] + self.assertEqual(E[int], Annotated[tuple[int], dec]) + self.assertEqual(E[int, str], Annotated[tuple[int, str], dec]) self.assertEqual( - D[int, str, bool, float], - Annotated[Tuple[int, str, bool, float], dec] + E[int, str, float], + Annotated[tuple[int, str, float], dec] ) with self.assertRaises(TypeError): - D[int] - - # Now let's try creating an alias from an alias. + E[()] - Ts2 = TypeVarTuple('Ts2') - T3 = TypeVar('T3') - T4 = TypeVar('T4') + F = Annotated[Tuple[Unpack[Ts], T], dec] + self.assertEqual(F[int], Annotated[Tuple[int], dec]) + self.assertEqual(F[int, str], Annotated[Tuple[int, str], dec]) + self.assertEqual( + F[int, str, float], + Annotated[Tuple[int, str, float], dec] + ) + with self.assertRaises(TypeError): + F[()] - E = D[T3, Unpack[Ts2], T4] + G = Annotated[tuple[T1, *Ts, T2], dec] + self.assertEqual(G[int, str], Annotated[tuple[int, str], dec]) self.assertEqual( - E, - Annotated[Tuple[T3, Unpack[Ts2], T4], dec] + G[int, str, float], + Annotated[tuple[int, str, float], dec] ) self.assertEqual( - E[int, str], Annotated[Tuple[int, str], dec] + G[int, str, bool, float], + Annotated[tuple[int, str, bool, float], dec] ) + with self.assertRaises(TypeError): + G[int] + + H = Annotated[Tuple[T1, Unpack[Ts], T2], dec] + self.assertEqual(H[int, str], Annotated[Tuple[int, str], dec]) self.assertEqual( - E[int, str, float], + H[int, str, float], Annotated[Tuple[int, str, float], dec] ) self.assertEqual( - E[int, str, bool, float], + H[int, str, bool, float], Annotated[Tuple[int, str, bool, float], dec] ) with self.assertRaises(TypeError): - E[int] + H[int] + + # Now let's try creating an alias from an alias. + + Ts2 = TypeVarTuple('Ts2') + T3 = TypeVar('T3') + T4 = TypeVar('T4') + + # G is Annotated[tuple[T1, *Ts, T2], dec]. + I = G[T3, *Ts2, T4] + J = G[T3, Unpack[Ts2], T4] + + for x, y in [ + (I, Annotated[tuple[T3, *Ts2, T4], dec]), + (J, Annotated[tuple[T3, Unpack[Ts2], T4], dec]), + (I[int, str], Annotated[tuple[int, str], dec]), + (J[int, str], Annotated[tuple[int, str], dec]), + (I[int, str, float], Annotated[tuple[int, str, float], dec]), + (J[int, str, float], Annotated[tuple[int, str, float], dec]), + (I[int, str, bool, float], + Annotated[tuple[int, str, bool, float], dec]), + (J[int, str, bool, float], + Annotated[tuple[int, str, bool, float], dec]), + ]: + self.assertEqual(x, y) + + with self.assertRaises(TypeError): + I[int] + with self.assertRaises(TypeError): + J[int] def test_annotated_in_other_types(self): X = List[Annotated[T, 5]] diff --git a/Misc/NEWS.d/next/Tests/2022-10-15-07-46-48.gh-issue-87390.asR-Zo.rst b/Misc/NEWS.d/next/Tests/2022-10-15-07-46-48.gh-issue-87390.asR-Zo.rst new file mode 100644 index 000000000000..181e12c7430b --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2022-10-15-07-46-48.gh-issue-87390.asR-Zo.rst @@ -0,0 +1 @@ +Add tests for star-unpacking with PEP 646, and some other miscellaneous PEP 646 tests. From webhook-mailer at python.org Tue Oct 25 11:33:03 2022 From: webhook-mailer at python.org (AlexWaygood) Date: Tue, 25 Oct 2022 15:33:03 -0000 Subject: [Python-checkins] gh-98602: [typing docs] Use quotes for forward reference in TypeVarTuple example (#98605) Message-ID: https://github.com/python/cpython/commit/be0cf82ae4e49891dcd5e37012d6f6ce08bc4726 commit: be0cf82ae4e49891dcd5e37012d6f6ce08bc4726 branch: main author: Eclips4 <80244920+Eclips4 at users.noreply.github.com> committer: AlexWaygood date: 2022-10-25T16:32:52+01:00 summary: gh-98602: [typing docs] Use quotes for forward reference in TypeVarTuple example (#98605) files: M Doc/library/typing.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index ead7835bfffa..8c8286059d53 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -1351,7 +1351,7 @@ These are not used in annotations. They are building blocks for creating generic Shape = TypeVarTuple('Shape') class Array(Generic[*Shape]): def __getitem__(self, key: tuple[*Shape]) -> float: ... - def __abs__(self) -> Array[*Shape]: ... + def __abs__(self) -> "Array[*Shape]": ... def get_shape(self) -> tuple[*Shape]: ... Type variable tuples can be happily combined with normal type variables:: From webhook-mailer at python.org Tue Oct 25 11:42:18 2022 From: webhook-mailer at python.org (miss-islington) Date: Tue, 25 Oct 2022 15:42:18 -0000 Subject: [Python-checkins] gh-98602: [typing docs] Use quotes for forward reference in TypeVarTuple example (GH-98605) Message-ID: https://github.com/python/cpython/commit/4cd5ea62acae3de3bb33734bc5103d6454a97629 commit: 4cd5ea62acae3de3bb33734bc5103d6454a97629 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-25T08:42:12-07:00 summary: gh-98602: [typing docs] Use quotes for forward reference in TypeVarTuple example (GH-98605) (cherry picked from commit be0cf82ae4e49891dcd5e37012d6f6ce08bc4726) Co-authored-by: Eclips4 <80244920+Eclips4 at users.noreply.github.com> files: M Doc/library/typing.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 353e7eb1ca87..313c67b75c0c 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -1351,7 +1351,7 @@ These are not used in annotations. They are building blocks for creating generic Shape = TypeVarTuple('Shape') class Array(Generic[*Shape]): def __getitem__(self, key: tuple[*Shape]) -> float: ... - def __abs__(self) -> Array[*Shape]: ... + def __abs__(self) -> "Array[*Shape]": ... def get_shape(self) -> tuple[*Shape]: ... Type variable tuples can be happily combined with normal type variables:: From webhook-mailer at python.org Tue Oct 25 12:59:36 2022 From: webhook-mailer at python.org (zware) Date: Tue, 25 Oct 2022 16:59:36 -0000 Subject: [Python-checkins] Update link to supported versions table in security policy (GH-98670) Message-ID: https://github.com/python/cpython/commit/175247f364f76e0a7e466e967a2af75a90e74473 commit: 175247f364f76e0a7e466e967a2af75a90e74473 branch: main author: Zachary Ware committer: zware date: 2022-10-25T11:59:19-05:00 summary: Update link to supported versions table in security policy (GH-98670) files: M .github/SECURITY.md diff --git a/.github/SECURITY.md b/.github/SECURITY.md index 2aebc5a0bf71..923720bce0bc 100644 --- a/.github/SECURITY.md +++ b/.github/SECURITY.md @@ -4,7 +4,7 @@ The Python team applies security fixes according to the table in [the devguide]( -https://devguide.python.org/#status-of-python-branches +https://devguide.python.org/versions/#supported-versions ). ## Reporting a Vulnerability From webhook-mailer at python.org Tue Oct 25 13:13:43 2022 From: webhook-mailer at python.org (zware) Date: Tue, 25 Oct 2022 17:13:43 -0000 Subject: [Python-checkins] Update build status links in contributing doc (GH-98672) Message-ID: https://github.com/python/cpython/commit/6ffb4e24e0358833194515e68bd01dc6c6024c66 commit: 6ffb4e24e0358833194515e68bd01dc6c6024c66 branch: main author: Zachary Ware committer: zware date: 2022-10-25T12:13:37-05:00 summary: Update build status links in contributing doc (GH-98672) files: M .github/CONTRIBUTING.rst diff --git a/.github/CONTRIBUTING.rst b/.github/CONTRIBUTING.rst index f4affee76e1d..2ef9cdc19148 100644 --- a/.github/CONTRIBUTING.rst +++ b/.github/CONTRIBUTING.rst @@ -4,21 +4,9 @@ Contributing to Python Build Status ------------ -- main +- `Buildbot status overview `_ - + `Stable buildbots `_ - -- 3.9 - - + `Stable buildbots `_ - -- 3.8 - - + `Stable buildbots `_ - -- 3.7 - - + `Stable buildbots `_ +- `GitHub Actions status `_ Thank You From webhook-mailer at python.org Tue Oct 25 14:27:27 2022 From: webhook-mailer at python.org (erlend-aasland) Date: Tue, 25 Oct 2022 18:27:27 -0000 Subject: [Python-checkins] gh-94328: Update Windows installer to use SQLite 3.39.4 (#98640) Message-ID: https://github.com/python/cpython/commit/0c84593275969d9b8f42e75abb2638b69d5b5f4a commit: 0c84593275969d9b8f42e75abb2638b69d5b5f4a branch: main author: Erlend E. Aasland committer: erlend-aasland date: 2022-10-25T20:27:21+02:00 summary: gh-94328: Update Windows installer to use SQLite 3.39.4 (#98640) files: A Misc/NEWS.d/next/Windows/2022-10-25-10-34-17.gh-issue-94328.19NhdU.rst M PCbuild/get_externals.bat M PCbuild/python.props M PCbuild/readme.txt diff --git a/Misc/NEWS.d/next/Windows/2022-10-25-10-34-17.gh-issue-94328.19NhdU.rst b/Misc/NEWS.d/next/Windows/2022-10-25-10-34-17.gh-issue-94328.19NhdU.rst new file mode 100644 index 000000000000..eb48ff9b6ec6 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2022-10-25-10-34-17.gh-issue-94328.19NhdU.rst @@ -0,0 +1 @@ +Update Windows installer to use SQLite 3.39.4. diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat index 9c6bc4eac496..681c79f85d0c 100644 --- a/PCbuild/get_externals.bat +++ b/PCbuild/get_externals.bat @@ -54,7 +54,7 @@ set libraries= set libraries=%libraries% bzip2-1.0.8 if NOT "%IncludeLibffiSrc%"=="false" set libraries=%libraries% libffi-3.4.3 if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-1.1.1q -set libraries=%libraries% sqlite-3.38.4.0 +set libraries=%libraries% sqlite-3.39.4.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tcl-core-8.6.12.1 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tk-8.6.12.1 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tix-8.4.3.6 diff --git a/PCbuild/python.props b/PCbuild/python.props index c3ab12e7c672..5fa32dfffd17 100644 --- a/PCbuild/python.props +++ b/PCbuild/python.props @@ -61,7 +61,7 @@ $(EXTERNALS_DIR) $([System.IO.Path]::GetFullPath(`$(PySourcePath)externals`)) $(ExternalsDir)\ - $(ExternalsDir)sqlite-3.38.4.0\ + $(ExternalsDir)sqlite-3.39.4.0\ $(ExternalsDir)bzip2-1.0.8\ $(ExternalsDir)xz-5.2.5\ $(ExternalsDir)libffi-3.4.3\ diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt index c536fac94cc6..5ba3e3940627 100644 --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -187,7 +187,7 @@ _ssl again when building. _sqlite3 - Wraps SQLite 3.38.4, which is itself built by sqlite3.vcxproj + Wraps SQLite 3.39.4, which is itself built by sqlite3.vcxproj Homepage: https://www.sqlite.org/ _tkinter From webhook-mailer at python.org Tue Oct 25 17:51:52 2022 From: webhook-mailer at python.org (miss-islington) Date: Tue, 25 Oct 2022 21:51:52 -0000 Subject: [Python-checkins] gh-94328: Update Windows installer to use SQLite 3.39.4 (GH-98640) Message-ID: https://github.com/python/cpython/commit/f7194cace0b6cf46726ebdd7c1cac815a8186025 commit: f7194cace0b6cf46726ebdd7c1cac815a8186025 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-25T14:51:32-07:00 summary: gh-94328: Update Windows installer to use SQLite 3.39.4 (GH-98640) (cherry picked from commit 0c84593275969d9b8f42e75abb2638b69d5b5f4a) Co-authored-by: Erlend E. Aasland files: A Misc/NEWS.d/next/Windows/2022-10-25-10-34-17.gh-issue-94328.19NhdU.rst M PCbuild/get_externals.bat M PCbuild/python.props M PCbuild/readme.txt diff --git a/Misc/NEWS.d/next/Windows/2022-10-25-10-34-17.gh-issue-94328.19NhdU.rst b/Misc/NEWS.d/next/Windows/2022-10-25-10-34-17.gh-issue-94328.19NhdU.rst new file mode 100644 index 000000000000..eb48ff9b6ec6 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2022-10-25-10-34-17.gh-issue-94328.19NhdU.rst @@ -0,0 +1 @@ +Update Windows installer to use SQLite 3.39.4. diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat index 9c6bc4eac496..681c79f85d0c 100644 --- a/PCbuild/get_externals.bat +++ b/PCbuild/get_externals.bat @@ -54,7 +54,7 @@ set libraries= set libraries=%libraries% bzip2-1.0.8 if NOT "%IncludeLibffiSrc%"=="false" set libraries=%libraries% libffi-3.4.3 if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-1.1.1q -set libraries=%libraries% sqlite-3.38.4.0 +set libraries=%libraries% sqlite-3.39.4.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tcl-core-8.6.12.1 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tk-8.6.12.1 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tix-8.4.3.6 diff --git a/PCbuild/python.props b/PCbuild/python.props index c3ab12e7c672..5fa32dfffd17 100644 --- a/PCbuild/python.props +++ b/PCbuild/python.props @@ -61,7 +61,7 @@ $(EXTERNALS_DIR) $([System.IO.Path]::GetFullPath(`$(PySourcePath)externals`)) $(ExternalsDir)\ - $(ExternalsDir)sqlite-3.38.4.0\ + $(ExternalsDir)sqlite-3.39.4.0\ $(ExternalsDir)bzip2-1.0.8\ $(ExternalsDir)xz-5.2.5\ $(ExternalsDir)libffi-3.4.3\ diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt index c536fac94cc6..5ba3e3940627 100644 --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -187,7 +187,7 @@ _ssl again when building. _sqlite3 - Wraps SQLite 3.38.4, which is itself built by sqlite3.vcxproj + Wraps SQLite 3.39.4, which is itself built by sqlite3.vcxproj Homepage: https://www.sqlite.org/ _tkinter From webhook-mailer at python.org Tue Oct 25 18:34:27 2022 From: webhook-mailer at python.org (pablogsal) Date: Tue, 25 Oct 2022 22:34:27 -0000 Subject: [Python-checkins] gh-96143: Move the perf trampoline files to the Python directory (#98675) Message-ID: https://github.com/python/cpython/commit/1f737edb67e702095feb97118a911afb569f5705 commit: 1f737edb67e702095feb97118a911afb569f5705 branch: main author: Pablo Galindo Salgado committer: pablogsal date: 2022-10-25T23:34:22+01:00 summary: gh-96143: Move the perf trampoline files to the Python directory (#98675) files: A Python/asm_trampoline.S A Python/perf_trampoline.c D Objects/asm_trampoline.S D Objects/perf_trampoline.c M Makefile.pre.in M PCbuild/_freeze_module.vcxproj M PCbuild/_freeze_module.vcxproj.filters M PCbuild/pythoncore.vcxproj M PCbuild/pythoncore.vcxproj.filters M Tools/c-analyzer/cpython/globals-to-fix.tsv M Tools/c-analyzer/cpython/ignored.tsv M configure M configure.ac diff --git a/Makefile.pre.in b/Makefile.pre.in index 5b4bf15eb8aa..6ab1422c7898 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -426,6 +426,7 @@ PYTHON_OBJS= \ Python/formatter_unicode.o \ Python/fileutils.o \ Python/suggestions.o \ + Python/perf_trampoline.o \ Python/$(DYNLOADFILE) \ $(LIBOBJS) \ $(MACHDEP_OBJS) \ @@ -479,7 +480,6 @@ OBJECT_OBJS= \ Objects/unicodectype.o \ Objects/unionobject.o \ Objects/weakrefobject.o \ - Objects/perf_trampoline.o \ @PERF_TRAMPOLINE_OBJ@ DEEPFREEZE_OBJS = Python/deepfreeze/deepfreeze.o @@ -2370,7 +2370,7 @@ config.status: $(srcdir)/configure .PRECIOUS: config.status $(BUILDPYTHON) Makefile Makefile.pre -Objects/asm_trampoline.o: $(srcdir)/Objects/asm_trampoline.S +Python/asm_trampoline.o: $(srcdir)/Python/asm_trampoline.S $(CC) -c $(PY_CORE_CFLAGS) -o $@ $< # Some make's put the object file in the current directory diff --git a/PCbuild/_freeze_module.vcxproj b/PCbuild/_freeze_module.vcxproj index 49e5cc89a261..8454bd67b1db 100644 --- a/PCbuild/_freeze_module.vcxproj +++ b/PCbuild/_freeze_module.vcxproj @@ -129,7 +129,6 @@ - @@ -211,6 +210,7 @@ + diff --git a/PCbuild/_freeze_module.vcxproj.filters b/PCbuild/_freeze_module.vcxproj.filters index 96ab2f2a4aac..6e8498dceb1c 100644 --- a/PCbuild/_freeze_module.vcxproj.filters +++ b/PCbuild/_freeze_module.vcxproj.filters @@ -85,7 +85,7 @@ Source Files - + Source Files diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index ff17304032cd..111ad67f7da0 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -429,7 +429,6 @@ - @@ -513,6 +512,7 @@ + diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index 7d7fe7267c8f..ab7d01974b00 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -923,9 +923,6 @@ Objects - - Objects - Objects @@ -1127,6 +1124,9 @@ Python + + Python + Python diff --git a/Objects/asm_trampoline.S b/Python/asm_trampoline.S similarity index 100% rename from Objects/asm_trampoline.S rename to Python/asm_trampoline.S diff --git a/Objects/perf_trampoline.c b/Python/perf_trampoline.c similarity index 100% rename from Objects/perf_trampoline.c rename to Python/perf_trampoline.c diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 196d62d361b6..e327f0a50c68 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -380,7 +380,7 @@ Objects/floatobject.c - float_format - Objects/longobject.c long_from_non_binary_base log_base_BASE - Objects/longobject.c long_from_non_binary_base convwidth_base - Objects/longobject.c long_from_non_binary_base convmultmax_base - -Objects/perf_trampoline.c - perf_map_file - +Python/perf_trampoline.c - perf_map_file - Objects/unicodeobject.c - ucnhash_capi - Parser/action_helpers.c _PyPegen_dummy_name cache - Python/dtoa.c - p5s - @@ -456,10 +456,10 @@ Objects/dictobject.c - next_dict_keys_version - Objects/funcobject.c - next_func_version - Objects/moduleobject.c - max_module_number - Objects/object.c - _Py_RefTotal - -Objects/perf_trampoline.c - perf_status - -Objects/perf_trampoline.c - extra_code_index - -Objects/perf_trampoline.c - code_arena - -Objects/perf_trampoline.c - trampoline_api - +Python/perf_trampoline.c - perf_status - +Python/perf_trampoline.c - extra_code_index - +Python/perf_trampoline.c - code_arena - +Python/perf_trampoline.c - trampoline_api - Objects/typeobject.c - next_version_tag - Objects/typeobject.c resolve_slotdups ptrs - Parser/pegen.c - memo_statistics - diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index 28c2325c263d..dbfb0e01e7f7 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -77,8 +77,8 @@ Objects/object.c - _Py_GenericAliasIterType - Objects/object.c - _PyMemoryIter_Type - Objects/object.c - _PyLineIterator - Objects/object.c - _PyPositionsIterator - -Objects/perf_trampoline.c - _Py_trampoline_func_start - -Objects/perf_trampoline.c - _Py_trampoline_func_end - +Python/perf_trampoline.c - _Py_trampoline_func_start - +Python/perf_trampoline.c - _Py_trampoline_func_end - Python/importdl.h - _PyImport_DynLoadFiletab - Modules/expat/xmlrole.c - prolog0 - @@ -465,7 +465,7 @@ Objects/obmalloc.c - _PyMem_Debug - Objects/obmalloc.c - _PyMem_Raw - Objects/obmalloc.c - _PyObject - Objects/obmalloc.c - usedpools - -Objects/perf_trampoline.c - _Py_perfmap_callbacks - +Python/perf_trampoline.c - _Py_perfmap_callbacks - Objects/typeobject.c - name_op - Objects/unicodeobject.c - stripfuncnames - Objects/unicodeobject.c - utf7_category - diff --git a/configure b/configure index 15d97963742f..953c558d6048 100755 --- a/configure +++ b/configure @@ -11629,7 +11629,7 @@ if test "x$perf_trampoline" = xyes; then : $as_echo "#define PY_HAVE_PERF_TRAMPOLINE 1" >>confdefs.h - PERF_TRAMPOLINE_OBJ=Objects/asm_trampoline.o + PERF_TRAMPOLINE_OBJ=Python/asm_trampoline.o if test "x$Py_DEBUG" = xtrue; then : diff --git a/configure.ac b/configure.ac index c7945aaf8505..210ce3292cfd 100644 --- a/configure.ac +++ b/configure.ac @@ -3474,7 +3474,7 @@ AC_MSG_RESULT([$perf_trampoline]) AS_VAR_IF([perf_trampoline], [yes], [ AC_DEFINE([PY_HAVE_PERF_TRAMPOLINE], [1], [Define to 1 if you have the perf trampoline.]) - PERF_TRAMPOLINE_OBJ=Objects/asm_trampoline.o + PERF_TRAMPOLINE_OBJ=Python/asm_trampoline.o dnl perf needs frame pointers for unwinding, include compiler option in debug builds AS_VAR_IF([Py_DEBUG], [true], [ From webhook-mailer at python.org Tue Oct 25 18:57:07 2022 From: webhook-mailer at python.org (pablogsal) Date: Tue, 25 Oct 2022 22:57:07 -0000 Subject: [Python-checkins] gh-91058: Add error suggestions to 'import from' import errors (#98305) Message-ID: https://github.com/python/cpython/commit/7cfbb49fcd4c85f9bab3797302eadf93df490344 commit: 7cfbb49fcd4c85f9bab3797302eadf93df490344 branch: main author: Pablo Galindo Salgado committer: pablogsal date: 2022-10-25T23:56:59+01:00 summary: gh-91058: Add error suggestions to 'import from' import errors (#98305) files: A Misc/NEWS.d/next/Core and Builtins/2022-10-15-22-25-20.gh-issue-91058.Uo2kW-.rst M Include/cpython/pyerrors.h M Include/internal/pycore_global_strings.h M Include/internal/pycore_runtime_init_generated.h M Lib/test/test_call.py M Lib/test/test_traceback.py M Lib/traceback.py M Objects/exceptions.c M Python/ceval.c M Python/errors.c M Python/suggestions.c diff --git a/Include/cpython/pyerrors.h b/Include/cpython/pyerrors.h index f33d3caaa208..141341667795 100644 --- a/Include/cpython/pyerrors.h +++ b/Include/cpython/pyerrors.h @@ -37,6 +37,7 @@ typedef struct { PyObject *msg; PyObject *name; PyObject *path; + PyObject *name_from; } PyImportErrorObject; typedef struct { @@ -176,4 +177,11 @@ PyAPI_FUNC(void) _Py_NO_RETURN _Py_FatalErrorFormat( const char *format, ...); +extern PyObject *_PyErr_SetImportErrorWithNameFrom( + PyObject *, + PyObject *, + PyObject *, + PyObject *); + + #define Py_FatalError(message) _Py_FatalErrorFunc(__func__, (message)) diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 9c716a3012f4..43f4dac89386 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -478,6 +478,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(n_sequence_fields) STRUCT_FOR_ID(n_unnamed_fields) STRUCT_FOR_ID(name) + STRUCT_FOR_ID(name_from) STRUCT_FOR_ID(namespace_separator) STRUCT_FOR_ID(namespaces) STRUCT_FOR_ID(narg) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index 55c7c9e3194c..f7823d36ef81 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -987,6 +987,7 @@ extern "C" { INIT_ID(n_sequence_fields), \ INIT_ID(n_unnamed_fields), \ INIT_ID(name), \ + INIT_ID(name_from), \ INIT_ID(namespace_separator), \ INIT_ID(namespaces), \ INIT_ID(narg), \ @@ -2286,6 +2287,8 @@ _PyUnicode_InitStaticStrings(void) { PyUnicode_InternInPlace(&string); string = &_Py_ID(name); PyUnicode_InternInPlace(&string); + string = &_Py_ID(name_from); + PyUnicode_InternInPlace(&string); string = &_Py_ID(namespace_separator); PyUnicode_InternInPlace(&string); string = &_Py_ID(namespaces); @@ -6505,6 +6508,10 @@ _PyStaticObjects_CheckRefcnt(void) { _PyObject_Dump((PyObject *)&_Py_ID(name)); Py_FatalError("immortal object has less refcnt than expected _PyObject_IMMORTAL_REFCNT"); }; + if (Py_REFCNT((PyObject *)&_Py_ID(name_from)) < _PyObject_IMMORTAL_REFCNT) { + _PyObject_Dump((PyObject *)&_Py_ID(name_from)); + Py_FatalError("immortal object has less refcnt than expected _PyObject_IMMORTAL_REFCNT"); + }; if (Py_REFCNT((PyObject *)&_Py_ID(namespace_separator)) < _PyObject_IMMORTAL_REFCNT) { _PyObject_Dump((PyObject *)&_Py_ID(namespace_separator)); Py_FatalError("immortal object has less refcnt than expected _PyObject_IMMORTAL_REFCNT"); diff --git a/Lib/test/test_call.py b/Lib/test/test_call.py index 1f3307f822a5..0b37116cd682 100644 --- a/Lib/test/test_call.py +++ b/Lib/test/test_call.py @@ -140,9 +140,9 @@ def test_varargs14_kw(self): itertools.product, 0, repeat=1, foo=2) def test_varargs15_kw(self): - msg = r"^ImportError\(\) takes at most 2 keyword arguments \(3 given\)$" + msg = r"^ImportError\(\) takes at most 3 keyword arguments \(4 given\)$" self.assertRaisesRegex(TypeError, msg, - ImportError, 0, name=1, path=2, foo=3) + ImportError, 0, name=1, path=2, name_from=3, foo=3) def test_varargs16_kw(self): msg = r"^min\(\) takes at most 2 keyword arguments \(3 given\)$" diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 2d17e0600650..cf52d17ff8fa 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -6,14 +6,20 @@ import sys import types import inspect +import importlib import unittest import re +import tempfile +import random +import string from test import support +import shutil from test.support import (Error, captured_output, cpython_only, ALWAYS_EQ, requires_debug_ranges, has_no_debug_ranges, requires_subprocess) from test.support.os_helper import TESTFN, unlink from test.support.script_helper import assert_python_ok, assert_python_failure +from test.support.import_helper import forget import json import textwrap @@ -2985,6 +2991,122 @@ def __getattribute__(self, attr): self.assertIn("Did you mean", actual) self.assertIn("bluch", actual) + def make_module(self, code): + tmpdir = Path(tempfile.mkdtemp()) + self.addCleanup(shutil.rmtree, tmpdir) + + sys.path.append(str(tmpdir)) + self.addCleanup(sys.path.pop) + + mod_name = ''.join(random.choices(string.ascii_letters, k=16)) + module = tmpdir / (mod_name + ".py") + module.write_text(code) + + return mod_name + + def get_import_from_suggestion(self, mod_dict, name): + modname = self.make_module(mod_dict) + + def callable(): + try: + exec(f"from {modname} import {name}") + except ImportError as e: + raise e from None + except Exception as e: + self.fail(f"Expected ImportError but got {type(e)}") + self.addCleanup(forget, modname) + + result_lines = self.get_exception( + callable, slice_start=-1, slice_end=None + ) + return result_lines[0] + + def test_import_from_suggestions(self): + substitution = textwrap.dedent("""\ + noise = more_noise = a = bc = None + blech = None + """) + + elimination = textwrap.dedent(""" + noise = more_noise = a = bc = None + blch = None + """) + + addition = textwrap.dedent(""" + noise = more_noise = a = bc = None + bluchin = None + """) + + substitutionOverElimination = textwrap.dedent(""" + blach = None + bluc = None + """) + + substitutionOverAddition = textwrap.dedent(""" + blach = None + bluchi = None + """) + + eliminationOverAddition = textwrap.dedent(""" + blucha = None + bluc = None + """) + + caseChangeOverSubstitution = textwrap.dedent(""" + Luch = None + fluch = None + BLuch = None + """) + + for code, suggestion in [ + (addition, "'bluchin'?"), + (substitution, "'blech'?"), + (elimination, "'blch'?"), + (addition, "'bluchin'?"), + (substitutionOverElimination, "'blach'?"), + (substitutionOverAddition, "'blach'?"), + (eliminationOverAddition, "'bluc'?"), + (caseChangeOverSubstitution, "'BLuch'?"), + ]: + actual = self.get_import_from_suggestion(code, 'bluch') + self.assertIn(suggestion, actual) + + def test_import_from_suggestions_do_not_trigger_for_long_attributes(self): + code = "blech = None" + + actual = self.get_suggestion(code, 'somethingverywrong') + self.assertNotIn("blech", actual) + + def test_import_from_error_bad_suggestions_do_not_trigger_for_small_names(self): + code = "vvv = mom = w = id = pytho = None" + + for name in ("b", "v", "m", "py"): + with self.subTest(name=name): + actual = self.get_import_from_suggestion(code, name) + self.assertNotIn("you mean", actual) + self.assertNotIn("vvv", actual) + self.assertNotIn("mom", actual) + self.assertNotIn("'id'", actual) + self.assertNotIn("'w'", actual) + self.assertNotIn("'pytho'", actual) + + def test_import_from_suggestions_do_not_trigger_for_big_namespaces(self): + # A module with lots of names will not be considered for suggestions. + chunks = [f"index_{index} = " for index in range(200)] + chunks.append(" None") + code = " ".join(chunks) + actual = self.get_import_from_suggestion(code, 'bluch') + self.assertNotIn("blech", actual) + + def test_import_from_error_with_bad_name(self): + def raise_attribute_error_with_bad_name(): + raise ImportError(name=12, obj=23, name_from=11) + + result_lines = self.get_exception( + raise_attribute_error_with_bad_name, slice_start=-1, slice_end=None + ) + self.assertNotIn("?", result_lines[-1]) + def test_name_error_suggestions(self): def Substitution(): noise = more_noise = a = bc = None diff --git a/Lib/traceback.py b/Lib/traceback.py index bb7856a5142e..6270100348a6 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -707,9 +707,16 @@ def __init__(self, exc_type, exc_value, exc_traceback, *, limit=None, self.offset = exc_value.offset self.end_offset = exc_value.end_offset self.msg = exc_value.msg + elif exc_type and issubclass(exc_type, ImportError) and \ + getattr(exc_value, "name_from", None) is not None: + wrong_name = getattr(exc_value, "name_from", None) + suggestion = _compute_suggestion_error(exc_value, exc_traceback, wrong_name) + if suggestion: + self._str += f". Did you mean: '{suggestion}'?" elif exc_type and issubclass(exc_type, (NameError, AttributeError)) and \ getattr(exc_value, "name", None) is not None: - suggestion = _compute_suggestion_error(exc_value, exc_traceback) + wrong_name = getattr(exc_value, "name", None) + suggestion = _compute_suggestion_error(exc_value, exc_traceback, wrong_name) if suggestion: self._str += f". Did you mean: '{suggestion}'?" if issubclass(exc_type, NameError): @@ -1005,8 +1012,7 @@ def _substitution_cost(ch_a, ch_b): return _MOVE_COST -def _compute_suggestion_error(exc_value, tb): - wrong_name = getattr(exc_value, "name", None) +def _compute_suggestion_error(exc_value, tb, wrong_name): if wrong_name is None or not isinstance(wrong_name, str): return None if isinstance(exc_value, AttributeError): @@ -1015,6 +1021,12 @@ def _compute_suggestion_error(exc_value, tb): d = dir(obj) except Exception: return None + elif isinstance(exc_value, ImportError): + try: + mod = __import__(exc_value.name) + d = dir(mod) + except Exception: + return None else: assert isinstance(exc_value, NameError) # find most recent frame diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-15-22-25-20.gh-issue-91058.Uo2kW-.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-15-22-25-20.gh-issue-91058.Uo2kW-.rst new file mode 100644 index 000000000000..042c7cebd894 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-15-22-25-20.gh-issue-91058.Uo2kW-.rst @@ -0,0 +1,3 @@ +:exc:`ImportError` raised from failed ``from import `` now +include suggestions for the value of ```` based on the available names +in ````. Patch by Pablo Galindo diff --git a/Objects/exceptions.c b/Objects/exceptions.c index 80e98bb4ffa4..4b4f31a209b6 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -1464,11 +1464,12 @@ SimpleExtendsException(PyExc_BaseException, KeyboardInterrupt, static int ImportError_init(PyImportErrorObject *self, PyObject *args, PyObject *kwds) { - static char *kwlist[] = {"name", "path", 0}; + static char *kwlist[] = {"name", "path", "name_from", 0}; PyObject *empty_tuple; PyObject *msg = NULL; PyObject *name = NULL; PyObject *path = NULL; + PyObject *name_from = NULL; if (BaseException_init((PyBaseExceptionObject *)self, args, NULL) == -1) return -1; @@ -1476,8 +1477,8 @@ ImportError_init(PyImportErrorObject *self, PyObject *args, PyObject *kwds) empty_tuple = PyTuple_New(0); if (!empty_tuple) return -1; - if (!PyArg_ParseTupleAndKeywords(empty_tuple, kwds, "|$OO:ImportError", kwlist, - &name, &path)) { + if (!PyArg_ParseTupleAndKeywords(empty_tuple, kwds, "|$OOO:ImportError", kwlist, + &name, &path, &name_from)) { Py_DECREF(empty_tuple); return -1; } @@ -1489,6 +1490,9 @@ ImportError_init(PyImportErrorObject *self, PyObject *args, PyObject *kwds) Py_XINCREF(path); Py_XSETREF(self->path, path); + Py_XINCREF(name_from); + Py_XSETREF(self->name_from, name_from); + if (PyTuple_GET_SIZE(args) == 1) { msg = PyTuple_GET_ITEM(args, 0); Py_INCREF(msg); @@ -1504,6 +1508,7 @@ ImportError_clear(PyImportErrorObject *self) Py_CLEAR(self->msg); Py_CLEAR(self->name); Py_CLEAR(self->path); + Py_CLEAR(self->name_from); return BaseException_clear((PyBaseExceptionObject *)self); } @@ -1521,6 +1526,7 @@ ImportError_traverse(PyImportErrorObject *self, visitproc visit, void *arg) Py_VISIT(self->msg); Py_VISIT(self->name); Py_VISIT(self->path); + Py_VISIT(self->name_from); return BaseException_traverse((PyBaseExceptionObject *)self, visit, arg); } @@ -1540,7 +1546,7 @@ static PyObject * ImportError_getstate(PyImportErrorObject *self) { PyObject *dict = ((PyBaseExceptionObject *)self)->dict; - if (self->name || self->path) { + if (self->name || self->path || self->name_from) { dict = dict ? PyDict_Copy(dict) : PyDict_New(); if (dict == NULL) return NULL; @@ -1552,6 +1558,10 @@ ImportError_getstate(PyImportErrorObject *self) Py_DECREF(dict); return NULL; } + if (self->name_from && PyDict_SetItem(dict, &_Py_ID(name_from), self->name_from) < 0) { + Py_DECREF(dict); + return NULL; + } return dict; } else if (dict) { @@ -1588,6 +1598,8 @@ static PyMemberDef ImportError_members[] = { PyDoc_STR("module name")}, {"path", T_OBJECT, offsetof(PyImportErrorObject, path), 0, PyDoc_STR("module path")}, + {"name_from", T_OBJECT, offsetof(PyImportErrorObject, name_from), 0, + PyDoc_STR("name imported from module")}, {NULL} /* Sentinel */ }; diff --git a/Python/ceval.c b/Python/ceval.c index fb8dd4811628..35ce767710e1 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -6900,7 +6900,7 @@ import_from(PyThreadState *tstate, PyObject *v, PyObject *name) name, pkgname_or_unknown ); /* NULL checks for errmsg and pkgname done by PyErr_SetImportError. */ - PyErr_SetImportError(errmsg, pkgname, NULL); + _PyErr_SetImportErrorWithNameFrom(errmsg, pkgname, NULL, name); } else { PyObject *spec = PyObject_GetAttr(v, &_Py_ID(__spec__)); @@ -6913,7 +6913,7 @@ import_from(PyThreadState *tstate, PyObject *v, PyObject *name) errmsg = PyUnicode_FromFormat(fmt, name, pkgname_or_unknown, pkgpath); /* NULL checks for errmsg and pkgname done by PyErr_SetImportError. */ - PyErr_SetImportError(errmsg, pkgname, pkgpath); + _PyErr_SetImportErrorWithNameFrom(errmsg, pkgname, pkgpath, name); } Py_XDECREF(errmsg); diff --git a/Python/errors.c b/Python/errors.c index 2aa748c60c37..fc3e46892094 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -975,9 +975,10 @@ PyObject *PyErr_SetFromWindowsErrWithFilename( #endif /* MS_WINDOWS */ -PyObject * -PyErr_SetImportErrorSubclass(PyObject *exception, PyObject *msg, - PyObject *name, PyObject *path) +static PyObject * +_PyErr_SetImportErrorSubclassWithNameFrom( + PyObject *exception, PyObject *msg, + PyObject *name, PyObject *path, PyObject* from_name) { PyThreadState *tstate = _PyThreadState_GET(); int issubclass; @@ -1005,6 +1006,10 @@ PyErr_SetImportErrorSubclass(PyObject *exception, PyObject *msg, if (path == NULL) { path = Py_None; } + if (from_name == NULL) { + from_name = Py_None; + } + kwargs = PyDict_New(); if (kwargs == NULL) { @@ -1016,6 +1021,9 @@ PyErr_SetImportErrorSubclass(PyObject *exception, PyObject *msg, if (PyDict_SetItemString(kwargs, "path", path) < 0) { goto done; } + if (PyDict_SetItemString(kwargs, "name_from", from_name) < 0) { + goto done; + } error = PyObject_VectorcallDict(exception, &msg, 1, kwargs); if (error != NULL) { @@ -1028,6 +1036,20 @@ PyErr_SetImportErrorSubclass(PyObject *exception, PyObject *msg, return NULL; } + +PyObject * +PyErr_SetImportErrorSubclass(PyObject *exception, PyObject *msg, + PyObject *name, PyObject *path) +{ + return _PyErr_SetImportErrorSubclassWithNameFrom(exception, msg, name, path, NULL); +} + +PyObject * +_PyErr_SetImportErrorWithNameFrom(PyObject *msg, PyObject *name, PyObject *path, PyObject* from_name) +{ + return _PyErr_SetImportErrorSubclassWithNameFrom(PyExc_ImportError, msg, name, path, from_name); +} + PyObject * PyErr_SetImportError(PyObject *msg, PyObject *name, PyObject *path) { diff --git a/Python/suggestions.c b/Python/suggestions.c index 89b86f78bc7a..82376b6cd985 100644 --- a/Python/suggestions.c +++ b/Python/suggestions.c @@ -312,6 +312,38 @@ offer_suggestions_for_name_error(PyNameErrorObject *exc) return result; } +static PyObject * +offer_suggestions_for_import_error(PyImportErrorObject *exc) +{ + PyObject *mod_name = exc->name; // borrowed reference + PyObject *name = exc->name_from; // borrowed reference + if (name == NULL || mod_name == NULL || name == Py_None || + !PyUnicode_CheckExact(name) || !PyUnicode_CheckExact(mod_name)) { + return NULL; + } + + PyObject* mod = PyImport_GetModule(mod_name); + if (mod == NULL) { + return NULL; + } + + PyObject *dir = PyObject_Dir(mod); + Py_DECREF(mod); + if (dir == NULL) { + return NULL; + } + + PyObject *suggestion = calculate_suggestions(dir, name); + Py_DECREF(dir); + if (!suggestion) { + return NULL; + } + + PyObject* result = PyUnicode_FromFormat(". Did you mean: %R?", suggestion); + Py_DECREF(suggestion); + return result; +} + // Offer suggestions for a given exception. Returns a python string object containing the // suggestions. This function returns NULL if no suggestion was found or if an exception happened, // users must call PyErr_Occurred() to disambiguate. @@ -324,6 +356,8 @@ _Py_Offer_Suggestions(PyObject *exception) result = offer_suggestions_for_attribute_error((PyAttributeErrorObject *) exception); } else if (Py_IS_TYPE(exception, (PyTypeObject*)PyExc_NameError)) { result = offer_suggestions_for_name_error((PyNameErrorObject *) exception); + } else if (Py_IS_TYPE(exception, (PyTypeObject*)PyExc_ImportError)) { + result = offer_suggestions_for_import_error((PyImportErrorObject *) exception); } return result; } From webhook-mailer at python.org Tue Oct 25 18:58:10 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Tue, 25 Oct 2022 22:58:10 -0000 Subject: [Python-checkins] gh-97937: dis docs: add adaptive=False (#97939) Message-ID: https://github.com/python/cpython/commit/5d8bf2b106e694423bafaa3e1ea1edf20037573c commit: 5d8bf2b106e694423bafaa3e1ea1edf20037573c branch: main author: Jelle Zijlstra committer: JelleZijlstra date: 2022-10-25T15:58:04-07:00 summary: gh-97937: dis docs: add adaptive=False (#97939) Co-authored-by: Shantanu <12621235+hauntsaninja at users.noreply.github.com> Co-authored-by: Brandt Bucher files: M Doc/library/dis.rst diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 33df7be43634..c6b43035c294 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -38,7 +38,9 @@ interpreter. Some instructions are accompanied by one or more inline cache entries, which take the form of :opcode:`CACHE` instructions. These instructions are hidden by default, but can be shown by passing ``show_caches=True`` to - any :mod:`dis` utility. + any :mod:`dis` utility. Furthermore, the interpreter now adapts the + bytecode to specialize it for different runtime conditions. The + adaptive bytecode can be shown by passing ``adaptive=True``. Example: Given the function :func:`myfunc`:: @@ -70,8 +72,8 @@ The bytecode analysis API allows pieces of Python code to be wrapped in a :class:`Bytecode` object that provides easy access to details of the compiled code. -.. class:: Bytecode(x, *, first_line=None, current_offset=None, show_caches=False) - +.. class:: Bytecode(x, *, first_line=None, current_offset=None,\ + show_caches=False, adaptive=False) Analyse the bytecode corresponding to a function, generator, asynchronous generator, coroutine, method, string of source code, or a code object (as @@ -90,6 +92,12 @@ code. disassembled code. Setting this means :meth:`.dis` will display a "current instruction" marker against the specified opcode. + If *show_caches* is ``True``, :meth:`.dis` will display inline cache + entries used by the interpreter to specialize the bytecode. + + If *adaptive* is ``True``, :meth:`.dis` will display specialized bytecode + that may be different from the original bytecode. + .. classmethod:: from_traceback(tb, *, show_caches=False) Construct a :class:`Bytecode` instance from the given traceback, setting @@ -117,7 +125,7 @@ code. This can now handle coroutine and asynchronous generator objects. .. versionchanged:: 3.11 - Added the ``show_caches`` parameter. + Added the *show_caches* and *adaptive* parameters. Example: @@ -172,7 +180,7 @@ operation is being performed, so the intermediate analysis object isn't useful: Added *file* parameter. -.. function:: dis(x=None, *, file=None, depth=None, show_caches=False) +.. function:: dis(x=None, *, file=None, depth=None, show_caches=False, adaptive=False) Disassemble the *x* object. *x* can denote either a module, a class, a method, a function, a generator, an asynchronous generator, a coroutine, @@ -193,6 +201,12 @@ operation is being performed, so the intermediate analysis object isn't useful: The maximal depth of recursion is limited by *depth* unless it is ``None``. ``depth=0`` means no recursion. + If *show_caches* is ``True``, this function will display inline cache + entries used by the interpreter to specialize the bytecode. + + If *adaptive* is ``True``, this function will display specialized bytecode + that may be different from the original bytecode. + .. versionchanged:: 3.4 Added *file* parameter. @@ -203,10 +217,10 @@ operation is being performed, so the intermediate analysis object isn't useful: This can now handle coroutine and asynchronous generator objects. .. versionchanged:: 3.11 - Added the ``show_caches`` parameter. + Added the *show_caches* and *adaptive* parameters. -.. function:: distb(tb=None, *, file=None, show_caches=False) +.. function:: distb(tb=None, *, file=None, show_caches=False, adaptive=False) Disassemble the top-of-stack function of a traceback, using the last traceback if none was passed. The instruction causing the exception is @@ -219,11 +233,11 @@ operation is being performed, so the intermediate analysis object isn't useful: Added *file* parameter. .. versionchanged:: 3.11 - Added the ``show_caches`` parameter. + Added the *show_caches* and *adaptive* parameters. -.. function:: disassemble(code, lasti=-1, *, file=None, show_caches=False) - disco(code, lasti=-1, *, file=None, show_caches=False) +.. function:: disassemble(code, lasti=-1, *, file=None, show_caches=False, adaptive=False) + disco(code, lasti=-1, *, file=None, show_caches=False, adaptive=False) Disassemble a code object, indicating the last instruction if *lasti* was provided. The output is divided in the following columns: @@ -246,10 +260,10 @@ operation is being performed, so the intermediate analysis object isn't useful: Added *file* parameter. .. versionchanged:: 3.11 - Added the ``show_caches`` parameter. + Added the *show_caches* and *adaptive* parameters. -.. function:: get_instructions(x, *, first_line=None, show_caches=False) +.. function:: get_instructions(x, *, first_line=None, show_caches=False, adaptive=False) Return an iterator over the instructions in the supplied function, method, source code string or code object. @@ -262,10 +276,12 @@ operation is being performed, so the intermediate analysis object isn't useful: source line information (if any) is taken directly from the disassembled code object. + The *show_caches* and *adaptive* parameters work as they do in :func:`dis`. + .. versionadded:: 3.4 .. versionchanged:: 3.11 - Added the ``show_caches`` parameter. + Added the *show_caches* and *adaptive* parameters. .. function:: findlinestarts(code) From webhook-mailer at python.org Tue Oct 25 19:06:14 2022 From: webhook-mailer at python.org (miss-islington) Date: Tue, 25 Oct 2022 23:06:14 -0000 Subject: [Python-checkins] gh-97937: dis docs: add adaptive=False (GH-97939) Message-ID: https://github.com/python/cpython/commit/4fc042f28f1ae91c7b1b2fd9892fbea50a3211c1 commit: 4fc042f28f1ae91c7b1b2fd9892fbea50a3211c1 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-25T16:06:08-07:00 summary: gh-97937: dis docs: add adaptive=False (GH-97939) Co-authored-by: Shantanu <12621235+hauntsaninja at users.noreply.github.com> Co-authored-by: Brandt Bucher (cherry picked from commit 5d8bf2b106e694423bafaa3e1ea1edf20037573c) Co-authored-by: Jelle Zijlstra files: M Doc/library/dis.rst diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 98866b72a30a..1e323bd50066 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -38,7 +38,9 @@ interpreter. Some instructions are accompanied by one or more inline cache entries, which take the form of :opcode:`CACHE` instructions. These instructions are hidden by default, but can be shown by passing ``show_caches=True`` to - any :mod:`dis` utility. + any :mod:`dis` utility. Furthermore, the interpreter now adapts the + bytecode to specialize it for different runtime conditions. The + adaptive bytecode can be shown by passing ``adaptive=True``. Example: Given the function :func:`myfunc`:: @@ -71,8 +73,8 @@ The bytecode analysis API allows pieces of Python code to be wrapped in a :class:`Bytecode` object that provides easy access to details of the compiled code. -.. class:: Bytecode(x, *, first_line=None, current_offset=None, show_caches=False) - +.. class:: Bytecode(x, *, first_line=None, current_offset=None,\ + show_caches=False, adaptive=False) Analyse the bytecode corresponding to a function, generator, asynchronous generator, coroutine, method, string of source code, or a code object (as @@ -91,6 +93,12 @@ code. disassembled code. Setting this means :meth:`.dis` will display a "current instruction" marker against the specified opcode. + If *show_caches* is ``True``, :meth:`.dis` will display inline cache + entries used by the interpreter to specialize the bytecode. + + If *adaptive* is ``True``, :meth:`.dis` will display specialized bytecode + that may be different from the original bytecode. + .. classmethod:: from_traceback(tb, *, show_caches=False) Construct a :class:`Bytecode` instance from the given traceback, setting @@ -118,7 +126,7 @@ code. This can now handle coroutine and asynchronous generator objects. .. versionchanged:: 3.11 - Added the ``show_caches`` parameter. + Added the *show_caches* and *adaptive* parameters. Example: @@ -174,7 +182,7 @@ operation is being performed, so the intermediate analysis object isn't useful: Added *file* parameter. -.. function:: dis(x=None, *, file=None, depth=None, show_caches=False) +.. function:: dis(x=None, *, file=None, depth=None, show_caches=False, adaptive=False) Disassemble the *x* object. *x* can denote either a module, a class, a method, a function, a generator, an asynchronous generator, a coroutine, @@ -195,6 +203,12 @@ operation is being performed, so the intermediate analysis object isn't useful: The maximal depth of recursion is limited by *depth* unless it is ``None``. ``depth=0`` means no recursion. + If *show_caches* is ``True``, this function will display inline cache + entries used by the interpreter to specialize the bytecode. + + If *adaptive* is ``True``, this function will display specialized bytecode + that may be different from the original bytecode. + .. versionchanged:: 3.4 Added *file* parameter. @@ -205,10 +219,10 @@ operation is being performed, so the intermediate analysis object isn't useful: This can now handle coroutine and asynchronous generator objects. .. versionchanged:: 3.11 - Added the ``show_caches`` parameter. + Added the *show_caches* and *adaptive* parameters. -.. function:: distb(tb=None, *, file=None, show_caches=False) +.. function:: distb(tb=None, *, file=None, show_caches=False, adaptive=False) Disassemble the top-of-stack function of a traceback, using the last traceback if none was passed. The instruction causing the exception is @@ -221,11 +235,11 @@ operation is being performed, so the intermediate analysis object isn't useful: Added *file* parameter. .. versionchanged:: 3.11 - Added the ``show_caches`` parameter. + Added the *show_caches* and *adaptive* parameters. -.. function:: disassemble(code, lasti=-1, *, file=None, show_caches=False) - disco(code, lasti=-1, *, file=None, show_caches=False) +.. function:: disassemble(code, lasti=-1, *, file=None, show_caches=False, adaptive=False) + disco(code, lasti=-1, *, file=None, show_caches=False, adaptive=False) Disassemble a code object, indicating the last instruction if *lasti* was provided. The output is divided in the following columns: @@ -248,10 +262,10 @@ operation is being performed, so the intermediate analysis object isn't useful: Added *file* parameter. .. versionchanged:: 3.11 - Added the ``show_caches`` parameter. + Added the *show_caches* and *adaptive* parameters. -.. function:: get_instructions(x, *, first_line=None, show_caches=False) +.. function:: get_instructions(x, *, first_line=None, show_caches=False, adaptive=False) Return an iterator over the instructions in the supplied function, method, source code string or code object. @@ -264,10 +278,12 @@ operation is being performed, so the intermediate analysis object isn't useful: source line information (if any) is taken directly from the disassembled code object. + The *show_caches* and *adaptive* parameters work as they do in :func:`dis`. + .. versionadded:: 3.4 .. versionchanged:: 3.11 - Added the ``show_caches`` parameter. + Added the *show_caches* and *adaptive* parameters. .. function:: findlinestarts(code) From webhook-mailer at python.org Tue Oct 25 19:36:19 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Tue, 25 Oct 2022 23:36:19 -0000 Subject: [Python-checkins] Fix typos in deprecation section of 3.11 What's New (#98628) Message-ID: https://github.com/python/cpython/commit/faea6a131a9d06208e9043b499a90e11bdfbb479 commit: faea6a131a9d06208e9043b499a90e11bdfbb479 branch: main author: Jacob Walls committer: JelleZijlstra date: 2022-10-25T16:35:53-07:00 summary: Fix typos in deprecation section of 3.11 What's New (#98628) files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index cc8437f1709a..ab56f0d354c7 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1722,7 +1722,7 @@ Modules * The :mod:`asynchat`, :mod:`asyncore` and :mod:`smtpd` modules have been deprecated since at least Python 3.6. Their documentation and deprecation - warnings have now been updated to note they will removed in Python 3.12. + warnings have now been updated to note they will be removed in Python 3.12. (Contributed by Hugo van Kemenade in :issue:`47022`.) * The :mod:`lib2to3` package and :ref:`2to3 <2to3-reference>` tool @@ -1741,8 +1741,8 @@ Standard Library ---------------- * The following have been deprecated in :mod:`configparser` since Python 3.2. - Their deprecation warnings have now been updated to note they will removed in - Python 3.12: + Their deprecation warnings have now been updated to note they will be removed + in Python 3.12: * the :class:`!configparser.SafeConfigParser` class * the :attr:`!configparser.ParsingError.filename` property From webhook-mailer at python.org Tue Oct 25 19:37:59 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Tue, 25 Oct 2022 23:37:59 -0000 Subject: [Python-checkins] gh-94808: Improve coverage of `unicode_find` and `unicode_rfind` (#98648) Message-ID: https://github.com/python/cpython/commit/b1783bc124712fa03fea9621a0eb4119d29b14fe commit: b1783bc124712fa03fea9621a0eb4119d29b14fe branch: main author: Nikita Sobolev committer: JelleZijlstra date: 2022-10-25T16:37:53-07:00 summary: gh-94808: Improve coverage of `unicode_find` and `unicode_rfind` (#98648) files: M Lib/test/test_unicode.py diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py index 05e7e30d639a..7230591d2c82 100644 --- a/Lib/test/test_unicode.py +++ b/Lib/test/test_unicode.py @@ -261,6 +261,20 @@ def test_find(self): self.checkequalnofix(9, 'abcdefghiabc', 'find', 'abc', 1) self.checkequalnofix(-1, 'abcdefghiabc', 'find', 'def', 4) + # test utf-8 non-ascii char + self.checkequal(0, '????', 'find', '?') + self.checkequal(3, '????', 'find', '?', 1) + self.checkequal(-1, '????', 'find', '?', 1, 3) + self.checkequal(-1, '????', 'find', 'e') # english `e` + # test utf-8 non-ascii slice + self.checkequal(1, '???? ????', 'find', '??') + self.checkequal(1, '???? ????', 'find', '??', 1) + self.checkequal(1, '???? ????', 'find', '??', 1, 3) + self.checkequal(6, '???? ????', 'find', '??', 2) + self.checkequal(-1, '???? ????', 'find', '??', 6, 7) + self.checkequal(-1, '???? ????', 'find', '??', 7) + self.checkequal(-1, '???? ????', 'find', 'ec') # english `ec` + self.assertRaises(TypeError, 'hello'.find) self.assertRaises(TypeError, 'hello'.find, 42) # test mixed kinds @@ -291,6 +305,19 @@ def test_rfind(self): self.checkequalnofix(9, 'abcdefghiabc', 'rfind', 'abc') self.checkequalnofix(12, 'abcdefghiabc', 'rfind', '') self.checkequalnofix(12, 'abcdefghiabc', 'rfind', '') + # test utf-8 non-ascii char + self.checkequal(1, '????', 'rfind', '?') + self.checkequal(1, '????', 'rfind', '?', 1) + self.checkequal(-1, '????', 'rfind', '?', 2) + self.checkequal(-1, '????', 'rfind', 'e') # english `e` + # test utf-8 non-ascii slice + self.checkequal(6, '???? ????', 'rfind', '??') + self.checkequal(6, '???? ????', 'rfind', '??', 1) + self.checkequal(1, '???? ????', 'rfind', '??', 1, 3) + self.checkequal(6, '???? ????', 'rfind', '??', 2) + self.checkequal(-1, '???? ????', 'rfind', '??', 6, 7) + self.checkequal(-1, '???? ????', 'rfind', '??', 7) + self.checkequal(-1, '???? ????', 'rfind', 'ec') # english `ec` # test mixed kinds self.checkequal(0, 'a' + '\u0102' * 100, 'rfind', 'a') self.checkequal(0, 'a' + '\U00100304' * 100, 'rfind', 'a') From webhook-mailer at python.org Tue Oct 25 19:41:57 2022 From: webhook-mailer at python.org (miss-islington) Date: Tue, 25 Oct 2022 23:41:57 -0000 Subject: [Python-checkins] gh-95913: Fix, sort & expand pending removal sect in 3.11 WhatsNew (GH-98583) Message-ID: https://github.com/python/cpython/commit/08c3c910553e55e238abe7fd7b7fee258ec5e11e commit: 08c3c910553e55e238abe7fd7b7fee258ec5e11e branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-25T16:41:51-07:00 summary: gh-95913: Fix, sort & expand pending removal sect in 3.11 WhatsNew (GH-98583) * Fix names/references of pending removal APIs * Sort list of APIs pending removal alphabetically * Add missing modules/submodules pending removal in 3.12 * Add table of unittest deprecated aliases to 3.11 What's New Co-authored-by: Jelle Zijlstra Co-authored-by: Petr Viktorin (cherry picked from commit e19c2b979fab3483dc6c04774053dbbe83e769fb) Co-authored-by: C.A.M. Gerlach files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 8f13bf3fa173..f819c92cb3fb 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1847,33 +1847,56 @@ and will be removed in Python 3.12. C APIs pending removal are :ref:`listed separately `. -* :class:`pkgutil.ImpImporter` -* :class:`pkgutil.ImpLoader` -* :envvar:`PYTHONTHREADDEBUG` +* The :mod:`asynchat` module +* The :mod:`asyncore` module +* The :ref:`entire distutils package ` +* The :mod:`imp` module +* The :class:`typing.io ` namespace +* The :class:`typing.re ` namespace +* :func:`!cgi.log` * :func:`importlib.find_loader` -* :func:`importlib.util.module_for_loader` -* :func:`importlib.util.set_loader_wrapper` -* :func:`importlib.util.set_package_wrapper` * :meth:`importlib.abc.Loader.module_repr` -* :meth:`importlib.abc.Loadermodule_repr` -* :meth:`importlib.abc.MetaPathFinder.find_module` * :meth:`importlib.abc.MetaPathFinder.find_module` * :meth:`importlib.abc.PathEntryFinder.find_loader` * :meth:`importlib.abc.PathEntryFinder.find_module` -* :meth:`importlib.machinery.BuiltinImporter.find_module` -* :meth:`importlib.machinery.BuiltinLoader.module_repr` -* :meth:`importlib.machinery.FileFinder.find_loader` -* :meth:`importlib.machinery.FileFinder.find_module` -* :meth:`importlib.machinery.FrozenImporter.find_module` -* :meth:`importlib.machinery.FrozenLoader.module_repr` +* :meth:`!importlib.machinery.BuiltinImporter.find_module` +* :meth:`!importlib.machinery.BuiltinLoader.module_repr` +* :meth:`!importlib.machinery.FileFinder.find_loader` +* :meth:`!importlib.machinery.FileFinder.find_module` +* :meth:`!importlib.machinery.FrozenImporter.find_module` +* :meth:`!importlib.machinery.FrozenLoader.module_repr` * :meth:`importlib.machinery.PathFinder.find_module` -* :meth:`importlib.machinery.WindowsRegistryFinder.find_module` +* :meth:`!importlib.machinery.WindowsRegistryFinder.find_module` +* :func:`importlib.util.module_for_loader` +* :func:`!importlib.util.set_loader_wrapper` +* :func:`!importlib.util.set_package_wrapper` +* :class:`pkgutil.ImpImporter` +* :class:`pkgutil.ImpLoader` * :meth:`pathlib.Path.link_to` -* The entire :ref:`distutils namespace ` -* :func:`cgi.log` -* :func:`sqlite3.OptimizedUnicode` -* :func:`sqlite3.enable_shared_cache` - +* :func:`!sqlite3.enable_shared_cache` +* :func:`!sqlite3.OptimizedUnicode` +* :envvar:`PYTHONTHREADDEBUG` environment variable +* The following deprecated aliases in :mod:`unittest`: + + ============================ =============================== =============== + Deprecated alias Method Name Deprecated in + ============================ =============================== =============== + ``failUnless`` :meth:`.assertTrue` 3.1 + ``failIf`` :meth:`.assertFalse` 3.1 + ``failUnlessEqual`` :meth:`.assertEqual` 3.1 + ``failIfEqual`` :meth:`.assertNotEqual` 3.1 + ``failUnlessAlmostEqual`` :meth:`.assertAlmostEqual` 3.1 + ``failIfAlmostEqual`` :meth:`.assertNotAlmostEqual` 3.1 + ``failUnlessRaises`` :meth:`.assertRaises` 3.1 + ``assert_`` :meth:`.assertTrue` 3.2 + ``assertEquals`` :meth:`.assertEqual` 3.2 + ``assertNotEquals`` :meth:`.assertNotEqual` 3.2 + ``assertAlmostEquals`` :meth:`.assertAlmostEqual` 3.2 + ``assertNotAlmostEquals`` :meth:`.assertNotAlmostEqual` 3.2 + ``assertRegexpMatches`` :meth:`.assertRegex` 3.2 + ``assertRaisesRegexp`` :meth:`.assertRaisesRegex` 3.2 + ``assertNotRegexpMatches`` :meth:`.assertNotRegex` 3.5 + ============================ =============================== =============== .. _whatsnew311-removed: .. _whatsnew311-python-api-removed: From webhook-mailer at python.org Tue Oct 25 19:43:00 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Tue, 25 Oct 2022 23:43:00 -0000 Subject: [Python-checkins] fix a typo in whatsnew/3.11 (#98603) Message-ID: https://github.com/python/cpython/commit/45644905ea1352b79a0d5ab4f02e00a258206116 commit: 45644905ea1352b79a0d5ab4f02e00a258206116 branch: main author: July Tikhonov committer: JelleZijlstra date: 2022-10-25T16:42:54-07:00 summary: fix a typo in whatsnew/3.11 (#98603) files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index ab56f0d354c7..6eb90df89cac 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1903,7 +1903,7 @@ C APIs pending removal are Removed ======= -This section lists Python APIs that have been removed in Python 3.12. +This section lists Python APIs that have been removed in Python 3.11. Removed C APIs are :ref:`listed separately `. From webhook-mailer at python.org Tue Oct 25 19:44:24 2022 From: webhook-mailer at python.org (miss-islington) Date: Tue, 25 Oct 2022 23:44:24 -0000 Subject: [Python-checkins] Fix typos in deprecation section of 3.11 What's New (GH-98628) Message-ID: https://github.com/python/cpython/commit/298364f79446a01943801b6995f3456779bf4a7e commit: 298364f79446a01943801b6995f3456779bf4a7e branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-25T16:44:18-07:00 summary: Fix typos in deprecation section of 3.11 What's New (GH-98628) (cherry picked from commit faea6a131a9d06208e9043b499a90e11bdfbb479) Co-authored-by: Jacob Walls files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index f819c92cb3fb..59e2d2adb8ae 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1723,7 +1723,7 @@ Modules * The :mod:`asynchat`, :mod:`asyncore` and :mod:`smtpd` modules have been deprecated since at least Python 3.6. Their documentation and deprecation - warnings have now been updated to note they will removed in Python 3.12. + warnings have now been updated to note they will be removed in Python 3.12. (Contributed by Hugo van Kemenade in :issue:`47022`.) * The :mod:`lib2to3` package and :ref:`2to3 <2to3-reference>` tool @@ -1742,8 +1742,8 @@ Standard Library ---------------- * The following have been deprecated in :mod:`configparser` since Python 3.2. - Their deprecation warnings have now been updated to note they will removed in - Python 3.12: + Their deprecation warnings have now been updated to note they will be removed + in Python 3.12: * the :class:`!configparser.SafeConfigParser` class * the :attr:`!configparser.ParsingError.filename` property From webhook-mailer at python.org Tue Oct 25 19:50:15 2022 From: webhook-mailer at python.org (miss-islington) Date: Tue, 25 Oct 2022 23:50:15 -0000 Subject: [Python-checkins] fix a typo in whatsnew/3.11 (GH-98603) Message-ID: https://github.com/python/cpython/commit/fa95b69856974ec34eac13ebe4d4bde8a582b776 commit: fa95b69856974ec34eac13ebe4d4bde8a582b776 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-25T16:50:09-07:00 summary: fix a typo in whatsnew/3.11 (GH-98603) (cherry picked from commit 45644905ea1352b79a0d5ab4f02e00a258206116) Co-authored-by: July Tikhonov files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 59e2d2adb8ae..f09ccb133fbc 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1904,7 +1904,7 @@ C APIs pending removal are Removed ======= -This section lists Python APIs that have been removed in Python 3.12. +This section lists Python APIs that have been removed in Python 3.11. Removed C APIs are :ref:`listed separately `. From webhook-mailer at python.org Tue Oct 25 20:02:54 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 26 Oct 2022 00:02:54 -0000 Subject: [Python-checkins] gh-94808: Improve coverage of `unicode_find` and `unicode_rfind` (GH-98648) Message-ID: https://github.com/python/cpython/commit/cb323a86127166ee65d50be7d5d0e7848478ae70 commit: cb323a86127166ee65d50be7d5d0e7848478ae70 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-25T17:02:48-07:00 summary: gh-94808: Improve coverage of `unicode_find` and `unicode_rfind` (GH-98648) (cherry picked from commit b1783bc124712fa03fea9621a0eb4119d29b14fe) Co-authored-by: Nikita Sobolev files: M Lib/test/test_unicode.py diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py index f5ce095d1c12..0feb61629174 100644 --- a/Lib/test/test_unicode.py +++ b/Lib/test/test_unicode.py @@ -221,6 +221,20 @@ def test_find(self): self.checkequalnofix(9, 'abcdefghiabc', 'find', 'abc', 1) self.checkequalnofix(-1, 'abcdefghiabc', 'find', 'def', 4) + # test utf-8 non-ascii char + self.checkequal(0, '????', 'find', '?') + self.checkequal(3, '????', 'find', '?', 1) + self.checkequal(-1, '????', 'find', '?', 1, 3) + self.checkequal(-1, '????', 'find', 'e') # english `e` + # test utf-8 non-ascii slice + self.checkequal(1, '???? ????', 'find', '??') + self.checkequal(1, '???? ????', 'find', '??', 1) + self.checkequal(1, '???? ????', 'find', '??', 1, 3) + self.checkequal(6, '???? ????', 'find', '??', 2) + self.checkequal(-1, '???? ????', 'find', '??', 6, 7) + self.checkequal(-1, '???? ????', 'find', '??', 7) + self.checkequal(-1, '???? ????', 'find', 'ec') # english `ec` + self.assertRaises(TypeError, 'hello'.find) self.assertRaises(TypeError, 'hello'.find, 42) # test mixed kinds @@ -251,6 +265,19 @@ def test_rfind(self): self.checkequalnofix(9, 'abcdefghiabc', 'rfind', 'abc') self.checkequalnofix(12, 'abcdefghiabc', 'rfind', '') self.checkequalnofix(12, 'abcdefghiabc', 'rfind', '') + # test utf-8 non-ascii char + self.checkequal(1, '????', 'rfind', '?') + self.checkequal(1, '????', 'rfind', '?', 1) + self.checkequal(-1, '????', 'rfind', '?', 2) + self.checkequal(-1, '????', 'rfind', 'e') # english `e` + # test utf-8 non-ascii slice + self.checkequal(6, '???? ????', 'rfind', '??') + self.checkequal(6, '???? ????', 'rfind', '??', 1) + self.checkequal(1, '???? ????', 'rfind', '??', 1, 3) + self.checkequal(6, '???? ????', 'rfind', '??', 2) + self.checkequal(-1, '???? ????', 'rfind', '??', 6, 7) + self.checkequal(-1, '???? ????', 'rfind', '??', 7) + self.checkequal(-1, '???? ????', 'rfind', 'ec') # english `ec` # test mixed kinds self.checkequal(0, 'a' + '\u0102' * 100, 'rfind', 'a') self.checkequal(0, 'a' + '\U00100304' * 100, 'rfind', 'a') From webhook-mailer at python.org Tue Oct 25 20:04:07 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 26 Oct 2022 00:04:07 -0000 Subject: [Python-checkins] gh-94808: Improve coverage of `unicode_find` and `unicode_rfind` (GH-98648) Message-ID: https://github.com/python/cpython/commit/18b788c63a6cfa5870bc9cbb5694140318e7a1c7 commit: 18b788c63a6cfa5870bc9cbb5694140318e7a1c7 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-25T17:04:01-07:00 summary: gh-94808: Improve coverage of `unicode_find` and `unicode_rfind` (GH-98648) (cherry picked from commit b1783bc124712fa03fea9621a0eb4119d29b14fe) Co-authored-by: Nikita Sobolev files: M Lib/test/test_unicode.py diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py index 60e5b1902cf6..c8c07a463d1b 100644 --- a/Lib/test/test_unicode.py +++ b/Lib/test/test_unicode.py @@ -257,6 +257,20 @@ def test_find(self): self.checkequalnofix(9, 'abcdefghiabc', 'find', 'abc', 1) self.checkequalnofix(-1, 'abcdefghiabc', 'find', 'def', 4) + # test utf-8 non-ascii char + self.checkequal(0, '????', 'find', '?') + self.checkequal(3, '????', 'find', '?', 1) + self.checkequal(-1, '????', 'find', '?', 1, 3) + self.checkequal(-1, '????', 'find', 'e') # english `e` + # test utf-8 non-ascii slice + self.checkequal(1, '???? ????', 'find', '??') + self.checkequal(1, '???? ????', 'find', '??', 1) + self.checkequal(1, '???? ????', 'find', '??', 1, 3) + self.checkequal(6, '???? ????', 'find', '??', 2) + self.checkequal(-1, '???? ????', 'find', '??', 6, 7) + self.checkequal(-1, '???? ????', 'find', '??', 7) + self.checkequal(-1, '???? ????', 'find', 'ec') # english `ec` + self.assertRaises(TypeError, 'hello'.find) self.assertRaises(TypeError, 'hello'.find, 42) # test mixed kinds @@ -287,6 +301,19 @@ def test_rfind(self): self.checkequalnofix(9, 'abcdefghiabc', 'rfind', 'abc') self.checkequalnofix(12, 'abcdefghiabc', 'rfind', '') self.checkequalnofix(12, 'abcdefghiabc', 'rfind', '') + # test utf-8 non-ascii char + self.checkequal(1, '????', 'rfind', '?') + self.checkequal(1, '????', 'rfind', '?', 1) + self.checkequal(-1, '????', 'rfind', '?', 2) + self.checkequal(-1, '????', 'rfind', 'e') # english `e` + # test utf-8 non-ascii slice + self.checkequal(6, '???? ????', 'rfind', '??') + self.checkequal(6, '???? ????', 'rfind', '??', 1) + self.checkequal(1, '???? ????', 'rfind', '??', 1, 3) + self.checkequal(6, '???? ????', 'rfind', '??', 2) + self.checkequal(-1, '???? ????', 'rfind', '??', 6, 7) + self.checkequal(-1, '???? ????', 'rfind', '??', 7) + self.checkequal(-1, '???? ????', 'rfind', 'ec') # english `ec` # test mixed kinds self.checkequal(0, 'a' + '\u0102' * 100, 'rfind', 'a') self.checkequal(0, 'a' + '\U00100304' * 100, 'rfind', 'a') From webhook-mailer at python.org Tue Oct 25 21:47:02 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Wed, 26 Oct 2022 01:47:02 -0000 Subject: [Python-checkins] [3.11] GH-87390: Add remaining tests for PEP 646 (GH-98267) (#98667) Message-ID: https://github.com/python/cpython/commit/83c8df29dd07b87031ecce8547b05f059dd091bb commit: 83c8df29dd07b87031ecce8547b05f059dd091bb branch: 3.11 author: Jelle Zijlstra committer: JelleZijlstra date: 2022-10-25T18:46:57-07:00 summary: [3.11] GH-87390: Add remaining tests for PEP 646 (GH-98267) (#98667) Co-authored-by: Guido van Rossum . Co-authored-by: Matthew Rahtz (cherry picked from commit cb95cc24efecf32ad035318867b065a2b042d25a) files: A Misc/NEWS.d/next/Tests/2022-10-15-07-46-48.gh-issue-87390.asR-Zo.rst M Lib/test/test_genericalias.py M Lib/test/test_typing.py diff --git a/Lib/test/test_genericalias.py b/Lib/test/test_genericalias.py index 6959c2ae3c80..e44193a0f72d 100644 --- a/Lib/test/test_genericalias.py +++ b/Lib/test/test_genericalias.py @@ -203,23 +203,11 @@ class MyList(list): self.assertEqual(repr(list[str]), 'list[str]') self.assertEqual(repr(list[()]), 'list[()]') self.assertEqual(repr(tuple[int, ...]), 'tuple[int, ...]') - x1 = tuple[ - tuple( # Effectively the same as starring; TODO - tuple[int] - ) - ] + x1 = tuple[*tuple[int]] self.assertEqual(repr(x1), 'tuple[*tuple[int]]') - x2 = tuple[ - tuple( # Ditto TODO - tuple[int, str] - ) - ] + x2 = tuple[*tuple[int, str]] self.assertEqual(repr(x2), 'tuple[*tuple[int, str]]') - x3 = tuple[ - tuple( # Ditto TODO - tuple[int, ...] - ) - ] + x3 = tuple[*tuple[int, ...]] self.assertEqual(repr(x3), 'tuple[*tuple[int, ...]]') self.assertTrue(repr(MyList[int]).endswith('.BaseTest.test_repr..MyList[int]')) self.assertEqual(repr(list[str]()), '[]') # instances should keep their normal repr @@ -273,42 +261,24 @@ def test_parameters(self): self.assertEqual(L5.__args__, (Callable[[K, V], K],)) self.assertEqual(L5.__parameters__, (K, V)) - T1 = tuple[ - tuple( # Ditto TODO - tuple[int] - ) - ] + T1 = tuple[*tuple[int]] self.assertEqual( T1.__args__, - tuple( # Ditto TODO - tuple[int] - ) + (*tuple[int],), ) self.assertEqual(T1.__parameters__, ()) - T2 = tuple[ - tuple( # Ditto TODO - tuple[T] - ) - ] + T2 = tuple[*tuple[T]] self.assertEqual( T2.__args__, - tuple( # Ditto TODO - tuple[T] - ) + (*tuple[T],), ) self.assertEqual(T2.__parameters__, (T,)) - T4 = tuple[ - tuple( # Ditto TODO - tuple[int, str] - ) - ] + T4 = tuple[*tuple[int, str]] self.assertEqual( T4.__args__, - tuple( # Ditto TODO - tuple[int, str] - ) + (*tuple[int, str],), ) self.assertEqual(T4.__parameters__, ()) @@ -343,18 +313,7 @@ def test_equality(self): self.assertEqual(list[int], list[int]) self.assertEqual(dict[str, int], dict[str, int]) self.assertEqual((*tuple[int],)[0], (*tuple[int],)[0]) - self.assertEqual( - tuple[ - tuple( # Effectively the same as starring; TODO - tuple[int] - ) - ], - tuple[ - tuple( # Ditto TODO - tuple[int] - ) - ] - ) + self.assertEqual(tuple[*tuple[int]], tuple[*tuple[int]]) self.assertNotEqual(dict[str, int], dict[str, str]) self.assertNotEqual(list, list[int]) self.assertNotEqual(list[int], list) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index b36804216fa2..7c48c869ad4f 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -50,6 +50,8 @@ py_typing = import_helper.import_fresh_module('typing', blocked=['_typing']) c_typing = import_helper.import_fresh_module('typing', fresh=['_typing']) +CANNOT_SUBCLASS_TYPE = 'Cannot subclass special typing classes' + class BaseTestCase(TestCase): @@ -587,10 +589,9 @@ def test_no_duplicates_if_replacement_not_in_templates(self): class GenericAliasSubstitutionTests(BaseTestCase): """Tests for type variable substitution in generic aliases. - Note that the expected results here are tentative, based on a - still-being-worked-out spec for what we allow at runtime (given that - implementation of *full* substitution logic at runtime would add too much - complexity to typing.py). This spec is currently being discussed at + For variadic cases, these tests should be regarded as the source of truth, + since we hadn't realised the full complexity of variadic substitution + at the time of finalizing PEP 646. For full discussion, see https://github.com/python/cpython/issues/91162. """ @@ -677,9 +678,6 @@ class C(Generic[T1, T2]): pass ('generic[T1, T2]', '[tuple_type[int, ...]]', 'TypeError'), ('generic[T1, T2]', '[tuple_type[int, ...], tuple_type[str, ...]]', 'generic[tuple_type[int, ...], tuple_type[str, ...]]'), - # Should raise TypeError according to the tentative spec: unpacked - # types cannot be used as arguments to aliases that expect a fixed - # number of arguments. ('generic[T1, T2]', '[*tuple_type[int, ...]]', 'TypeError'), ('generic[T1, T2]', '[int, *tuple_type[str, ...]]', 'TypeError'), ('generic[T1, T2]', '[*tuple_type[int, ...], str]', 'TypeError'), @@ -687,10 +685,12 @@ class C(Generic[T1, T2]): pass ('generic[T1, T2]', '[*Ts]', 'TypeError'), ('generic[T1, T2]', '[T, *Ts]', 'TypeError'), ('generic[T1, T2]', '[*Ts, T]', 'TypeError'), - # Should raise TypeError according to the tentative spec: unpacked - # types cannot be used as arguments to generics that expect a fixed - # number of arguments. - # (None of the things in `generics` were defined using *Ts.) + # This one isn't technically valid - none of the things that + # `generic` can be (defined in `generics` above) are variadic, so we + # shouldn't really be able to do `generic[T1, *tuple_type[int, ...]]`. + # So even if type checkers shouldn't allow it, we allow it at + # runtime, in accordance with a general philosophy of "Keep the + # runtime lenient so people can experiment with typing constructs". ('generic[T1, *tuple_type[int, ...]]', '[str]', 'generic[str, *tuple_type[int, ...]]'), ] @@ -752,8 +752,6 @@ class C(Generic[*Ts]): pass generics = ['C', 'tuple', 'Tuple'] tuple_types = ['tuple', 'Tuple'] - # The majority of these have three separate cases for C, tuple and - # Tuple because tuple currently behaves differently. tests = [ # Alias # Args # Expected result ('generic[*Ts]', '[()]', 'generic[()]'), @@ -786,7 +784,11 @@ class C(Generic[*Ts]): pass ('generic[*Ts, list[T]]', '[int, str, bool]', 'generic[int, str, list[bool]]'), ('generic[T, *Ts]', '[*tuple_type[int, ...]]', 'generic[int, *tuple_type[int, ...]]'), + ('generic[T, *Ts]', '[str, *tuple_type[int, ...]]', 'generic[str, *tuple_type[int, ...]]'), + ('generic[T, *Ts]', '[*tuple_type[int, ...], str]', 'generic[int, *tuple_type[int, ...], str]'), ('generic[*Ts, T]', '[*tuple_type[int, ...]]', 'generic[*tuple_type[int, ...], int]'), + ('generic[*Ts, T]', '[str, *tuple_type[int, ...]]', 'generic[str, *tuple_type[int, ...], int]'), + ('generic[*Ts, T]', '[*tuple_type[int, ...], str]', 'generic[*tuple_type[int, ...], str]'), ('generic[T1, *Ts, T2]', '[*tuple_type[int, ...]]', 'generic[int, *tuple_type[int, ...], int]'), ('generic[T, str, *Ts]', '[*tuple_type[int, ...]]', 'generic[int, str, *tuple_type[int, ...]]'), ('generic[*Ts, str, T]', '[*tuple_type[int, ...]]', 'generic[*tuple_type[int, ...], str, int]'), @@ -825,13 +827,19 @@ class C(Generic[*Ts]): pass class UnpackTests(BaseTestCase): def test_accepts_single_type(self): + (*tuple[int],) Unpack[Tuple[int]] def test_rejects_multiple_types(self): with self.assertRaises(TypeError): Unpack[Tuple[int], Tuple[str]] + # We can't do the equivalent for `*` here - + # *(Tuple[int], Tuple[str]) is just plain tuple unpacking, + # which is valid. def test_rejects_multiple_parameterization(self): + with self.assertRaises(TypeError): + (*tuple[int],)[0][tuple[int]] with self.assertRaises(TypeError): Unpack[Tuple[int]][Tuple[int]] @@ -870,19 +878,20 @@ def test_cannot_call_instance(self): def test_unpacked_typevartuple_is_equal_to_itself(self): Ts = TypeVarTuple('Ts') + self.assertEqual((*Ts,)[0], (*Ts,)[0]) self.assertEqual(Unpack[Ts], Unpack[Ts]) def test_parameterised_tuple_is_equal_to_itself(self): Ts = TypeVarTuple('Ts') - self.assertEqual(tuple[Unpack[Ts]], tuple[Unpack[Ts]]) + self.assertEqual(tuple[*Ts], tuple[*Ts]) self.assertEqual(Tuple[Unpack[Ts]], Tuple[Unpack[Ts]]) def tests_tuple_arg_ordering_matters(self): Ts1 = TypeVarTuple('Ts1') Ts2 = TypeVarTuple('Ts2') self.assertNotEqual( - tuple[Unpack[Ts1], Unpack[Ts2]], - tuple[Unpack[Ts2], Unpack[Ts1]], + tuple[*Ts1, *Ts2], + tuple[*Ts2, *Ts1], ) self.assertNotEqual( Tuple[Unpack[Ts1], Unpack[Ts2]], @@ -891,8 +900,8 @@ def tests_tuple_arg_ordering_matters(self): def test_tuple_args_and_parameters_are_correct(self): Ts = TypeVarTuple('Ts') - t1 = tuple[Unpack[Ts]] - self.assertEqual(t1.__args__, (Unpack[Ts],)) + t1 = tuple[*Ts] + self.assertEqual(t1.__args__, (*Ts,)) self.assertEqual(t1.__parameters__, (Ts,)) t2 = Tuple[Unpack[Ts]] self.assertEqual(t2.__args__, (Unpack[Ts],)) @@ -902,128 +911,218 @@ def test_var_substitution(self): Ts = TypeVarTuple('Ts') T = TypeVar('T') T2 = TypeVar('T2') - class G(Generic[Unpack[Ts]]): pass + class G1(Generic[*Ts]): pass + class G2(Generic[Unpack[Ts]]): pass - for A in G, Tuple, tuple: - B = A[Unpack[Ts]] + for A in G1, G2, Tuple, tuple: + B = A[*Ts] self.assertEqual(B[()], A[()]) self.assertEqual(B[float], A[float]) self.assertEqual(B[float, str], A[float, str]) - C = List[A[Unpack[Ts]]] - self.assertEqual(C[()], List[A[()]]) - self.assertEqual(C[float], List[A[float]]) - self.assertEqual(C[float, str], List[A[float, str]]) + C = A[Unpack[Ts]] + self.assertEqual(C[()], A[()]) + self.assertEqual(C[float], A[float]) + self.assertEqual(C[float, str], A[float, str]) + + D = list[A[*Ts]] + self.assertEqual(D[()], list[A[()]]) + self.assertEqual(D[float], list[A[float]]) + self.assertEqual(D[float, str], list[A[float, str]]) + + E = List[A[Unpack[Ts]]] + self.assertEqual(E[()], List[A[()]]) + self.assertEqual(E[float], List[A[float]]) + self.assertEqual(E[float, str], List[A[float, str]]) - D = A[T, Unpack[Ts], T2] + F = A[T, *Ts, T2] with self.assertRaises(TypeError): - D[()] + F[()] with self.assertRaises(TypeError): - D[float] - self.assertEqual(D[float, str], A[float, str]) - self.assertEqual(D[float, str, int], A[float, str, int]) - self.assertEqual(D[float, str, int, bytes], A[float, str, int, bytes]) + F[float] + self.assertEqual(F[float, str], A[float, str]) + self.assertEqual(F[float, str, int], A[float, str, int]) + self.assertEqual(F[float, str, int, bytes], A[float, str, int, bytes]) - E = Tuple[List[T], A[Unpack[Ts]], List[T2]] + G = A[T, Unpack[Ts], T2] with self.assertRaises(TypeError): - E[()] + G[()] with self.assertRaises(TypeError): - E[float] + G[float] + self.assertEqual(G[float, str], A[float, str]) + self.assertEqual(G[float, str, int], A[float, str, int]) + self.assertEqual(G[float, str, int, bytes], A[float, str, int, bytes]) + + H = tuple[list[T], A[*Ts], list[T2]] + with self.assertRaises(TypeError): + H[()] + with self.assertRaises(TypeError): + H[float] if A != Tuple: - self.assertEqual(E[float, str], + self.assertEqual(H[float, str], + tuple[list[float], A[()], list[str]]) + self.assertEqual(H[float, str, int], + tuple[list[float], A[str], list[int]]) + self.assertEqual(H[float, str, int, bytes], + tuple[list[float], A[str, int], list[bytes]]) + + I = Tuple[List[T], A[Unpack[Ts]], List[T2]] + with self.assertRaises(TypeError): + I[()] + with self.assertRaises(TypeError): + I[float] + if A != Tuple: + self.assertEqual(I[float, str], Tuple[List[float], A[()], List[str]]) - self.assertEqual(E[float, str, int], + self.assertEqual(I[float, str, int], Tuple[List[float], A[str], List[int]]) - self.assertEqual(E[float, str, int, bytes], + self.assertEqual(I[float, str, int, bytes], Tuple[List[float], A[str, int], List[bytes]]) def test_bad_var_substitution(self): Ts = TypeVarTuple('Ts') T = TypeVar('T') T2 = TypeVar('T2') - class G(Generic[Unpack[Ts]]): pass + class G1(Generic[*Ts]): pass + class G2(Generic[Unpack[Ts]]): pass - for A in G, Tuple, tuple: + for A in G1, G2, Tuple, tuple: B = A[Ts] with self.assertRaises(TypeError): B[int, str] C = A[T, T2] + with self.assertRaises(TypeError): + C[*Ts] with self.assertRaises(TypeError): C[Unpack[Ts]] - def test_repr_is_correct(self): - Ts = TypeVarTuple('Ts') - T = TypeVar('T') - T2 = TypeVar('T2') - class G(Generic[Unpack[Ts]]): pass - - for A in G, Tuple: - B = A[T, Unpack[Ts], str, T2] + B = A[T, *Ts, str, T2] + with self.assertRaises(TypeError): + B[int, *Ts] with self.assertRaises(TypeError): - B[int, Unpack[Ts]] + B[int, *Ts, *Ts] + C = A[T, Unpack[Ts], str, T2] + with self.assertRaises(TypeError): + C[int, Unpack[Ts]] with self.assertRaises(TypeError): C[int, Unpack[Ts], Unpack[Ts]] def test_repr_is_correct(self): Ts = TypeVarTuple('Ts') + T = TypeVar('T') + T2 = TypeVar('T2') + + class G1(Generic[*Ts]): pass + class G2(Generic[Unpack[Ts]]): pass + self.assertEqual(repr(Ts), 'Ts') + + self.assertEqual(repr((*Ts,)[0]), '*Ts') self.assertEqual(repr(Unpack[Ts]), '*Ts') - self.assertEqual(repr(tuple[Unpack[Ts]]), 'tuple[*Ts]') + + self.assertEqual(repr(tuple[*Ts]), 'tuple[*Ts]') self.assertEqual(repr(Tuple[Unpack[Ts]]), 'typing.Tuple[*Ts]') - self.assertEqual(repr(Unpack[tuple[Unpack[Ts]]]), '*tuple[*Ts]') + + self.assertEqual(repr(*tuple[*Ts]), '*tuple[*Ts]') self.assertEqual(repr(Unpack[Tuple[Unpack[Ts]]]), '*typing.Tuple[*Ts]') def test_variadic_class_repr_is_correct(self): Ts = TypeVarTuple('Ts') - class A(Generic[Unpack[Ts]]): pass + class A(Generic[*Ts]): pass + class B(Generic[Unpack[Ts]]): pass self.assertEndsWith(repr(A[()]), 'A[()]') + self.assertEndsWith(repr(B[()]), 'B[()]') self.assertEndsWith(repr(A[float]), 'A[float]') + self.assertEndsWith(repr(B[float]), 'B[float]') self.assertEndsWith(repr(A[float, str]), 'A[float, str]') - self.assertEndsWith(repr(A[Unpack[tuple[int, ...]]]), + self.assertEndsWith(repr(B[float, str]), 'B[float, str]') + + self.assertEndsWith(repr(A[*tuple[int, ...]]), 'A[*tuple[int, ...]]') - self.assertEndsWith(repr(A[float, Unpack[tuple[int, ...]]]), + self.assertEndsWith(repr(B[Unpack[Tuple[int, ...]]]), + 'B[*typing.Tuple[int, ...]]') + + self.assertEndsWith(repr(A[float, *tuple[int, ...]]), 'A[float, *tuple[int, ...]]') - self.assertEndsWith(repr(A[Unpack[tuple[int, ...]], str]), + self.assertEndsWith(repr(A[float, Unpack[Tuple[int, ...]]]), + 'A[float, *typing.Tuple[int, ...]]') + + self.assertEndsWith(repr(A[*tuple[int, ...], str]), 'A[*tuple[int, ...], str]') - self.assertEndsWith(repr(A[float, Unpack[tuple[int, ...]], str]), + self.assertEndsWith(repr(B[Unpack[Tuple[int, ...]], str]), + 'B[*typing.Tuple[int, ...], str]') + + self.assertEndsWith(repr(A[float, *tuple[int, ...], str]), 'A[float, *tuple[int, ...], str]') + self.assertEndsWith(repr(B[float, Unpack[Tuple[int, ...]], str]), + 'B[float, *typing.Tuple[int, ...], str]') def test_variadic_class_alias_repr_is_correct(self): Ts = TypeVarTuple('Ts') class A(Generic[Unpack[Ts]]): pass - B = A[Unpack[Ts]] + B = A[*Ts] self.assertEndsWith(repr(B), 'A[*Ts]') self.assertEndsWith(repr(B[()]), 'A[()]') self.assertEndsWith(repr(B[float]), 'A[float]') self.assertEndsWith(repr(B[float, str]), 'A[float, str]') - C = A[Unpack[Ts], int] - self.assertEndsWith(repr(C), 'A[*Ts, int]') - self.assertEndsWith(repr(C[()]), 'A[int]') - self.assertEndsWith(repr(C[float]), 'A[float, int]') - self.assertEndsWith(repr(C[float, str]), 'A[float, str, int]') + C = A[Unpack[Ts]] + self.assertEndsWith(repr(C), 'A[*Ts]') + self.assertEndsWith(repr(C[()]), 'A[()]') + self.assertEndsWith(repr(C[float]), 'A[float]') + self.assertEndsWith(repr(C[float, str]), 'A[float, str]') - D = A[int, Unpack[Ts]] - self.assertEndsWith(repr(D), 'A[int, *Ts]') + D = A[*Ts, int] + self.assertEndsWith(repr(D), 'A[*Ts, int]') self.assertEndsWith(repr(D[()]), 'A[int]') - self.assertEndsWith(repr(D[float]), 'A[int, float]') - self.assertEndsWith(repr(D[float, str]), 'A[int, float, str]') - - E = A[int, Unpack[Ts], str] - self.assertEndsWith(repr(E), 'A[int, *Ts, str]') - self.assertEndsWith(repr(E[()]), 'A[int, str]') - self.assertEndsWith(repr(E[float]), 'A[int, float, str]') - self.assertEndsWith(repr(E[float, str]), 'A[int, float, str, str]') - - F = A[Unpack[Ts], Unpack[tuple[str, ...]]] - self.assertEndsWith(repr(F), 'A[*Ts, *tuple[str, ...]]') - self.assertEndsWith(repr(F[()]), 'A[*tuple[str, ...]]') - self.assertEndsWith(repr(F[float]), 'A[float, *tuple[str, ...]]') - self.assertEndsWith(repr(F[float, str]), 'A[float, str, *tuple[str, ...]]') + self.assertEndsWith(repr(D[float]), 'A[float, int]') + self.assertEndsWith(repr(D[float, str]), 'A[float, str, int]') + + E = A[Unpack[Ts], int] + self.assertEndsWith(repr(E), 'A[*Ts, int]') + self.assertEndsWith(repr(E[()]), 'A[int]') + self.assertEndsWith(repr(E[float]), 'A[float, int]') + self.assertEndsWith(repr(E[float, str]), 'A[float, str, int]') + + F = A[int, *Ts] + self.assertEndsWith(repr(F), 'A[int, *Ts]') + self.assertEndsWith(repr(F[()]), 'A[int]') + self.assertEndsWith(repr(F[float]), 'A[int, float]') + self.assertEndsWith(repr(F[float, str]), 'A[int, float, str]') + + G = A[int, Unpack[Ts]] + self.assertEndsWith(repr(G), 'A[int, *Ts]') + self.assertEndsWith(repr(G[()]), 'A[int]') + self.assertEndsWith(repr(G[float]), 'A[int, float]') + self.assertEndsWith(repr(G[float, str]), 'A[int, float, str]') + + H = A[int, *Ts, str] + self.assertEndsWith(repr(H), 'A[int, *Ts, str]') + self.assertEndsWith(repr(H[()]), 'A[int, str]') + self.assertEndsWith(repr(H[float]), 'A[int, float, str]') + self.assertEndsWith(repr(H[float, str]), 'A[int, float, str, str]') + + I = A[int, Unpack[Ts], str] + self.assertEndsWith(repr(I), 'A[int, *Ts, str]') + self.assertEndsWith(repr(I[()]), 'A[int, str]') + self.assertEndsWith(repr(I[float]), 'A[int, float, str]') + self.assertEndsWith(repr(I[float, str]), 'A[int, float, str, str]') + + J = A[*Ts, *tuple[str, ...]] + self.assertEndsWith(repr(J), 'A[*Ts, *tuple[str, ...]]') + self.assertEndsWith(repr(J[()]), 'A[*tuple[str, ...]]') + self.assertEndsWith(repr(J[float]), 'A[float, *tuple[str, ...]]') + self.assertEndsWith(repr(J[float, str]), 'A[float, str, *tuple[str, ...]]') + + K = A[Unpack[Ts], Unpack[Tuple[str, ...]]] + self.assertEndsWith(repr(K), 'A[*Ts, *typing.Tuple[str, ...]]') + self.assertEndsWith(repr(K[()]), 'A[*typing.Tuple[str, ...]]') + self.assertEndsWith(repr(K[float]), 'A[float, *typing.Tuple[str, ...]]') + self.assertEndsWith(repr(K[float, str]), 'A[float, str, *typing.Tuple[str, ...]]') def test_cannot_subclass_class(self): with self.assertRaises(TypeError): @@ -1033,30 +1132,69 @@ def test_cannot_subclass_instance(self): Ts = TypeVarTuple('Ts') with self.assertRaises(TypeError): class C(Ts): pass - with self.assertRaises(TypeError): + with self.assertRaisesRegex(TypeError, CANNOT_SUBCLASS_TYPE): + class C(type(Unpack)): pass + with self.assertRaisesRegex(TypeError, CANNOT_SUBCLASS_TYPE): + class C(type(*Ts)): pass + with self.assertRaisesRegex(TypeError, CANNOT_SUBCLASS_TYPE): + class C(type(Unpack[Ts])): pass + with self.assertRaisesRegex(TypeError, + r'Cannot subclass typing\.Unpack'): + class C(Unpack): pass + with self.assertRaisesRegex(TypeError, r'Cannot subclass \*Ts'): + class C(*Ts): pass + with self.assertRaisesRegex(TypeError, r'Cannot subclass \*Ts'): class C(Unpack[Ts]): pass def test_variadic_class_args_are_correct(self): T = TypeVar('T') Ts = TypeVarTuple('Ts') - class A(Generic[Unpack[Ts]]): pass - B = A[()] - self.assertEqual(B.__args__, ()) - C = A[int] - self.assertEqual(C.__args__, (int,)) - D = A[int, str] - self.assertEqual(D.__args__, (int, str)) - E = A[T] - self.assertEqual(E.__args__, (T,)) - F = A[Unpack[Ts]] - self.assertEqual(F.__args__, (Unpack[Ts],)) - G = A[T, Unpack[Ts]] - self.assertEqual(G.__args__, (T, Unpack[Ts])) - H = A[Unpack[Ts], T] - self.assertEqual(H.__args__, (Unpack[Ts], T)) + class A(Generic[*Ts]): pass + class B(Generic[Unpack[Ts]]): pass + + C = A[()] + D = B[()] + self.assertEqual(C.__args__, ()) + self.assertEqual(D.__args__, ()) + + E = A[int] + F = B[int] + self.assertEqual(E.__args__, (int,)) + self.assertEqual(F.__args__, (int,)) + + G = A[int, str] + H = B[int, str] + self.assertEqual(G.__args__, (int, str)) + self.assertEqual(H.__args__, (int, str)) + + I = A[T] + J = B[T] + self.assertEqual(I.__args__, (T,)) + self.assertEqual(J.__args__, (T,)) + + K = A[*Ts] + L = B[Unpack[Ts]] + self.assertEqual(K.__args__, (*Ts,)) + self.assertEqual(L.__args__, (Unpack[Ts],)) + + M = A[T, *Ts] + N = B[T, Unpack[Ts]] + self.assertEqual(M.__args__, (T, *Ts)) + self.assertEqual(N.__args__, (T, Unpack[Ts])) + + O = A[*Ts, T] + P = B[Unpack[Ts], T] + self.assertEqual(O.__args__, (*Ts, T)) + self.assertEqual(P.__args__, (Unpack[Ts], T)) def test_variadic_class_origin_is_correct(self): Ts = TypeVarTuple('Ts') + + class C(Generic[*Ts]): pass + self.assertIs(C[int].__origin__, C) + self.assertIs(C[T].__origin__, C) + self.assertIs(C[Unpack[Ts]].__origin__, C) + class D(Generic[Unpack[Ts]]): pass self.assertIs(D[int].__origin__, D) self.assertIs(D[T].__origin__, D) @@ -1065,21 +1203,21 @@ class D(Generic[Unpack[Ts]]): pass def test_tuple_args_are_correct(self): Ts = TypeVarTuple('Ts') - self.assertEqual(tuple[Unpack[Ts]].__args__, (Unpack[Ts],)) + self.assertEqual(tuple[*Ts].__args__, (*Ts,)) self.assertEqual(Tuple[Unpack[Ts]].__args__, (Unpack[Ts],)) - self.assertEqual(tuple[Unpack[Ts], int].__args__, (Unpack[Ts], int)) + self.assertEqual(tuple[*Ts, int].__args__, (*Ts, int)) self.assertEqual(Tuple[Unpack[Ts], int].__args__, (Unpack[Ts], int)) - self.assertEqual(tuple[int, Unpack[Ts]].__args__, (int, Unpack[Ts])) + self.assertEqual(tuple[int, *Ts].__args__, (int, *Ts)) self.assertEqual(Tuple[int, Unpack[Ts]].__args__, (int, Unpack[Ts])) - self.assertEqual(tuple[int, Unpack[Ts], str].__args__, - (int, Unpack[Ts], str)) + self.assertEqual(tuple[int, *Ts, str].__args__, + (int, *Ts, str)) self.assertEqual(Tuple[int, Unpack[Ts], str].__args__, (int, Unpack[Ts], str)) - self.assertEqual(tuple[Unpack[Ts], int].__args__, (Unpack[Ts], int)) + self.assertEqual(tuple[*Ts, int].__args__, (*Ts, int)) self.assertEqual(Tuple[Unpack[Ts]].__args__, (Unpack[Ts],)) def test_callable_args_are_correct(self): @@ -1089,63 +1227,97 @@ def test_callable_args_are_correct(self): # TypeVarTuple in the arguments - a = Callable[[Unpack[Ts]], None] - self.assertEqual(a.__args__, (Unpack[Ts], type(None))) + a = Callable[[*Ts], None] + b = Callable[[Unpack[Ts]], None] + self.assertEqual(a.__args__, (*Ts, type(None))) + self.assertEqual(b.__args__, (Unpack[Ts], type(None))) - b = Callable[[int, Unpack[Ts]], None] - self.assertEqual(b.__args__, (int, Unpack[Ts], type(None))) + c = Callable[[int, *Ts], None] + d = Callable[[int, Unpack[Ts]], None] + self.assertEqual(c.__args__, (int, *Ts, type(None))) + self.assertEqual(d.__args__, (int, Unpack[Ts], type(None))) - c = Callable[[Unpack[Ts], int], None] - self.assertEqual(c.__args__, (Unpack[Ts], int, type(None))) + e = Callable[[*Ts, int], None] + f = Callable[[Unpack[Ts], int], None] + self.assertEqual(e.__args__, (*Ts, int, type(None))) + self.assertEqual(f.__args__, (Unpack[Ts], int, type(None))) - d = Callable[[str, Unpack[Ts], int], None] - self.assertEqual(d.__args__, (str, Unpack[Ts], int, type(None))) + g = Callable[[str, *Ts, int], None] + h = Callable[[str, Unpack[Ts], int], None] + self.assertEqual(g.__args__, (str, *Ts, int, type(None))) + self.assertEqual(h.__args__, (str, Unpack[Ts], int, type(None))) # TypeVarTuple as the return - e = Callable[[None], Unpack[Ts]] - self.assertEqual(e.__args__, (type(None), Unpack[Ts])) + i = Callable[[None], *Ts] + j = Callable[[None], Unpack[Ts]] + self.assertEqual(i.__args__, (type(None), *Ts)) + self.assertEqual(i.__args__, (type(None), Unpack[Ts])) - f = Callable[[None], tuple[int, Unpack[Ts]]] - self.assertEqual(f.__args__, (type(None), tuple[int, Unpack[Ts]])) + k = Callable[[None], tuple[int, *Ts]] + l = Callable[[None], Tuple[int, Unpack[Ts]]] + self.assertEqual(k.__args__, (type(None), tuple[int, *Ts])) + self.assertEqual(l.__args__, (type(None), Tuple[int, Unpack[Ts]])) - g = Callable[[None], tuple[Unpack[Ts], int]] - self.assertEqual(g.__args__, (type(None), tuple[Unpack[Ts], int])) + m = Callable[[None], tuple[*Ts, int]] + n = Callable[[None], Tuple[Unpack[Ts], int]] + self.assertEqual(m.__args__, (type(None), tuple[*Ts, int])) + self.assertEqual(n.__args__, (type(None), Tuple[Unpack[Ts], int])) - h = Callable[[None], tuple[str, Unpack[Ts], int]] - self.assertEqual(h.__args__, (type(None), tuple[str, Unpack[Ts], int])) + o = Callable[[None], tuple[str, *Ts, int]] + p = Callable[[None], Tuple[str, Unpack[Ts], int]] + self.assertEqual(o.__args__, (type(None), tuple[str, *Ts, int])) + self.assertEqual(p.__args__, (type(None), Tuple[str, Unpack[Ts], int])) # TypeVarTuple in both - i = Callable[[Unpack[Ts]], Unpack[Ts]] - self.assertEqual(i.__args__, (Unpack[Ts], Unpack[Ts])) + q = Callable[[*Ts], *Ts] + r = Callable[[Unpack[Ts]], Unpack[Ts]] + self.assertEqual(q.__args__, (*Ts, *Ts)) + self.assertEqual(r.__args__, (Unpack[Ts], Unpack[Ts])) - j = Callable[[Unpack[Ts1]], Unpack[Ts2]] - self.assertEqual(j.__args__, (Unpack[Ts1], Unpack[Ts2])) + s = Callable[[*Ts1], *Ts2] + u = Callable[[Unpack[Ts1]], Unpack[Ts2]] + self.assertEqual(s.__args__, (*Ts1, *Ts2)) + self.assertEqual(u.__args__, (Unpack[Ts1], Unpack[Ts2])) def test_variadic_class_with_duplicate_typevartuples_fails(self): Ts1 = TypeVarTuple('Ts1') Ts2 = TypeVarTuple('Ts2') + + with self.assertRaises(TypeError): + class C(Generic[*Ts1, *Ts1]): pass with self.assertRaises(TypeError): class C(Generic[Unpack[Ts1], Unpack[Ts1]]): pass + + with self.assertRaises(TypeError): + class C(Generic[*Ts1, *Ts2, *Ts1]): pass with self.assertRaises(TypeError): class C(Generic[Unpack[Ts1], Unpack[Ts2], Unpack[Ts1]]): pass def test_type_concatenation_in_variadic_class_argument_list_succeeds(self): Ts = TypeVarTuple('Ts') class C(Generic[Unpack[Ts]]): pass + + C[int, *Ts] C[int, Unpack[Ts]] + + C[*Ts, int] C[Unpack[Ts], int] + + C[int, *Ts, str] C[int, Unpack[Ts], str] + + C[int, bool, *Ts, float, str] C[int, bool, Unpack[Ts], float, str] def test_type_concatenation_in_tuple_argument_list_succeeds(self): Ts = TypeVarTuple('Ts') - tuple[int, Unpack[Ts]] - tuple[Unpack[Ts], int] - tuple[int, Unpack[Ts], str] - tuple[int, bool, Unpack[Ts], float, str] + tuple[int, *Ts] + tuple[*Ts, int] + tuple[int, *Ts, str] + tuple[int, bool, *Ts, float, str] Tuple[int, Unpack[Ts]] Tuple[Unpack[Ts], int] @@ -1159,6 +1331,8 @@ class C(Generic[Ts]): pass def test_variadic_class_definition_using_concrete_types_fails(self): Ts = TypeVarTuple('Ts') + with self.assertRaises(TypeError): + class F(Generic[*Ts, int]): pass with self.assertRaises(TypeError): class E(Generic[Unpack[Ts], int]): pass @@ -1167,32 +1341,50 @@ def test_variadic_class_with_2_typevars_accepts_2_or_more_args(self): T1 = TypeVar('T1') T2 = TypeVar('T2') - class A(Generic[T1, T2, Unpack[Ts]]): pass + class A(Generic[T1, T2, *Ts]): pass A[int, str] A[int, str, float] A[int, str, float, bool] - class B(Generic[T1, Unpack[Ts], T2]): pass + class B(Generic[T1, T2, Unpack[Ts]]): pass B[int, str] B[int, str, float] B[int, str, float, bool] - class C(Generic[Unpack[Ts], T1, T2]): pass + class C(Generic[T1, *Ts, T2]): pass C[int, str] C[int, str, float] C[int, str, float, bool] + class D(Generic[T1, Unpack[Ts], T2]): pass + D[int, str] + D[int, str, float] + D[int, str, float, bool] + + class E(Generic[*Ts, T1, T2]): pass + E[int, str] + E[int, str, float] + E[int, str, float, bool] + + class F(Generic[Unpack[Ts], T1, T2]): pass + F[int, str] + F[int, str, float] + F[int, str, float, bool] + def test_variadic_args_annotations_are_correct(self): Ts = TypeVarTuple('Ts') + def f(*args: Unpack[Ts]): pass + def g(*args: *Ts): pass self.assertEqual(f.__annotations__, {'args': Unpack[Ts]}) + self.assertEqual(g.__annotations__, {'args': (*Ts,)[0]}) def test_variadic_args_with_ellipsis_annotations_are_correct(self): Ts = TypeVarTuple('Ts') - def a(*args: Unpack[tuple[int, ...]]): pass + def a(*args: *tuple[int, ...]): pass self.assertEqual(a.__annotations__, - {'args': Unpack[tuple[int, ...]]}) + {'args': (*tuple[int, ...],)[0]}) def b(*args: Unpack[Tuple[int, ...]]): pass self.assertEqual(b.__annotations__, @@ -1201,30 +1393,30 @@ def b(*args: Unpack[Tuple[int, ...]]): pass def test_concatenation_in_variadic_args_annotations_are_correct(self): Ts = TypeVarTuple('Ts') - # Unpacking using `Unpack`, native `tuple` type + # Unpacking using `*`, native `tuple` type - def a(*args: Unpack[tuple[int, Unpack[Ts]]]): pass + def a(*args: *tuple[int, *Ts]): pass self.assertEqual( a.__annotations__, - {'args': Unpack[tuple[int, Unpack[Ts]]]}, + {'args': (*tuple[int, *Ts],)[0]}, ) - def b(*args: Unpack[tuple[Unpack[Ts], int]]): pass + def b(*args: *tuple[*Ts, int]): pass self.assertEqual( b.__annotations__, - {'args': Unpack[tuple[Unpack[Ts], int]]}, + {'args': (*tuple[*Ts, int],)[0]}, ) - def c(*args: Unpack[tuple[str, Unpack[Ts], int]]): pass + def c(*args: *tuple[str, *Ts, int]): pass self.assertEqual( c.__annotations__, - {'args': Unpack[tuple[str, Unpack[Ts], int]]}, + {'args': (*tuple[str, *Ts, int],)[0]}, ) - def d(*args: Unpack[tuple[int, bool, Unpack[Ts], float, str]]): pass + def d(*args: *tuple[int, bool, *Ts, float, str]): pass self.assertEqual( d.__annotations__, - {'args': Unpack[tuple[int, bool, Unpack[Ts], float, str]]}, + {'args': (*tuple[int, bool, *Ts, float, str],)[0]}, ) # Unpacking using `Unpack`, `Tuple` type from typing.py @@ -1255,47 +1447,78 @@ def h(*args: Unpack[Tuple[int, bool, Unpack[Ts], float, str]]): pass def test_variadic_class_same_args_results_in_equalty(self): Ts = TypeVarTuple('Ts') - class C(Generic[Unpack[Ts]]): pass + class C(Generic[*Ts]): pass + class D(Generic[Unpack[Ts]]): pass self.assertEqual(C[int], C[int]) + self.assertEqual(D[int], D[int]) Ts1 = TypeVarTuple('Ts1') Ts2 = TypeVarTuple('Ts2') + + self.assertEqual( + C[*Ts1], + C[*Ts1], + ) self.assertEqual( - C[Unpack[Ts1]], - C[Unpack[Ts1]], + D[Unpack[Ts1]], + D[Unpack[Ts1]], ) + + self.assertEqual( + C[*Ts1, *Ts2], + C[*Ts1, *Ts2], + ) + self.assertEqual( + D[Unpack[Ts1], Unpack[Ts2]], + D[Unpack[Ts1], Unpack[Ts2]], + ) + self.assertEqual( - C[Unpack[Ts1], Unpack[Ts2]], - C[Unpack[Ts1], Unpack[Ts2]], + C[int, *Ts1, *Ts2], + C[int, *Ts1, *Ts2], ) self.assertEqual( - C[int, Unpack[Ts1], Unpack[Ts2]], - C[int, Unpack[Ts1], Unpack[Ts2]], + D[int, Unpack[Ts1], Unpack[Ts2]], + D[int, Unpack[Ts1], Unpack[Ts2]], ) def test_variadic_class_arg_ordering_matters(self): Ts = TypeVarTuple('Ts') - class C(Generic[Unpack[Ts]]): pass + class C(Generic[*Ts]): pass + class D(Generic[Unpack[Ts]]): pass self.assertNotEqual( C[int, str], C[str, int], ) + self.assertNotEqual( + D[int, str], + D[str, int], + ) Ts1 = TypeVarTuple('Ts1') Ts2 = TypeVarTuple('Ts2') + self.assertNotEqual( - C[Unpack[Ts1], Unpack[Ts2]], - C[Unpack[Ts2], Unpack[Ts1]], + C[*Ts1, *Ts2], + C[*Ts2, *Ts1], + ) + self.assertNotEqual( + D[Unpack[Ts1], Unpack[Ts2]], + D[Unpack[Ts2], Unpack[Ts1]], ) def test_variadic_class_arg_typevartuple_identity_matters(self): Ts = TypeVarTuple('Ts') - class C(Generic[Unpack[Ts]]): pass Ts1 = TypeVarTuple('Ts1') Ts2 = TypeVarTuple('Ts2') - self.assertNotEqual(C[Unpack[Ts1]], C[Unpack[Ts2]]) + + class C(Generic[*Ts]): pass + class D(Generic[Unpack[Ts]]): pass + + self.assertNotEqual(C[*Ts1], C[*Ts2]) + self.assertNotEqual(D[Unpack[Ts1]], D[Unpack[Ts2]]) class TypeVarTuplePicklingTests(BaseTestCase): @@ -1315,10 +1538,15 @@ def test_pickling_then_unpickling_results_in_same_identity(self, proto): def test_pickling_then_unpickling_unpacked_results_in_same_identity(self, proto): global global_Ts # See explanation at start of class. global_Ts = TypeVarTuple('global_Ts') - unpacked1 = Unpack[global_Ts] + + unpacked1 = (*global_Ts,)[0] unpacked2 = pickle.loads(pickle.dumps(unpacked1, proto)) self.assertIs(unpacked1, unpacked2) + unpacked3 = Unpack[global_Ts] + unpacked4 = pickle.loads(pickle.dumps(unpacked3, proto)) + self.assertIs(unpacked3, unpacked4) + @all_pickle_protocols def test_pickling_then_unpickling_tuple_with_typevartuple_equality( self, proto @@ -1327,17 +1555,19 @@ def test_pickling_then_unpickling_tuple_with_typevartuple_equality( global_T = TypeVar('global_T') global_Ts = TypeVarTuple('global_Ts') - a1 = Tuple[Unpack[global_Ts]] - a2 = pickle.loads(pickle.dumps(a1, proto)) - self.assertEqual(a1, a2) + tuples = [ + tuple[*global_Ts], + Tuple[Unpack[global_Ts]], - a1 = Tuple[T, Unpack[global_Ts]] - a2 = pickle.loads(pickle.dumps(a1, proto)) - self.assertEqual(a1, a2) + tuple[T, *global_Ts], + Tuple[T, Unpack[global_Ts]], - a1 = Tuple[int, Unpack[global_Ts]] - a2 = pickle.loads(pickle.dumps(a1, proto)) - self.assertEqual(a1, a2) + tuple[int, *global_Ts], + Tuple[int, Unpack[global_Ts]], + ] + for t in tuples: + t2 = pickle.loads(pickle.dumps(t, proto)) + self.assertEqual(t, t2) class UnionTests(BaseTestCase): @@ -4905,6 +5135,7 @@ def h(x: collections.abc.Callable[P, int]): ... class GetUtilitiesTestCase(TestCase): def test_get_origin(self): T = TypeVar('T') + Ts = TypeVarTuple('Ts') P = ParamSpec('P') class C(Generic[T]): pass self.assertIs(get_origin(C[int]), C) @@ -4928,6 +5159,10 @@ class C(Generic[T]): pass self.assertIs(get_origin(P.kwargs), P) self.assertIs(get_origin(Required[int]), Required) self.assertIs(get_origin(NotRequired[int]), NotRequired) + self.assertIs(get_origin((*Ts,)[0]), Unpack) + self.assertIs(get_origin(Unpack[Ts]), Unpack) + self.assertIs(get_origin((*tuple[*Ts],)[0]), tuple) + self.assertIs(get_origin(Unpack[Tuple[Unpack[Ts]]]), Unpack) def test_get_args(self): T = TypeVar('T') @@ -4967,6 +5202,16 @@ class C(Generic[T]): pass self.assertEqual(get_args(list | str), (list, str)) self.assertEqual(get_args(Required[int]), (int,)) self.assertEqual(get_args(NotRequired[int]), (int,)) + self.assertEqual(get_args(TypeAlias), ()) + self.assertEqual(get_args(TypeGuard[int]), (int,)) + Ts = TypeVarTuple('Ts') + self.assertEqual(get_args(Ts), ()) + self.assertEqual(get_args((*Ts,)[0]), (Ts,)) + self.assertEqual(get_args(Unpack[Ts]), (Ts,)) + self.assertEqual(get_args(tuple[*Ts]), (*Ts,)) + self.assertEqual(get_args(tuple[Unpack[Ts]]), (Unpack[Ts],)) + self.assertEqual(get_args((*tuple[*Ts],)[0]), (*Ts,)) + self.assertEqual(get_args(Unpack[tuple[Unpack[Ts]]]), (tuple[Unpack[Ts]],)) class CollectionsAbcTests(BaseTestCase): @@ -6632,69 +6877,112 @@ def test_typevar_subst(self): T1 = TypeVar('T1') T2 = TypeVar('T2') - A = Annotated[Tuple[Unpack[Ts]], dec] - self.assertEqual(A[int], Annotated[Tuple[int], dec]) - self.assertEqual(A[str, int], Annotated[Tuple[str, int], dec]) + A = Annotated[tuple[*Ts], dec] + self.assertEqual(A[int], Annotated[tuple[int], dec]) + self.assertEqual(A[str, int], Annotated[tuple[str, int], dec]) with self.assertRaises(TypeError): - Annotated[Unpack[Ts], dec] + Annotated[*Ts, dec] - B = Annotated[Tuple[T, Unpack[Ts]], dec] + B = Annotated[Tuple[Unpack[Ts]], dec] self.assertEqual(B[int], Annotated[Tuple[int], dec]) - self.assertEqual(B[int, str], Annotated[Tuple[int, str], dec]) - self.assertEqual( - B[int, str, float], - Annotated[Tuple[int, str, float], dec] - ) + self.assertEqual(B[str, int], Annotated[Tuple[str, int], dec]) with self.assertRaises(TypeError): - B[()] + Annotated[Unpack[Ts], dec] - C = Annotated[Tuple[Unpack[Ts], T], dec] - self.assertEqual(C[int], Annotated[Tuple[int], dec]) - self.assertEqual(C[int, str], Annotated[Tuple[int, str], dec]) + C = Annotated[tuple[T, *Ts], dec] + self.assertEqual(C[int], Annotated[tuple[int], dec]) + self.assertEqual(C[int, str], Annotated[tuple[int, str], dec]) self.assertEqual( C[int, str, float], - Annotated[Tuple[int, str, float], dec] + Annotated[tuple[int, str, float], dec] ) with self.assertRaises(TypeError): C[()] - D = Annotated[Tuple[T1, Unpack[Ts], T2], dec] + D = Annotated[Tuple[T, Unpack[Ts]], dec] + self.assertEqual(D[int], Annotated[Tuple[int], dec]) self.assertEqual(D[int, str], Annotated[Tuple[int, str], dec]) self.assertEqual( D[int, str, float], Annotated[Tuple[int, str, float], dec] ) + with self.assertRaises(TypeError): + D[()] + + E = Annotated[tuple[*Ts, T], dec] + self.assertEqual(E[int], Annotated[tuple[int], dec]) + self.assertEqual(E[int, str], Annotated[tuple[int, str], dec]) self.assertEqual( - D[int, str, bool, float], - Annotated[Tuple[int, str, bool, float], dec] + E[int, str, float], + Annotated[tuple[int, str, float], dec] ) with self.assertRaises(TypeError): - D[int] - - # Now let's try creating an alias from an alias. + E[()] - Ts2 = TypeVarTuple('Ts2') - T3 = TypeVar('T3') - T4 = TypeVar('T4') + F = Annotated[Tuple[Unpack[Ts], T], dec] + self.assertEqual(F[int], Annotated[Tuple[int], dec]) + self.assertEqual(F[int, str], Annotated[Tuple[int, str], dec]) + self.assertEqual( + F[int, str, float], + Annotated[Tuple[int, str, float], dec] + ) + with self.assertRaises(TypeError): + F[()] - E = D[T3, Unpack[Ts2], T4] + G = Annotated[tuple[T1, *Ts, T2], dec] + self.assertEqual(G[int, str], Annotated[tuple[int, str], dec]) self.assertEqual( - E, - Annotated[Tuple[T3, Unpack[Ts2], T4], dec] + G[int, str, float], + Annotated[tuple[int, str, float], dec] ) self.assertEqual( - E[int, str], Annotated[Tuple[int, str], dec] + G[int, str, bool, float], + Annotated[tuple[int, str, bool, float], dec] ) + with self.assertRaises(TypeError): + G[int] + + H = Annotated[Tuple[T1, Unpack[Ts], T2], dec] + self.assertEqual(H[int, str], Annotated[Tuple[int, str], dec]) self.assertEqual( - E[int, str, float], + H[int, str, float], Annotated[Tuple[int, str, float], dec] ) self.assertEqual( - E[int, str, bool, float], + H[int, str, bool, float], Annotated[Tuple[int, str, bool, float], dec] ) with self.assertRaises(TypeError): - E[int] + H[int] + + # Now let's try creating an alias from an alias. + + Ts2 = TypeVarTuple('Ts2') + T3 = TypeVar('T3') + T4 = TypeVar('T4') + + # G is Annotated[tuple[T1, *Ts, T2], dec]. + I = G[T3, *Ts2, T4] + J = G[T3, Unpack[Ts2], T4] + + for x, y in [ + (I, Annotated[tuple[T3, *Ts2, T4], dec]), + (J, Annotated[tuple[T3, Unpack[Ts2], T4], dec]), + (I[int, str], Annotated[tuple[int, str], dec]), + (J[int, str], Annotated[tuple[int, str], dec]), + (I[int, str, float], Annotated[tuple[int, str, float], dec]), + (J[int, str, float], Annotated[tuple[int, str, float], dec]), + (I[int, str, bool, float], + Annotated[tuple[int, str, bool, float], dec]), + (J[int, str, bool, float], + Annotated[tuple[int, str, bool, float], dec]), + ]: + self.assertEqual(x, y) + + with self.assertRaises(TypeError): + I[int] + with self.assertRaises(TypeError): + J[int] def test_annotated_in_other_types(self): X = List[Annotated[T, 5]] diff --git a/Misc/NEWS.d/next/Tests/2022-10-15-07-46-48.gh-issue-87390.asR-Zo.rst b/Misc/NEWS.d/next/Tests/2022-10-15-07-46-48.gh-issue-87390.asR-Zo.rst new file mode 100644 index 000000000000..181e12c7430b --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2022-10-15-07-46-48.gh-issue-87390.asR-Zo.rst @@ -0,0 +1 @@ +Add tests for star-unpacking with PEP 646, and some other miscellaneous PEP 646 tests. From webhook-mailer at python.org Tue Oct 25 22:16:24 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Wed, 26 Oct 2022 02:16:24 -0000 Subject: [Python-checkins] gh-84747: Add `async for` comment for StreamReader (#98633) Message-ID: https://github.com/python/cpython/commit/4196ee5c8b489f457874759ee22c9237e08f85c4 commit: 4196ee5c8b489f457874759ee22c9237e08f85c4 branch: main author: Stanley <46876382+slateny at users.noreply.github.com> committer: JelleZijlstra date: 2022-10-25T19:16:18-07:00 summary: gh-84747: Add `async for` comment for StreamReader (#98633) files: M Doc/library/asyncio-stream.rst diff --git a/Doc/library/asyncio-stream.rst b/Doc/library/asyncio-stream.rst index ce88d70d6607..d87e3c042c99 100644 --- a/Doc/library/asyncio-stream.rst +++ b/Doc/library/asyncio-stream.rst @@ -183,7 +183,8 @@ StreamReader .. class:: StreamReader Represents a reader object that provides APIs to read data - from the IO stream. + from the IO stream. As an :term:`asynchronous iterable`, the + object supports the :keyword:`async for` statement. It is not recommended to instantiate *StreamReader* objects directly; use :func:`open_connection` and :func:`start_server` From webhook-mailer at python.org Tue Oct 25 22:23:14 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 26 Oct 2022 02:23:14 -0000 Subject: [Python-checkins] gh-84747: Add `async for` comment for StreamReader (GH-98633) Message-ID: https://github.com/python/cpython/commit/8777d059bbb3f6bd52c8fb43ed5ddfa9951f44ef commit: 8777d059bbb3f6bd52c8fb43ed5ddfa9951f44ef branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-25T19:23:08-07:00 summary: gh-84747: Add `async for` comment for StreamReader (GH-98633) (cherry picked from commit 4196ee5c8b489f457874759ee22c9237e08f85c4) Co-authored-by: Stanley <46876382+slateny at users.noreply.github.com> files: M Doc/library/asyncio-stream.rst diff --git a/Doc/library/asyncio-stream.rst b/Doc/library/asyncio-stream.rst index ce88d70d6607..d87e3c042c99 100644 --- a/Doc/library/asyncio-stream.rst +++ b/Doc/library/asyncio-stream.rst @@ -183,7 +183,8 @@ StreamReader .. class:: StreamReader Represents a reader object that provides APIs to read data - from the IO stream. + from the IO stream. As an :term:`asynchronous iterable`, the + object supports the :keyword:`async for` statement. It is not recommended to instantiate *StreamReader* objects directly; use :func:`open_connection` and :func:`start_server` From webhook-mailer at python.org Tue Oct 25 22:23:14 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 26 Oct 2022 02:23:14 -0000 Subject: [Python-checkins] gh-84747: Add `async for` comment for StreamReader (GH-98633) Message-ID: https://github.com/python/cpython/commit/866dc74afacb389077472e175d6f5cb8befc3efc commit: 866dc74afacb389077472e175d6f5cb8befc3efc branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-25T19:23:08-07:00 summary: gh-84747: Add `async for` comment for StreamReader (GH-98633) (cherry picked from commit 4196ee5c8b489f457874759ee22c9237e08f85c4) Co-authored-by: Stanley <46876382+slateny at users.noreply.github.com> files: M Doc/library/asyncio-stream.rst diff --git a/Doc/library/asyncio-stream.rst b/Doc/library/asyncio-stream.rst index 19210a556057..bed10a40fb7e 100644 --- a/Doc/library/asyncio-stream.rst +++ b/Doc/library/asyncio-stream.rst @@ -183,7 +183,8 @@ StreamReader .. class:: StreamReader Represents a reader object that provides APIs to read data - from the IO stream. + from the IO stream. As an :term:`asynchronous iterable`, the + object supports the :keyword:`async for` statement. It is not recommended to instantiate *StreamReader* objects directly; use :func:`open_connection` and :func:`start_server` From webhook-mailer at python.org Tue Oct 25 22:54:33 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Wed, 26 Oct 2022 02:54:33 -0000 Subject: [Python-checkins] gh-77753: Add example for values that compare equal in stdtypes (#98497) Message-ID: https://github.com/python/cpython/commit/0ca6a4d64086055a8a3aa4b4c024fc080de148ab commit: 0ca6a4d64086055a8a3aa4b4c024fc080de148ab branch: main author: Stanley <46876382+slateny at users.noreply.github.com> committer: JelleZijlstra date: 2022-10-25T19:54:27-07:00 summary: gh-77753: Add example for values that compare equal in stdtypes (#98497) Co-authored-by: Jelle Zijlstra files: M Doc/library/stdtypes.rst diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 2952c50787ad..6701d794b511 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -4370,11 +4370,9 @@ type, the :dfn:`dictionary`. (For other containers see the built-in A dictionary's keys are *almost* arbitrary values. Values that are not :term:`hashable`, that is, values containing lists, dictionaries or other mutable types (that are compared by value rather than by object identity) may -not be used as keys. Numeric types used for keys obey the normal rules for -numeric comparison: if two numbers compare equal (such as ``1`` and ``1.0``) -then they can be used interchangeably to index the same dictionary entry. (Note -however, that since computers store floating-point numbers as approximations it -is usually unwise to use them as dictionary keys.) +not be used as keys. +Values that compare equal (such as ``1``, ``1.0``, and ``True``) +can be used interchangeably to index the same dictionary entry. .. class:: dict(**kwargs) dict(mapping, **kwargs) From webhook-mailer at python.org Tue Oct 25 23:01:18 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 26 Oct 2022 03:01:18 -0000 Subject: [Python-checkins] gh-77753: Add example for values that compare equal in stdtypes (GH-98497) Message-ID: https://github.com/python/cpython/commit/0f937250631100d574c7b857c098a440b028f2b2 commit: 0f937250631100d574c7b857c098a440b028f2b2 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-25T20:01:11-07:00 summary: gh-77753: Add example for values that compare equal in stdtypes (GH-98497) Co-authored-by: Jelle Zijlstra (cherry picked from commit 0ca6a4d64086055a8a3aa4b4c024fc080de148ab) Co-authored-by: Stanley <46876382+slateny at users.noreply.github.com> files: M Doc/library/stdtypes.rst diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 868d7bb2501b..1dbf3e2f8815 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -4330,11 +4330,9 @@ type, the :dfn:`dictionary`. (For other containers see the built-in A dictionary's keys are *almost* arbitrary values. Values that are not :term:`hashable`, that is, values containing lists, dictionaries or other mutable types (that are compared by value rather than by object identity) may -not be used as keys. Numeric types used for keys obey the normal rules for -numeric comparison: if two numbers compare equal (such as ``1`` and ``1.0``) -then they can be used interchangeably to index the same dictionary entry. (Note -however, that since computers store floating-point numbers as approximations it -is usually unwise to use them as dictionary keys.) +not be used as keys. +Values that compare equal (such as ``1``, ``1.0``, and ``True``) +can be used interchangeably to index the same dictionary entry. .. class:: dict(**kwargs) dict(mapping, **kwargs) From webhook-mailer at python.org Tue Oct 25 23:02:50 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 26 Oct 2022 03:02:50 -0000 Subject: [Python-checkins] gh-77753: Add example for values that compare equal in stdtypes (GH-98497) Message-ID: https://github.com/python/cpython/commit/7a25d27ec2c33ef132f72ebaef40279b53964509 commit: 7a25d27ec2c33ef132f72ebaef40279b53964509 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-25T20:02:44-07:00 summary: gh-77753: Add example for values that compare equal in stdtypes (GH-98497) Co-authored-by: Jelle Zijlstra (cherry picked from commit 0ca6a4d64086055a8a3aa4b4c024fc080de148ab) Co-authored-by: Stanley <46876382+slateny at users.noreply.github.com> files: M Doc/library/stdtypes.rst diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 14d2a27a87ba..68b333acd8f0 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -4370,11 +4370,9 @@ type, the :dfn:`dictionary`. (For other containers see the built-in A dictionary's keys are *almost* arbitrary values. Values that are not :term:`hashable`, that is, values containing lists, dictionaries or other mutable types (that are compared by value rather than by object identity) may -not be used as keys. Numeric types used for keys obey the normal rules for -numeric comparison: if two numbers compare equal (such as ``1`` and ``1.0``) -then they can be used interchangeably to index the same dictionary entry. (Note -however, that since computers store floating-point numbers as approximations it -is usually unwise to use them as dictionary keys.) +not be used as keys. +Values that compare equal (such as ``1``, ``1.0``, and ``True``) +can be used interchangeably to index the same dictionary entry. .. class:: dict(**kwargs) dict(mapping, **kwargs) From webhook-mailer at python.org Tue Oct 25 23:26:33 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Wed, 26 Oct 2022 03:26:33 -0000 Subject: [Python-checkins] docs: Change links to label refs (#98454) Message-ID: https://github.com/python/cpython/commit/268129a74f01adb7bb14cd71d1f38378e39d304d commit: 268129a74f01adb7bb14cd71d1f38378e39d304d branch: main author: Stanley <46876382+slateny at users.noreply.github.com> committer: JelleZijlstra date: 2022-10-25T20:26:28-07:00 summary: docs: Change links to label refs (#98454) Co-authored-by: C.A.M. Gerlach files: M Doc/howto/clinic.rst M Doc/howto/isolating-extensions.rst M Doc/library/dataclasses.rst M Doc/library/importlib.metadata.rst M Doc/reference/datamodel.rst M Doc/using/venv-create.inc M Doc/whatsnew/2.2.rst M Doc/whatsnew/3.6.rst M Doc/whatsnew/3.8.rst M Misc/NEWS.d/3.9.0a3.rst diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst index b8afc7e6d762..a97f1d23f53f 100644 --- a/Doc/howto/clinic.rst +++ b/Doc/howto/clinic.rst @@ -1,5 +1,7 @@ .. highlight:: c +.. _howto-clinic: + ********************** Argument Clinic How-To ********************** diff --git a/Doc/howto/isolating-extensions.rst b/Doc/howto/isolating-extensions.rst index 2657b4ec6aaf..2eddb582da7c 100644 --- a/Doc/howto/isolating-extensions.rst +++ b/Doc/howto/isolating-extensions.rst @@ -461,7 +461,7 @@ Module State Access from Slot Methods, Getters and Setters .. After adding to limited API: - If you use the `limited API __, + If you use the :ref:`limited API , you must update ``Py_LIMITED_API`` to ``0x030b0000``, losing ABI compatibility with earlier versions. diff --git a/Doc/library/dataclasses.rst b/Doc/library/dataclasses.rst index 4364ac342471..ab8df8b02c5f 100644 --- a/Doc/library/dataclasses.rst +++ b/Doc/library/dataclasses.rst @@ -191,7 +191,7 @@ Module contents .. versionchanged:: 3.11 If a field name is already included in the ``__slots__`` of a base class, it will not be included in the generated ``__slots__`` - to prevent `overriding them `_. + to prevent :ref:`overriding them `. Therefore, do not use ``__slots__`` to retrieve the field names of a dataclass. Use :func:`fields` instead. To be able to determine inherited slots, diff --git a/Doc/library/importlib.metadata.rst b/Doc/library/importlib.metadata.rst index 4b94ccc49c47..988d1a317f59 100644 --- a/Doc/library/importlib.metadata.rst +++ b/Doc/library/importlib.metadata.rst @@ -360,7 +360,7 @@ Because `Distribution Package `. To find a distribution package's metadata, ``importlib.metadata`` queries the list of :term:`meta path finders ` on :data:`sys.meta_path`. @@ -396,4 +396,3 @@ a custom finder, return instances of this derived ``Distribution`` in the .. _`entry point API`: https://setuptools.readthedocs.io/en/latest/pkg_resources.html#entry-points .. _`metadata API`: https://setuptools.readthedocs.io/en/latest/pkg_resources.html#metadata-api -.. _`finders`: https://docs.python.org/3/reference/import.html#finders-and-loaders diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index 9dacd66ee564..301f41f3952c 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -1904,6 +1904,8 @@ Attribute lookup speed can be significantly improved as well. and *__weakref__* for each instance. +.. _datamodel-note-slots: + Notes on using *__slots__* """""""""""""""""""""""""" diff --git a/Doc/using/venv-create.inc b/Doc/using/venv-create.inc index fd8cc019b4d1..d535b254f056 100644 --- a/Doc/using/venv-create.inc +++ b/Doc/using/venv-create.inc @@ -16,8 +16,8 @@ re-used. .. deprecated:: 3.6 ``pyvenv`` was the recommended tool for creating virtual environments for - Python 3.3 and 3.4, and is `deprecated in Python 3.6 - `_. + Python 3.3 and 3.4, and is + :ref:`deprecated in Python 3.6 `. .. versionchanged:: 3.5 The use of ``venv`` is now recommended for creating virtual environments. diff --git a/Doc/whatsnew/2.2.rst b/Doc/whatsnew/2.2.rst index 39997661bb96..0c3bfda19339 100644 --- a/Doc/whatsnew/2.2.rst +++ b/Doc/whatsnew/2.2.rst @@ -395,7 +395,7 @@ This section has just been a quick overview of the new features, giving enough of an explanation to start you programming, but many details have been simplified or ignored. Where should you go to get a more complete picture? -https://docs.python.org/dev/howto/descriptor.html is a lengthy tutorial introduction to +The :ref:`descriptorhowto` is a lengthy tutorial introduction to the descriptor features, written by Guido van Rossum. If my description has whetted your appetite, go read this tutorial next, because it goes into much more detail about the new features while still remaining quite easy to read. diff --git a/Doc/whatsnew/3.6.rst b/Doc/whatsnew/3.6.rst index 9308d1a76fec..e4294c88b585 100644 --- a/Doc/whatsnew/3.6.rst +++ b/Doc/whatsnew/3.6.rst @@ -2052,6 +2052,8 @@ tkinter The :mod:`tkinter.tix` module is now deprecated. :mod:`tkinter` users should use :mod:`tkinter.ttk` instead. +.. _whatsnew36-venv: + venv ~~~~ diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst index 95aa6f7a8582..37a6cf24e545 100644 --- a/Doc/whatsnew/3.8.rst +++ b/Doc/whatsnew/3.8.rst @@ -122,8 +122,8 @@ Positional-only parameters There is a new function parameter syntax ``/`` to indicate that some function parameters must be specified positionally and cannot be used as keyword arguments. This is the same notation shown by ``help()`` for C -functions annotated with Larry Hastings' `Argument Clinic -`_ tool. +functions annotated with Larry Hastings' +:ref:`Argument Clinic ` tool. In the following example, parameters *a* and *b* are positional-only, while *c* or *d* can be positional or keyword, and *e* or *f* are diff --git a/Misc/NEWS.d/3.9.0a3.rst b/Misc/NEWS.d/3.9.0a3.rst index 77ccc7453c21..54b61ca3b778 100644 --- a/Misc/NEWS.d/3.9.0a3.rst +++ b/Misc/NEWS.d/3.9.0a3.rst @@ -805,8 +805,7 @@ event loop only if called from the main thread. .. section: Documentation Add an entry for ``__module__`` in the "function" & "method" sections of the -`inspect docs types and members table -`_ +:mod:`inspect` docs' :ref:`inspect-types` table. .. From webhook-mailer at python.org Tue Oct 25 23:48:29 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Wed, 26 Oct 2022 03:48:29 -0000 Subject: [Python-checkins] gh-98348: Mention ReferenceError in weakref.proxy documentation (#98355) Message-ID: https://github.com/python/cpython/commit/216f45e4fec42407ff744b915523a226a0070ff1 commit: 216f45e4fec42407ff744b915523a226a0070ff1 branch: main author: fancidev committer: JelleZijlstra date: 2022-10-25T20:48:24-07:00 summary: gh-98348: Mention ReferenceError in weakref.proxy documentation (#98355) files: M Doc/library/weakref.rst diff --git a/Doc/library/weakref.rst b/Doc/library/weakref.rst index 8397de4fb488..a1e542b1e927 100644 --- a/Doc/library/weakref.rst +++ b/Doc/library/weakref.rst @@ -146,6 +146,9 @@ See :ref:`__slots__ documentation ` for details. prevent their use as dictionary keys. *callback* is the same as the parameter of the same name to the :func:`ref` function. + Accessing an attribute of the proxy object after the referent is + garbage collected raises :exc:`ReferenceError`. + .. versionchanged:: 3.8 Extended the operator support on proxy objects to include the matrix multiplication operators ``@`` and ``@=``. From webhook-mailer at python.org Tue Oct 25 23:55:36 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 26 Oct 2022 03:55:36 -0000 Subject: [Python-checkins] gh-98348: Mention ReferenceError in weakref.proxy documentation (GH-98355) Message-ID: https://github.com/python/cpython/commit/5e085853176df87a04fc9ebc19111c6b61b18f4c commit: 5e085853176df87a04fc9ebc19111c6b61b18f4c branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-25T20:55:29-07:00 summary: gh-98348: Mention ReferenceError in weakref.proxy documentation (GH-98355) (cherry picked from commit 216f45e4fec42407ff744b915523a226a0070ff1) Co-authored-by: fancidev files: M Doc/library/weakref.rst diff --git a/Doc/library/weakref.rst b/Doc/library/weakref.rst index 4b0945c020f8..9a8289a7b533 100644 --- a/Doc/library/weakref.rst +++ b/Doc/library/weakref.rst @@ -144,6 +144,9 @@ See :ref:`__slots__ documentation ` for details. prevent their use as dictionary keys. *callback* is the same as the parameter of the same name to the :func:`ref` function. + Accessing an attribute of the proxy object after the referent is + garbage collected raises :exc:`ReferenceError`. + .. versionchanged:: 3.8 Extended the operator support on proxy objects to include the matrix multiplication operators ``@`` and ``@=``. From webhook-mailer at python.org Tue Oct 25 23:55:36 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 26 Oct 2022 03:55:36 -0000 Subject: [Python-checkins] gh-98348: Mention ReferenceError in weakref.proxy documentation (GH-98355) Message-ID: https://github.com/python/cpython/commit/2aedba59ecc7e89479226f0013c1771c4ef66413 commit: 2aedba59ecc7e89479226f0013c1771c4ef66413 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-25T20:55:29-07:00 summary: gh-98348: Mention ReferenceError in weakref.proxy documentation (GH-98355) (cherry picked from commit 216f45e4fec42407ff744b915523a226a0070ff1) Co-authored-by: fancidev files: M Doc/library/weakref.rst diff --git a/Doc/library/weakref.rst b/Doc/library/weakref.rst index 8397de4fb488..a1e542b1e927 100644 --- a/Doc/library/weakref.rst +++ b/Doc/library/weakref.rst @@ -146,6 +146,9 @@ See :ref:`__slots__ documentation ` for details. prevent their use as dictionary keys. *callback* is the same as the parameter of the same name to the :func:`ref` function. + Accessing an attribute of the proxy object after the referent is + garbage collected raises :exc:`ReferenceError`. + .. versionchanged:: 3.8 Extended the operator support on proxy objects to include the matrix multiplication operators ``@`` and ``@=``. From webhook-mailer at python.org Wed Oct 26 00:33:38 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Wed, 26 Oct 2022 04:33:38 -0000 Subject: [Python-checkins] gh-94808: cover `PyMapping_HasKeyString` and `PyMapping_HasKey` (#98486) Message-ID: https://github.com/python/cpython/commit/5d30544485dc56ab999ad7656ef6559306fd013f commit: 5d30544485dc56ab999ad7656ef6559306fd013f branch: main author: Nikita Sobolev committer: JelleZijlstra date: 2022-10-25T21:33:32-07:00 summary: gh-94808: cover `PyMapping_HasKeyString` and `PyMapping_HasKey` (#98486) files: M Lib/test/test_capi.py M Modules/_testcapimodule.c diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py index 364c607b3c18..7e69bf2cd5e1 100644 --- a/Lib/test/test_capi.py +++ b/Lib/test/test_capi.py @@ -404,6 +404,18 @@ def items(self): self.assertRaises(TypeError, _testcapi.get_mapping_values, bad_mapping) self.assertRaises(TypeError, _testcapi.get_mapping_items, bad_mapping) + def test_mapping_has_key(self): + dct = {'a': 1} + self.assertTrue(_testcapi.mapping_has_key(dct, 'a')) + self.assertFalse(_testcapi.mapping_has_key(dct, 'b')) + + class SubDict(dict): + pass + + dct2 = SubDict({'a': 1}) + self.assertTrue(_testcapi.mapping_has_key(dct2, 'a')) + self.assertFalse(_testcapi.mapping_has_key(dct2, 'b')) + @unittest.skipUnless(hasattr(_testcapi, 'negative_refcount'), 'need _testcapi.negative_refcount') def test_negative_refcount(self): diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 194b2de2f0d6..e792a2cd33c5 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -4690,6 +4690,40 @@ get_mapping_items(PyObject* self, PyObject *obj) return PyMapping_Items(obj); } +static PyObject * +test_mapping_has_key_string(PyObject *self, PyObject *Py_UNUSED(args)) +{ + PyObject *context = PyDict_New(); + PyObject *val = PyLong_FromLong(1); + + // Since this uses `const char*` it is easier to test this in C: + PyDict_SetItemString(context, "a", val); + if (!PyMapping_HasKeyString(context, "a")) { + PyErr_SetString(PyExc_RuntimeError, + "Existing mapping key does not exist"); + return NULL; + } + if (PyMapping_HasKeyString(context, "b")) { + PyErr_SetString(PyExc_RuntimeError, + "Missing mapping key exists"); + return NULL; + } + + Py_DECREF(val); + Py_DECREF(context); + Py_RETURN_NONE; +} + +static PyObject * +mapping_has_key(PyObject* self, PyObject *args) +{ + PyObject *context, *key; + if (!PyArg_ParseTuple(args, "OO", &context, &key)) { + return NULL; + } + return PyLong_FromLong(PyMapping_HasKey(context, key)); +} + static PyObject * test_pythread_tss_key_state(PyObject *self, PyObject *args) @@ -6054,6 +6088,8 @@ static PyMethodDef TestMethods[] = { {"get_mapping_keys", get_mapping_keys, METH_O}, {"get_mapping_values", get_mapping_values, METH_O}, {"get_mapping_items", get_mapping_items, METH_O}, + {"test_mapping_has_key_string", test_mapping_has_key_string, METH_NOARGS}, + {"mapping_has_key", mapping_has_key, METH_VARARGS}, {"test_pythread_tss_key_state", test_pythread_tss_key_state, METH_VARARGS}, {"hamt", new_hamt, METH_NOARGS}, {"bad_get", _PyCFunction_CAST(bad_get), METH_FASTCALL}, From webhook-mailer at python.org Wed Oct 26 00:53:41 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 26 Oct 2022 04:53:41 -0000 Subject: [Python-checkins] gh-94808: cover `PyMapping_HasKeyString` and `PyMapping_HasKey` (GH-98486) Message-ID: https://github.com/python/cpython/commit/fd9bdde769f371f6824d6dbe724db4b3ba9831ad commit: fd9bdde769f371f6824d6dbe724db4b3ba9831ad branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-25T21:53:36-07:00 summary: gh-94808: cover `PyMapping_HasKeyString` and `PyMapping_HasKey` (GH-98486) (cherry picked from commit 5d30544485dc56ab999ad7656ef6559306fd013f) Co-authored-by: Nikita Sobolev files: M Lib/test/test_capi.py M Modules/_testcapimodule.c diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py index 0adb689beb82..404a13a0bcc2 100644 --- a/Lib/test/test_capi.py +++ b/Lib/test/test_capi.py @@ -371,6 +371,18 @@ def items(self): self.assertRaises(TypeError, _testcapi.get_mapping_values, bad_mapping) self.assertRaises(TypeError, _testcapi.get_mapping_items, bad_mapping) + def test_mapping_has_key(self): + dct = {'a': 1} + self.assertTrue(_testcapi.mapping_has_key(dct, 'a')) + self.assertFalse(_testcapi.mapping_has_key(dct, 'b')) + + class SubDict(dict): + pass + + dct2 = SubDict({'a': 1}) + self.assertTrue(_testcapi.mapping_has_key(dct2, 'a')) + self.assertFalse(_testcapi.mapping_has_key(dct2, 'b')) + @unittest.skipUnless(hasattr(_testcapi, 'negative_refcount'), 'need _testcapi.negative_refcount') def test_negative_refcount(self): diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 5c582dda4fbf..20c90c441e6b 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -5155,6 +5155,40 @@ get_mapping_items(PyObject* self, PyObject *obj) return PyMapping_Items(obj); } +static PyObject * +test_mapping_has_key_string(PyObject *self, PyObject *Py_UNUSED(args)) +{ + PyObject *context = PyDict_New(); + PyObject *val = PyLong_FromLong(1); + + // Since this uses `const char*` it is easier to test this in C: + PyDict_SetItemString(context, "a", val); + if (!PyMapping_HasKeyString(context, "a")) { + PyErr_SetString(PyExc_RuntimeError, + "Existing mapping key does not exist"); + return NULL; + } + if (PyMapping_HasKeyString(context, "b")) { + PyErr_SetString(PyExc_RuntimeError, + "Missing mapping key exists"); + return NULL; + } + + Py_DECREF(val); + Py_DECREF(context); + Py_RETURN_NONE; +} + +static PyObject * +mapping_has_key(PyObject* self, PyObject *args) +{ + PyObject *context, *key; + if (!PyArg_ParseTuple(args, "OO", &context, &key)) { + return NULL; + } + return PyLong_FromLong(PyMapping_HasKey(context, key)); +} + static PyObject * test_pythread_tss_key_state(PyObject *self, PyObject *args) @@ -5894,6 +5928,8 @@ static PyMethodDef TestMethods[] = { {"get_mapping_keys", get_mapping_keys, METH_O}, {"get_mapping_values", get_mapping_values, METH_O}, {"get_mapping_items", get_mapping_items, METH_O}, + {"test_mapping_has_key_string", test_mapping_has_key_string, METH_NOARGS}, + {"mapping_has_key", mapping_has_key, METH_VARARGS}, {"test_pythread_tss_key_state", test_pythread_tss_key_state, METH_VARARGS}, {"hamt", new_hamt, METH_NOARGS}, {"bad_get", (PyCFunction)(void(*)(void))bad_get, METH_FASTCALL}, From webhook-mailer at python.org Wed Oct 26 00:57:55 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 26 Oct 2022 04:57:55 -0000 Subject: [Python-checkins] gh-94808: cover `PyMapping_HasKeyString` and `PyMapping_HasKey` (GH-98486) Message-ID: https://github.com/python/cpython/commit/db14a9d594e9d73b293916d6e52065a2d91f1c1f commit: db14a9d594e9d73b293916d6e52065a2d91f1c1f branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-25T21:57:49-07:00 summary: gh-94808: cover `PyMapping_HasKeyString` and `PyMapping_HasKey` (GH-98486) (cherry picked from commit 5d30544485dc56ab999ad7656ef6559306fd013f) Co-authored-by: Nikita Sobolev files: M Lib/test/test_capi.py M Modules/_testcapimodule.c diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py index d5012a76a600..a4d643fb056e 100644 --- a/Lib/test/test_capi.py +++ b/Lib/test/test_capi.py @@ -403,6 +403,18 @@ def items(self): self.assertRaises(TypeError, _testcapi.get_mapping_values, bad_mapping) self.assertRaises(TypeError, _testcapi.get_mapping_items, bad_mapping) + def test_mapping_has_key(self): + dct = {'a': 1} + self.assertTrue(_testcapi.mapping_has_key(dct, 'a')) + self.assertFalse(_testcapi.mapping_has_key(dct, 'b')) + + class SubDict(dict): + pass + + dct2 = SubDict({'a': 1}) + self.assertTrue(_testcapi.mapping_has_key(dct2, 'a')) + self.assertFalse(_testcapi.mapping_has_key(dct2, 'b')) + @unittest.skipUnless(hasattr(_testcapi, 'negative_refcount'), 'need _testcapi.negative_refcount') def test_negative_refcount(self): diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index bab8d6027cfe..1c085a45f8c4 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -5348,6 +5348,40 @@ get_mapping_items(PyObject* self, PyObject *obj) return PyMapping_Items(obj); } +static PyObject * +test_mapping_has_key_string(PyObject *self, PyObject *Py_UNUSED(args)) +{ + PyObject *context = PyDict_New(); + PyObject *val = PyLong_FromLong(1); + + // Since this uses `const char*` it is easier to test this in C: + PyDict_SetItemString(context, "a", val); + if (!PyMapping_HasKeyString(context, "a")) { + PyErr_SetString(PyExc_RuntimeError, + "Existing mapping key does not exist"); + return NULL; + } + if (PyMapping_HasKeyString(context, "b")) { + PyErr_SetString(PyExc_RuntimeError, + "Missing mapping key exists"); + return NULL; + } + + Py_DECREF(val); + Py_DECREF(context); + Py_RETURN_NONE; +} + +static PyObject * +mapping_has_key(PyObject* self, PyObject *args) +{ + PyObject *context, *key; + if (!PyArg_ParseTuple(args, "OO", &context, &key)) { + return NULL; + } + return PyLong_FromLong(PyMapping_HasKey(context, key)); +} + static PyObject * test_pythread_tss_key_state(PyObject *self, PyObject *args) @@ -6382,6 +6416,8 @@ static PyMethodDef TestMethods[] = { {"get_mapping_keys", get_mapping_keys, METH_O}, {"get_mapping_values", get_mapping_values, METH_O}, {"get_mapping_items", get_mapping_items, METH_O}, + {"test_mapping_has_key_string", test_mapping_has_key_string, METH_NOARGS}, + {"mapping_has_key", mapping_has_key, METH_VARARGS}, {"test_pythread_tss_key_state", test_pythread_tss_key_state, METH_VARARGS}, {"hamt", new_hamt, METH_NOARGS}, {"bad_get", _PyCFunction_CAST(bad_get), METH_FASTCALL}, From webhook-mailer at python.org Wed Oct 26 01:00:56 2022 From: webhook-mailer at python.org (nascheme) Date: Wed, 26 Oct 2022 05:00:56 -0000 Subject: [Python-checkins] gh-90716: add _pylong.py module (#96673) Message-ID: https://github.com/python/cpython/commit/de6981680bcf6496e5996a853b2eaa700ed59b2c commit: de6981680bcf6496e5996a853b2eaa700ed59b2c branch: main author: Neil Schemenauer committer: nascheme date: 2022-10-25T22:00:50-07:00 summary: gh-90716: add _pylong.py module (#96673) Add Python implementations of certain longobject.c functions. These use asymptotically faster algorithms that can be used for operations on integers with many digits. In those cases, the performance overhead of the Python implementation is not significant since the asymptotic behavior is what dominates runtime. Functions provided by this module should be considered private and not part of any public API. Co-author: Tim Peters Co-author: Mark Dickinson Co-author: Bjorn Martinsson files: A Lib/_pylong.py A Misc/NEWS.d/next/Core and Builtins/2022-09-09-16-32-58.gh-issue-90716.z4yuYq.rst A Tools/scripts/divmod_threshold.py M Lib/test/test_int.py M Objects/longobject.c M Python/stdlib_module_names.h diff --git a/Lib/_pylong.py b/Lib/_pylong.py new file mode 100644 index 000000000000..e0d4e9042193 --- /dev/null +++ b/Lib/_pylong.py @@ -0,0 +1,295 @@ +"""Python implementations of some algorithms for use by longobject.c. +The goal is to provide asymptotically faster algorithms that can be +used for operations on integers with many digits. In those cases, the +performance overhead of the Python implementation is not significant +since the asymptotic behavior is what dominates runtime. Functions +provided by this module should be considered private and not part of any +public API. + +Note: for ease of maintainability, please prefer clear code and avoid +"micro-optimizations". This module will only be imported and used for +integers with a huge number of digits. Saving a few microseconds with +tricky or non-obvious code is not worth it. For people looking for +maximum performance, they should use something like gmpy2.""" + +import sys +import re +import decimal + +_DEBUG = False + + +def int_to_decimal(n): + """Asymptotically fast conversion of an 'int' to Decimal.""" + + # Function due to Tim Peters. See GH issue #90716 for details. + # https://github.com/python/cpython/issues/90716 + # + # The implementation in longobject.c of base conversion algorithms + # between power-of-2 and non-power-of-2 bases are quadratic time. + # This function implements a divide-and-conquer algorithm that is + # faster for large numbers. Builds an equal decimal.Decimal in a + # "clever" recursive way. If we want a string representation, we + # apply str to _that_. + + if _DEBUG: + print('int_to_decimal', n.bit_length(), file=sys.stderr) + + D = decimal.Decimal + D2 = D(2) + + BITLIM = 128 + + mem = {} + + def w2pow(w): + """Return D(2)**w and store the result. Also possibly save some + intermediate results. In context, these are likely to be reused + across various levels of the conversion to Decimal.""" + if (result := mem.get(w)) is None: + if w <= BITLIM: + result = D2**w + elif w - 1 in mem: + result = (t := mem[w - 1]) + t + else: + w2 = w >> 1 + # If w happens to be odd, w-w2 is one larger then w2 + # now. Recurse on the smaller first (w2), so that it's + # in the cache and the larger (w-w2) can be handled by + # the cheaper `w-1 in mem` branch instead. + result = w2pow(w2) * w2pow(w - w2) + mem[w] = result + return result + + def inner(n, w): + if w <= BITLIM: + return D(n) + w2 = w >> 1 + hi = n >> w2 + lo = n - (hi << w2) + return inner(lo, w2) + inner(hi, w - w2) * w2pow(w2) + + with decimal.localcontext() as ctx: + ctx.prec = decimal.MAX_PREC + ctx.Emax = decimal.MAX_EMAX + ctx.Emin = decimal.MIN_EMIN + ctx.traps[decimal.Inexact] = 1 + + if n < 0: + negate = True + n = -n + else: + negate = False + result = inner(n, n.bit_length()) + if negate: + result = -result + return result + + +def int_to_decimal_string(n): + """Asymptotically fast conversion of an 'int' to a decimal string.""" + return str(int_to_decimal(n)) + + +def _str_to_int_inner(s): + """Asymptotically fast conversion of a 'str' to an 'int'.""" + + # Function due to Bjorn Martinsson. See GH issue #90716 for details. + # https://github.com/python/cpython/issues/90716 + # + # The implementation in longobject.c of base conversion algorithms + # between power-of-2 and non-power-of-2 bases are quadratic time. + # This function implements a divide-and-conquer algorithm making use + # of Python's built in big int multiplication. Since Python uses the + # Karatsuba algorithm for multiplication, the time complexity + # of this function is O(len(s)**1.58). + + DIGLIM = 2048 + + mem = {} + + def w5pow(w): + """Return 5**w and store the result. + Also possibly save some intermediate results. In context, these + are likely to be reused across various levels of the conversion + to 'int'. + """ + if (result := mem.get(w)) is None: + if w <= DIGLIM: + result = 5**w + elif w - 1 in mem: + result = mem[w - 1] * 5 + else: + w2 = w >> 1 + # If w happens to be odd, w-w2 is one larger then w2 + # now. Recurse on the smaller first (w2), so that it's + # in the cache and the larger (w-w2) can be handled by + # the cheaper `w-1 in mem` branch instead. + result = w5pow(w2) * w5pow(w - w2) + mem[w] = result + return result + + def inner(a, b): + if b - a <= DIGLIM: + return int(s[a:b]) + mid = (a + b + 1) >> 1 + return inner(mid, b) + ((inner(a, mid) * w5pow(b - mid)) << (b - mid)) + + return inner(0, len(s)) + + +def int_from_string(s): + """Asymptotically fast version of PyLong_FromString(), conversion + of a string of decimal digits into an 'int'.""" + if _DEBUG: + print('int_from_string', len(s), file=sys.stderr) + # PyLong_FromString() has already removed leading +/-, checked for invalid + # use of underscore characters, checked that string consists of only digits + # and underscores, and stripped leading whitespace. The input can still + # contain underscores and have trailing whitespace. + s = s.rstrip().replace('_', '') + return _str_to_int_inner(s) + + +def str_to_int(s): + """Asymptotically fast version of decimal string to 'int' conversion.""" + # FIXME: this doesn't support the full syntax that int() supports. + m = re.match(r'\s*([+-]?)([0-9_]+)\s*', s) + if not m: + raise ValueError('invalid literal for int() with base 10') + v = int_from_string(m.group(2)) + if m.group(1) == '-': + v = -v + return v + + +# Fast integer division, based on code from Mark Dickinson, fast_div.py +# GH-47701. Additional refinements and optimizations by Bjorn Martinsson. The +# algorithm is due to Burnikel and Ziegler, in their paper "Fast Recursive +# Division". + +_DIV_LIMIT = 4000 + + +def _div2n1n(a, b, n): + """Divide a 2n-bit nonnegative integer a by an n-bit positive integer + b, using a recursive divide-and-conquer algorithm. + + Inputs: + n is a positive integer + b is a positive integer with exactly n bits + a is a nonnegative integer such that a < 2**n * b + + Output: + (q, r) such that a = b*q+r and 0 <= r < b. + + """ + if a.bit_length() - n <= _DIV_LIMIT: + return divmod(a, b) + pad = n & 1 + if pad: + a <<= 1 + b <<= 1 + n += 1 + half_n = n >> 1 + mask = (1 << half_n) - 1 + b1, b2 = b >> half_n, b & mask + q1, r = _div3n2n(a >> n, (a >> half_n) & mask, b, b1, b2, half_n) + q2, r = _div3n2n(r, a & mask, b, b1, b2, half_n) + if pad: + r >>= 1 + return q1 << half_n | q2, r + + +def _div3n2n(a12, a3, b, b1, b2, n): + """Helper function for _div2n1n; not intended to be called directly.""" + if a12 >> n == b1: + q, r = (1 << n) - 1, a12 - (b1 << n) + b1 + else: + q, r = _div2n1n(a12, b1, n) + r = (r << n | a3) - q * b2 + while r < 0: + q -= 1 + r += b + return q, r + + +def _int2digits(a, n): + """Decompose non-negative int a into base 2**n + + Input: + a is a non-negative integer + + Output: + List of the digits of a in base 2**n in little-endian order, + meaning the most significant digit is last. The most + significant digit is guaranteed to be non-zero. + If a is 0 then the output is an empty list. + + """ + a_digits = [0] * ((a.bit_length() + n - 1) // n) + + def inner(x, L, R): + if L + 1 == R: + a_digits[L] = x + return + mid = (L + R) >> 1 + shift = (mid - L) * n + upper = x >> shift + lower = x ^ (upper << shift) + inner(lower, L, mid) + inner(upper, mid, R) + + if a: + inner(a, 0, len(a_digits)) + return a_digits + + +def _digits2int(digits, n): + """Combine base-2**n digits into an int. This function is the + inverse of `_int2digits`. For more details, see _int2digits. + """ + + def inner(L, R): + if L + 1 == R: + return digits[L] + mid = (L + R) >> 1 + shift = (mid - L) * n + return (inner(mid, R) << shift) + inner(L, mid) + + return inner(0, len(digits)) if digits else 0 + + +def _divmod_pos(a, b): + """Divide a non-negative integer a by a positive integer b, giving + quotient and remainder.""" + # Use grade-school algorithm in base 2**n, n = nbits(b) + n = b.bit_length() + a_digits = _int2digits(a, n) + + r = 0 + q_digits = [] + for a_digit in reversed(a_digits): + q_digit, r = _div2n1n((r << n) + a_digit, b, n) + q_digits.append(q_digit) + q_digits.reverse() + q = _digits2int(q_digits, n) + return q, r + + +def int_divmod(a, b): + """Asymptotically fast replacement for divmod, for 'int'. + Its time complexity is O(n**1.58), where n = #bits(a) + #bits(b). + """ + if _DEBUG: + print('int_divmod', a.bit_length(), b.bit_length(), file=sys.stderr) + if b == 0: + raise ZeroDivisionError + elif b < 0: + q, r = int_divmod(-a, -b) + return q, -r + elif a < 0: + q, r = int_divmod(~a, b) + return ~q, b + ~r + else: + return _divmod_pos(a, b) diff --git a/Lib/test/test_int.py b/Lib/test/test_int.py index 625c388cd947..f484c59f675f 100644 --- a/Lib/test/test_int.py +++ b/Lib/test/test_int.py @@ -795,5 +795,52 @@ class IntSubclassStrDigitLimitsTests(IntStrDigitLimitsTests): int_class = IntSubclass +class PyLongModuleTests(unittest.TestCase): + # Tests of the functions in _pylong.py. Those get used when the + # number of digits in the input values are large enough. + + def setUp(self): + super().setUp() + self._previous_limit = sys.get_int_max_str_digits() + sys.set_int_max_str_digits(0) + + def tearDown(self): + sys.set_int_max_str_digits(self._previous_limit) + super().tearDown() + + def test_pylong_int_to_decimal(self): + n = (1 << 100_000) - 1 + suffix = '9883109375' + s = str(n) + assert s[-10:] == suffix + s = str(-n) + assert s[-10:] == suffix + s = '%d' % n + assert s[-10:] == suffix + s = b'%d' % n + assert s[-10:] == suffix.encode('ascii') + + def test_pylong_int_divmod(self): + n = (1 << 100_000) + a, b = divmod(n*3 + 1, n) + assert a == 3 and b == 1 + + def test_pylong_str_to_int(self): + v1 = 1 << 100_000 + s = str(v1) + v2 = int(s) + assert v1 == v2 + v3 = int(' -' + s) + assert -v1 == v3 + v4 = int(' +' + s + ' ') + assert v1 == v4 + with self.assertRaises(ValueError) as err: + int(s + 'z') + with self.assertRaises(ValueError) as err: + int(s + '_') + with self.assertRaises(ValueError) as err: + int('_' + s) + + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-09-16-32-58.gh-issue-90716.z4yuYq.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-09-16-32-58.gh-issue-90716.z4yuYq.rst new file mode 100644 index 000000000000..d04e2c03c747 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-09-09-16-32-58.gh-issue-90716.z4yuYq.rst @@ -0,0 +1,3 @@ +Add _pylong.py module. It includes asymptotically faster algorithms that +can be used for operations on integers with many digits. It is used by +longobject.c to speed up some operations. diff --git a/Objects/longobject.c b/Objects/longobject.c index 304fabfad744..cf859ccb9707 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -39,6 +39,9 @@ medium_value(PyLongObject *x) #define _MAX_STR_DIGITS_ERROR_FMT_TO_INT "Exceeds the limit (%d) for integer string conversion: value has %zd digits; use sys.set_int_max_str_digits() to increase the limit" #define _MAX_STR_DIGITS_ERROR_FMT_TO_STR "Exceeds the limit (%d) for integer string conversion; use sys.set_int_max_str_digits() to increase the limit" +/* If defined, use algorithms from the _pylong.py module */ +#define WITH_PYLONG_MODULE 1 + static inline void _Py_DECREF_INT(PyLongObject *op) { @@ -1732,6 +1735,69 @@ rem1(PyLongObject *a, digit n) ); } +#ifdef WITH_PYLONG_MODULE +/* asymptotically faster long_to_decimal_string, using _pylong.py */ +static int +pylong_int_to_decimal_string(PyObject *aa, + PyObject **p_output, + _PyUnicodeWriter *writer, + _PyBytesWriter *bytes_writer, + char **bytes_str) +{ + PyObject *s = NULL; + PyObject *mod = PyImport_ImportModule("_pylong"); + if (mod == NULL) { + return -1; + } + s = PyObject_CallMethod(mod, "int_to_decimal_string", "O", aa); + if (s == NULL) { + goto error; + } + assert(PyUnicode_Check(s)); + if (writer) { + Py_ssize_t size = PyUnicode_GET_LENGTH(s); + if (_PyUnicodeWriter_Prepare(writer, size, '9') == -1) { + goto error; + } + if (_PyUnicodeWriter_WriteStr(writer, s) < 0) { + goto error; + } + goto success; + } + else if (bytes_writer) { + Py_ssize_t size = PyUnicode_GET_LENGTH(s); + const void *data = PyUnicode_DATA(s); + int kind = PyUnicode_KIND(s); + *bytes_str = _PyBytesWriter_Prepare(bytes_writer, *bytes_str, size); + if (*bytes_str == NULL) { + goto error; + } + char *p = *bytes_str; + for (Py_ssize_t i=0; i < size; i++) { + Py_UCS4 ch = PyUnicode_READ(kind, data, i); + *p++ = (char) ch; + } + (*bytes_str) = p; + goto success; + } + else { + *p_output = (PyObject *)s; + Py_INCREF(s); + goto success; + } + +error: + Py_DECREF(mod); + Py_XDECREF(s); + return -1; + +success: + Py_DECREF(mod); + Py_DECREF(s); + return 0; +} +#endif /* WITH_PYLONG_MODULE */ + /* Convert an integer to a base 10 string. Returns a new non-shared string. (Return value is non-shared so that callers can modify the returned value if necessary.) */ @@ -1776,6 +1842,17 @@ long_to_decimal_string_internal(PyObject *aa, } } +#if WITH_PYLONG_MODULE + if (size_a > 1000) { + /* Switch to _pylong.int_to_decimal_string(). */ + return pylong_int_to_decimal_string(aa, + p_output, + writer, + bytes_writer, + bytes_str); + } +#endif + /* quick and dirty upper bound for the number of digits required to express a in base _PyLong_DECIMAL_BASE: @@ -2272,6 +2349,39 @@ long_from_binary_base(const char *start, const char *end, Py_ssize_t digits, int return 0; } +static PyObject *long_neg(PyLongObject *v); + +#ifdef WITH_PYLONG_MODULE +/* asymptotically faster str-to-long conversion for base 10, using _pylong.py */ +static int +pylong_int_from_string(const char *start, const char *end, PyLongObject **res) +{ + PyObject *mod = PyImport_ImportModule("_pylong"); + if (mod == NULL) { + goto error; + } + PyObject *s = PyUnicode_FromStringAndSize(start, end-start); + if (s == NULL) { + goto error; + } + PyObject *result = PyObject_CallMethod(mod, "int_from_string", "O", s); + Py_DECREF(s); + Py_DECREF(mod); + if (result == NULL) { + goto error; + } + if (!PyLong_Check(result)) { + PyErr_SetString(PyExc_TypeError, "an integer is required"); + goto error; + } + *res = (PyLongObject *)result; + return 0; +error: + *res = NULL; + return 0; +} +#endif /* WITH_PYLONG_MODULE */ + /*** long_from_non_binary_base: parameters and return values are the same as long_from_binary_base. @@ -2586,6 +2696,12 @@ long_from_string_base(const char **str, int base, PyLongObject **res) return 0; } } +#if WITH_PYLONG_MODULE + if (digits > 6000 && base == 10) { + /* Switch to _pylong.int_from_string() */ + return pylong_int_from_string(start, end, res); + } +#endif /* Use the quadratic algorithm for non binary bases. */ return long_from_non_binary_base(start, end, digits, base, res); } @@ -3913,6 +4029,48 @@ fast_floor_div(PyLongObject *a, PyLongObject *b) return PyLong_FromLong(div); } +#ifdef WITH_PYLONG_MODULE +/* asymptotically faster divmod, using _pylong.py */ +static int +pylong_int_divmod(PyLongObject *v, PyLongObject *w, + PyLongObject **pdiv, PyLongObject **pmod) +{ + PyObject *mod = PyImport_ImportModule("_pylong"); + if (mod == NULL) { + return -1; + } + PyObject *result = PyObject_CallMethod(mod, "int_divmod", "OO", v, w); + Py_DECREF(mod); + if (result == NULL) { + return -1; + } + if (!PyTuple_Check(result)) { + Py_DECREF(result); + PyErr_SetString(PyExc_ValueError, + "tuple is required from int_divmod()"); + return -1; + } + PyObject *q = PyTuple_GET_ITEM(result, 0); + PyObject *r = PyTuple_GET_ITEM(result, 1); + if (!PyLong_Check(q) || !PyLong_Check(r)) { + Py_DECREF(result); + PyErr_SetString(PyExc_ValueError, + "tuple of int is required from int_divmod()"); + return -1; + } + if (pdiv != NULL) { + Py_INCREF(q); + *pdiv = (PyLongObject *)q; + } + if (pmod != NULL) { + Py_INCREF(r); + *pmod = (PyLongObject *)r; + } + Py_DECREF(result); + return 0; +} +#endif /* WITH_PYLONG_MODULE */ + /* The / and % operators are now defined in terms of divmod(). The expression a mod b has the value a - b*floor(a/b). The long_divrem function gives the remainder after division of @@ -3964,6 +4122,18 @@ l_divmod(PyLongObject *v, PyLongObject *w, } return 0; } +#if WITH_PYLONG_MODULE + Py_ssize_t size_v = Py_ABS(Py_SIZE(v)); /* digits in numerator */ + Py_ssize_t size_w = Py_ABS(Py_SIZE(w)); /* digits in denominator */ + if (size_w > 300 && (size_v - size_w) > 150) { + /* Switch to _pylong.int_divmod(). If the quotient is small then + "schoolbook" division is linear-time so don't use in that case. + These limits are empirically determined and should be slightly + conservative so that _pylong is used in cases it is likely + to be faster. See Tools/scripts/divmod_threshold.py. */ + return pylong_int_divmod(v, w, pdiv, pmod); + } +#endif if (long_divrem(v, w, &div, &mod) < 0) return -1; if ((Py_SIZE(mod) < 0 && Py_SIZE(w) > 0) || diff --git a/Python/stdlib_module_names.h b/Python/stdlib_module_names.h index 12827e775754..c31bf1ed09f6 100644 --- a/Python/stdlib_module_names.h +++ b/Python/stdlib_module_names.h @@ -58,6 +58,7 @@ static const char* _Py_stdlib_module_names[] = { "_py_abc", "_pydecimal", "_pyio", +"_pylong", "_queue", "_random", "_scproxy", diff --git a/Tools/scripts/divmod_threshold.py b/Tools/scripts/divmod_threshold.py new file mode 100644 index 000000000000..69819fe30981 --- /dev/null +++ b/Tools/scripts/divmod_threshold.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python3 +# +# Determine threshold for switching from longobject.c divmod to +# _pylong.int_divmod(). + +from random import randrange +from time import perf_counter as now +from _pylong import int_divmod as divmod_fast + +BITS_PER_DIGIT = 30 + + +def rand_digits(n): + top = 1 << (n * BITS_PER_DIGIT) + return randrange(top >> 1, top) + + +def probe_den(nd): + den = rand_digits(nd) + count = 0 + for nn in range(nd, nd + 3000): + num = rand_digits(nn) + t0 = now() + e1, e2 = divmod(num, den) + t1 = now() + f1, f2 = divmod_fast(num, den) + t2 = now() + s1 = t1 - t0 + s2 = t2 - t1 + assert e1 == f1 + assert e2 == f2 + if s2 < s1: + count += 1 + if count >= 3: + print( + "for", + nd, + "denom digits,", + nn - nd, + "extra num digits is enough", + ) + break + else: + count = 0 + else: + print("for", nd, "denom digits, no num seems big enough") + + +def main(): + for nd in range(30): + nd = (nd + 1) * 100 + probe_den(nd) + + +if __name__ == '__main__': + main() From webhook-mailer at python.org Wed Oct 26 09:15:46 2022 From: webhook-mailer at python.org (AlexWaygood) Date: Wed, 26 Oct 2022 13:15:46 -0000 Subject: [Python-checkins] gh-98713: Use `@cpython_only` for a test that fails on PyPy (#98714) Message-ID: https://github.com/python/cpython/commit/9495360c7256938a6185838561cf416599b7e94f commit: 9495360c7256938a6185838561cf416599b7e94f branch: main author: Nikita Sobolev committer: AlexWaygood date: 2022-10-26T14:15:39+01:00 summary: gh-98713: Use `@cpython_only` for a test that fails on PyPy (#98714) Co-authored-by: Alex Waygood files: A Misc/NEWS.d/next/Tests/2022-10-26-15-19-20.gh-issue-98713.Lnu32R.rst M Lib/test/test_typing.py diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index a3f52b8934d0..9571d9529034 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -42,7 +42,7 @@ import weakref import types -from test.support import import_helper, captured_stderr +from test.support import import_helper, captured_stderr, cpython_only from test import mod_generics_cache from test import _typed_dict_helper @@ -4635,6 +4635,7 @@ def blah(): blah() + @cpython_only # gh-98713 def test_overload_on_compiled_functions(self): with patch("typing._overload_registry", defaultdict(lambda: defaultdict(dict))): diff --git a/Misc/NEWS.d/next/Tests/2022-10-26-15-19-20.gh-issue-98713.Lnu32R.rst b/Misc/NEWS.d/next/Tests/2022-10-26-15-19-20.gh-issue-98713.Lnu32R.rst new file mode 100644 index 000000000000..57e58943df49 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2022-10-26-15-19-20.gh-issue-98713.Lnu32R.rst @@ -0,0 +1,3 @@ +Fix a bug in the :mod:`typing` tests where a test relying on CPython-specific +implementation details was not decorated with ``@cpython_only`` and was not +skipped on other implementations. From webhook-mailer at python.org Wed Oct 26 09:41:48 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 26 Oct 2022 13:41:48 -0000 Subject: [Python-checkins] gh-98713: Use `@cpython_only` for a test that fails on PyPy (GH-98714) Message-ID: https://github.com/python/cpython/commit/ce2b56e280d8c1bfe9385ed2f674bd8da919429c commit: ce2b56e280d8c1bfe9385ed2f674bd8da919429c branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-26T06:41:42-07:00 summary: gh-98713: Use `@cpython_only` for a test that fails on PyPy (GH-98714) Co-authored-by: Alex Waygood (cherry picked from commit 9495360c7256938a6185838561cf416599b7e94f) Co-authored-by: Nikita Sobolev files: A Misc/NEWS.d/next/Tests/2022-10-26-15-19-20.gh-issue-98713.Lnu32R.rst M Lib/test/test_typing.py diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 7c48c869ad4f..50fe679c6a31 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -42,7 +42,7 @@ import weakref import types -from test.support import import_helper, captured_stderr +from test.support import import_helper, captured_stderr, cpython_only from test import mod_generics_cache from test import _typed_dict_helper @@ -4615,6 +4615,7 @@ def blah(): blah() + @cpython_only # gh-98713 def test_overload_on_compiled_functions(self): with patch("typing._overload_registry", defaultdict(lambda: defaultdict(dict))): diff --git a/Misc/NEWS.d/next/Tests/2022-10-26-15-19-20.gh-issue-98713.Lnu32R.rst b/Misc/NEWS.d/next/Tests/2022-10-26-15-19-20.gh-issue-98713.Lnu32R.rst new file mode 100644 index 000000000000..57e58943df49 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2022-10-26-15-19-20.gh-issue-98713.Lnu32R.rst @@ -0,0 +1,3 @@ +Fix a bug in the :mod:`typing` tests where a test relying on CPython-specific +implementation details was not decorated with ``@cpython_only`` and was not +skipped on other implementations. From webhook-mailer at python.org Wed Oct 26 10:06:31 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Wed, 26 Oct 2022 14:06:31 -0000 Subject: [Python-checkins] =?utf-8?q?gh-98644=3A_point_people_to_tomllib_?= =?utf-8?q?from_configparser=E2=80=99s_docs_=28=2398645=29?= Message-ID: https://github.com/python/cpython/commit/5e74bad93ccc681f0d407aaa3a6830a2d54a20a2 commit: 5e74bad93ccc681f0d407aaa3a6830a2d54a20a2 branch: main author: Philipp A committer: JelleZijlstra date: 2022-10-26T07:06:20-07:00 summary: gh-98644: point people to tomllib from configparser?s docs (#98645) Co-authored-by: Jelle Zijlstra files: M Doc/library/configparser.rst diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst index bf49f2bfbe1b..a925a3dd4fb9 100644 --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -33,13 +33,17 @@ can be customized by end users easily. .. seealso:: + Module :mod:`tomllib` + TOML is a well-specified format for application configuration files. + It is specifically designed to be an improved version of INI. + Module :mod:`shlex` - Support for creating Unix shell-like mini-languages which can be used as - an alternate format for application configuration files. + Support for creating Unix shell-like mini-languages which can also + be used for application configuration files. Module :mod:`json` - The json module implements a subset of JavaScript syntax which can also - be used for this purpose. + The ``json`` module implements a subset of JavaScript syntax which is + sometimes used for configuration, but does not support comments. .. testsetup:: From webhook-mailer at python.org Wed Oct 26 10:14:55 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 26 Oct 2022 14:14:55 -0000 Subject: [Python-checkins] =?utf-8?q?gh-98644=3A_point_people_to_tomllib_?= =?utf-8?q?from_configparser=E2=80=99s_docs_=28GH-98645=29?= Message-ID: https://github.com/python/cpython/commit/ca266aaf451e9fe6cee99e2d224f6433e8fc525a commit: ca266aaf451e9fe6cee99e2d224f6433e8fc525a branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-26T07:14:44-07:00 summary: gh-98644: point people to tomllib from configparser?s docs (GH-98645) Co-authored-by: Jelle Zijlstra (cherry picked from commit 5e74bad93ccc681f0d407aaa3a6830a2d54a20a2) Co-authored-by: Philipp A files: M Doc/library/configparser.rst diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst index 72aa20d73d8b..bfd6a7f58b3e 100644 --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -33,13 +33,17 @@ can be customized by end users easily. .. seealso:: + Module :mod:`tomllib` + TOML is a well-specified format for application configuration files. + It is specifically designed to be an improved version of INI. + Module :mod:`shlex` - Support for creating Unix shell-like mini-languages which can be used as - an alternate format for application configuration files. + Support for creating Unix shell-like mini-languages which can also + be used for application configuration files. Module :mod:`json` - The json module implements a subset of JavaScript syntax which can also - be used for this purpose. + The ``json`` module implements a subset of JavaScript syntax which is + sometimes used for configuration, but does not support comments. .. testsetup:: From webhook-mailer at python.org Wed Oct 26 10:53:53 2022 From: webhook-mailer at python.org (erlend-aasland) Date: Wed, 26 Oct 2022 14:53:53 -0000 Subject: [Python-checkins] gh-98716: Revert gh-96081: Escape lone stars in sqlite3 docs (#98720) Message-ID: https://github.com/python/cpython/commit/365852a03a0c934ccd9b6c2b8e24c71181c41f03 commit: 365852a03a0c934ccd9b6c2b8e24c71181c41f03 branch: main author: Erlend E. Aasland committer: erlend-aasland date: 2022-10-26T16:53:46+02:00 summary: gh-98716: Revert gh-96081: Escape lone stars in sqlite3 docs (#98720) files: M Doc/library/sqlite3.rst diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index 26a085877ec1..a9bab9add763 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -577,7 +577,7 @@ Connection objects supplied, this must be a callable returning an instance of :class:`Cursor` or its subclasses. - .. method:: blobopen(table, column, row, /, \*, readonly=False, name="main") + .. method:: blobopen(table, column, row, /, *, readonly=False, name="main") Open a :class:`Blob` handle to an existing :abbr:`BLOB (Binary Large OBject)`. @@ -647,7 +647,7 @@ Connection objects :meth:`~Cursor.executescript` on it with the given *sql_script*. Return the new cursor object. - .. method:: create_function(name, narg, func, \*, deterministic=False) + .. method:: create_function(name, narg, func, *, deterministic=False) Create or remove a user-defined SQL function. @@ -1040,7 +1040,7 @@ Connection objects con.close() - .. method:: backup(target, \*, pages=-1, progress=None, name="main", sleep=0.250) + .. method:: backup(target, *, pages=-1, progress=None, name="main", sleep=0.250) Create a backup of an SQLite database. @@ -1169,7 +1169,7 @@ Connection objects .. _SQLite limit category: https://www.sqlite.org/c3ref/c_limit_attached.html - .. method:: serialize(\*, name="main") + .. method:: serialize(*, name="main") Serialize a database into a :class:`bytes` object. For an ordinary on-disk database file, the serialization is just a copy of the @@ -1191,7 +1191,7 @@ Connection objects .. versionadded:: 3.11 - .. method:: deserialize(data, /, \*, name="main") + .. method:: deserialize(data, /, *, name="main") Deserialize a :meth:`serialized ` database into a :class:`Connection`. From webhook-mailer at python.org Wed Oct 26 11:02:00 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 26 Oct 2022 15:02:00 -0000 Subject: [Python-checkins] gh-98716: Revert gh-96081: Escape lone stars in sqlite3 docs (GH-98720) Message-ID: https://github.com/python/cpython/commit/78df56ec6988c234a463d3ec04459f6be95009cb commit: 78df56ec6988c234a463d3ec04459f6be95009cb branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-26T08:01:54-07:00 summary: gh-98716: Revert gh-96081: Escape lone stars in sqlite3 docs (GH-98720) (cherry picked from commit 365852a03a0c934ccd9b6c2b8e24c71181c41f03) Co-authored-by: Erlend E. Aasland files: M Doc/library/sqlite3.rst diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index 8fdb75349540..116a2ce78fc6 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -564,7 +564,7 @@ Connection objects supplied, this must be a callable returning an instance of :class:`Cursor` or its subclasses. - .. method:: blobopen(table, column, row, /, \*, readonly=False, name="main") + .. method:: blobopen(table, column, row, /, *, readonly=False, name="main") Open a :class:`Blob` handle to an existing :abbr:`BLOB (Binary Large OBject)`. @@ -634,7 +634,7 @@ Connection objects :meth:`~Cursor.executescript` on it with the given *sql_script*. Return the new cursor object. - .. method:: create_function(name, narg, func, \*, deterministic=False) + .. method:: create_function(name, narg, func, *, deterministic=False) Create or remove a user-defined SQL function. @@ -1027,7 +1027,7 @@ Connection objects con.close() - .. method:: backup(target, \*, pages=-1, progress=None, name="main", sleep=0.250) + .. method:: backup(target, *, pages=-1, progress=None, name="main", sleep=0.250) Create a backup of an SQLite database. @@ -1156,7 +1156,7 @@ Connection objects .. _SQLite limit category: https://www.sqlite.org/c3ref/c_limit_attached.html - .. method:: serialize(\*, name="main") + .. method:: serialize(*, name="main") Serialize a database into a :class:`bytes` object. For an ordinary on-disk database file, the serialization is just a copy of the @@ -1178,7 +1178,7 @@ Connection objects .. versionadded:: 3.11 - .. method:: deserialize(data, /, \*, name="main") + .. method:: deserialize(data, /, *, name="main") Deserialize a :meth:`serialized ` database into a :class:`Connection`. From webhook-mailer at python.org Wed Oct 26 13:05:05 2022 From: webhook-mailer at python.org (Fidget-Spinner) Date: Wed, 26 Oct 2022 17:05:05 -0000 Subject: [Python-checkins] Fix small typo in the removed/deprecated section of the 3.11 whats new (GH-98722) Message-ID: https://github.com/python/cpython/commit/24c56b4642d467c194c57188d4a3b1848ee444c2 commit: 24c56b4642d467c194c57188d4a3b1848ee444c2 branch: main author: Pablo Galindo Salgado committer: Fidget-Spinner date: 2022-10-27T01:05:00+08:00 summary: Fix small typo in the removed/deprecated section of the 3.11 whats new (GH-98722) files: From webhook-mailer at python.org Wed Oct 26 13:16:35 2022 From: webhook-mailer at python.org (ericsnowcurrently) Date: Wed, 26 Oct 2022 17:16:35 -0000 Subject: [Python-checkins] gh-98608: Change _Py_NewInterpreter() to _Py_NewInterpreterFromConfig() (gh-98609) Message-ID: https://github.com/python/cpython/commit/f32369480df54cb06884537ef16cb5a4143393f0 commit: f32369480df54cb06884537ef16cb5a4143393f0 branch: main author: Eric Snow committer: ericsnowcurrently date: 2022-10-26T11:16:30-06:00 summary: gh-98608: Change _Py_NewInterpreter() to _Py_NewInterpreterFromConfig() (gh-98609) (see https://github.com/python/cpython/issues/98608) This change does the following: 1. change the argument to a new `_PyInterpreterConfig` struct 2. rename the function to `_Py_NewInterpreterFromConfig()`, inspired by `Py_InitializeFromConfig()` (takes a `_PyInterpreterConfig` instead of `isolated_subinterpreter`) 3. split up the boolean `isolated_subinterpreter` into the corresponding multiple granular settings * allow_fork * allow_subprocess * allow_threads 4. add `PyInterpreterState.feature_flags` to store those settings 5. add a function for checking if a feature is enabled on an opaque `PyInterpreterState *` 6. drop `PyConfig._isolated_interpreter` The existing default (see `Py_NewInterpeter()` and `Py_Initialize*()`) allows fork, subprocess, and threads and the optional "isolated" interpreter (see the `_xxsubinterpreters` module) disables all three. None of that changes here; the defaults are preserved. Note that the given `_PyInterpreterConfig` will not be used outside `_Py_NewInterpreterFromConfig()`, nor preserved. This contrasts with how `PyConfig` is currently preserved, used, and even modified outside `Py_InitializeFromConfig()`. I'd rather just avoid that mess from the start for `_PyInterpreterConfig`. We can preserve it later if we find an actual need. This change allows us to follow up with a number of improvements (e.g. stop disallowing subprocess and support disallowing exec instead). (Note that this PR adds "private" symbols. We'll probably make them public, and add docs, in a separate change.) files: A Misc/NEWS.d/next/C API/2022-10-24-11-26-55.gh-issue-98608._Q2lNV.rst M Doc/c-api/init_config.rst M Include/cpython/initconfig.h M Include/cpython/pylifecycle.h M Include/cpython/pystate.h M Include/internal/pycore_interp.h M Lib/test/_test_embed_set_config.py M Lib/test/support/__init__.py M Lib/test/test_capi.py M Lib/test/test_embed.py M Modules/_posixsubprocess.c M Modules/_testcapimodule.c M Modules/_testinternalcapi.c M Modules/_threadmodule.c M Modules/_winapi.c M Modules/_xxsubinterpretersmodule.c M Modules/posixmodule.c M Programs/_testembed.c M Python/initconfig.c M Python/pylifecycle.c M Python/pystate.c diff --git a/Doc/c-api/init_config.rst b/Doc/c-api/init_config.rst index ea76315fc09b..64bdfefd6494 100644 --- a/Doc/c-api/init_config.rst +++ b/Doc/c-api/init_config.rst @@ -1571,8 +1571,6 @@ Private provisional API: * :c:member:`PyConfig._init_main`: if set to ``0``, :c:func:`Py_InitializeFromConfig` stops at the "Core" initialization phase. -* :c:member:`PyConfig._isolated_interpreter`: if non-zero, - disallow threads, subprocesses and fork. .. c:function:: PyStatus _Py_InitializeMain(void) diff --git a/Include/cpython/initconfig.h b/Include/cpython/initconfig.h index c22c8d52b4f2..64748cf78beb 100644 --- a/Include/cpython/initconfig.h +++ b/Include/cpython/initconfig.h @@ -213,10 +213,6 @@ typedef struct PyConfig { // If equal to 0, stop Python initialization before the "main" phase. int _init_main; - // If non-zero, disallow threads, subprocesses, and fork. - // Default: 0. - int _isolated_interpreter; - // If non-zero, we believe we're running from a source tree. int _is_python_build; } PyConfig; @@ -245,6 +241,21 @@ PyAPI_FUNC(PyStatus) PyConfig_SetWideStringList(PyConfig *config, Py_ssize_t length, wchar_t **items); +/* --- PyInterpreterConfig ------------------------------------ */ + +typedef struct { + int allow_fork; + int allow_subprocess; + int allow_threads; +} _PyInterpreterConfig; + +#define _PyInterpreterConfig_LEGACY_INIT \ + { \ + .allow_fork = 1, \ + .allow_subprocess = 1, \ + .allow_threads = 1, \ + } + /* --- Helper functions --------------------------------------- */ /* Get the original command line arguments, before Python modified them. diff --git a/Include/cpython/pylifecycle.h b/Include/cpython/pylifecycle.h index bb5b07ef5901..e1f83acbffc3 100644 --- a/Include/cpython/pylifecycle.h +++ b/Include/cpython/pylifecycle.h @@ -62,4 +62,5 @@ PyAPI_FUNC(int) _Py_CoerceLegacyLocale(int warn); PyAPI_FUNC(int) _Py_LegacyLocaleDetected(int warn); PyAPI_FUNC(char *) _Py_SetLocaleFromEnv(int category); -PyAPI_FUNC(PyThreadState *) _Py_NewInterpreter(int isolated_subinterpreter); +PyAPI_FUNC(PyThreadState *) _Py_NewInterpreterFromConfig( + const _PyInterpreterConfig *); diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h index 7722a384cbfa..7996bd34eac9 100644 --- a/Include/cpython/pystate.h +++ b/Include/cpython/pystate.h @@ -3,11 +3,38 @@ #endif +/* +Runtime Feature Flags + +Each flag indicate whether or not a specific runtime feature +is available in a given context. For example, forking the process +might not be allowed in the current interpreter (i.e. os.fork() would fail). +*/ + +// We leave the first 10 for less-specific features. + +/* Set if threads are allowed. */ +#define Py_RTFLAGS_THREADS (1UL << 10) + +/* Set if os.fork() is allowed. */ +#define Py_RTFLAGS_FORK (1UL << 15) + +/* Set if subprocesses are allowed. */ +#define Py_RTFLAGS_SUBPROCESS (1UL << 16) + + +PyAPI_FUNC(int) _PyInterpreterState_HasFeature(PyInterpreterState *interp, + unsigned long feature); + + +/* private interpreter helpers */ + PyAPI_FUNC(int) _PyInterpreterState_RequiresIDRef(PyInterpreterState *); PyAPI_FUNC(void) _PyInterpreterState_RequireIDRef(PyInterpreterState *, int); PyAPI_FUNC(PyObject *) _PyInterpreterState_GetMainModule(PyInterpreterState *); + /* State unique per thread */ /* Py_tracefunc return -1 when raising an exception, or 0 for success. */ diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index 9017e84e15af..6f8fbeb1ba3e 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -143,6 +143,7 @@ struct _is { #ifdef HAVE_DLOPEN int dlopenflags; #endif + unsigned long feature_flags; PyObject *dict; /* Stores per-interpreter state */ diff --git a/Lib/test/_test_embed_set_config.py b/Lib/test/_test_embed_set_config.py index 7ff641b37bf1..0c016b5d75d7 100644 --- a/Lib/test/_test_embed_set_config.py +++ b/Lib/test/_test_embed_set_config.py @@ -84,7 +84,6 @@ def test_set_invalid(self): 'skip_source_first_line', '_install_importlib', '_init_main', - '_isolated_interpreter', ] if MS_WINDOWS: options.append('legacy_windows_stdio') diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 9fdad641232c..3e6a787e617a 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -1793,6 +1793,22 @@ def run_in_subinterp(code): Run code in a subinterpreter. Raise unittest.SkipTest if the tracemalloc module is enabled. """ + _check_tracemalloc() + import _testcapi + return _testcapi.run_in_subinterp(code) + + +def run_in_subinterp_with_config(code, **config): + """ + Run code in a subinterpreter. Raise unittest.SkipTest if the tracemalloc + module is enabled. + """ + _check_tracemalloc() + import _testcapi + return _testcapi.run_in_subinterp_with_config(code, **config) + + +def _check_tracemalloc(): # Issue #10915, #15751: PyGILState_*() functions don't work with # sub-interpreters, the tracemalloc module uses these functions internally try: @@ -1804,8 +1820,6 @@ def run_in_subinterp(code): raise unittest.SkipTest("run_in_subinterp() cannot be used " "if tracemalloc module is tracing " "memory allocations") - import _testcapi - return _testcapi.run_in_subinterp(code) def check_free_after_iterating(test, iter, cls, args=()): diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py index 7e69bf2cd5e1..9446d472addd 100644 --- a/Lib/test/test_capi.py +++ b/Lib/test/test_capi.py @@ -1096,6 +1096,45 @@ def test_py_config_isoloated_per_interpreter(self): # test fails, assume that the environment in this process may # be altered and suspect. + @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()") + def test_configured_settings(self): + """ + The config with which an interpreter is created corresponds + 1-to-1 with the new interpreter's settings. This test verifies + that they match. + """ + import json + + THREADS = 1<<10 + FORK = 1<<15 + SUBPROCESS = 1<<16 + + features = ['fork', 'subprocess', 'threads'] + kwlist = [f'allow_{n}' for n in features] + for config, expected in { + (True, True, True): FORK | SUBPROCESS | THREADS, + (False, False, False): 0, + (False, True, True): SUBPROCESS | THREADS, + }.items(): + kwargs = dict(zip(kwlist, config)) + expected = { + 'feature_flags': expected, + } + with self.subTest(config): + r, w = os.pipe() + script = textwrap.dedent(f''' + import _testinternalcapi, json, os + settings = _testinternalcapi.get_interp_settings() + with os.fdopen({w}, "w") as stdin: + json.dump(settings, stdin) + ''') + with os.fdopen(r) as stdout: + support.run_in_subinterp_with_config(script, **kwargs) + out = stdout.read() + settings = json.loads(out) + + self.assertEqual(settings, expected) + def test_mutate_exception(self): """ Exceptions saved in global module state get shared between diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py index c5aeb9459848..f622d443257f 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -496,7 +496,6 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase): 'check_hash_pycs_mode': 'default', 'pathconfig_warnings': 1, '_init_main': 1, - '_isolated_interpreter': 0, 'use_frozen_modules': not support.Py_DEBUG, 'safe_path': 0, '_is_python_build': IGNORE_CONFIG, @@ -881,8 +880,6 @@ def test_init_from_config(self): 'check_hash_pycs_mode': 'always', 'pathconfig_warnings': 0, - - '_isolated_interpreter': 1, } self.check_all_configs("test_init_from_config", config, preconfig, api=API_COMPAT) @@ -1650,6 +1647,25 @@ def test_init_use_frozen_modules(self): self.check_all_configs("test_init_use_frozen_modules", config, api=API_PYTHON, env=env) + def test_init_main_interpreter_settings(self): + THREADS = 1<<10 + FORK = 1<<15 + SUBPROCESS = 1<<16 + expected = { + # All optional features should be enabled. + 'feature_flags': THREADS | FORK | SUBPROCESS, + } + out, err = self.run_embedded_interpreter( + 'test_init_main_interpreter_settings', + ) + self.assertEqual(err, '') + try: + out = json.loads(out) + except json.JSONDecodeError: + self.fail(f'fail to decode stdout: {out!r}') + + self.assertEqual(out, expected) + class SetConfigTests(unittest.TestCase): def test_set_config(self): diff --git a/Misc/NEWS.d/next/C API/2022-10-24-11-26-55.gh-issue-98608._Q2lNV.rst b/Misc/NEWS.d/next/C API/2022-10-24-11-26-55.gh-issue-98608._Q2lNV.rst new file mode 100644 index 000000000000..5abbd96a4261 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2022-10-24-11-26-55.gh-issue-98608._Q2lNV.rst @@ -0,0 +1,4 @@ +A ``_PyInterpreterConfig`` has been added and ``_Py_NewInterpreter()`` has +been renamed to ``_Py_NewInterpreterFromConfig()``. The +"isolated_subinterpreters" argument is now a granular config that captures +the previous behavior. Note that this is all "private" API. diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c index 44e60d7c1495..8275b116093d 100644 --- a/Modules/_posixsubprocess.c +++ b/Modules/_posixsubprocess.c @@ -842,8 +842,7 @@ subprocess_fork_exec(PyObject *module, PyObject *args) } PyInterpreterState *interp = PyInterpreterState_Get(); - const PyConfig *config = _PyInterpreterState_GetConfig(interp); - if (config->_isolated_interpreter) { + if (!_PyInterpreterState_HasFeature(interp, Py_RTFLAGS_SUBPROCESS)) { PyErr_SetString(PyExc_RuntimeError, "subprocess not supported for isolated subinterpreters"); return NULL; diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index e792a2cd33c5..fdf2f204acb2 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -3225,6 +3225,66 @@ run_in_subinterp(PyObject *self, PyObject *args) return PyLong_FromLong(r); } +/* To run some code in a sub-interpreter. */ +static PyObject * +run_in_subinterp_with_config(PyObject *self, PyObject *args, PyObject *kwargs) +{ + const char *code; + int allow_fork = -1; + int allow_subprocess = -1; + int allow_threads = -1; + int r; + PyThreadState *substate, *mainstate; + /* only initialise 'cflags.cf_flags' to test backwards compatibility */ + PyCompilerFlags cflags = {0}; + + static char *kwlist[] = {"code", + "allow_fork", "allow_subprocess", "allow_threads", + NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "s$ppp:run_in_subinterp_with_config", kwlist, + &code, &allow_fork, &allow_subprocess, &allow_threads)) { + return NULL; + } + if (allow_fork < 0) { + PyErr_SetString(PyExc_ValueError, "missing allow_fork"); + return NULL; + } + if (allow_subprocess < 0) { + PyErr_SetString(PyExc_ValueError, "missing allow_subprocess"); + return NULL; + } + if (allow_threads < 0) { + PyErr_SetString(PyExc_ValueError, "missing allow_threads"); + return NULL; + } + + mainstate = PyThreadState_Get(); + + PyThreadState_Swap(NULL); + + const _PyInterpreterConfig config = { + .allow_fork = allow_fork, + .allow_subprocess = allow_subprocess, + .allow_threads = allow_threads, + }; + substate = _Py_NewInterpreterFromConfig(&config); + if (substate == NULL) { + /* Since no new thread state was created, there is no exception to + propagate; raise a fresh one after swapping in the old thread + state. */ + PyThreadState_Swap(mainstate); + PyErr_SetString(PyExc_RuntimeError, "sub-interpreter creation failed"); + return NULL; + } + r = PyRun_SimpleStringFlags(code, &cflags); + Py_EndInterpreter(substate); + + PyThreadState_Swap(mainstate); + + return PyLong_FromLong(r); +} + static int check_time_rounding(int round) { @@ -5998,6 +6058,9 @@ static PyMethodDef TestMethods[] = { METH_NOARGS}, {"crash_no_current_thread", crash_no_current_thread, METH_NOARGS}, {"run_in_subinterp", run_in_subinterp, METH_VARARGS}, + {"run_in_subinterp_with_config", + _PyCFunction_CAST(run_in_subinterp_with_config), + METH_VARARGS | METH_KEYWORDS}, {"pytime_object_to_time_t", test_pytime_object_to_time_t, METH_VARARGS}, {"pytime_object_to_timeval", test_pytime_object_to_timeval, METH_VARARGS}, {"pytime_object_to_timespec", test_pytime_object_to_timespec, METH_VARARGS}, diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 5724bd5f200f..d74f92808d3a 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -550,6 +550,51 @@ _testinternalcapi_optimize_cfg_impl(PyObject *module, PyObject *instructions, } +static PyObject * +get_interp_settings(PyObject *self, PyObject *args) +{ + int interpid = -1; + if (!PyArg_ParseTuple(args, "|i:get_interp_settings", &interpid)) { + return NULL; + } + + PyInterpreterState *interp = NULL; + if (interpid < 0) { + PyThreadState *tstate = _PyThreadState_GET(); + interp = tstate ? tstate->interp : _PyInterpreterState_Main(); + } + else if (interpid == 0) { + interp = _PyInterpreterState_Main(); + } + else { + PyErr_Format(PyExc_NotImplementedError, + "%zd", interpid); + return NULL; + } + assert(interp != NULL); + + PyObject *settings = PyDict_New(); + if (settings == NULL) { + return NULL; + } + + /* Add the feature flags. */ + PyObject *flags = PyLong_FromUnsignedLong(interp->feature_flags); + if (flags == NULL) { + Py_DECREF(settings); + return NULL; + } + int res = PyDict_SetItemString(settings, "feature_flags", flags); + Py_DECREF(flags); + if (res != 0) { + Py_DECREF(settings); + return NULL; + } + + return settings; +} + + static PyMethodDef TestMethods[] = { {"get_configs", get_configs, METH_NOARGS}, {"get_recursion_depth", get_recursion_depth, METH_NOARGS}, @@ -569,6 +614,7 @@ static PyMethodDef TestMethods[] = { {"set_eval_frame_default", set_eval_frame_default, METH_NOARGS, NULL}, {"set_eval_frame_record", set_eval_frame_record, METH_O, NULL}, _TESTINTERNALCAPI_OPTIMIZE_CFG_METHODDEF + {"get_interp_settings", get_interp_settings, METH_VARARGS, NULL}, {NULL, NULL} /* sentinel */ }; diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c index 4ac90dc80689..93b3b8d85d66 100644 --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -1128,7 +1128,7 @@ thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs) } PyInterpreterState *interp = _PyInterpreterState_GET(); - if (interp->config._isolated_interpreter) { + if (!_PyInterpreterState_HasFeature(interp, Py_RTFLAGS_THREADS)) { PyErr_SetString(PyExc_RuntimeError, "thread is not supported for isolated subinterpreters"); return NULL; diff --git a/Modules/_winapi.c b/Modules/_winapi.c index 4845b4e6d4ad..2a916cc9f467 100644 --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -1090,8 +1090,7 @@ _winapi_CreateProcess_impl(PyObject *module, } PyInterpreterState *interp = PyInterpreterState_Get(); - const PyConfig *config = _PyInterpreterState_GetConfig(interp); - if (config->_isolated_interpreter) { + if (!_PyInterpreterState_HasFeature(interp, Py_RTFLAGS_SUBPROCESS)) { PyErr_SetString(PyExc_RuntimeError, "subprocess not supported for isolated subinterpreters"); return NULL; diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c index f40601ad3a1a..f38de57f69e2 100644 --- a/Modules/_xxsubinterpretersmodule.c +++ b/Modules/_xxsubinterpretersmodule.c @@ -2003,8 +2003,13 @@ interp_create(PyObject *self, PyObject *args, PyObject *kwds) // Create and initialize the new interpreter. PyThreadState *save_tstate = _PyThreadState_GET(); + const _PyInterpreterConfig config = { + .allow_fork = !isolated, + .allow_subprocess = !isolated, + .allow_threads = !isolated, + }; // XXX Possible GILState issues? - PyThreadState *tstate = _Py_NewInterpreter(isolated); + PyThreadState *tstate = _Py_NewInterpreterFromConfig(&config); PyThreadState_Swap(save_tstate); if (tstate == NULL) { /* Since no new thread state was created, there is no exception to diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 56ea319ecb3a..a5eb86631211 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -6760,7 +6760,7 @@ os_fork_impl(PyObject *module) { pid_t pid; PyInterpreterState *interp = _PyInterpreterState_GET(); - if (interp->config._isolated_interpreter) { + if (!_PyInterpreterState_HasFeature(interp, Py_RTFLAGS_FORK)) { PyErr_SetString(PyExc_RuntimeError, "fork not supported for isolated subinterpreters"); return NULL; diff --git a/Programs/_testembed.c b/Programs/_testembed.c index d635c5a4abe3..ba599591d3c4 100644 --- a/Programs/_testembed.c +++ b/Programs/_testembed.c @@ -681,8 +681,6 @@ static int test_init_from_config(void) config.safe_path = 1; - config._isolated_interpreter = 1; - putenv("PYTHONINTMAXSTRDIGITS=6666"); config.int_max_str_digits = 31337; @@ -1901,6 +1899,18 @@ static int test_unicode_id_init(void) } +static int test_init_main_interpreter_settings(void) +{ + _testembed_Py_Initialize(); + (void) PyRun_SimpleStringFlags( + "import _testinternalcapi, json; " + "print(json.dumps(_testinternalcapi.get_interp_settings(0)))", + 0); + Py_Finalize(); + return 0; +} + + #ifndef MS_WINDOWS #include "test_frozenmain.h" // M_test_frozenmain @@ -2087,6 +2097,7 @@ static struct TestCase TestCases[] = { {"test_run_main_loop", test_run_main_loop}, {"test_get_argc_argv", test_get_argc_argv}, {"test_init_use_frozen_modules", test_init_use_frozen_modules}, + {"test_init_main_interpreter_settings", test_init_main_interpreter_settings}, // Audit {"test_open_code_hook", test_open_code_hook}, diff --git a/Python/initconfig.c b/Python/initconfig.c index bbc2ebb09fd0..4b784290b014 100644 --- a/Python/initconfig.c +++ b/Python/initconfig.c @@ -780,7 +780,6 @@ _PyConfig_InitCompatConfig(PyConfig *config) config->check_hash_pycs_mode = NULL; config->pathconfig_warnings = -1; config->_init_main = 1; - config->_isolated_interpreter = 0; #ifdef MS_WINDOWS config->legacy_windows_stdio = -1; #endif @@ -1015,7 +1014,6 @@ _PyConfig_Copy(PyConfig *config, const PyConfig *config2) COPY_WSTR_ATTR(check_hash_pycs_mode); COPY_ATTR(pathconfig_warnings); COPY_ATTR(_init_main); - COPY_ATTR(_isolated_interpreter); COPY_ATTR(use_frozen_modules); COPY_ATTR(safe_path); COPY_WSTRLIST(orig_argv); @@ -1123,7 +1121,6 @@ _PyConfig_AsDict(const PyConfig *config) SET_ITEM_WSTR(check_hash_pycs_mode); SET_ITEM_INT(pathconfig_warnings); SET_ITEM_INT(_init_main); - SET_ITEM_INT(_isolated_interpreter); SET_ITEM_WSTRLIST(orig_argv); SET_ITEM_INT(use_frozen_modules); SET_ITEM_INT(safe_path); @@ -1418,7 +1415,6 @@ _PyConfig_FromDict(PyConfig *config, PyObject *dict) GET_UINT(_install_importlib); GET_UINT(_init_main); - GET_UINT(_isolated_interpreter); GET_UINT(use_frozen_modules); GET_UINT(safe_path); GET_UINT(_is_python_build); diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 4195a9dbca81..334abfb191fe 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -611,6 +611,22 @@ pycore_init_runtime(_PyRuntimeState *runtime, } +static void +init_interp_settings(PyInterpreterState *interp, const _PyInterpreterConfig *config) +{ + assert(interp->feature_flags == 0); + if (config->allow_fork) { + interp->feature_flags |= Py_RTFLAGS_FORK; + } + if (config->allow_subprocess) { + interp->feature_flags |= Py_RTFLAGS_SUBPROCESS; + } + if (config->allow_threads) { + interp->feature_flags |= Py_RTFLAGS_THREADS; + } +} + + static PyStatus init_interp_create_gil(PyThreadState *tstate) { @@ -638,7 +654,7 @@ init_interp_create_gil(PyThreadState *tstate) static PyStatus pycore_create_interpreter(_PyRuntimeState *runtime, - const PyConfig *config, + const PyConfig *src_config, PyThreadState **tstate_p) { /* Auto-thread-state API */ @@ -653,11 +669,14 @@ pycore_create_interpreter(_PyRuntimeState *runtime, } assert(_Py_IsMainInterpreter(interp)); - status = _PyConfig_Copy(&interp->config, config); + status = _PyConfig_Copy(&interp->config, src_config); if (_PyStatus_EXCEPTION(status)) { return status; } + const _PyInterpreterConfig config = _PyInterpreterConfig_LEGACY_INIT; + init_interp_settings(interp, &config); + PyThreadState *tstate = PyThreadState_New(interp); if (tstate == NULL) { return _PyStatus_ERR("can't make first thread"); @@ -1961,7 +1980,7 @@ Py_Finalize(void) */ static PyStatus -new_interpreter(PyThreadState **tstate_p, int isolated_subinterpreter) +new_interpreter(PyThreadState **tstate_p, const _PyInterpreterConfig *config) { PyStatus status; @@ -1995,23 +2014,23 @@ new_interpreter(PyThreadState **tstate_p, int isolated_subinterpreter) PyThreadState *save_tstate = PyThreadState_Swap(tstate); /* Copy the current interpreter config into the new interpreter */ - const PyConfig *config; + const PyConfig *src_config; if (save_tstate != NULL) { - config = _PyInterpreterState_GetConfig(save_tstate->interp); + src_config = _PyInterpreterState_GetConfig(save_tstate->interp); } else { /* No current thread state, copy from the main interpreter */ PyInterpreterState *main_interp = _PyInterpreterState_Main(); - config = _PyInterpreterState_GetConfig(main_interp); + src_config = _PyInterpreterState_GetConfig(main_interp); } - - status = _PyConfig_Copy(&interp->config, config); + status = _PyConfig_Copy(&interp->config, src_config); if (_PyStatus_EXCEPTION(status)) { goto error; } - interp->config._isolated_interpreter = isolated_subinterpreter; + + init_interp_settings(interp, config); status = init_interp_create_gil(tstate); if (_PyStatus_EXCEPTION(status)) { @@ -2045,21 +2064,21 @@ new_interpreter(PyThreadState **tstate_p, int isolated_subinterpreter) } PyThreadState * -_Py_NewInterpreter(int isolated_subinterpreter) +_Py_NewInterpreterFromConfig(const _PyInterpreterConfig *config) { PyThreadState *tstate = NULL; - PyStatus status = new_interpreter(&tstate, isolated_subinterpreter); + PyStatus status = new_interpreter(&tstate, config); if (_PyStatus_EXCEPTION(status)) { Py_ExitStatusException(status); } return tstate; - } PyThreadState * Py_NewInterpreter(void) { - return _Py_NewInterpreter(0); + const _PyInterpreterConfig config = _PyInterpreterConfig_LEGACY_INIT; + return _Py_NewInterpreterFromConfig(&config); } /* Delete an interpreter and its last thread. This requires that the diff --git a/Python/pystate.c b/Python/pystate.c index c74868ddfa20..dd6d6e92eca8 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -2177,6 +2177,14 @@ _Py_GetConfig(void) return _PyInterpreterState_GetConfig(tstate->interp); } + +int +_PyInterpreterState_HasFeature(PyInterpreterState *interp, unsigned long feature) +{ + return ((interp->feature_flags & feature) != 0); +} + + #define MINIMUM_OVERHEAD 1000 static PyObject ** From webhook-mailer at python.org Wed Oct 26 14:09:08 2022 From: webhook-mailer at python.org (mdickinson) Date: Wed, 26 Oct 2022 18:09:08 -0000 Subject: [Python-checkins] gh-98727: Remove old style classes from `test_cmath` (GH-98728) Message-ID: https://github.com/python/cpython/commit/6777e09166fc384ea0a4b50202c7b0bd7a23330c commit: 6777e09166fc384ea0a4b50202c7b0bd7a23330c branch: main author: Nikita Sobolev committer: mdickinson date: 2022-10-26T19:08:34+01:00 summary: gh-98727: Remove old style classes from `test_cmath` (GH-98728) files: M Lib/test/test_cmath.py diff --git a/Lib/test/test_cmath.py b/Lib/test/test_cmath.py index 4bdec6d2d838..9fa08dc4ff3f 100644 --- a/Lib/test/test_cmath.py +++ b/Lib/test/test_cmath.py @@ -192,14 +192,7 @@ def test_user_object(self): # end up being passed to the cmath functions # usual case: new-style class implementing __complex__ - class MyComplex(object): - def __init__(self, value): - self.value = value - def __complex__(self): - return self.value - - # old-style class implementing __complex__ - class MyComplexOS: + class MyComplex: def __init__(self, value): self.value = value def __complex__(self): @@ -208,18 +201,13 @@ def __complex__(self): # classes for which __complex__ raises an exception class SomeException(Exception): pass - class MyComplexException(object): - def __complex__(self): - raise SomeException - class MyComplexExceptionOS: + class MyComplexException: def __complex__(self): raise SomeException # some classes not providing __float__ or __complex__ class NeitherComplexNorFloat(object): pass - class NeitherComplexNorFloatOS: - pass class Index: def __int__(self): return 2 def __index__(self): return 2 @@ -228,48 +216,32 @@ def __int__(self): return 2 # other possible combinations of __float__ and __complex__ # that should work - class FloatAndComplex(object): + class FloatAndComplex: def __float__(self): return flt_arg def __complex__(self): return cx_arg - class FloatAndComplexOS: - def __float__(self): - return flt_arg - def __complex__(self): - return cx_arg - class JustFloat(object): - def __float__(self): - return flt_arg - class JustFloatOS: + class JustFloat: def __float__(self): return flt_arg for f in self.test_functions: # usual usage self.assertEqual(f(MyComplex(cx_arg)), f(cx_arg)) - self.assertEqual(f(MyComplexOS(cx_arg)), f(cx_arg)) # other combinations of __float__ and __complex__ self.assertEqual(f(FloatAndComplex()), f(cx_arg)) - self.assertEqual(f(FloatAndComplexOS()), f(cx_arg)) self.assertEqual(f(JustFloat()), f(flt_arg)) - self.assertEqual(f(JustFloatOS()), f(flt_arg)) self.assertEqual(f(Index()), f(int(Index()))) # TypeError should be raised for classes not providing # either __complex__ or __float__, even if they provide - # __int__ or __index__. An old-style class - # currently raises AttributeError instead of a TypeError; - # this could be considered a bug. + # __int__ or __index__: self.assertRaises(TypeError, f, NeitherComplexNorFloat()) self.assertRaises(TypeError, f, MyInt()) - self.assertRaises(Exception, f, NeitherComplexNorFloatOS()) # non-complex return value from __complex__ -> TypeError for bad_complex in non_complexes: self.assertRaises(TypeError, f, MyComplex(bad_complex)) - self.assertRaises(TypeError, f, MyComplexOS(bad_complex)) # exceptions in __complex__ should be propagated correctly self.assertRaises(SomeException, f, MyComplexException()) - self.assertRaises(SomeException, f, MyComplexExceptionOS()) def test_input_type(self): # ints should be acceptable inputs to all cmath From webhook-mailer at python.org Wed Oct 26 16:18:56 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Wed, 26 Oct 2022 20:18:56 -0000 Subject: [Python-checkins] [3.11] Change links to label refs (GH-98454) (#98725) Message-ID: https://github.com/python/cpython/commit/5f86275ec2d9c82997e9a314409773cc53799d4e commit: 5f86275ec2d9c82997e9a314409773cc53799d4e branch: 3.11 author: Stanley <46876382+slateny at users.noreply.github.com> committer: JelleZijlstra date: 2022-10-26T13:18:50-07:00 summary: [3.11] Change links to label refs (GH-98454) (#98725) Co-authored-by: C.A.M. Gerlach (cherry picked from commit 268129a74f01adb7bb14cd71d1f38378e39d304d) files: M Doc/howto/clinic.rst M Doc/howto/isolating-extensions.rst M Doc/library/dataclasses.rst M Doc/reference/datamodel.rst M Doc/using/venv-create.inc M Doc/whatsnew/2.2.rst M Doc/whatsnew/3.6.rst M Doc/whatsnew/3.8.rst M Misc/NEWS.d/3.9.0a3.rst diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst index e5ed32f69a8e..4e9b3dee0913 100644 --- a/Doc/howto/clinic.rst +++ b/Doc/howto/clinic.rst @@ -1,5 +1,7 @@ .. highlight:: c +.. _howto-clinic: + ********************** Argument Clinic How-To ********************** diff --git a/Doc/howto/isolating-extensions.rst b/Doc/howto/isolating-extensions.rst index 2657b4ec6aaf..2eddb582da7c 100644 --- a/Doc/howto/isolating-extensions.rst +++ b/Doc/howto/isolating-extensions.rst @@ -461,7 +461,7 @@ Module State Access from Slot Methods, Getters and Setters .. After adding to limited API: - If you use the `limited API __, + If you use the :ref:`limited API , you must update ``Py_LIMITED_API`` to ``0x030b0000``, losing ABI compatibility with earlier versions. diff --git a/Doc/library/dataclasses.rst b/Doc/library/dataclasses.rst index 4364ac342471..ab8df8b02c5f 100644 --- a/Doc/library/dataclasses.rst +++ b/Doc/library/dataclasses.rst @@ -191,7 +191,7 @@ Module contents .. versionchanged:: 3.11 If a field name is already included in the ``__slots__`` of a base class, it will not be included in the generated ``__slots__`` - to prevent `overriding them `_. + to prevent :ref:`overriding them `. Therefore, do not use ``__slots__`` to retrieve the field names of a dataclass. Use :func:`fields` instead. To be able to determine inherited slots, diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index f2465cdf40f6..70021c47c32d 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -1904,6 +1904,8 @@ Attribute lookup speed can be significantly improved as well. and *__weakref__* for each instance. +.. _datamodel-note-slots: + Notes on using *__slots__* """""""""""""""""""""""""" diff --git a/Doc/using/venv-create.inc b/Doc/using/venv-create.inc index b929705648c5..0422cd2e4e76 100644 --- a/Doc/using/venv-create.inc +++ b/Doc/using/venv-create.inc @@ -16,8 +16,8 @@ re-used. .. deprecated:: 3.6 ``pyvenv`` was the recommended tool for creating virtual environments for - Python 3.3 and 3.4, and is `deprecated in Python 3.6 - `_. + Python 3.3 and 3.4, and is + :ref:`deprecated in Python 3.6 `. .. versionchanged:: 3.5 The use of ``venv`` is now recommended for creating virtual environments. diff --git a/Doc/whatsnew/2.2.rst b/Doc/whatsnew/2.2.rst index 39997661bb96..0c3bfda19339 100644 --- a/Doc/whatsnew/2.2.rst +++ b/Doc/whatsnew/2.2.rst @@ -395,7 +395,7 @@ This section has just been a quick overview of the new features, giving enough of an explanation to start you programming, but many details have been simplified or ignored. Where should you go to get a more complete picture? -https://docs.python.org/dev/howto/descriptor.html is a lengthy tutorial introduction to +The :ref:`descriptorhowto` is a lengthy tutorial introduction to the descriptor features, written by Guido van Rossum. If my description has whetted your appetite, go read this tutorial next, because it goes into much more detail about the new features while still remaining quite easy to read. diff --git a/Doc/whatsnew/3.6.rst b/Doc/whatsnew/3.6.rst index 70e45258654f..f138fa5c0e9f 100644 --- a/Doc/whatsnew/3.6.rst +++ b/Doc/whatsnew/3.6.rst @@ -2052,6 +2052,8 @@ tkinter The :mod:`tkinter.tix` module is now deprecated. :mod:`tkinter` users should use :mod:`tkinter.ttk` instead. +.. _whatsnew36-venv: + venv ~~~~ diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst index 7f85ff3ffa91..4e2dbe3b539f 100644 --- a/Doc/whatsnew/3.8.rst +++ b/Doc/whatsnew/3.8.rst @@ -122,8 +122,8 @@ Positional-only parameters There is a new function parameter syntax ``/`` to indicate that some function parameters must be specified positionally and cannot be used as keyword arguments. This is the same notation shown by ``help()`` for C -functions annotated with Larry Hastings' `Argument Clinic -`_ tool. +functions annotated with Larry Hastings' +:ref:`Argument Clinic ` tool. In the following example, parameters *a* and *b* are positional-only, while *c* or *d* can be positional or keyword, and *e* or *f* are diff --git a/Misc/NEWS.d/3.9.0a3.rst b/Misc/NEWS.d/3.9.0a3.rst index 77ccc7453c21..54b61ca3b778 100644 --- a/Misc/NEWS.d/3.9.0a3.rst +++ b/Misc/NEWS.d/3.9.0a3.rst @@ -805,8 +805,7 @@ event loop only if called from the main thread. .. section: Documentation Add an entry for ``__module__`` in the "function" & "method" sections of the -`inspect docs types and members table -`_ +:mod:`inspect` docs' :ref:`inspect-types` table. .. From webhook-mailer at python.org Wed Oct 26 16:19:26 2022 From: webhook-mailer at python.org (erlend-aasland) Date: Wed, 26 Oct 2022 20:19:26 -0000 Subject: [Python-checkins] [3.10] gh-98716: Revert gh-96081: Escape lone stars in sqlite3 docs (GH-98720) (#98737) Message-ID: https://github.com/python/cpython/commit/4b41b11a63ad82b5cfd3c45b871295973982a3b0 commit: 4b41b11a63ad82b5cfd3c45b871295973982a3b0 branch: 3.10 author: Erlend E. Aasland committer: erlend-aasland date: 2022-10-26T22:19:20+02:00 summary: [3.10] gh-98716: Revert gh-96081: Escape lone stars in sqlite3 docs (GH-98720) (#98737) (cherry picked from commit 365852a03a0c934ccd9b6c2b8e24c71181c41f03) Co-authored-by: Erlend E. Aasland files: M Doc/library/sqlite3.rst diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index 5f276c8d8e68..8573130536bd 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -557,7 +557,7 @@ Connection objects :meth:`~Cursor.executescript` on it with the given *sql_script*. Return the new cursor object. - .. method:: create_function(name, narg, func, \*, deterministic=False) + .. method:: create_function(name, narg, func, *, deterministic=False) Create or remove a user-defined SQL function. @@ -855,7 +855,7 @@ Connection objects con.close() - .. method:: backup(target, \*, pages=-1, progress=None, name="main", sleep=0.250) + .. method:: backup(target, *, pages=-1, progress=None, name="main", sleep=0.250) Create a backup of an SQLite database. From webhook-mailer at python.org Wed Oct 26 16:19:44 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Wed, 26 Oct 2022 20:19:44 -0000 Subject: [Python-checkins] [3.10] Change links to label refs (GH-98454) (#98726) Message-ID: https://github.com/python/cpython/commit/f786485f134c76a216b0dd891273f1006bb44863 commit: f786485f134c76a216b0dd891273f1006bb44863 branch: 3.10 author: Stanley <46876382+slateny at users.noreply.github.com> committer: JelleZijlstra date: 2022-10-26T13:19:39-07:00 summary: [3.10] Change links to label refs (GH-98454) (#98726) Co-authored-by: C.A.M. Gerlach files: M Doc/howto/clinic.rst M Doc/reference/datamodel.rst M Doc/using/venv-create.inc M Doc/whatsnew/2.2.rst M Doc/whatsnew/3.6.rst M Doc/whatsnew/3.8.rst M Misc/NEWS.d/3.9.0a3.rst diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst index 5a5cbab61b65..62ce28bd25f7 100644 --- a/Doc/howto/clinic.rst +++ b/Doc/howto/clinic.rst @@ -1,5 +1,7 @@ .. highlight:: c +.. _howto-clinic: + ********************** Argument Clinic How-To ********************** diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index e92b9a2eaf4e..2be83d8dd152 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -1837,6 +1837,8 @@ Attribute lookup speed can be significantly improved as well. and *__weakref__* for each instance. +.. _datamodel-note-slots: + Notes on using *__slots__* """""""""""""""""""""""""" diff --git a/Doc/using/venv-create.inc b/Doc/using/venv-create.inc index b929705648c5..0422cd2e4e76 100644 --- a/Doc/using/venv-create.inc +++ b/Doc/using/venv-create.inc @@ -16,8 +16,8 @@ re-used. .. deprecated:: 3.6 ``pyvenv`` was the recommended tool for creating virtual environments for - Python 3.3 and 3.4, and is `deprecated in Python 3.6 - `_. + Python 3.3 and 3.4, and is + :ref:`deprecated in Python 3.6 `. .. versionchanged:: 3.5 The use of ``venv`` is now recommended for creating virtual environments. diff --git a/Doc/whatsnew/2.2.rst b/Doc/whatsnew/2.2.rst index 39997661bb96..0c3bfda19339 100644 --- a/Doc/whatsnew/2.2.rst +++ b/Doc/whatsnew/2.2.rst @@ -395,7 +395,7 @@ This section has just been a quick overview of the new features, giving enough of an explanation to start you programming, but many details have been simplified or ignored. Where should you go to get a more complete picture? -https://docs.python.org/dev/howto/descriptor.html is a lengthy tutorial introduction to +The :ref:`descriptorhowto` is a lengthy tutorial introduction to the descriptor features, written by Guido van Rossum. If my description has whetted your appetite, go read this tutorial next, because it goes into much more detail about the new features while still remaining quite easy to read. diff --git a/Doc/whatsnew/3.6.rst b/Doc/whatsnew/3.6.rst index cbde9395bd3b..f8f45a312ff8 100644 --- a/Doc/whatsnew/3.6.rst +++ b/Doc/whatsnew/3.6.rst @@ -2052,6 +2052,8 @@ tkinter The :mod:`tkinter.tix` module is now deprecated. :mod:`tkinter` users should use :mod:`tkinter.ttk` instead. +.. _whatsnew36-venv: + venv ~~~~ diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst index 7f85ff3ffa91..4e2dbe3b539f 100644 --- a/Doc/whatsnew/3.8.rst +++ b/Doc/whatsnew/3.8.rst @@ -122,8 +122,8 @@ Positional-only parameters There is a new function parameter syntax ``/`` to indicate that some function parameters must be specified positionally and cannot be used as keyword arguments. This is the same notation shown by ``help()`` for C -functions annotated with Larry Hastings' `Argument Clinic -`_ tool. +functions annotated with Larry Hastings' +:ref:`Argument Clinic ` tool. In the following example, parameters *a* and *b* are positional-only, while *c* or *d* can be positional or keyword, and *e* or *f* are diff --git a/Misc/NEWS.d/3.9.0a3.rst b/Misc/NEWS.d/3.9.0a3.rst index 77ccc7453c21..54b61ca3b778 100644 --- a/Misc/NEWS.d/3.9.0a3.rst +++ b/Misc/NEWS.d/3.9.0a3.rst @@ -805,8 +805,7 @@ event loop only if called from the main thread. .. section: Documentation Add an entry for ``__module__`` in the "function" & "method" sections of the -`inspect docs types and members table -`_ +:mod:`inspect` docs' :ref:`inspect-types` table. .. From webhook-mailer at python.org Wed Oct 26 17:40:54 2022 From: webhook-mailer at python.org (vsajip) Date: Wed, 26 Oct 2022 21:40:54 -0000 Subject: [Python-checkins] gh-98741: Remove useless check_home usage from is_python_build usage (GH-98743) Message-ID: https://github.com/python/cpython/commit/a508631b3cf883316cc55e04692f70f1665d49d0 commit: a508631b3cf883316cc55e04692f70f1665d49d0 branch: main author: Henry Schreiner committer: vsajip date: 2022-10-26T22:40:47+01:00 summary: gh-98741: Remove useless check_home usage from is_python_build usage (GH-98743) files: M Lib/test/support/__init__.py M Lib/venv/__init__.py diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 3e6a787e617a..1dee708deb8c 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -1503,7 +1503,7 @@ def _platform_specific(self): self._env = {k.upper(): os.getenv(k) for k in os.environ} self._env["PYTHONHOME"] = os.path.dirname(self.real) - if sysconfig.is_python_build(True): + if sysconfig.is_python_build(): self._env["PYTHONPATH"] = STDLIB_DIR else: def _platform_specific(self): diff --git a/Lib/venv/__init__.py b/Lib/venv/__init__.py index 5e695c75ff49..7bfc2d1b6fe0 100644 --- a/Lib/venv/__init__.py +++ b/Lib/venv/__init__.py @@ -260,7 +260,7 @@ def symlink_or_copy(self, src, dst, relative_symlinks_ok=False): basename + ext) # Builds or venv's from builds need to remap source file # locations, as we do not put them into Lib/venv/scripts - if sysconfig.is_python_build(True) or not os.path.isfile(srcfn): + if sysconfig.is_python_build() or not os.path.isfile(srcfn): if basename.endswith('_d'): ext = '_d' + ext basename = basename[:-2] @@ -311,7 +311,7 @@ def setup_python(self, context): f for f in os.listdir(dirname) if os.path.normcase(os.path.splitext(f)[1]) in ('.exe', '.dll') ] - if sysconfig.is_python_build(True): + if sysconfig.is_python_build(): suffixes = [ f for f in suffixes if os.path.normcase(f).startswith(('python', 'vcruntime')) @@ -326,7 +326,7 @@ def setup_python(self, context): if os.path.lexists(src): copier(src, os.path.join(binpath, suffix)) - if sysconfig.is_python_build(True): + if sysconfig.is_python_build(): # copy init.tcl for root, dirs, files in os.walk(context.python_dir): if 'init.tcl' in files: From webhook-mailer at python.org Wed Oct 26 18:36:03 2022 From: webhook-mailer at python.org (vsajip) Date: Wed, 26 Oct 2022 22:36:03 -0000 Subject: [Python-checkins] [3.11] gh-98741: Remove useless check_home usage from is_python_build usage (GH-98743) (GH-98746) Message-ID: https://github.com/python/cpython/commit/3bad567d085e5380fd6c4309e44aee7b8ee4ea36 commit: 3bad567d085e5380fd6c4309e44aee7b8ee4ea36 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: vsajip date: 2022-10-26T23:35:54+01:00 summary: [3.11] gh-98741: Remove useless check_home usage from is_python_build usage (GH-98743) (GH-98746) Co-authored-by: Henry Schreiner files: M Lib/test/support/__init__.py M Lib/venv/__init__.py diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 46087a98a2e1..8ee8147f4161 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -1498,7 +1498,7 @@ def _platform_specific(self): self._env = {k.upper(): os.getenv(k) for k in os.environ} self._env["PYTHONHOME"] = os.path.dirname(self.real) - if sysconfig.is_python_build(True): + if sysconfig.is_python_build(): self._env["PYTHONPATH"] = STDLIB_DIR else: def _platform_specific(self): diff --git a/Lib/venv/__init__.py b/Lib/venv/__init__.py index fbb002ff2778..6bce30810882 100644 --- a/Lib/venv/__init__.py +++ b/Lib/venv/__init__.py @@ -259,7 +259,7 @@ def symlink_or_copy(self, src, dst, relative_symlinks_ok=False): basename + ext) # Builds or venv's from builds need to remap source file # locations, as we do not put them into Lib/venv/scripts - if sysconfig.is_python_build(True) or not os.path.isfile(srcfn): + if sysconfig.is_python_build() or not os.path.isfile(srcfn): if basename.endswith('_d'): ext = '_d' + ext basename = basename[:-2] @@ -310,7 +310,7 @@ def setup_python(self, context): f for f in os.listdir(dirname) if os.path.normcase(os.path.splitext(f)[1]) in ('.exe', '.dll') ] - if sysconfig.is_python_build(True): + if sysconfig.is_python_build(): suffixes = [ f for f in suffixes if os.path.normcase(f).startswith(('python', 'vcruntime')) @@ -325,7 +325,7 @@ def setup_python(self, context): if os.path.lexists(src): copier(src, os.path.join(binpath, suffix)) - if sysconfig.is_python_build(True): + if sysconfig.is_python_build(): # copy init.tcl for root, dirs, files in os.walk(context.python_dir): if 'init.tcl' in files: From webhook-mailer at python.org Wed Oct 26 18:53:42 2022 From: webhook-mailer at python.org (benjaminp) Date: Wed, 26 Oct 2022 22:53:42 -0000 Subject: [Python-checkins] Fix readline.c compiler warning. (GH-98738) Message-ID: https://github.com/python/cpython/commit/29b391b1378577825a658b14764a8ff3e0b5c958 commit: 29b391b1378577825a658b14764a8ff3e0b5c958 branch: main author: Benjamin Peterson committer: benjaminp date: 2022-10-26T15:53:25-07:00 summary: Fix readline.c compiler warning. (GH-98738) ``` Modules/readline.c:1260:37: warning: assigning to 'char *' from 'const char *' discards qualifiers [-Wincompatible-pointer-types-discards-qualifiers] completer_word_break_characters = ^ ``` files: M Modules/readline.c diff --git a/Modules/readline.c b/Modules/readline.c index 1b616fc4f3b4..27b89de72794 100644 --- a/Modules/readline.c +++ b/Modules/readline.c @@ -1258,9 +1258,9 @@ setup_readline(readlinestate *mod_state) rl_attempted_completion_function = flex_complete; /* Set Python word break characters */ completer_word_break_characters = - rl_completer_word_break_characters = strdup(" \t\n`~!@#$%^&*()-=+[{]}\\|;:'\",<>/?"); /* All nonalphanums except '.' */ + rl_completer_word_break_characters = completer_word_break_characters; mod_state->begidx = PyLong_FromLong(0L); mod_state->endidx = PyLong_FromLong(0L); From webhook-mailer at python.org Wed Oct 26 19:16:15 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 26 Oct 2022 23:16:15 -0000 Subject: [Python-checkins] Fix readline.c compiler warning. (GH-98738) Message-ID: https://github.com/python/cpython/commit/75990a56b7f5545b7673972881c2769586742f69 commit: 75990a56b7f5545b7673972881c2769586742f69 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-26T16:16:09-07:00 summary: Fix readline.c compiler warning. (GH-98738) ``` Modules/readline.c:1260:37: warning: assigning to 'char *' from 'const char *' discards qualifiers [-Wincompatible-pointer-types-discards-qualifiers] completer_word_break_characters = ^ ``` (cherry picked from commit 29b391b1378577825a658b14764a8ff3e0b5c958) Co-authored-by: Benjamin Peterson files: M Modules/readline.c diff --git a/Modules/readline.c b/Modules/readline.c index 1b616fc4f3b4..27b89de72794 100644 --- a/Modules/readline.c +++ b/Modules/readline.c @@ -1258,9 +1258,9 @@ setup_readline(readlinestate *mod_state) rl_attempted_completion_function = flex_complete; /* Set Python word break characters */ completer_word_break_characters = - rl_completer_word_break_characters = strdup(" \t\n`~!@#$%^&*()-=+[{]}\\|;:'\",<>/?"); /* All nonalphanums except '.' */ + rl_completer_word_break_characters = completer_word_break_characters; mod_state->begidx = PyLong_FromLong(0L); mod_state->endidx = PyLong_FromLong(0L); From webhook-mailer at python.org Wed Oct 26 19:28:49 2022 From: webhook-mailer at python.org (miss-islington) Date: Wed, 26 Oct 2022 23:28:49 -0000 Subject: [Python-checkins] Fix readline.c compiler warning. (GH-98738) Message-ID: https://github.com/python/cpython/commit/5074c35c2a5659e74cd7a0e925a0d7e493ea28e1 commit: 5074c35c2a5659e74cd7a0e925a0d7e493ea28e1 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-26T16:28:40-07:00 summary: Fix readline.c compiler warning. (GH-98738) ``` Modules/readline.c:1260:37: warning: assigning to 'char *' from 'const char *' discards qualifiers [-Wincompatible-pointer-types-discards-qualifiers] completer_word_break_characters = ^ ``` (cherry picked from commit 29b391b1378577825a658b14764a8ff3e0b5c958) Co-authored-by: Benjamin Peterson files: M Modules/readline.c diff --git a/Modules/readline.c b/Modules/readline.c index c79d22f85f84..1d5067209072 100644 --- a/Modules/readline.c +++ b/Modules/readline.c @@ -1256,9 +1256,9 @@ setup_readline(readlinestate *mod_state) rl_attempted_completion_function = flex_complete; /* Set Python word break characters */ completer_word_break_characters = - rl_completer_word_break_characters = strdup(" \t\n`~!@#$%^&*()-=+[{]}\\|;:'\",<>/?"); /* All nonalphanums except '.' */ + rl_completer_word_break_characters = completer_word_break_characters; mod_state->begidx = PyLong_FromLong(0L); mod_state->endidx = PyLong_FromLong(0L); From webhook-mailer at python.org Wed Oct 26 20:47:34 2022 From: webhook-mailer at python.org (JelleZijlstra) Date: Thu, 27 Oct 2022 00:47:34 -0000 Subject: [Python-checkins] gh-94808: cover `PyFunction_GetDefaults` and `PyFunction_SetDefaults` (#98449) Message-ID: https://github.com/python/cpython/commit/7b24333fff51f9ca36ef19748016cc2b39ab6301 commit: 7b24333fff51f9ca36ef19748016cc2b39ab6301 branch: main author: Nikita Sobolev committer: JelleZijlstra date: 2022-10-26T17:47:29-07:00 summary: gh-94808: cover `PyFunction_GetDefaults` and `PyFunction_SetDefaults` (#98449) files: M Lib/test/test_capi.py M Modules/_testcapimodule.c diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py index 9446d472addd..2a35576fc57e 100644 --- a/Lib/test/test_capi.py +++ b/Lib/test/test_capi.py @@ -942,6 +942,48 @@ def some(): with self.assertRaises(SystemError): _testcapi.function_get_module(None) # not a function + def test_function_get_defaults(self): + def some(pos_only='p', zero=0, optional=None): + pass + + defaults = _testcapi.function_get_defaults(some) + self.assertEqual(defaults, ('p', 0, None)) + self.assertEqual(defaults, some.__defaults__) + + with self.assertRaises(SystemError): + _testcapi.function_get_module(None) # not a function + + def test_function_set_defaults(self): + def some(pos_only='p', zero=0, optional=None): + pass + + old_defaults = ('p', 0, None) + self.assertEqual(_testcapi.function_get_defaults(some), old_defaults) + self.assertEqual(some.__defaults__, old_defaults) + + with self.assertRaises(SystemError): + _testcapi.function_set_defaults(some, 1) # not tuple or None + self.assertEqual(_testcapi.function_get_defaults(some), old_defaults) + self.assertEqual(some.__defaults__, old_defaults) + + new_defaults = ('q', 1, None) + _testcapi.function_set_defaults(some, new_defaults) + self.assertEqual(_testcapi.function_get_defaults(some), new_defaults) + self.assertEqual(some.__defaults__, new_defaults) + + class tuplesub(tuple): ... # tuple subclasses must work + + new_defaults = tuplesub(((1, 2), ['a', 'b'], None)) + _testcapi.function_set_defaults(some, new_defaults) + self.assertEqual(_testcapi.function_get_defaults(some), new_defaults) + self.assertEqual(some.__defaults__, new_defaults) + + # `None` is special, it sets `defaults` to `NULL`, + # it needs special handling in `_testcapi`: + _testcapi.function_set_defaults(some, None) + self.assertEqual(_testcapi.function_get_defaults(some), None) + self.assertEqual(some.__defaults__, None) + class TestPendingCalls(unittest.TestCase): diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index fdf2f204acb2..bade0db64f51 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -5788,6 +5788,33 @@ function_get_module(PyObject *self, PyObject *func) } } +static PyObject * +function_get_defaults(PyObject *self, PyObject *func) +{ + PyObject *defaults = PyFunction_GetDefaults(func); + if (defaults != NULL) { + Py_INCREF(defaults); + return defaults; + } else if (PyErr_Occurred()) { + return NULL; + } else { + Py_RETURN_NONE; // This can happen when `defaults` are set to `None` + } +} + +static PyObject * +function_set_defaults(PyObject *self, PyObject *args) +{ + PyObject *func = NULL, *defaults = NULL; + if (!PyArg_ParseTuple(args, "OO", &func, &defaults)) { + return NULL; + } + int result = PyFunction_SetDefaults(func, defaults); + if (result == -1) + return NULL; + Py_RETURN_NONE; +} + // type watchers @@ -6202,6 +6229,8 @@ static PyMethodDef TestMethods[] = { {"function_get_code", function_get_code, METH_O, NULL}, {"function_get_globals", function_get_globals, METH_O, NULL}, {"function_get_module", function_get_module, METH_O, NULL}, + {"function_get_defaults", function_get_defaults, METH_O, NULL}, + {"function_set_defaults", function_set_defaults, METH_VARARGS, NULL}, {"add_type_watcher", add_type_watcher, METH_O, NULL}, {"clear_type_watcher", clear_type_watcher, METH_O, NULL}, {"watch_type", watch_type, METH_VARARGS, NULL}, From webhook-mailer at python.org Wed Oct 26 22:37:22 2022 From: webhook-mailer at python.org (Fidget-Spinner) Date: Thu, 27 Oct 2022 02:37:22 -0000 Subject: [Python-checkins] gh-98703: Fix asyncio proactor_events calling _call_connection_lost multiple times (GH-98704) Message-ID: https://github.com/python/cpython/commit/8a755423eba8e19704d96905730cf7f50083eb23 commit: 8a755423eba8e19704d96905730cf7f50083eb23 branch: main author: Ken Jin committer: Fidget-Spinner date: 2022-10-27T10:37:12+08:00 summary: gh-98703: Fix asyncio proactor_events calling _call_connection_lost multiple times (GH-98704) Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> files: A Misc/NEWS.d/next/Library/2022-10-26-07-51-55.gh-issue-98703.0hW773.rst M Lib/asyncio/proactor_events.py diff --git a/Lib/asyncio/proactor_events.py b/Lib/asyncio/proactor_events.py index 2685a3376cfd..c6aab408fc74 100644 --- a/Lib/asyncio/proactor_events.py +++ b/Lib/asyncio/proactor_events.py @@ -152,6 +152,8 @@ def _force_close(self, exc): self._loop.call_soon(self._call_connection_lost, exc) def _call_connection_lost(self, exc): + if self._called_connection_lost: + return try: self._protocol.connection_lost(exc) finally: diff --git a/Misc/NEWS.d/next/Library/2022-10-26-07-51-55.gh-issue-98703.0hW773.rst b/Misc/NEWS.d/next/Library/2022-10-26-07-51-55.gh-issue-98703.0hW773.rst new file mode 100644 index 000000000000..3107519a8714 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-26-07-51-55.gh-issue-98703.0hW773.rst @@ -0,0 +1,2 @@ +Fix :meth:`asyncio.StreamWriter.drain` to call ``protocol.connection_lost`` +callback only once on Windows. From webhook-mailer at python.org Wed Oct 26 23:04:04 2022 From: webhook-mailer at python.org (miss-islington) Date: Thu, 27 Oct 2022 03:04:04 -0000 Subject: [Python-checkins] gh-98703: Fix asyncio proactor_events calling _call_connection_lost multiple times (GH-98704) Message-ID: https://github.com/python/cpython/commit/bb80f6ad92f6765cdcd9c887c389ea37103e6902 commit: bb80f6ad92f6765cdcd9c887c389ea37103e6902 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-26T20:03:58-07:00 summary: gh-98703: Fix asyncio proactor_events calling _call_connection_lost multiple times (GH-98704) Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> (cherry picked from commit 8a755423eba8e19704d96905730cf7f50083eb23) Co-authored-by: Ken Jin files: A Misc/NEWS.d/next/Library/2022-10-26-07-51-55.gh-issue-98703.0hW773.rst M Lib/asyncio/proactor_events.py diff --git a/Lib/asyncio/proactor_events.py b/Lib/asyncio/proactor_events.py index 610d67387d12..0916d9eb5706 100644 --- a/Lib/asyncio/proactor_events.py +++ b/Lib/asyncio/proactor_events.py @@ -152,6 +152,8 @@ def _force_close(self, exc): self._loop.call_soon(self._call_connection_lost, exc) def _call_connection_lost(self, exc): + if self._called_connection_lost: + return try: self._protocol.connection_lost(exc) finally: diff --git a/Misc/NEWS.d/next/Library/2022-10-26-07-51-55.gh-issue-98703.0hW773.rst b/Misc/NEWS.d/next/Library/2022-10-26-07-51-55.gh-issue-98703.0hW773.rst new file mode 100644 index 000000000000..3107519a8714 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-26-07-51-55.gh-issue-98703.0hW773.rst @@ -0,0 +1,2 @@ +Fix :meth:`asyncio.StreamWriter.drain` to call ``protocol.connection_lost`` +callback only once on Windows. From webhook-mailer at python.org Wed Oct 26 23:04:49 2022 From: webhook-mailer at python.org (miss-islington) Date: Thu, 27 Oct 2022 03:04:49 -0000 Subject: [Python-checkins] gh-98703: Fix asyncio proactor_events calling _call_connection_lost multiple times (GH-98704) Message-ID: https://github.com/python/cpython/commit/08ce791f94618a6f553a9017fcaf5b84e85cb602 commit: 08ce791f94618a6f553a9017fcaf5b84e85cb602 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-26T20:04:43-07:00 summary: gh-98703: Fix asyncio proactor_events calling _call_connection_lost multiple times (GH-98704) Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> (cherry picked from commit 8a755423eba8e19704d96905730cf7f50083eb23) Co-authored-by: Ken Jin files: A Misc/NEWS.d/next/Library/2022-10-26-07-51-55.gh-issue-98703.0hW773.rst M Lib/asyncio/proactor_events.py diff --git a/Lib/asyncio/proactor_events.py b/Lib/asyncio/proactor_events.py index 2685a3376cfd..c6aab408fc74 100644 --- a/Lib/asyncio/proactor_events.py +++ b/Lib/asyncio/proactor_events.py @@ -152,6 +152,8 @@ def _force_close(self, exc): self._loop.call_soon(self._call_connection_lost, exc) def _call_connection_lost(self, exc): + if self._called_connection_lost: + return try: self._protocol.connection_lost(exc) finally: diff --git a/Misc/NEWS.d/next/Library/2022-10-26-07-51-55.gh-issue-98703.0hW773.rst b/Misc/NEWS.d/next/Library/2022-10-26-07-51-55.gh-issue-98703.0hW773.rst new file mode 100644 index 000000000000..3107519a8714 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-26-07-51-55.gh-issue-98703.0hW773.rst @@ -0,0 +1,2 @@ +Fix :meth:`asyncio.StreamWriter.drain` to call ``protocol.connection_lost`` +callback only once on Windows. From webhook-mailer at python.org Wed Oct 26 23:07:36 2022 From: webhook-mailer at python.org (Fidget-Spinner) Date: Thu, 27 Oct 2022 03:07:36 -0000 Subject: [Python-checkins] gh-98703: Add tests for closing `_ProactorSocketTransport` with proactor event loop (GH-98730) Message-ID: https://github.com/python/cpython/commit/96ae80f1d004f2df4a707919853f0745c9c352d1 commit: 96ae80f1d004f2df4a707919853f0745c9c352d1 branch: main author: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> committer: Fidget-Spinner date: 2022-10-27T11:07:31+08:00 summary: gh-98703: Add tests for closing `_ProactorSocketTransport` with proactor event loop (GH-98730) files: M Lib/test/test_asyncio/test_proactor_events.py diff --git a/Lib/test/test_asyncio/test_proactor_events.py b/Lib/test/test_asyncio/test_proactor_events.py index 7fd8b261cd5e..ae30185cef77 100644 --- a/Lib/test/test_asyncio/test_proactor_events.py +++ b/Lib/test/test_asyncio/test_proactor_events.py @@ -297,6 +297,27 @@ def test_force_close_idempotent(self): # and waiters will never be notified leading to hang. self.assertTrue(self.protocol.connection_lost.called) + def test_force_close_protocol_connection_lost_once(self): + tr = self.socket_transport() + self.assertFalse(self.protocol.connection_lost.called) + tr._closing = True + # Calling _force_close twice should not call + # protocol.connection_lost twice + tr._force_close(None) + tr._force_close(None) + test_utils.run_briefly(self.loop) + self.assertEqual(1, self.protocol.connection_lost.call_count) + + def test_close_protocol_connection_lost_once(self): + tr = self.socket_transport() + self.assertFalse(self.protocol.connection_lost.called) + # Calling close twice should not call + # protocol.connection_lost twice + tr.close() + tr.close() + test_utils.run_briefly(self.loop) + self.assertEqual(1, self.protocol.connection_lost.call_count) + def test_fatal_error_2(self): tr = self.socket_transport() tr._buffer = [b'data'] From webhook-mailer at python.org Wed Oct 26 23:20:59 2022 From: webhook-mailer at python.org (ericsnowcurrently) Date: Thu, 27 Oct 2022 03:20:59 -0000 Subject: [Python-checkins] gh-98627: Use a Switch in PyModule_FromDefAndSpec2() (gh-98734) Message-ID: https://github.com/python/cpython/commit/731909ebef3add602374e8a10002c4574bb24d4b commit: 731909ebef3add602374e8a10002c4574bb24d4b branch: main author: Eric Snow committer: ericsnowcurrently date: 2022-10-26T21:20:54-06:00 summary: gh-98627: Use a Switch in PyModule_FromDefAndSpec2() (gh-98734) This helps simplify some changes in follow-up PRs. It also matches what we're doing in PyModule_ExecDef(). files: M Objects/moduleobject.c diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index dba20a0b3646..ee8ef7f5b4a5 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -291,23 +291,27 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio } for (cur_slot = def->m_slots; cur_slot && cur_slot->slot; cur_slot++) { - if (cur_slot->slot == Py_mod_create) { - if (create) { + switch (cur_slot->slot) { + case Py_mod_create: + if (create) { + PyErr_Format( + PyExc_SystemError, + "module %s has multiple create slots", + name); + goto error; + } + create = cur_slot->value; + break; + case Py_mod_exec: + has_execution_slots = 1; + break; + default: + assert(cur_slot->slot < 0 || cur_slot->slot > _Py_mod_LAST_SLOT); PyErr_Format( PyExc_SystemError, - "module %s has multiple create slots", - name); + "module %s uses unknown slot ID %i", + name, cur_slot->slot); goto error; - } - create = cur_slot->value; - } else if (cur_slot->slot < 0 || cur_slot->slot > _Py_mod_LAST_SLOT) { - PyErr_Format( - PyExc_SystemError, - "module %s uses unknown slot ID %i", - name, cur_slot->slot); - goto error; - } else { - has_execution_slots = 1; } } From webhook-mailer at python.org Wed Oct 26 23:33:27 2022 From: webhook-mailer at python.org (miss-islington) Date: Thu, 27 Oct 2022 03:33:27 -0000 Subject: [Python-checkins] gh-98703: Add tests for closing `_ProactorSocketTransport` with proactor event loop (GH-98730) Message-ID: https://github.com/python/cpython/commit/8e475adf3052796b3fb644a6373b682b482bb13e commit: 8e475adf3052796b3fb644a6373b682b482bb13e branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-26T20:33:19-07:00 summary: gh-98703: Add tests for closing `_ProactorSocketTransport` with proactor event loop (GH-98730) (cherry picked from commit 96ae80f1d004f2df4a707919853f0745c9c352d1) Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> files: M Lib/test/test_asyncio/test_proactor_events.py diff --git a/Lib/test/test_asyncio/test_proactor_events.py b/Lib/test/test_asyncio/test_proactor_events.py index 7fd8b261cd5e..ae30185cef77 100644 --- a/Lib/test/test_asyncio/test_proactor_events.py +++ b/Lib/test/test_asyncio/test_proactor_events.py @@ -297,6 +297,27 @@ def test_force_close_idempotent(self): # and waiters will never be notified leading to hang. self.assertTrue(self.protocol.connection_lost.called) + def test_force_close_protocol_connection_lost_once(self): + tr = self.socket_transport() + self.assertFalse(self.protocol.connection_lost.called) + tr._closing = True + # Calling _force_close twice should not call + # protocol.connection_lost twice + tr._force_close(None) + tr._force_close(None) + test_utils.run_briefly(self.loop) + self.assertEqual(1, self.protocol.connection_lost.call_count) + + def test_close_protocol_connection_lost_once(self): + tr = self.socket_transport() + self.assertFalse(self.protocol.connection_lost.called) + # Calling close twice should not call + # protocol.connection_lost twice + tr.close() + tr.close() + test_utils.run_briefly(self.loop) + self.assertEqual(1, self.protocol.connection_lost.call_count) + def test_fatal_error_2(self): tr = self.socket_transport() tr._buffer = [b'data'] From webhook-mailer at python.org Wed Oct 26 23:35:12 2022 From: webhook-mailer at python.org (miss-islington) Date: Thu, 27 Oct 2022 03:35:12 -0000 Subject: [Python-checkins] gh-98703: Add tests for closing `_ProactorSocketTransport` with proactor event loop (GH-98730) Message-ID: https://github.com/python/cpython/commit/9338e9a5f4418e4ddb2509d7c7b2e0a784abb614 commit: 9338e9a5f4418e4ddb2509d7c7b2e0a784abb614 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-26T20:35:07-07:00 summary: gh-98703: Add tests for closing `_ProactorSocketTransport` with proactor event loop (GH-98730) (cherry picked from commit 96ae80f1d004f2df4a707919853f0745c9c352d1) Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> files: M Lib/test/test_asyncio/test_proactor_events.py diff --git a/Lib/test/test_asyncio/test_proactor_events.py b/Lib/test/test_asyncio/test_proactor_events.py index 3b219609eefc..60b30c6a46a6 100644 --- a/Lib/test/test_asyncio/test_proactor_events.py +++ b/Lib/test/test_asyncio/test_proactor_events.py @@ -296,6 +296,27 @@ def test_force_close_idempotent(self): # and waiters will never be notified leading to hang. self.assertTrue(self.protocol.connection_lost.called) + def test_force_close_protocol_connection_lost_once(self): + tr = self.socket_transport() + self.assertFalse(self.protocol.connection_lost.called) + tr._closing = True + # Calling _force_close twice should not call + # protocol.connection_lost twice + tr._force_close(None) + tr._force_close(None) + test_utils.run_briefly(self.loop) + self.assertEqual(1, self.protocol.connection_lost.call_count) + + def test_close_protocol_connection_lost_once(self): + tr = self.socket_transport() + self.assertFalse(self.protocol.connection_lost.called) + # Calling close twice should not call + # protocol.connection_lost twice + tr.close() + tr.close() + test_utils.run_briefly(self.loop) + self.assertEqual(1, self.protocol.connection_lost.call_count) + def test_fatal_error_2(self): tr = self.socket_transport() tr._buffer = [b'data'] From webhook-mailer at python.org Thu Oct 27 02:33:48 2022 From: webhook-mailer at python.org (miss-islington) Date: Thu, 27 Oct 2022 06:33:48 -0000 Subject: [Python-checkins] =?utf-8?q?Python_documents_state_elsewhere_tha?= =?utf-8?q?t_a_comma_is_not_an_operator=2C_so_=E2=80=A6_=28GH-98736=29?= Message-ID: https://github.com/python/cpython/commit/d578aaea6257458c199328100cbb5af64c6a043e commit: d578aaea6257458c199328100cbb5af64c6a043e branch: main author: Gerardwx committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-26T23:33:42-07:00 summary: Python documents state elsewhere that a comma is not an operator, so ? (GH-98736) ?calling it an operator here is confusing. See https://docs.python.org/3/reference/lexical_analysis.html#operators and https://docs.python.org/3/faq/programming.html#id22. files: M Doc/reference/expressions.rst diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst index 28c17566009f..920e4d19b82d 100644 --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -154,7 +154,7 @@ tuple may or may not yield the same object). single: , (comma) Note that tuples are not formed by the parentheses, but rather by use of the -comma operator. The exception is the empty tuple, for which parentheses *are* +comma. The exception is the empty tuple, for which parentheses *are* required --- allowing unparenthesized "nothing" in expressions would cause ambiguities and allow common typos to pass uncaught. From webhook-mailer at python.org Thu Oct 27 05:46:22 2022 From: webhook-mailer at python.org (encukou) Date: Thu, 27 Oct 2022 09:46:22 -0000 Subject: [Python-checkins] gh-98586: Add vector call APIs to the Limited API (GH-98587) Message-ID: https://github.com/python/cpython/commit/e60892f9db1316dbabf7a652d7648e4f968b745d commit: e60892f9db1316dbabf7a652d7648e4f968b745d branch: main author: Wenzel Jakob committer: encukou date: 2022-10-27T11:45:42+02:00 summary: gh-98586: Add vector call APIs to the Limited API (GH-98587) Expose the facilities for making vector calls through Python's limited API. files: A Misc/NEWS.d/next/Core and Builtins/2022-10-24-10-30-30.gh-issue-98586.Tha5Iy.rst M Doc/data/stable_abi.dat M Include/abstract.h M Include/cpython/abstract.h M Lib/test/test_call.py M Lib/test/test_stable_abi_ctypes.py M Misc/stable_abi.toml M Modules/_testcapi/vectorcall_limited.c M PC/python3dll.c diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat index fde62eacd00a..133658491c5a 100644 --- a/Doc/data/stable_abi.dat +++ b/Doc/data/stable_abi.dat @@ -1,4 +1,5 @@ role,name,added,ifdef_note,struct_abi_kind +macro,PY_VECTORCALL_ARGUMENTS_OFFSET,3.12,, function,PyAIter_Check,3.10,, function,PyArg_Parse,3.2,, function,PyArg_ParseTuple,3.2,, @@ -536,6 +537,8 @@ function,PyObject_SetItem,3.2,, function,PyObject_Size,3.2,, function,PyObject_Str,3.2,, function,PyObject_Type,3.2,, +function,PyObject_Vectorcall,3.12,, +function,PyObject_VectorcallMethod,3.12,, var,PyProperty_Type,3.2,, var,PyRangeIter_Type,3.2,, var,PyRange_Type,3.2,, diff --git a/Include/abstract.h b/Include/abstract.h index 784ff7e92867..064b0300b51e 100644 --- a/Include/abstract.h +++ b/Include/abstract.h @@ -238,6 +238,22 @@ PyAPI_FUNC(Py_ssize_t) PyVectorcall_NARGS(size_t nargsf); "tuple" and keyword arguments "dict". "dict" may also be NULL */ PyAPI_FUNC(PyObject *) PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *dict); +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030C0000 +#define PY_VECTORCALL_ARGUMENTS_OFFSET \ + (_Py_STATIC_CAST(size_t, 1) << (8 * sizeof(size_t) - 1)) + +/* Perform a PEP 590-style vector call on 'callable' */ +PyAPI_FUNC(PyObject *) PyObject_Vectorcall( + PyObject *callable, + PyObject *const *args, + size_t nargsf, + PyObject *kwnames); + +/* Call the method 'name' on args[0] with arguments in args[1..nargsf-1]. */ +PyAPI_FUNC(PyObject *) PyObject_VectorcallMethod( + PyObject *name, PyObject *const *args, + size_t nargsf, PyObject *kwnames); +#endif /* Implemented elsewhere: diff --git a/Include/cpython/abstract.h b/Include/cpython/abstract.h index 6da29cde9f60..3b27aab2fc47 100644 --- a/Include/cpython/abstract.h +++ b/Include/cpython/abstract.h @@ -50,9 +50,6 @@ PyAPI_FUNC(PyObject *) _PyObject_MakeTpCall( PyObject *const *args, Py_ssize_t nargs, PyObject *keywords); -#define PY_VECTORCALL_ARGUMENTS_OFFSET \ - (_Py_STATIC_CAST(size_t, 1) << (8 * sizeof(size_t) - 1)) - // PyVectorcall_NARGS() is exported as a function for the stable ABI. // Here (when we are not using the stable ABI), the name is overridden to // call a static inline function for best performance. @@ -65,12 +62,6 @@ _PyVectorcall_NARGS(size_t n) PyAPI_FUNC(vectorcallfunc) PyVectorcall_Function(PyObject *callable); -PyAPI_FUNC(PyObject *) PyObject_Vectorcall( - PyObject *callable, - PyObject *const *args, - size_t nargsf, - PyObject *kwnames); - // Backwards compatibility aliases for API that was provisional in Python 3.8 #define _PyObject_Vectorcall PyObject_Vectorcall #define _PyObject_VectorcallMethod PyObject_VectorcallMethod @@ -96,10 +87,6 @@ PyAPI_FUNC(PyObject *) _PyObject_FastCall( PyAPI_FUNC(PyObject *) PyObject_CallOneArg(PyObject *func, PyObject *arg); -PyAPI_FUNC(PyObject *) PyObject_VectorcallMethod( - PyObject *name, PyObject *const *args, - size_t nargsf, PyObject *kwnames); - static inline PyObject * PyObject_CallMethodNoArgs(PyObject *self, PyObject *name) { diff --git a/Lib/test/test_call.py b/Lib/test/test_call.py index 0b37116cd682..d4ddb7922ef3 100644 --- a/Lib/test/test_call.py +++ b/Lib/test/test_call.py @@ -812,11 +812,43 @@ def get_a(x): assert_equal("overridden", get_a(x)) @requires_limited_api - def test_vectorcall_limited(self): + def test_vectorcall_limited_incoming(self): from _testcapi import pyobject_vectorcall obj = _testcapi.LimitedVectorCallClass() self.assertEqual(pyobject_vectorcall(obj, (), ()), "vectorcall called") + @requires_limited_api + def test_vectorcall_limited_outgoing(self): + from _testcapi import call_vectorcall + + args_captured = [] + kwargs_captured = [] + + def f(*args, **kwargs): + args_captured.append(args) + kwargs_captured.append(kwargs) + return "success" + + self.assertEqual(call_vectorcall(f), "success") + self.assertEqual(args_captured, [("foo",)]) + self.assertEqual(kwargs_captured, [{"baz": "bar"}]) + + @requires_limited_api + def test_vectorcall_limited_outgoing_method(self): + from _testcapi import call_vectorcall_method + + args_captured = [] + kwargs_captured = [] + + class TestInstance: + def f(self, *args, **kwargs): + args_captured.append(args) + kwargs_captured.append(kwargs) + return "success" + + self.assertEqual(call_vectorcall_method(TestInstance()), "success") + self.assertEqual(args_captured, [("foo",)]) + self.assertEqual(kwargs_captured, [{"baz": "bar"}]) class A: def method_two_args(self, x, y): diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py index a803e3a50259..67c653428a6d 100644 --- a/Lib/test/test_stable_abi_ctypes.py +++ b/Lib/test/test_stable_abi_ctypes.py @@ -547,6 +547,8 @@ def test_windows_feature_macros(self): "PyObject_Size", "PyObject_Str", "PyObject_Type", + "PyObject_Vectorcall", + "PyObject_VectorcallMethod", "PyProperty_Type", "PyRangeIter_Type", "PyRange_Type", diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-24-10-30-30.gh-issue-98586.Tha5Iy.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-24-10-30-30.gh-issue-98586.Tha5Iy.rst new file mode 100644 index 000000000000..5d7b0c892496 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-24-10-30-30.gh-issue-98586.Tha5Iy.rst @@ -0,0 +1,7 @@ +Added the methods :c:func:`PyObject_Vectorcall` and +:c:func:`PyObject_VectorcallMethod` to the :ref:`Limited API ` along +with the auxiliary macro constant :c:macro:`PY_VECTORCALL_ARGUMENTS_OFFSET`. + +The availability of these functions enables more efficient :PEP:`590` vector +calls from binary extension modules that avoid argument boxing/unboxing +overheads. diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml index e78646fdea59..e18a6e8f6a9c 100644 --- a/Misc/stable_abi.toml +++ b/Misc/stable_abi.toml @@ -2293,3 +2293,9 @@ added = '3.12' [typedef.vectorcallfunc] added = '3.12' +[function.PyObject_Vectorcall] + added = '3.12' +[function.PyObject_VectorcallMethod] + added = '3.12' +[macro.PY_VECTORCALL_ARGUMENTS_OFFSET] + added = '3.12' diff --git a/Modules/_testcapi/vectorcall_limited.c b/Modules/_testcapi/vectorcall_limited.c index ee57af84b1bb..a69f1d3f2a79 100644 --- a/Modules/_testcapi/vectorcall_limited.c +++ b/Modules/_testcapi/vectorcall_limited.c @@ -32,6 +32,105 @@ LimitedVectorCallClass_new(PyTypeObject *tp, PyTypeObject *a, PyTypeObject *kw) return self; } +static PyObject * +call_vectorcall(PyObject* self, PyObject *callable) +{ + PyObject *args[3] = { NULL, NULL, NULL }; + PyObject *kwname = NULL, *kwnames = NULL, *result = NULL; + + args[1] = PyUnicode_FromString("foo"); + if (!args[1]) { + goto leave; + } + + args[2] = PyUnicode_FromString("bar"); + if (!args[2]) { + goto leave; + } + + kwname = PyUnicode_InternFromString("baz"); + if (!kwname) { + goto leave; + } + + kwnames = PyTuple_New(1); + if (!kwnames) { + goto leave; + } + + if (PyTuple_SetItem(kwnames, 0, kwname)) { + goto leave; + } + + result = PyObject_Vectorcall( + callable, + args + 1, + 1 | PY_VECTORCALL_ARGUMENTS_OFFSET, + kwnames + ); + +leave: + Py_XDECREF(args[1]); + Py_XDECREF(args[2]); + Py_XDECREF(kwnames); + + return result; +} + +static PyObject * +call_vectorcall_method(PyObject* self, PyObject *callable) +{ + PyObject *args[3] = { NULL, NULL, NULL }; + PyObject *name = NULL, *kwname = NULL, + *kwnames = NULL, *result = NULL; + + name = PyUnicode_FromString("f"); + if (!name) { + goto leave; + } + + args[0] = callable; + args[1] = PyUnicode_FromString("foo"); + if (!args[1]) { + goto leave; + } + + args[2] = PyUnicode_FromString("bar"); + if (!args[2]) { + goto leave; + } + + kwname = PyUnicode_InternFromString("baz"); + if (!kwname) { + goto leave; + } + + kwnames = PyTuple_New(1); + if (!kwnames) { + goto leave; + } + + if (PyTuple_SetItem(kwnames, 0, kwname)) { + goto leave; + } + + + result = PyObject_VectorcallMethod( + name, + args, + 2 | PY_VECTORCALL_ARGUMENTS_OFFSET, + kwnames + ); + +leave: + Py_XDECREF(name); + Py_XDECREF(args[1]); + Py_XDECREF(args[2]); + Py_XDECREF(kwnames); + + return result; +} + static PyMemberDef LimitedVectorCallClass_members[] = { {"__vectorcalloffset__", T_PYSSIZET, sizeof(PyObject), READONLY}, {NULL} @@ -54,10 +153,8 @@ static PyType_Spec LimitedVectorCallClass_spec = { }; static PyMethodDef TestMethods[] = { - /* Add module methods here. - * (Empty list left here as template/example, since using - * PyModule_AddFunctions isn't very common.) - */ + {"call_vectorcall", call_vectorcall, METH_O}, + {"call_vectorcall_method", call_vectorcall_method, METH_O}, {NULL}, }; diff --git a/PC/python3dll.c b/PC/python3dll.c index c1b88c66903b..931f316bb998 100755 --- a/PC/python3dll.c +++ b/PC/python3dll.c @@ -485,6 +485,8 @@ EXPORT_FUNC(PyObject_SetItem) EXPORT_FUNC(PyObject_Size) EXPORT_FUNC(PyObject_Str) EXPORT_FUNC(PyObject_Type) +EXPORT_FUNC(PyObject_Vectorcall) +EXPORT_FUNC(PyObject_VectorcallMethod) EXPORT_FUNC(PyOS_CheckStack) EXPORT_FUNC(PyOS_double_to_string) EXPORT_FUNC(PyOS_FSPath) From webhook-mailer at python.org Thu Oct 27 06:55:10 2022 From: webhook-mailer at python.org (markshannon) Date: Thu, 27 Oct 2022 10:55:10 -0000 Subject: [Python-checkins] GH-96793: Change `FOR_ITER` to not pop the iterator on exhaustion. (GH-96801) Message-ID: https://github.com/python/cpython/commit/22863df7ca5f9cd01a40ab3dce3d067ec5666081 commit: 22863df7ca5f9cd01a40ab3dce3d067ec5666081 branch: main author: Mark Shannon committer: markshannon date: 2022-10-27T11:55:03+01:00 summary: GH-96793: Change `FOR_ITER` to not pop the iterator on exhaustion. (GH-96801) Change FOR_ITER to have the same stack effect regardless of whether it branches or not. Performance is unchanged as FOR_ITER (and specialized forms jump over the cleanup code). files: A Misc/NEWS.d/next/Core and Builtins/2022-09-13-14-07-06.gh-issue-96793.7DLRSm.rst M Doc/library/dis.rst M Include/internal/pycore_opcode.h M Include/opcode.h M Lib/importlib/_bootstrap_external.py M Lib/opcode.py M Lib/test/test__opcode.py M Lib/test/test_dis.py M Objects/frameobject.c M Programs/test_frozenmain.h M Python/ceval.c M Python/compile.c M Python/opcode_targets.h M Python/specialize.c diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index c6b43035c294..1eaa9f32442d 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -413,6 +413,15 @@ The Python compiler currently generates the following bytecode instructions. Removes the top-of-stack (TOS) item. +.. opcode:: END_FOR + + Removes the top two values from the stack. + Equivalent to POP_TOP; POP_TOP. + Used to clean up at the end of loops, hence the name. + + .. versionadded:: 3.12 + + .. opcode:: COPY (i) Push the *i*-th item to the top of the stack. The item is not removed from its @@ -1088,9 +1097,11 @@ iterations of the loop. TOS is an :term:`iterator`. Call its :meth:`~iterator.__next__` method. If this yields a new value, push it on the stack (leaving the iterator below - it). If the iterator indicates it is exhausted, TOS is popped, and the byte + it). If the iterator indicates it is exhausted then the byte code counter is incremented by *delta*. + .. versionchanged:: 3.12 + Up until 3.11 the iterator was popped when it was exhausted. .. opcode:: LOAD_GLOBAL (namei) diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index c8ef5dd73525..33617b4be444 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -122,6 +122,7 @@ const uint8_t _PyOpcode_Deopt[256] = { [DICT_MERGE] = DICT_MERGE, [DICT_UPDATE] = DICT_UPDATE, [END_ASYNC_FOR] = END_ASYNC_FOR, + [END_FOR] = END_FOR, [EXTENDED_ARG] = EXTENDED_ARG, [EXTENDED_ARG_QUICK] = EXTENDED_ARG, [FORMAT_VALUE] = FORMAT_VALUE, @@ -244,18 +245,19 @@ static const char *const _PyOpcode_OpName[263] = { [POP_TOP] = "POP_TOP", [PUSH_NULL] = "PUSH_NULL", [BINARY_OP_ADAPTIVE] = "BINARY_OP_ADAPTIVE", + [END_FOR] = "END_FOR", [BINARY_OP_ADD_FLOAT] = "BINARY_OP_ADD_FLOAT", [BINARY_OP_ADD_INT] = "BINARY_OP_ADD_INT", [BINARY_OP_ADD_UNICODE] = "BINARY_OP_ADD_UNICODE", [BINARY_OP_INPLACE_ADD_UNICODE] = "BINARY_OP_INPLACE_ADD_UNICODE", - [BINARY_OP_MULTIPLY_FLOAT] = "BINARY_OP_MULTIPLY_FLOAT", [NOP] = "NOP", [UNARY_POSITIVE] = "UNARY_POSITIVE", [UNARY_NEGATIVE] = "UNARY_NEGATIVE", [UNARY_NOT] = "UNARY_NOT", + [BINARY_OP_MULTIPLY_FLOAT] = "BINARY_OP_MULTIPLY_FLOAT", [BINARY_OP_MULTIPLY_INT] = "BINARY_OP_MULTIPLY_INT", - [BINARY_OP_SUBTRACT_FLOAT] = "BINARY_OP_SUBTRACT_FLOAT", [UNARY_INVERT] = "UNARY_INVERT", + [BINARY_OP_SUBTRACT_FLOAT] = "BINARY_OP_SUBTRACT_FLOAT", [BINARY_OP_SUBTRACT_INT] = "BINARY_OP_SUBTRACT_INT", [BINARY_SUBSCR_ADAPTIVE] = "BINARY_SUBSCR_ADAPTIVE", [BINARY_SUBSCR_DICT] = "BINARY_SUBSCR_DICT", @@ -264,20 +266,20 @@ static const char *const _PyOpcode_OpName[263] = { [BINARY_SUBSCR_TUPLE_INT] = "BINARY_SUBSCR_TUPLE_INT", [CALL_ADAPTIVE] = "CALL_ADAPTIVE", [CALL_PY_EXACT_ARGS] = "CALL_PY_EXACT_ARGS", - [CALL_PY_WITH_DEFAULTS] = "CALL_PY_WITH_DEFAULTS", [BINARY_SUBSCR] = "BINARY_SUBSCR", [BINARY_SLICE] = "BINARY_SLICE", [STORE_SLICE] = "STORE_SLICE", + [CALL_PY_WITH_DEFAULTS] = "CALL_PY_WITH_DEFAULTS", [CALL_BOUND_METHOD_EXACT_ARGS] = "CALL_BOUND_METHOD_EXACT_ARGS", - [CALL_BUILTIN_CLASS] = "CALL_BUILTIN_CLASS", [GET_LEN] = "GET_LEN", [MATCH_MAPPING] = "MATCH_MAPPING", [MATCH_SEQUENCE] = "MATCH_SEQUENCE", [MATCH_KEYS] = "MATCH_KEYS", - [CALL_BUILTIN_FAST_WITH_KEYWORDS] = "CALL_BUILTIN_FAST_WITH_KEYWORDS", + [CALL_BUILTIN_CLASS] = "CALL_BUILTIN_CLASS", [PUSH_EXC_INFO] = "PUSH_EXC_INFO", [CHECK_EXC_MATCH] = "CHECK_EXC_MATCH", [CHECK_EG_MATCH] = "CHECK_EG_MATCH", + [CALL_BUILTIN_FAST_WITH_KEYWORDS] = "CALL_BUILTIN_FAST_WITH_KEYWORDS", [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = "CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS", [CALL_NO_KW_BUILTIN_FAST] = "CALL_NO_KW_BUILTIN_FAST", [CALL_NO_KW_BUILTIN_O] = "CALL_NO_KW_BUILTIN_O", @@ -288,7 +290,6 @@ static const char *const _PyOpcode_OpName[263] = { [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = "CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS", [CALL_NO_KW_METHOD_DESCRIPTOR_O] = "CALL_NO_KW_METHOD_DESCRIPTOR_O", [CALL_NO_KW_STR_1] = "CALL_NO_KW_STR_1", - [CALL_NO_KW_TUPLE_1] = "CALL_NO_KW_TUPLE_1", [WITH_EXCEPT_START] = "WITH_EXCEPT_START", [GET_AITER] = "GET_AITER", [GET_ANEXT] = "GET_ANEXT", @@ -296,37 +297,37 @@ static const char *const _PyOpcode_OpName[263] = { [BEFORE_WITH] = "BEFORE_WITH", [END_ASYNC_FOR] = "END_ASYNC_FOR", [CLEANUP_THROW] = "CLEANUP_THROW", + [CALL_NO_KW_TUPLE_1] = "CALL_NO_KW_TUPLE_1", [CALL_NO_KW_TYPE_1] = "CALL_NO_KW_TYPE_1", [COMPARE_OP_ADAPTIVE] = "COMPARE_OP_ADAPTIVE", [COMPARE_OP_FLOAT_JUMP] = "COMPARE_OP_FLOAT_JUMP", - [COMPARE_OP_INT_JUMP] = "COMPARE_OP_INT_JUMP", [STORE_SUBSCR] = "STORE_SUBSCR", [DELETE_SUBSCR] = "DELETE_SUBSCR", + [COMPARE_OP_INT_JUMP] = "COMPARE_OP_INT_JUMP", [COMPARE_OP_STR_JUMP] = "COMPARE_OP_STR_JUMP", [EXTENDED_ARG_QUICK] = "EXTENDED_ARG_QUICK", [FOR_ITER_ADAPTIVE] = "FOR_ITER_ADAPTIVE", [FOR_ITER_LIST] = "FOR_ITER_LIST", [FOR_ITER_RANGE] = "FOR_ITER_RANGE", - [JUMP_BACKWARD_QUICK] = "JUMP_BACKWARD_QUICK", [GET_ITER] = "GET_ITER", [GET_YIELD_FROM_ITER] = "GET_YIELD_FROM_ITER", [PRINT_EXPR] = "PRINT_EXPR", [LOAD_BUILD_CLASS] = "LOAD_BUILD_CLASS", + [JUMP_BACKWARD_QUICK] = "JUMP_BACKWARD_QUICK", [LOAD_ATTR_ADAPTIVE] = "LOAD_ATTR_ADAPTIVE", - [LOAD_ATTR_CLASS] = "LOAD_ATTR_CLASS", [LOAD_ASSERTION_ERROR] = "LOAD_ASSERTION_ERROR", [RETURN_GENERATOR] = "RETURN_GENERATOR", + [LOAD_ATTR_CLASS] = "LOAD_ATTR_CLASS", [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = "LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN", [LOAD_ATTR_INSTANCE_VALUE] = "LOAD_ATTR_INSTANCE_VALUE", [LOAD_ATTR_MODULE] = "LOAD_ATTR_MODULE", [LOAD_ATTR_PROPERTY] = "LOAD_ATTR_PROPERTY", [LOAD_ATTR_SLOT] = "LOAD_ATTR_SLOT", - [LOAD_ATTR_WITH_HINT] = "LOAD_ATTR_WITH_HINT", [LIST_TO_TUPLE] = "LIST_TO_TUPLE", [RETURN_VALUE] = "RETURN_VALUE", [IMPORT_STAR] = "IMPORT_STAR", [SETUP_ANNOTATIONS] = "SETUP_ANNOTATIONS", - [LOAD_ATTR_METHOD_LAZY_DICT] = "LOAD_ATTR_METHOD_LAZY_DICT", + [LOAD_ATTR_WITH_HINT] = "LOAD_ATTR_WITH_HINT", [ASYNC_GEN_WRAP] = "ASYNC_GEN_WRAP", [PREP_RERAISE_STAR] = "PREP_RERAISE_STAR", [POP_EXCEPT] = "POP_EXCEPT", @@ -353,7 +354,7 @@ static const char *const _PyOpcode_OpName[263] = { [JUMP_FORWARD] = "JUMP_FORWARD", [JUMP_IF_FALSE_OR_POP] = "JUMP_IF_FALSE_OR_POP", [JUMP_IF_TRUE_OR_POP] = "JUMP_IF_TRUE_OR_POP", - [LOAD_ATTR_METHOD_NO_DICT] = "LOAD_ATTR_METHOD_NO_DICT", + [LOAD_ATTR_METHOD_LAZY_DICT] = "LOAD_ATTR_METHOD_LAZY_DICT", [POP_JUMP_IF_FALSE] = "POP_JUMP_IF_FALSE", [POP_JUMP_IF_TRUE] = "POP_JUMP_IF_TRUE", [LOAD_GLOBAL] = "LOAD_GLOBAL", @@ -361,7 +362,7 @@ static const char *const _PyOpcode_OpName[263] = { [CONTAINS_OP] = "CONTAINS_OP", [RERAISE] = "RERAISE", [COPY] = "COPY", - [LOAD_ATTR_METHOD_WITH_DICT] = "LOAD_ATTR_METHOD_WITH_DICT", + [LOAD_ATTR_METHOD_NO_DICT] = "LOAD_ATTR_METHOD_NO_DICT", [BINARY_OP] = "BINARY_OP", [SEND] = "SEND", [LOAD_FAST] = "LOAD_FAST", @@ -381,9 +382,9 @@ static const char *const _PyOpcode_OpName[263] = { [STORE_DEREF] = "STORE_DEREF", [DELETE_DEREF] = "DELETE_DEREF", [JUMP_BACKWARD] = "JUMP_BACKWARD", - [LOAD_ATTR_METHOD_WITH_VALUES] = "LOAD_ATTR_METHOD_WITH_VALUES", + [LOAD_ATTR_METHOD_WITH_DICT] = "LOAD_ATTR_METHOD_WITH_DICT", [CALL_FUNCTION_EX] = "CALL_FUNCTION_EX", - [LOAD_CONST__LOAD_FAST] = "LOAD_CONST__LOAD_FAST", + [LOAD_ATTR_METHOD_WITH_VALUES] = "LOAD_ATTR_METHOD_WITH_VALUES", [EXTENDED_ARG] = "EXTENDED_ARG", [LIST_APPEND] = "LIST_APPEND", [SET_ADD] = "SET_ADD", @@ -393,26 +394,27 @@ static const char *const _PyOpcode_OpName[263] = { [YIELD_VALUE] = "YIELD_VALUE", [RESUME] = "RESUME", [MATCH_CLASS] = "MATCH_CLASS", + [LOAD_CONST__LOAD_FAST] = "LOAD_CONST__LOAD_FAST", [LOAD_FAST__LOAD_CONST] = "LOAD_FAST__LOAD_CONST", - [LOAD_FAST__LOAD_FAST] = "LOAD_FAST__LOAD_FAST", [FORMAT_VALUE] = "FORMAT_VALUE", [BUILD_CONST_KEY_MAP] = "BUILD_CONST_KEY_MAP", [BUILD_STRING] = "BUILD_STRING", + [LOAD_FAST__LOAD_FAST] = "LOAD_FAST__LOAD_FAST", [LOAD_GLOBAL_ADAPTIVE] = "LOAD_GLOBAL_ADAPTIVE", [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN", [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE", - [RESUME_QUICK] = "RESUME_QUICK", [LIST_EXTEND] = "LIST_EXTEND", [SET_UPDATE] = "SET_UPDATE", [DICT_MERGE] = "DICT_MERGE", [DICT_UPDATE] = "DICT_UPDATE", + [RESUME_QUICK] = "RESUME_QUICK", [STORE_ATTR_ADAPTIVE] = "STORE_ATTR_ADAPTIVE", [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE", [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT", - [STORE_FAST__LOAD_FAST] = "STORE_FAST__LOAD_FAST", [CALL] = "CALL", [KW_NAMES] = "KW_NAMES", + [STORE_FAST__LOAD_FAST] = "STORE_FAST__LOAD_FAST", [STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST", [STORE_SUBSCR_ADAPTIVE] = "STORE_SUBSCR_ADAPTIVE", [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", @@ -421,7 +423,6 @@ static const char *const _PyOpcode_OpName[263] = { [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", - [181] = "<181>", [182] = "<182>", [183] = "<183>", [184] = "<184>", @@ -507,7 +508,6 @@ static const char *const _PyOpcode_OpName[263] = { #endif #define EXTRA_CASES \ - case 181: \ case 182: \ case 183: \ case 184: \ diff --git a/Include/opcode.h b/Include/opcode.h index 0871eb1bfe0a..9b9414cff401 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -11,6 +11,7 @@ extern "C" { #define CACHE 0 #define POP_TOP 1 #define PUSH_NULL 2 +#define END_FOR 4 #define NOP 9 #define UNARY_POSITIVE 10 #define UNARY_NEGATIVE 11 @@ -127,78 +128,78 @@ extern "C" { #define LOAD_METHOD 262 #define MAX_PSEUDO_OPCODE 262 #define BINARY_OP_ADAPTIVE 3 -#define BINARY_OP_ADD_FLOAT 4 -#define BINARY_OP_ADD_INT 5 -#define BINARY_OP_ADD_UNICODE 6 -#define BINARY_OP_INPLACE_ADD_UNICODE 7 -#define BINARY_OP_MULTIPLY_FLOAT 8 -#define BINARY_OP_MULTIPLY_INT 13 -#define BINARY_OP_SUBTRACT_FLOAT 14 -#define BINARY_OP_SUBTRACT_INT 16 -#define BINARY_SUBSCR_ADAPTIVE 17 -#define BINARY_SUBSCR_DICT 18 -#define BINARY_SUBSCR_GETITEM 19 -#define BINARY_SUBSCR_LIST_INT 20 -#define BINARY_SUBSCR_TUPLE_INT 21 -#define CALL_ADAPTIVE 22 -#define CALL_PY_EXACT_ARGS 23 -#define CALL_PY_WITH_DEFAULTS 24 -#define CALL_BOUND_METHOD_EXACT_ARGS 28 -#define CALL_BUILTIN_CLASS 29 -#define CALL_BUILTIN_FAST_WITH_KEYWORDS 34 -#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 38 -#define CALL_NO_KW_BUILTIN_FAST 39 -#define CALL_NO_KW_BUILTIN_O 40 -#define CALL_NO_KW_ISINSTANCE 41 -#define CALL_NO_KW_LEN 42 -#define CALL_NO_KW_LIST_APPEND 43 -#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 44 -#define CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 45 -#define CALL_NO_KW_METHOD_DESCRIPTOR_O 46 -#define CALL_NO_KW_STR_1 47 -#define CALL_NO_KW_TUPLE_1 48 -#define CALL_NO_KW_TYPE_1 56 -#define COMPARE_OP_ADAPTIVE 57 -#define COMPARE_OP_FLOAT_JUMP 58 -#define COMPARE_OP_INT_JUMP 59 -#define COMPARE_OP_STR_JUMP 62 -#define EXTENDED_ARG_QUICK 63 -#define FOR_ITER_ADAPTIVE 64 -#define FOR_ITER_LIST 65 -#define FOR_ITER_RANGE 66 -#define JUMP_BACKWARD_QUICK 67 -#define LOAD_ATTR_ADAPTIVE 72 -#define LOAD_ATTR_CLASS 73 -#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 76 -#define LOAD_ATTR_INSTANCE_VALUE 77 -#define LOAD_ATTR_MODULE 78 -#define LOAD_ATTR_PROPERTY 79 -#define LOAD_ATTR_SLOT 80 -#define LOAD_ATTR_WITH_HINT 81 -#define LOAD_ATTR_METHOD_LAZY_DICT 86 -#define LOAD_ATTR_METHOD_NO_DICT 113 -#define LOAD_ATTR_METHOD_WITH_DICT 121 -#define LOAD_ATTR_METHOD_WITH_VALUES 141 -#define LOAD_CONST__LOAD_FAST 143 -#define LOAD_FAST__LOAD_CONST 153 -#define LOAD_FAST__LOAD_FAST 154 -#define LOAD_GLOBAL_ADAPTIVE 158 -#define LOAD_GLOBAL_BUILTIN 159 -#define LOAD_GLOBAL_MODULE 160 -#define RESUME_QUICK 161 -#define STORE_ATTR_ADAPTIVE 166 -#define STORE_ATTR_INSTANCE_VALUE 167 -#define STORE_ATTR_SLOT 168 -#define STORE_ATTR_WITH_HINT 169 -#define STORE_FAST__LOAD_FAST 170 -#define STORE_FAST__STORE_FAST 173 -#define STORE_SUBSCR_ADAPTIVE 174 -#define STORE_SUBSCR_DICT 175 -#define STORE_SUBSCR_LIST_INT 176 -#define UNPACK_SEQUENCE_ADAPTIVE 177 -#define UNPACK_SEQUENCE_LIST 178 -#define UNPACK_SEQUENCE_TUPLE 179 -#define UNPACK_SEQUENCE_TWO_TUPLE 180 +#define BINARY_OP_ADD_FLOAT 5 +#define BINARY_OP_ADD_INT 6 +#define BINARY_OP_ADD_UNICODE 7 +#define BINARY_OP_INPLACE_ADD_UNICODE 8 +#define BINARY_OP_MULTIPLY_FLOAT 13 +#define BINARY_OP_MULTIPLY_INT 14 +#define BINARY_OP_SUBTRACT_FLOAT 16 +#define BINARY_OP_SUBTRACT_INT 17 +#define BINARY_SUBSCR_ADAPTIVE 18 +#define BINARY_SUBSCR_DICT 19 +#define BINARY_SUBSCR_GETITEM 20 +#define BINARY_SUBSCR_LIST_INT 21 +#define BINARY_SUBSCR_TUPLE_INT 22 +#define CALL_ADAPTIVE 23 +#define CALL_PY_EXACT_ARGS 24 +#define CALL_PY_WITH_DEFAULTS 28 +#define CALL_BOUND_METHOD_EXACT_ARGS 29 +#define CALL_BUILTIN_CLASS 34 +#define CALL_BUILTIN_FAST_WITH_KEYWORDS 38 +#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 39 +#define CALL_NO_KW_BUILTIN_FAST 40 +#define CALL_NO_KW_BUILTIN_O 41 +#define CALL_NO_KW_ISINSTANCE 42 +#define CALL_NO_KW_LEN 43 +#define CALL_NO_KW_LIST_APPEND 44 +#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 45 +#define CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 46 +#define CALL_NO_KW_METHOD_DESCRIPTOR_O 47 +#define CALL_NO_KW_STR_1 48 +#define CALL_NO_KW_TUPLE_1 56 +#define CALL_NO_KW_TYPE_1 57 +#define COMPARE_OP_ADAPTIVE 58 +#define COMPARE_OP_FLOAT_JUMP 59 +#define COMPARE_OP_INT_JUMP 62 +#define COMPARE_OP_STR_JUMP 63 +#define EXTENDED_ARG_QUICK 64 +#define FOR_ITER_ADAPTIVE 65 +#define FOR_ITER_LIST 66 +#define FOR_ITER_RANGE 67 +#define JUMP_BACKWARD_QUICK 72 +#define LOAD_ATTR_ADAPTIVE 73 +#define LOAD_ATTR_CLASS 76 +#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 77 +#define LOAD_ATTR_INSTANCE_VALUE 78 +#define LOAD_ATTR_MODULE 79 +#define LOAD_ATTR_PROPERTY 80 +#define LOAD_ATTR_SLOT 81 +#define LOAD_ATTR_WITH_HINT 86 +#define LOAD_ATTR_METHOD_LAZY_DICT 113 +#define LOAD_ATTR_METHOD_NO_DICT 121 +#define LOAD_ATTR_METHOD_WITH_DICT 141 +#define LOAD_ATTR_METHOD_WITH_VALUES 143 +#define LOAD_CONST__LOAD_FAST 153 +#define LOAD_FAST__LOAD_CONST 154 +#define LOAD_FAST__LOAD_FAST 158 +#define LOAD_GLOBAL_ADAPTIVE 159 +#define LOAD_GLOBAL_BUILTIN 160 +#define LOAD_GLOBAL_MODULE 161 +#define RESUME_QUICK 166 +#define STORE_ATTR_ADAPTIVE 167 +#define STORE_ATTR_INSTANCE_VALUE 168 +#define STORE_ATTR_SLOT 169 +#define STORE_ATTR_WITH_HINT 170 +#define STORE_FAST__LOAD_FAST 173 +#define STORE_FAST__STORE_FAST 174 +#define STORE_SUBSCR_ADAPTIVE 175 +#define STORE_SUBSCR_DICT 176 +#define STORE_SUBSCR_LIST_INT 177 +#define UNPACK_SEQUENCE_ADAPTIVE 178 +#define UNPACK_SEQUENCE_LIST 179 +#define UNPACK_SEQUENCE_TUPLE 180 +#define UNPACK_SEQUENCE_TWO_TUPLE 181 #define DO_TRACING 255 #define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\ diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index fc50e70539ca..9c14f71b6c07 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -423,6 +423,7 @@ def _write_atomic(path, data, mode=0o666): # Python 3.12a1 3507 (Set lineno of module's RESUME to 0) # Python 3.12a1 3508 (Add CLEANUP_THROW) # Python 3.12a1 3509 (Conditional jumps only jump forward) +# Python 3.12a1 3510 (FOR_ITER leaves iterator on the stack) # Python 3.13 will start with 3550 @@ -435,7 +436,7 @@ def _write_atomic(path, data, mode=0o666): # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # in PC/launcher.c must also be updated. -MAGIC_NUMBER = (3509).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3510).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c diff --git a/Lib/opcode.py b/Lib/opcode.py index 690923061418..d655b0e44a4c 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -78,6 +78,8 @@ def pseudo_op(name, op, real_ops): def_op('POP_TOP', 1) def_op('PUSH_NULL', 2) +def_op('END_FOR', 4) + def_op('NOP', 9) def_op('UNARY_POSITIVE', 10) def_op('UNARY_NEGATIVE', 11) diff --git a/Lib/test/test__opcode.py b/Lib/test/test__opcode.py index f548e3647b31..704d19fffd09 100644 --- a/Lib/test/test__opcode.py +++ b/Lib/test/test__opcode.py @@ -40,7 +40,7 @@ def test_stack_effect_jump(self): self.assertEqual(stack_effect(JUMP_IF_TRUE_OR_POP, 0, jump=False), -1) FOR_ITER = dis.opmap['FOR_ITER'] self.assertEqual(stack_effect(FOR_ITER, 0), 1) - self.assertEqual(stack_effect(FOR_ITER, 0, jump=True), -1) + self.assertEqual(stack_effect(FOR_ITER, 0, jump=True), 1) self.assertEqual(stack_effect(FOR_ITER, 0, jump=False), 1) JUMP_FORWARD = dis.opmap['JUMP_FORWARD'] self.assertEqual(stack_effect(JUMP_FORWARD, 0), 0) diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 667b267d27a0..c986a6b538f2 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -148,7 +148,8 @@ def bug708901(): %3d JUMP_BACKWARD 4 (to 30) -%3d >> LOAD_CONST 0 (None) +%3d >> END_FOR + LOAD_CONST 0 (None) RETURN_VALUE """ % (bug708901.__code__.co_firstlineno, bug708901.__code__.co_firstlineno + 1, @@ -699,7 +700,8 @@ def foo(x): BINARY_OP 0 (+) LIST_APPEND 2 JUMP_BACKWARD 9 (to 8) - >> RETURN_VALUE + >> END_FOR + RETURN_VALUE """ % (dis_nested_1, __file__, _h.__code__.co_firstlineno + 3, @@ -748,7 +750,8 @@ def loop_test(): POP_TOP JUMP_BACKWARD_QUICK 17 (to 16) -%3d >> LOAD_CONST 0 (None) +%3d >> END_FOR + LOAD_CONST 0 (None) RETURN_VALUE """ % (loop_test.__code__.co_firstlineno, loop_test.__code__.co_firstlineno + 1, @@ -1566,97 +1569,98 @@ def _prepare_test_cases(): Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=1, argval=88, argrepr='to 88', offset=84, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='JUMP_BACKWARD', opcode=140, arg=30, argval=28, argrepr='to 28', offset=86, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=88, starts_line=8, is_jump_target=True, positions=None), - Instruction(opname='JUMP_FORWARD', opcode=110, arg=13, argval=118, argrepr='to 118', offset=90, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=92, starts_line=10, is_jump_target=True, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=104, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=106, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=116, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST_CHECK', opcode=127, arg=0, argval='i', argrepr='i', offset=118, starts_line=11, is_jump_target=True, positions=None), - Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=35, argval=192, argrepr='to 192', offset=120, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=122, starts_line=12, is_jump_target=True, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=134, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=136, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=146, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=148, starts_line=13, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=150, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='BINARY_OP', opcode=122, arg=23, argval=23, argrepr='-=', offset=152, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=156, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=158, starts_line=14, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=160, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=162, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=1, argval=172, argrepr='to 172', offset=168, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_BACKWARD', opcode=140, arg=27, argval=118, argrepr='to 118', offset=170, starts_line=15, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=172, starts_line=16, is_jump_target=True, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=174, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=176, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=1, argval=186, argrepr='to 186', offset=182, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_FORWARD', opcode=110, arg=16, argval=218, argrepr='to 218', offset=184, starts_line=17, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=186, starts_line=11, is_jump_target=True, positions=None), - Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=1, argval=192, argrepr='to 192', offset=188, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_BACKWARD', opcode=140, arg=35, argval=122, argrepr='to 122', offset=190, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=192, starts_line=19, is_jump_target=True, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval='Who let lolcatz into this test suite?', argrepr="'Who let lolcatz into this test suite?'", offset=204, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=206, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=216, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='NOP', opcode=9, arg=None, argval=None, argrepr='', offset=218, starts_line=20, is_jump_target=True, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=220, starts_line=21, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval=0, argrepr='0', offset=222, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='BINARY_OP', opcode=122, arg=11, argval=11, argrepr='/', offset=224, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=228, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=230, starts_line=25, is_jump_target=False, positions=None), - Instruction(opname='BEFORE_WITH', opcode=53, arg=None, argval=None, argrepr='', offset=232, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='STORE_FAST', opcode=125, arg=1, argval='dodgy', argrepr='dodgy', offset=234, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=236, starts_line=26, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval='Never reach this', argrepr="'Never reach this'", offset=248, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=250, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=260, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=262, starts_line=25, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=264, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='JUMP_FORWARD', opcode=110, arg=14, argval=120, argrepr='to 120', offset=90, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='END_FOR', opcode=4, arg=None, argval=None, argrepr='', offset=92, starts_line=3, is_jump_target=True, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=94, starts_line=10, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=106, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=108, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=118, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST_CHECK', opcode=127, arg=0, argval='i', argrepr='i', offset=120, starts_line=11, is_jump_target=True, positions=None), + Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=35, argval=194, argrepr='to 194', offset=122, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=124, starts_line=12, is_jump_target=True, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=136, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=138, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=148, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=150, starts_line=13, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=152, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='BINARY_OP', opcode=122, arg=23, argval=23, argrepr='-=', offset=154, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=158, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=160, starts_line=14, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=162, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=164, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=1, argval=174, argrepr='to 174', offset=170, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='JUMP_BACKWARD', opcode=140, arg=27, argval=120, argrepr='to 120', offset=172, starts_line=15, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=174, starts_line=16, is_jump_target=True, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=176, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=178, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=1, argval=188, argrepr='to 188', offset=184, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='JUMP_FORWARD', opcode=110, arg=16, argval=220, argrepr='to 220', offset=186, starts_line=17, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=188, starts_line=11, is_jump_target=True, positions=None), + Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=1, argval=194, argrepr='to 194', offset=190, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='JUMP_BACKWARD', opcode=140, arg=35, argval=124, argrepr='to 124', offset=192, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=194, starts_line=19, is_jump_target=True, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval='Who let lolcatz into this test suite?', argrepr="'Who let lolcatz into this test suite?'", offset=206, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=208, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=218, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='NOP', opcode=9, arg=None, argval=None, argrepr='', offset=220, starts_line=20, is_jump_target=True, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=222, starts_line=21, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval=0, argrepr='0', offset=224, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='BINARY_OP', opcode=122, arg=11, argval=11, argrepr='/', offset=226, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=230, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=232, starts_line=25, is_jump_target=False, positions=None), + Instruction(opname='BEFORE_WITH', opcode=53, arg=None, argval=None, argrepr='', offset=234, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='STORE_FAST', opcode=125, arg=1, argval='dodgy', argrepr='dodgy', offset=236, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=238, starts_line=26, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval='Never reach this', argrepr="'Never reach this'", offset=250, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=252, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=262, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=264, starts_line=25, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=266, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=2, argval=2, argrepr='', offset=268, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=278, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=280, starts_line=28, is_jump_target=True, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=292, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=294, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=304, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=306, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=308, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=310, starts_line=25, is_jump_target=False, positions=None), - Instruction(opname='WITH_EXCEPT_START', opcode=49, arg=None, argval=None, argrepr='', offset=312, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=1, argval=318, argrepr='to 318', offset=314, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=2, argval=2, argrepr='', offset=316, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=318, starts_line=None, is_jump_target=True, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=320, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=322, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=268, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=2, argval=2, argrepr='', offset=270, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=280, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=282, starts_line=28, is_jump_target=True, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=294, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=296, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=306, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=308, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=310, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=312, starts_line=25, is_jump_target=False, positions=None), + Instruction(opname='WITH_EXCEPT_START', opcode=49, arg=None, argval=None, argrepr='', offset=314, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=1, argval=320, argrepr='to 320', offset=316, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=2, argval=2, argrepr='', offset=318, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=320, starts_line=None, is_jump_target=True, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=322, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=324, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_BACKWARD', opcode=140, arg=24, argval=280, argrepr='to 280', offset=326, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=328, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=330, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=332, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=334, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=4, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=336, starts_line=22, is_jump_target=False, positions=None), - Instruction(opname='CHECK_EXC_MATCH', opcode=36, arg=None, argval=None, argrepr='', offset=348, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=16, argval=384, argrepr='to 384', offset=350, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=352, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=354, starts_line=23, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=366, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=368, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=378, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=380, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_BACKWARD', opcode=140, arg=52, argval=280, argrepr='to 280', offset=382, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=384, starts_line=22, is_jump_target=True, positions=None), - Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=386, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=388, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=390, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=392, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=394, starts_line=28, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=406, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=408, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=418, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=420, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=422, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=424, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=426, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=326, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='JUMP_BACKWARD', opcode=140, arg=24, argval=282, argrepr='to 282', offset=328, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=330, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=332, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=334, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=336, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=4, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=338, starts_line=22, is_jump_target=False, positions=None), + Instruction(opname='CHECK_EXC_MATCH', opcode=36, arg=None, argval=None, argrepr='', offset=350, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=16, argval=386, argrepr='to 386', offset=352, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=354, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=356, starts_line=23, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=368, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=370, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=380, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=382, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='JUMP_BACKWARD', opcode=140, arg=52, argval=282, argrepr='to 282', offset=384, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=386, starts_line=22, is_jump_target=True, positions=None), + Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=388, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=390, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=392, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=394, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=396, starts_line=28, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=408, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=410, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=420, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=422, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=424, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=426, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=428, starts_line=None, is_jump_target=False, positions=None), ] # One last piece of inspect fodder to check the default line number handling diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-13-14-07-06.gh-issue-96793.7DLRSm.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-13-14-07-06.gh-issue-96793.7DLRSm.rst new file mode 100644 index 000000000000..dc03fab22365 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-09-13-14-07-06.gh-issue-96793.7DLRSm.rst @@ -0,0 +1,2 @@ +The :opcode:`FOR_ITER` now leaves the iterator on the stack on termination +of the loop. This is to assist specialization of loops for generators. diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 8b4494a5fe82..dd69207571b5 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -367,8 +367,8 @@ mark_stacks(PyCodeObject *code_obj, int len) break; case FOR_ITER: { - int64_t target_stack = pop_value(next_stack); - stacks[i+1] = push_value(next_stack, Object); + int64_t target_stack = push_value(next_stack, Object); + stacks[i+1] = target_stack; j = get_arg(code, i) + 1 + INLINE_CACHE_ENTRIES_FOR_ITER + i; assert(j < len); assert(stacks[j] == UNINITIALIZED || stacks[j] == target_stack); diff --git a/Programs/test_frozenmain.h b/Programs/test_frozenmain.h index 677ce180f95f..96be3ce3c25c 100644 --- a/Programs/test_frozenmain.h +++ b/Programs/test_frozenmain.h @@ -1,7 +1,7 @@ // Auto-generated by Programs/freeze_test_frozenmain.py unsigned char M_test_frozenmain[] = { 227,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, - 0,0,0,0,0,243,182,0,0,0,151,0,100,0,100,1, + 0,0,0,0,0,243,184,0,0,0,151,0,100,0,100,1, 108,0,90,0,100,0,100,1,108,1,90,1,2,0,101,2, 100,2,171,1,0,0,0,0,0,0,0,0,1,0,2,0, 101,2,100,3,101,0,106,6,0,0,0,0,0,0,0,0, @@ -12,31 +12,31 @@ unsigned char M_test_frozenmain[] = { 0,0,0,0,90,5,100,5,68,0,93,23,0,0,90,6, 2,0,101,2,100,6,101,6,155,0,100,7,101,5,101,6, 25,0,0,0,0,0,0,0,0,0,155,0,157,4,171,1, - 0,0,0,0,0,0,0,0,1,0,140,25,100,1,83,0, - 41,8,233,0,0,0,0,78,122,18,70,114,111,122,101,110, - 32,72,101,108,108,111,32,87,111,114,108,100,122,8,115,121, - 115,46,97,114,103,118,218,6,99,111,110,102,105,103,41,5, - 218,12,112,114,111,103,114,97,109,95,110,97,109,101,218,10, - 101,120,101,99,117,116,97,98,108,101,218,15,117,115,101,95, - 101,110,118,105,114,111,110,109,101,110,116,218,17,99,111,110, - 102,105,103,117,114,101,95,99,95,115,116,100,105,111,218,14, - 98,117,102,102,101,114,101,100,95,115,116,100,105,111,122,7, - 99,111,110,102,105,103,32,122,2,58,32,41,7,218,3,115, - 121,115,218,17,95,116,101,115,116,105,110,116,101,114,110,97, - 108,99,97,112,105,218,5,112,114,105,110,116,218,4,97,114, - 103,118,218,11,103,101,116,95,99,111,110,102,105,103,115,114, - 3,0,0,0,218,3,107,101,121,169,0,243,0,0,0,0, - 250,18,116,101,115,116,95,102,114,111,122,101,110,109,97,105, - 110,46,112,121,250,8,60,109,111,100,117,108,101,62,114,18, - 0,0,0,1,0,0,0,115,149,0,0,0,240,3,1,1, - 1,240,8,0,1,11,128,10,128,10,128,10,216,0,24,208, - 0,24,208,0,24,208,0,24,224,0,5,128,5,208,6,26, - 212,0,27,208,0,27,216,0,5,128,5,128,106,144,35,151, - 40,145,40,212,0,27,208,0,27,216,9,38,208,9,26,215, - 9,38,209,9,38,212,9,40,168,24,212,9,50,128,6,240, - 2,6,12,2,240,0,7,1,42,241,0,7,1,42,128,67, - 240,14,0,5,10,128,69,208,10,40,144,67,208,10,40,208, - 10,40,152,54,160,35,156,59,208,10,40,208,10,40,212,4, - 41,208,4,41,208,4,41,240,15,7,1,42,240,0,7,1, - 42,114,16,0,0,0, + 0,0,0,0,0,0,0,0,1,0,140,25,4,0,100,1, + 83,0,41,8,233,0,0,0,0,78,122,18,70,114,111,122, + 101,110,32,72,101,108,108,111,32,87,111,114,108,100,122,8, + 115,121,115,46,97,114,103,118,218,6,99,111,110,102,105,103, + 41,5,218,12,112,114,111,103,114,97,109,95,110,97,109,101, + 218,10,101,120,101,99,117,116,97,98,108,101,218,15,117,115, + 101,95,101,110,118,105,114,111,110,109,101,110,116,218,17,99, + 111,110,102,105,103,117,114,101,95,99,95,115,116,100,105,111, + 218,14,98,117,102,102,101,114,101,100,95,115,116,100,105,111, + 122,7,99,111,110,102,105,103,32,122,2,58,32,41,7,218, + 3,115,121,115,218,17,95,116,101,115,116,105,110,116,101,114, + 110,97,108,99,97,112,105,218,5,112,114,105,110,116,218,4, + 97,114,103,118,218,11,103,101,116,95,99,111,110,102,105,103, + 115,114,3,0,0,0,218,3,107,101,121,169,0,243,0,0, + 0,0,250,18,116,101,115,116,95,102,114,111,122,101,110,109, + 97,105,110,46,112,121,250,8,60,109,111,100,117,108,101,62, + 114,18,0,0,0,1,0,0,0,115,154,0,0,0,240,3, + 1,1,1,240,8,0,1,11,128,10,128,10,128,10,216,0, + 24,208,0,24,208,0,24,208,0,24,224,0,5,128,5,208, + 6,26,212,0,27,208,0,27,216,0,5,128,5,128,106,144, + 35,151,40,145,40,212,0,27,208,0,27,216,9,38,208,9, + 26,215,9,38,209,9,38,212,9,40,168,24,212,9,50,128, + 6,240,2,6,12,2,240,0,7,1,42,241,0,7,1,42, + 128,67,240,14,0,5,10,128,69,208,10,40,144,67,208,10, + 40,208,10,40,152,54,160,35,156,59,208,10,40,208,10,40, + 212,4,41,208,4,41,208,4,41,240,15,7,1,42,240,0, + 7,1,42,240,0,7,1,42,114,16,0,0,0, }; diff --git a/Python/ceval.c b/Python/ceval.c index 35ce767710e1..ac995d7c178d 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1298,6 +1298,14 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int DISPATCH(); } + TARGET(END_FOR) { + PyObject *value = POP(); + Py_DECREF(value); + value = POP(); + Py_DECREF(value); + DISPATCH(); + } + TARGET(UNARY_POSITIVE) { PyObject *value = TOP(); PyObject *res = PyNumber_Positive(value); @@ -3844,9 +3852,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int _PyErr_Clear(tstate); } /* iterator ended normally */ + assert(_Py_OPCODE(next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg] == END_FOR)); STACK_SHRINK(1); Py_DECREF(iter); - JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg); + /* Skip END_FOR */ + JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1); DISPATCH(); } @@ -3884,7 +3894,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int } STACK_SHRINK(1); Py_DECREF(it); - JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg); + JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1); DISPATCH(); } @@ -3898,7 +3908,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int if (r->index >= r->len) { STACK_SHRINK(1); Py_DECREF(r); - JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg); + JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1); DISPATCH(); } long value = (long)(r->start + diff --git a/Python/compile.c b/Python/compile.c index 67ccd2239381..779729119e2e 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1042,6 +1042,8 @@ stack_effect(int opcode, int oparg, int jump) return -1; case SWAP: return 0; + case END_FOR: + return -2; /* Unary operators */ case UNARY_POSITIVE: @@ -1098,8 +1100,7 @@ stack_effect(int opcode, int oparg, int jump) case UNPACK_EX: return (oparg&0xFF) + (oparg>>8); case FOR_ITER: - /* -1 at end of iterator, 1 if continue iterating. */ - return jump > 0 ? -1 : 1; + return 1; case SEND: return jump > 0 ? -1 : 0; case STORE_ATTR: @@ -3103,6 +3104,7 @@ compiler_for(struct compiler *c, stmt_ty s) ADDOP_JUMP(c, NO_LOCATION, JUMP, start); USE_LABEL(c, cleanup); + ADDOP(c, NO_LOCATION, END_FOR); compiler_pop_fblock(c, FOR_LOOP, start); @@ -5315,6 +5317,7 @@ compiler_sync_comprehension_generator(struct compiler *c, location loc, ADDOP_JUMP(c, elt_loc, JUMP, start); USE_LABEL(c, anchor); + ADDOP(c, NO_LOCATION, END_FOR); } return 1; diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index c1ff367d4fd3..53b2770607b4 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -3,18 +3,19 @@ static void *opcode_targets[256] = { &&TARGET_POP_TOP, &&TARGET_PUSH_NULL, &&TARGET_BINARY_OP_ADAPTIVE, + &&TARGET_END_FOR, &&TARGET_BINARY_OP_ADD_FLOAT, &&TARGET_BINARY_OP_ADD_INT, &&TARGET_BINARY_OP_ADD_UNICODE, &&TARGET_BINARY_OP_INPLACE_ADD_UNICODE, - &&TARGET_BINARY_OP_MULTIPLY_FLOAT, &&TARGET_NOP, &&TARGET_UNARY_POSITIVE, &&TARGET_UNARY_NEGATIVE, &&TARGET_UNARY_NOT, + &&TARGET_BINARY_OP_MULTIPLY_FLOAT, &&TARGET_BINARY_OP_MULTIPLY_INT, - &&TARGET_BINARY_OP_SUBTRACT_FLOAT, &&TARGET_UNARY_INVERT, + &&TARGET_BINARY_OP_SUBTRACT_FLOAT, &&TARGET_BINARY_OP_SUBTRACT_INT, &&TARGET_BINARY_SUBSCR_ADAPTIVE, &&TARGET_BINARY_SUBSCR_DICT, @@ -23,20 +24,20 @@ static void *opcode_targets[256] = { &&TARGET_BINARY_SUBSCR_TUPLE_INT, &&TARGET_CALL_ADAPTIVE, &&TARGET_CALL_PY_EXACT_ARGS, - &&TARGET_CALL_PY_WITH_DEFAULTS, &&TARGET_BINARY_SUBSCR, &&TARGET_BINARY_SLICE, &&TARGET_STORE_SLICE, + &&TARGET_CALL_PY_WITH_DEFAULTS, &&TARGET_CALL_BOUND_METHOD_EXACT_ARGS, - &&TARGET_CALL_BUILTIN_CLASS, &&TARGET_GET_LEN, &&TARGET_MATCH_MAPPING, &&TARGET_MATCH_SEQUENCE, &&TARGET_MATCH_KEYS, - &&TARGET_CALL_BUILTIN_FAST_WITH_KEYWORDS, + &&TARGET_CALL_BUILTIN_CLASS, &&TARGET_PUSH_EXC_INFO, &&TARGET_CHECK_EXC_MATCH, &&TARGET_CHECK_EG_MATCH, + &&TARGET_CALL_BUILTIN_FAST_WITH_KEYWORDS, &&TARGET_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, &&TARGET_CALL_NO_KW_BUILTIN_FAST, &&TARGET_CALL_NO_KW_BUILTIN_O, @@ -47,7 +48,6 @@ static void *opcode_targets[256] = { &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS, &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_O, &&TARGET_CALL_NO_KW_STR_1, - &&TARGET_CALL_NO_KW_TUPLE_1, &&TARGET_WITH_EXCEPT_START, &&TARGET_GET_AITER, &&TARGET_GET_ANEXT, @@ -55,37 +55,37 @@ static void *opcode_targets[256] = { &&TARGET_BEFORE_WITH, &&TARGET_END_ASYNC_FOR, &&TARGET_CLEANUP_THROW, + &&TARGET_CALL_NO_KW_TUPLE_1, &&TARGET_CALL_NO_KW_TYPE_1, &&TARGET_COMPARE_OP_ADAPTIVE, &&TARGET_COMPARE_OP_FLOAT_JUMP, - &&TARGET_COMPARE_OP_INT_JUMP, &&TARGET_STORE_SUBSCR, &&TARGET_DELETE_SUBSCR, + &&TARGET_COMPARE_OP_INT_JUMP, &&TARGET_COMPARE_OP_STR_JUMP, &&TARGET_EXTENDED_ARG_QUICK, &&TARGET_FOR_ITER_ADAPTIVE, &&TARGET_FOR_ITER_LIST, &&TARGET_FOR_ITER_RANGE, - &&TARGET_JUMP_BACKWARD_QUICK, &&TARGET_GET_ITER, &&TARGET_GET_YIELD_FROM_ITER, &&TARGET_PRINT_EXPR, &&TARGET_LOAD_BUILD_CLASS, + &&TARGET_JUMP_BACKWARD_QUICK, &&TARGET_LOAD_ATTR_ADAPTIVE, - &&TARGET_LOAD_ATTR_CLASS, &&TARGET_LOAD_ASSERTION_ERROR, &&TARGET_RETURN_GENERATOR, + &&TARGET_LOAD_ATTR_CLASS, &&TARGET_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, &&TARGET_LOAD_ATTR_INSTANCE_VALUE, &&TARGET_LOAD_ATTR_MODULE, &&TARGET_LOAD_ATTR_PROPERTY, &&TARGET_LOAD_ATTR_SLOT, - &&TARGET_LOAD_ATTR_WITH_HINT, &&TARGET_LIST_TO_TUPLE, &&TARGET_RETURN_VALUE, &&TARGET_IMPORT_STAR, &&TARGET_SETUP_ANNOTATIONS, - &&TARGET_LOAD_ATTR_METHOD_LAZY_DICT, + &&TARGET_LOAD_ATTR_WITH_HINT, &&TARGET_ASYNC_GEN_WRAP, &&TARGET_PREP_RERAISE_STAR, &&TARGET_POP_EXCEPT, @@ -112,7 +112,7 @@ static void *opcode_targets[256] = { &&TARGET_JUMP_FORWARD, &&TARGET_JUMP_IF_FALSE_OR_POP, &&TARGET_JUMP_IF_TRUE_OR_POP, - &&TARGET_LOAD_ATTR_METHOD_NO_DICT, + &&TARGET_LOAD_ATTR_METHOD_LAZY_DICT, &&TARGET_POP_JUMP_IF_FALSE, &&TARGET_POP_JUMP_IF_TRUE, &&TARGET_LOAD_GLOBAL, @@ -120,7 +120,7 @@ static void *opcode_targets[256] = { &&TARGET_CONTAINS_OP, &&TARGET_RERAISE, &&TARGET_COPY, - &&TARGET_LOAD_ATTR_METHOD_WITH_DICT, + &&TARGET_LOAD_ATTR_METHOD_NO_DICT, &&TARGET_BINARY_OP, &&TARGET_SEND, &&TARGET_LOAD_FAST, @@ -140,9 +140,9 @@ static void *opcode_targets[256] = { &&TARGET_STORE_DEREF, &&TARGET_DELETE_DEREF, &&TARGET_JUMP_BACKWARD, - &&TARGET_LOAD_ATTR_METHOD_WITH_VALUES, + &&TARGET_LOAD_ATTR_METHOD_WITH_DICT, &&TARGET_CALL_FUNCTION_EX, - &&TARGET_LOAD_CONST__LOAD_FAST, + &&TARGET_LOAD_ATTR_METHOD_WITH_VALUES, &&TARGET_EXTENDED_ARG, &&TARGET_LIST_APPEND, &&TARGET_SET_ADD, @@ -152,26 +152,27 @@ static void *opcode_targets[256] = { &&TARGET_YIELD_VALUE, &&TARGET_RESUME, &&TARGET_MATCH_CLASS, + &&TARGET_LOAD_CONST__LOAD_FAST, &&TARGET_LOAD_FAST__LOAD_CONST, - &&TARGET_LOAD_FAST__LOAD_FAST, &&TARGET_FORMAT_VALUE, &&TARGET_BUILD_CONST_KEY_MAP, &&TARGET_BUILD_STRING, + &&TARGET_LOAD_FAST__LOAD_FAST, &&TARGET_LOAD_GLOBAL_ADAPTIVE, &&TARGET_LOAD_GLOBAL_BUILTIN, &&TARGET_LOAD_GLOBAL_MODULE, - &&TARGET_RESUME_QUICK, &&TARGET_LIST_EXTEND, &&TARGET_SET_UPDATE, &&TARGET_DICT_MERGE, &&TARGET_DICT_UPDATE, + &&TARGET_RESUME_QUICK, &&TARGET_STORE_ATTR_ADAPTIVE, &&TARGET_STORE_ATTR_INSTANCE_VALUE, &&TARGET_STORE_ATTR_SLOT, &&TARGET_STORE_ATTR_WITH_HINT, - &&TARGET_STORE_FAST__LOAD_FAST, &&TARGET_CALL, &&TARGET_KW_NAMES, + &&TARGET_STORE_FAST__LOAD_FAST, &&TARGET_STORE_FAST__STORE_FAST, &&TARGET_STORE_SUBSCR_ADAPTIVE, &&TARGET_STORE_SUBSCR_DICT, @@ -253,6 +254,5 @@ static void *opcode_targets[256] = { &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, - &&_unknown_opcode, &&TARGET_DO_TRACING }; diff --git a/Python/specialize.c b/Python/specialize.c index b7c321e4878b..6e2fa4e25fa4 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -2208,12 +2208,8 @@ _Py_Specialize_ForIter(PyObject *iter, _Py_CODEUNIT *instr) _Py_SET_OPCODE(*instr, FOR_ITER_RANGE); goto success; } - else { - SPECIALIZATION_FAIL(FOR_ITER, - _PySpecialization_ClassifyIterator(iter)); - goto failure; - } -failure: + SPECIALIZATION_FAIL(FOR_ITER, + _PySpecialization_ClassifyIterator(iter)); STAT_INC(FOR_ITER, failure); cache->counter = adaptive_counter_backoff(cache->counter); return; From webhook-mailer at python.org Thu Oct 27 09:06:54 2022 From: webhook-mailer at python.org (pablogsal) Date: Thu, 27 Oct 2022 13:06:54 -0000 Subject: [Python-checkins] gh-96143: Improve perf profiler docs (#96445) Message-ID: https://github.com/python/cpython/commit/723ebe76e787cfa6b08cc9587dd679f3234a1025 commit: 723ebe76e787cfa6b08cc9587dd679f3234a1025 branch: main author: Erlend E. Aasland committer: pablogsal date: 2022-10-27T14:06:48+01:00 summary: gh-96143: Improve perf profiler docs (#96445) files: M Doc/howto/perf_profiling.rst M Doc/library/sys.rst M Doc/using/cmdline.rst M Doc/whatsnew/3.12.rst M Python/clinic/sysmodule.c.h M Python/sysmodule.c diff --git a/Doc/howto/perf_profiling.rst b/Doc/howto/perf_profiling.rst index 387fb3ff8935..ad2eb7b4d58a 100644 --- a/Doc/howto/perf_profiling.rst +++ b/Doc/howto/perf_profiling.rst @@ -8,10 +8,11 @@ Python support for the Linux ``perf`` profiler :author: Pablo Galindo -The Linux ``perf`` profiler is a very powerful tool that allows you to profile and -obtain information about the performance of your application. ``perf`` also has -a very vibrant ecosystem of tools that aid with the analysis of the data that it -produces. +`The Linux perf profiler `_ +is a very powerful tool that allows you to profile and obtain +information about the performance of your application. +``perf`` also has a very vibrant ecosystem of tools +that aid with the analysis of the data that it produces. The main problem with using the ``perf`` profiler with Python applications is that ``perf`` only allows to get information about native symbols, this is, the names of @@ -25,7 +26,7 @@ fly before the execution of every Python function and it will teach ``perf`` the relationship between this piece of code and the associated Python function using `perf map files`_. -.. warning:: +.. note:: Support for the ``perf`` profiler is only currently available for Linux on selected architectures. Check the output of the configure build step or @@ -51,11 +52,11 @@ For example, consider the following script: if __name__ == "__main__": baz(1000000) -We can run perf to sample CPU stack traces at 9999 Hertz: +We can run ``perf`` to sample CPU stack traces at 9999 Hertz:: $ perf record -F 9999 -g -o perf.data python my_script.py -Then we can use perf report to analyze the data: +Then we can use ``perf`` report to analyze the data: .. code-block:: shell-session @@ -101,7 +102,7 @@ As you can see here, the Python functions are not shown in the output, only ``_P functions use the same C function to evaluate bytecode so we cannot know which Python function corresponds to which bytecode-evaluating function. -Instead, if we run the same experiment with perf support activated we get: +Instead, if we run the same experiment with ``perf`` support enabled we get: .. code-block:: shell-session @@ -147,52 +148,58 @@ Instead, if we run the same experiment with perf support activated we get: -Enabling perf profiling mode ----------------------------- +How to enable ``perf`` profiling support +---------------------------------------- -There are two main ways to activate the perf profiling mode. If you want it to be -active since the start of the Python interpreter, you can use the ``-Xperf`` option: +``perf`` profiling support can either be enabled from the start using +the environment variable :envvar:`PYTHONPERFSUPPORT` or the +:option:`-X perf <-X>` option, +or dynamically using :func:`sys.activate_stack_trampoline` and +:func:`sys.deactivate_stack_trampoline`. - $ python -Xperf my_script.py +The :mod:`!sys` functions take precedence over the :option:`!-X` option, +the :option:`!-X` option takes precedence over the environment variable. -You can also set the :envvar:`PYTHONPERFSUPPORT` to a nonzero value to actiavate perf -profiling mode globally. +Example, using the environment variable:: -There is also support for dynamically activating and deactivating the perf -profiling mode by using the APIs in the :mod:`sys` module: + $ PYTHONPERFSUPPORT=1 + $ python script.py + $ perf report -g -i perf.data -.. code-block:: python - - import sys - sys.activate_stack_trampoline("perf") +Example, using the :option:`!-X` option:: - # Run some code with Perf profiling active + $ python -X perf script.py + $ perf report -g -i perf.data - sys.deactivate_stack_trampoline() +Example, using the :mod:`sys` APIs in file :file:`example.py`: - # Perf profiling is not active anymore +.. code-block:: python -These APIs can be handy if you want to activate/deactivate profiling mode in -response to a signal or other communication mechanism with your process. + import sys + sys.activate_stack_trampoline("perf") + do_profiled_stuff() + sys.deactivate_stack_trampoline() + non_profiled_stuff() -Now we can analyze the data with ``perf report``: +...then:: - $ perf report -g -i perf.data + $ python ./example.py + $ perf report -g -i perf.data How to obtain the best results -------------------------------- +------------------------------ For the best results, Python should be compiled with ``CFLAGS="-fno-omit-frame-pointer -mno-omit-leaf-frame-pointer"`` as this allows profilers to unwind using only the frame pointer and not on DWARF debug -information. This is because as the code that is interposed to allow perf +information. This is because as the code that is interposed to allow ``perf`` support is dynamically generated it doesn't have any DWARF debugging information available. -You can check if you system has been compiled with this flag by running: +You can check if your system has been compiled with this flag by running:: $ python -m sysconfig | grep 'no-omit-frame-pointer' diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 542b08b1878e..17bbfa50a2ed 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -1555,6 +1555,38 @@ always available. This function has been added on a provisional basis (see :pep:`411` for details.) Use it only for debugging purposes. +.. function:: activate_stack_trampoline(backend, /) + + Activate the stack profiler trampoline *backend*. + The only supported backend is ``"perf"``. + + .. availability:: Linux. + + .. versionadded:: 3.12 + + .. seealso:: + + * :ref:`perf_profiling` + * https://perf.wiki.kernel.org + +.. function:: deactivate_stack_trampoline() + + Deactivate the current stack profiler trampoline backend. + + If no stack profiler is activated, this function has no effect. + + .. availability:: Linux. + + .. versionadded:: 3.12 + +.. function:: is_stack_trampoline_active() + + Return ``True`` if a stack profiler trampoline is active. + + .. availability:: Linux. + + .. versionadded:: 3.12 + .. function:: _enablelegacywindowsfsencoding() Changes the :term:`filesystem encoding and error handler` to 'mbcs' and diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst index 02c9f3095b40..2a4d070ec057 100644 --- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -538,12 +538,11 @@ Miscellaneous options development (running from the source tree) then the default is "off". Note that the "importlib_bootstrap" and "importlib_bootstrap_external" frozen modules are always used, even if this flag is set to "off". - * ``-X perf`` to activate compatibility mode with the ``perf`` profiler. - When this option is activated, the Linux ``perf`` profiler will be able to + * ``-X perf`` enables support for the Linux ``perf`` profiler. + When this option is provided, the ``perf`` profiler will be able to report Python calls. This option is only available on some platforms and will do nothing if is not supported on the current system. The default value - is "off". See also :envvar:`PYTHONPERFSUPPORT` and :ref:`perf_profiling` - for more information. + is "off". See also :envvar:`PYTHONPERFSUPPORT` and :ref:`perf_profiling`. It also allows passing arbitrary values and retrieving them through the :data:`sys._xoptions` dictionary. @@ -1048,9 +1047,13 @@ conflict. .. envvar:: PYTHONPERFSUPPORT - If this variable is set to a nonzero value, it activates compatibility mode - with the ``perf`` profiler so Python calls can be detected by it. See the - :ref:`perf_profiling` section for more information. + If this variable is set to a nonzero value, it enables support for + the Linux ``perf`` profiler so Python calls can be detected by it. + + If set to ``0``, disable Linux ``perf`` profiler support. + + See also the :option:`-X perf <-X>` command-line option + and :ref:`perf_profiling`. .. versionadded:: 3.12 diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 8f8a99461510..39ad3ac7118b 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -74,6 +74,15 @@ Important deprecations, removals or restrictions: New Features ============ +* Add :ref:`perf_profiling` through the new + environment variable :envvar:`PYTHONPERFSUPPORT`, + the new command-line option :option:`-X perf <-X>`, + as well as the new :func:`sys.activate_stack_trampoline`, + :func:`sys.deactivate_stack_trampoline`, + and :func:`sys.is_stack_trampoline_active` APIs. + (Design by Pablo Galindo. Contributed by Pablo Galindo and Christian Heimes + with contributions from Gregory P. Smith [Google] and Mark Shannon + in :gh:`96123`.) Other Language Changes @@ -194,6 +203,19 @@ tempfile The :class:`tempfile.NamedTemporaryFile` function has a new optional parameter *delete_on_close* (Contributed by Evgeny Zorin in :gh:`58451`.) +sys +--- + +* Add :func:`sys.activate_stack_trampoline` and + :func:`sys.deactivate_stack_trampoline` for activating and deactivating + stack profiler trampolines, + and :func:`sys.is_stack_trampoline_active` for querying if stack profiler + trampolines are active. + (Contributed by Pablo Galindo and Christian Heimes + with contributions from Gregory P. Smith [Google] and Mark Shannon + in :gh:`96123`.) + + Optimizations ============= diff --git a/Python/clinic/sysmodule.c.h b/Python/clinic/sysmodule.c.h index 6864b8b0e03b..3dc7aa8118a5 100644 --- a/Python/clinic/sysmodule.c.h +++ b/Python/clinic/sysmodule.c.h @@ -1231,7 +1231,7 @@ PyDoc_STRVAR(sys_activate_stack_trampoline__doc__, "activate_stack_trampoline($module, backend, /)\n" "--\n" "\n" -"Activate the perf profiler trampoline."); +"Activate stack profiler trampoline *backend*."); #define SYS_ACTIVATE_STACK_TRAMPOLINE_METHODDEF \ {"activate_stack_trampoline", (PyCFunction)sys_activate_stack_trampoline, METH_O, sys_activate_stack_trampoline__doc__}, @@ -1268,7 +1268,9 @@ PyDoc_STRVAR(sys_deactivate_stack_trampoline__doc__, "deactivate_stack_trampoline($module, /)\n" "--\n" "\n" -"Dectivate the perf profiler trampoline."); +"Deactivate the current stack profiler trampoline backend.\n" +"\n" +"If no stack profiler is activated, this function has no effect."); #define SYS_DEACTIVATE_STACK_TRAMPOLINE_METHODDEF \ {"deactivate_stack_trampoline", (PyCFunction)sys_deactivate_stack_trampoline, METH_NOARGS, sys_deactivate_stack_trampoline__doc__}, @@ -1286,7 +1288,7 @@ PyDoc_STRVAR(sys_is_stack_trampoline_active__doc__, "is_stack_trampoline_active($module, /)\n" "--\n" "\n" -"Returns *True* if the perf profiler trampoline is active."); +"Return *True* if a stack profiler trampoline is active."); #define SYS_IS_STACK_TRAMPOLINE_ACTIVE_METHODDEF \ {"is_stack_trampoline_active", (PyCFunction)sys_is_stack_trampoline_active, METH_NOARGS, sys_is_stack_trampoline_active__doc__}, @@ -1343,4 +1345,4 @@ sys_is_stack_trampoline_active(PyObject *module, PyObject *Py_UNUSED(ignored)) #ifndef SYS_GETANDROIDAPILEVEL_METHODDEF #define SYS_GETANDROIDAPILEVEL_METHODDEF #endif /* !defined(SYS_GETANDROIDAPILEVEL_METHODDEF) */ -/*[clinic end generated code: output=15318cdd96b62b06 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=2b5e1bc24a3348bd input=a9049054013a1b77]*/ diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 708145651812..f73d332796c9 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -2127,12 +2127,12 @@ sys.activate_stack_trampoline backend: str / -Activate the perf profiler trampoline. +Activate stack profiler trampoline *backend*. [clinic start generated code]*/ static PyObject * sys_activate_stack_trampoline_impl(PyObject *module, const char *backend) -/*[clinic end generated code: output=5783cdeb51874b43 input=b09020e3a17c78c5]*/ +/*[clinic end generated code: output=5783cdeb51874b43 input=a12df928758a82b4]*/ { #ifdef PY_HAVE_PERF_TRAMPOLINE if (strcmp(backend, "perf") == 0) { @@ -2163,12 +2163,14 @@ sys_activate_stack_trampoline_impl(PyObject *module, const char *backend) /*[clinic input] sys.deactivate_stack_trampoline -Dectivate the perf profiler trampoline. +Deactivate the current stack profiler trampoline backend. + +If no stack profiler is activated, this function has no effect. [clinic start generated code]*/ static PyObject * sys_deactivate_stack_trampoline_impl(PyObject *module) -/*[clinic end generated code: output=b50da25465df0ef1 input=491f4fc1ed615736]*/ +/*[clinic end generated code: output=b50da25465df0ef1 input=9f629a6be9fe7fc8]*/ { if (_PyPerfTrampoline_Init(0) < 0) { return NULL; @@ -2179,12 +2181,12 @@ sys_deactivate_stack_trampoline_impl(PyObject *module) /*[clinic input] sys.is_stack_trampoline_active -Returns *True* if the perf profiler trampoline is active. +Return *True* if a stack profiler trampoline is active. [clinic start generated code]*/ static PyObject * sys_is_stack_trampoline_active_impl(PyObject *module) -/*[clinic end generated code: output=ab2746de0ad9d293 input=061fa5776ac9dd59]*/ +/*[clinic end generated code: output=ab2746de0ad9d293 input=29616b7bf6a0b703]*/ { #ifdef PY_HAVE_PERF_TRAMPOLINE if (_PyIsPerfTrampolineActive()) { From webhook-mailer at python.org Thu Oct 27 12:06:55 2022 From: webhook-mailer at python.org (benjaminp) Date: Thu, 27 Oct 2022 16:06:55 -0000 Subject: [Python-checkins] obmalloc: Remove unused variable. (GH-98770) Message-ID: https://github.com/python/cpython/commit/bded5edd9abf7ae6b2874916d70ec29ad209217c commit: bded5edd9abf7ae6b2874916d70ec29ad209217c branch: main author: Benjamin Peterson committer: benjaminp date: 2022-10-27T09:06:49-07:00 summary: obmalloc: Remove unused variable. (GH-98770) files: M Objects/obmalloc.c diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c index 1d487d8e807a..449b618a0e76 100644 --- a/Objects/obmalloc.c +++ b/Objects/obmalloc.c @@ -3000,7 +3000,6 @@ _PyObject_DebugMallocStats(FILE *out) * will be living in full pools -- would be a shame to miss them. */ for (i = 0; i < maxarenas; ++i) { - uint j; uintptr_t base = arenas[i].address; /* Skip arenas which are not allocated. */ @@ -3019,8 +3018,7 @@ _PyObject_DebugMallocStats(FILE *out) /* visit every pool in the arena */ assert(base <= (uintptr_t) arenas[i].pool_address); - for (j = 0; base < (uintptr_t) arenas[i].pool_address; - ++j, base += POOL_SIZE) { + for (; base < (uintptr_t) arenas[i].pool_address; base += POOL_SIZE) { poolp p = (poolp)base; const uint sz = p->szidx; uint freeblocks; From webhook-mailer at python.org Thu Oct 27 12:31:23 2022 From: webhook-mailer at python.org (miss-islington) Date: Thu, 27 Oct 2022 16:31:23 -0000 Subject: [Python-checkins] obmalloc: Remove unused variable. (GH-98770) Message-ID: https://github.com/python/cpython/commit/cfbc01fe48517c4cc15e4ad6f8cf08d273307ca9 commit: cfbc01fe48517c4cc15e4ad6f8cf08d273307ca9 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-27T09:30:46-07:00 summary: obmalloc: Remove unused variable. (GH-98770) (cherry picked from commit bded5edd9abf7ae6b2874916d70ec29ad209217c) Co-authored-by: Benjamin Peterson files: M Objects/obmalloc.c diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c index ce5da5f1b7b9..fae9c8110f19 100644 --- a/Objects/obmalloc.c +++ b/Objects/obmalloc.c @@ -2999,7 +2999,6 @@ _PyObject_DebugMallocStats(FILE *out) * will be living in full pools -- would be a shame to miss them. */ for (i = 0; i < maxarenas; ++i) { - uint j; uintptr_t base = arenas[i].address; /* Skip arenas which are not allocated. */ @@ -3018,8 +3017,7 @@ _PyObject_DebugMallocStats(FILE *out) /* visit every pool in the arena */ assert(base <= (uintptr_t) arenas[i].pool_address); - for (j = 0; base < (uintptr_t) arenas[i].pool_address; - ++j, base += POOL_SIZE) { + for (; base < (uintptr_t) arenas[i].pool_address; base += POOL_SIZE) { poolp p = (poolp)base; const uint sz = p->szidx; uint freeblocks; From webhook-mailer at python.org Thu Oct 27 12:33:50 2022 From: webhook-mailer at python.org (miss-islington) Date: Thu, 27 Oct 2022 16:33:50 -0000 Subject: [Python-checkins] obmalloc: Remove unused variable. (GH-98770) Message-ID: https://github.com/python/cpython/commit/6a1d165c4ccaffaf0872830f763c17f6d9437adf commit: 6a1d165c4ccaffaf0872830f763c17f6d9437adf branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-27T09:33:44-07:00 summary: obmalloc: Remove unused variable. (GH-98770) (cherry picked from commit bded5edd9abf7ae6b2874916d70ec29ad209217c) Co-authored-by: Benjamin Peterson files: M Objects/obmalloc.c diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c index ed8dd5a5042d..224206b932c1 100644 --- a/Objects/obmalloc.c +++ b/Objects/obmalloc.c @@ -2962,7 +2962,6 @@ _PyObject_DebugMallocStats(FILE *out) * will be living in full pools -- would be a shame to miss them. */ for (i = 0; i < maxarenas; ++i) { - uint j; uintptr_t base = arenas[i].address; /* Skip arenas which are not allocated. */ @@ -2981,8 +2980,7 @@ _PyObject_DebugMallocStats(FILE *out) /* visit every pool in the arena */ assert(base <= (uintptr_t) arenas[i].pool_address); - for (j = 0; base < (uintptr_t) arenas[i].pool_address; - ++j, base += POOL_SIZE) { + for (; base < (uintptr_t) arenas[i].pool_address; base += POOL_SIZE) { poolp p = (poolp)base; const uint sz = p->szidx; uint freeblocks; From webhook-mailer at python.org Thu Oct 27 16:45:41 2022 From: webhook-mailer at python.org (gpshead) Date: Thu, 27 Oct 2022 20:45:41 -0000 Subject: [Python-checkins] gh-98739: Update libexpat from 2.4.9 to 2.5.0 (#98742) Message-ID: https://github.com/python/cpython/commit/3e07f827b359617664ad0880f218f17ae4483299 commit: 3e07f827b359617664ad0880f218f17ae4483299 branch: main author: Shaun Walbridge <46331011+scdub at users.noreply.github.com> committer: gpshead date: 2022-10-27T13:45:12-07:00 summary: gh-98739: Update libexpat from 2.4.9 to 2.5.0 (#98742) * Update libexpat from 2.4.9 to 2.5.0 to address CVE-2022-43680. Co-authored-by: Shaun Walbridge files: A Misc/NEWS.d/next/Security/2022-10-26-21-04-23.gh-issue-98739.keBWcY.rst M Modules/expat/expat.h M Modules/expat/xmlparse.c M Modules/expat/xmltok_impl.h diff --git a/Misc/NEWS.d/next/Security/2022-10-26-21-04-23.gh-issue-98739.keBWcY.rst b/Misc/NEWS.d/next/Security/2022-10-26-21-04-23.gh-issue-98739.keBWcY.rst new file mode 100644 index 000000000000..b63a54b3676c --- /dev/null +++ b/Misc/NEWS.d/next/Security/2022-10-26-21-04-23.gh-issue-98739.keBWcY.rst @@ -0,0 +1 @@ +Update bundled libexpat to 2.5.0 diff --git a/Modules/expat/expat.h b/Modules/expat/expat.h index 2b47ce2a8d3a..1c83563cbf68 100644 --- a/Modules/expat/expat.h +++ b/Modules/expat/expat.h @@ -1054,8 +1054,8 @@ XML_SetBillionLaughsAttackProtectionActivationThreshold( See http://semver.org. */ #define XML_MAJOR_VERSION 2 -#define XML_MINOR_VERSION 4 -#define XML_MICRO_VERSION 9 +#define XML_MINOR_VERSION 5 +#define XML_MICRO_VERSION 0 #ifdef __cplusplus } diff --git a/Modules/expat/xmlparse.c b/Modules/expat/xmlparse.c index c0bece51d700..b6c2eca97567 100644 --- a/Modules/expat/xmlparse.c +++ b/Modules/expat/xmlparse.c @@ -1,4 +1,4 @@ -/* 90815a2b2c80c03b2b889fe1d427bb2b9e3282aa065e42784e001db4f23de324 (2.4.9+) +/* 5ab094ffadd6edfc94c3eee53af44a86951f9f1f0933ada3114bbce2bfb02c99 (2.5.0+) __ __ _ ___\ \/ /_ __ __ _| |_ / _ \\ /| '_ \ / _` | __| @@ -35,6 +35,7 @@ Copyright (c) 2021 Dong-hee Na Copyright (c) 2022 Samanta Navarro Copyright (c) 2022 Jeffrey Walton + Copyright (c) 2022 Jann Horn Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -1068,6 +1069,14 @@ parserCreate(const XML_Char *encodingName, parserInit(parser, encodingName); if (encodingName && ! parser->m_protocolEncodingName) { + if (dtd) { + // We need to stop the upcoming call to XML_ParserFree from happily + // destroying parser->m_dtd because the DTD is shared with the parent + // parser and the only guard that keeps XML_ParserFree from destroying + // parser->m_dtd is parser->m_isParamEntity but it will be set to + // XML_TRUE only later in XML_ExternalEntityParserCreate (or not at all). + parser->m_dtd = NULL; + } XML_ParserFree(parser); return NULL; } @@ -3011,9 +3020,6 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, int len; const char *rawName; TAG *tag = parser->m_tagStack; - parser->m_tagStack = tag->parent; - tag->parent = parser->m_freeTagList; - parser->m_freeTagList = tag; rawName = s + enc->minBytesPerChar * 2; len = XmlNameLength(enc, rawName); if (len != tag->rawNameLength @@ -3021,6 +3027,9 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, *eventPP = rawName; return XML_ERROR_TAG_MISMATCH; } + parser->m_tagStack = tag->parent; + tag->parent = parser->m_freeTagList; + parser->m_freeTagList = tag; --parser->m_tagLevel; if (parser->m_endElementHandler) { const XML_Char *localPart; @@ -4975,10 +4984,10 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, parser->m_handlerArg, parser->m_declElementType->name, parser->m_declAttributeId->name, parser->m_declAttributeType, 0, role == XML_ROLE_REQUIRED_ATTRIBUTE_VALUE); - poolClear(&parser->m_tempPool); handleDefault = XML_FALSE; } } + poolClear(&parser->m_tempPool); break; case XML_ROLE_DEFAULT_ATTRIBUTE_VALUE: case XML_ROLE_FIXED_ATTRIBUTE_VALUE: @@ -5386,7 +5395,7 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, * * If 'standalone' is false, the DTD must have no * parameter entities or we wouldn't have passed the outer - * 'if' statement. That measn the only entity in the hash + * 'if' statement. That means the only entity in the hash * table is the external subset name "#" which cannot be * given as a parameter entity name in XML syntax, so the * lookup must have returned NULL and we don't even reach @@ -5798,19 +5807,27 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end, if (result != XML_ERROR_NONE) return result; - else if (textEnd != next - && parser->m_parsingStatus.parsing == XML_SUSPENDED) { + + if (textEnd != next && parser->m_parsingStatus.parsing == XML_SUSPENDED) { entity->processed = (int)(next - (const char *)entity->textPtr); return result; - } else { + } + #ifdef XML_DTD - entityTrackingOnClose(parser, entity, __LINE__); + entityTrackingOnClose(parser, entity, __LINE__); #endif - entity->open = XML_FALSE; - parser->m_openInternalEntities = openEntity->next; - /* put openEntity back in list of free instances */ - openEntity->next = parser->m_freeInternalEntities; - parser->m_freeInternalEntities = openEntity; + entity->open = XML_FALSE; + parser->m_openInternalEntities = openEntity->next; + /* put openEntity back in list of free instances */ + openEntity->next = parser->m_freeInternalEntities; + parser->m_freeInternalEntities = openEntity; + + // If there are more open entities we want to stop right here and have the + // upcoming call to XML_ResumeParser continue with entity content, or it would + // be ignored altogether. + if (parser->m_openInternalEntities != NULL + && parser->m_parsingStatus.parsing == XML_SUSPENDED) { + return XML_ERROR_NONE; } #ifdef XML_DTD diff --git a/Modules/expat/xmltok_impl.h b/Modules/expat/xmltok_impl.h index c518aada013d..3469c4ae138c 100644 --- a/Modules/expat/xmltok_impl.h +++ b/Modules/expat/xmltok_impl.h @@ -45,7 +45,7 @@ enum { BT_LF, /* line feed = "\n" */ BT_GT, /* greater than = ">" */ BT_QUOT, /* quotation character = "\"" */ - BT_APOS, /* aposthrophe = "'" */ + BT_APOS, /* apostrophe = "'" */ BT_EQUALS, /* equal sign = "=" */ BT_QUEST, /* question mark = "?" */ BT_EXCL, /* exclamation mark = "!" */ From webhook-mailer at python.org Thu Oct 27 17:21:44 2022 From: webhook-mailer at python.org (miss-islington) Date: Thu, 27 Oct 2022 21:21:44 -0000 Subject: [Python-checkins] gh-98739: Update libexpat from 2.4.9 to 2.5.0 (GH-98742) Message-ID: https://github.com/python/cpython/commit/c5f3f296f4c9ec5a294dedc805be69929fe169cc commit: c5f3f296f4c9ec5a294dedc805be69929fe169cc branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-27T14:21:35-07:00 summary: gh-98739: Update libexpat from 2.4.9 to 2.5.0 (GH-98742) * Update libexpat from 2.4.9 to 2.5.0 to address CVE-2022-43680. Co-authored-by: Shaun Walbridge (cherry picked from commit 3e07f827b359617664ad0880f218f17ae4483299) Co-authored-by: Shaun Walbridge <46331011+scdub at users.noreply.github.com> files: A Misc/NEWS.d/next/Security/2022-10-26-21-04-23.gh-issue-98739.keBWcY.rst M Modules/expat/expat.h M Modules/expat/xmlparse.c M Modules/expat/xmltok_impl.h diff --git a/Misc/NEWS.d/next/Security/2022-10-26-21-04-23.gh-issue-98739.keBWcY.rst b/Misc/NEWS.d/next/Security/2022-10-26-21-04-23.gh-issue-98739.keBWcY.rst new file mode 100644 index 000000000000..b63a54b3676c --- /dev/null +++ b/Misc/NEWS.d/next/Security/2022-10-26-21-04-23.gh-issue-98739.keBWcY.rst @@ -0,0 +1 @@ +Update bundled libexpat to 2.5.0 diff --git a/Modules/expat/expat.h b/Modules/expat/expat.h index 2b47ce2a8d3a..1c83563cbf68 100644 --- a/Modules/expat/expat.h +++ b/Modules/expat/expat.h @@ -1054,8 +1054,8 @@ XML_SetBillionLaughsAttackProtectionActivationThreshold( See http://semver.org. */ #define XML_MAJOR_VERSION 2 -#define XML_MINOR_VERSION 4 -#define XML_MICRO_VERSION 9 +#define XML_MINOR_VERSION 5 +#define XML_MICRO_VERSION 0 #ifdef __cplusplus } diff --git a/Modules/expat/xmlparse.c b/Modules/expat/xmlparse.c index c0bece51d700..b6c2eca97567 100644 --- a/Modules/expat/xmlparse.c +++ b/Modules/expat/xmlparse.c @@ -1,4 +1,4 @@ -/* 90815a2b2c80c03b2b889fe1d427bb2b9e3282aa065e42784e001db4f23de324 (2.4.9+) +/* 5ab094ffadd6edfc94c3eee53af44a86951f9f1f0933ada3114bbce2bfb02c99 (2.5.0+) __ __ _ ___\ \/ /_ __ __ _| |_ / _ \\ /| '_ \ / _` | __| @@ -35,6 +35,7 @@ Copyright (c) 2021 Dong-hee Na Copyright (c) 2022 Samanta Navarro Copyright (c) 2022 Jeffrey Walton + Copyright (c) 2022 Jann Horn Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -1068,6 +1069,14 @@ parserCreate(const XML_Char *encodingName, parserInit(parser, encodingName); if (encodingName && ! parser->m_protocolEncodingName) { + if (dtd) { + // We need to stop the upcoming call to XML_ParserFree from happily + // destroying parser->m_dtd because the DTD is shared with the parent + // parser and the only guard that keeps XML_ParserFree from destroying + // parser->m_dtd is parser->m_isParamEntity but it will be set to + // XML_TRUE only later in XML_ExternalEntityParserCreate (or not at all). + parser->m_dtd = NULL; + } XML_ParserFree(parser); return NULL; } @@ -3011,9 +3020,6 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, int len; const char *rawName; TAG *tag = parser->m_tagStack; - parser->m_tagStack = tag->parent; - tag->parent = parser->m_freeTagList; - parser->m_freeTagList = tag; rawName = s + enc->minBytesPerChar * 2; len = XmlNameLength(enc, rawName); if (len != tag->rawNameLength @@ -3021,6 +3027,9 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, *eventPP = rawName; return XML_ERROR_TAG_MISMATCH; } + parser->m_tagStack = tag->parent; + tag->parent = parser->m_freeTagList; + parser->m_freeTagList = tag; --parser->m_tagLevel; if (parser->m_endElementHandler) { const XML_Char *localPart; @@ -4975,10 +4984,10 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, parser->m_handlerArg, parser->m_declElementType->name, parser->m_declAttributeId->name, parser->m_declAttributeType, 0, role == XML_ROLE_REQUIRED_ATTRIBUTE_VALUE); - poolClear(&parser->m_tempPool); handleDefault = XML_FALSE; } } + poolClear(&parser->m_tempPool); break; case XML_ROLE_DEFAULT_ATTRIBUTE_VALUE: case XML_ROLE_FIXED_ATTRIBUTE_VALUE: @@ -5386,7 +5395,7 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, * * If 'standalone' is false, the DTD must have no * parameter entities or we wouldn't have passed the outer - * 'if' statement. That measn the only entity in the hash + * 'if' statement. That means the only entity in the hash * table is the external subset name "#" which cannot be * given as a parameter entity name in XML syntax, so the * lookup must have returned NULL and we don't even reach @@ -5798,19 +5807,27 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end, if (result != XML_ERROR_NONE) return result; - else if (textEnd != next - && parser->m_parsingStatus.parsing == XML_SUSPENDED) { + + if (textEnd != next && parser->m_parsingStatus.parsing == XML_SUSPENDED) { entity->processed = (int)(next - (const char *)entity->textPtr); return result; - } else { + } + #ifdef XML_DTD - entityTrackingOnClose(parser, entity, __LINE__); + entityTrackingOnClose(parser, entity, __LINE__); #endif - entity->open = XML_FALSE; - parser->m_openInternalEntities = openEntity->next; - /* put openEntity back in list of free instances */ - openEntity->next = parser->m_freeInternalEntities; - parser->m_freeInternalEntities = openEntity; + entity->open = XML_FALSE; + parser->m_openInternalEntities = openEntity->next; + /* put openEntity back in list of free instances */ + openEntity->next = parser->m_freeInternalEntities; + parser->m_freeInternalEntities = openEntity; + + // If there are more open entities we want to stop right here and have the + // upcoming call to XML_ResumeParser continue with entity content, or it would + // be ignored altogether. + if (parser->m_openInternalEntities != NULL + && parser->m_parsingStatus.parsing == XML_SUSPENDED) { + return XML_ERROR_NONE; } #ifdef XML_DTD diff --git a/Modules/expat/xmltok_impl.h b/Modules/expat/xmltok_impl.h index c518aada013d..3469c4ae138c 100644 --- a/Modules/expat/xmltok_impl.h +++ b/Modules/expat/xmltok_impl.h @@ -45,7 +45,7 @@ enum { BT_LF, /* line feed = "\n" */ BT_GT, /* greater than = ">" */ BT_QUOT, /* quotation character = "\"" */ - BT_APOS, /* aposthrophe = "'" */ + BT_APOS, /* apostrophe = "'" */ BT_EQUALS, /* equal sign = "=" */ BT_QUEST, /* question mark = "?" */ BT_EXCL, /* exclamation mark = "!" */ From webhook-mailer at python.org Thu Oct 27 17:22:23 2022 From: webhook-mailer at python.org (miss-islington) Date: Thu, 27 Oct 2022 21:22:23 -0000 Subject: [Python-checkins] gh-98739: Update libexpat from 2.4.9 to 2.5.0 (GH-98742) Message-ID: https://github.com/python/cpython/commit/e77af8211008aae2b5b529a04edb28a11ace2ef8 commit: e77af8211008aae2b5b529a04edb28a11ace2ef8 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-27T14:22:18-07:00 summary: gh-98739: Update libexpat from 2.4.9 to 2.5.0 (GH-98742) * Update libexpat from 2.4.9 to 2.5.0 to address CVE-2022-43680. Co-authored-by: Shaun Walbridge (cherry picked from commit 3e07f827b359617664ad0880f218f17ae4483299) Co-authored-by: Shaun Walbridge <46331011+scdub at users.noreply.github.com> files: A Misc/NEWS.d/next/Security/2022-10-26-21-04-23.gh-issue-98739.keBWcY.rst M Modules/expat/expat.h M Modules/expat/xmlparse.c M Modules/expat/xmltok_impl.h diff --git a/Misc/NEWS.d/next/Security/2022-10-26-21-04-23.gh-issue-98739.keBWcY.rst b/Misc/NEWS.d/next/Security/2022-10-26-21-04-23.gh-issue-98739.keBWcY.rst new file mode 100644 index 000000000000..b63a54b3676c --- /dev/null +++ b/Misc/NEWS.d/next/Security/2022-10-26-21-04-23.gh-issue-98739.keBWcY.rst @@ -0,0 +1 @@ +Update bundled libexpat to 2.5.0 diff --git a/Modules/expat/expat.h b/Modules/expat/expat.h index 2b47ce2a8d3a..1c83563cbf68 100644 --- a/Modules/expat/expat.h +++ b/Modules/expat/expat.h @@ -1054,8 +1054,8 @@ XML_SetBillionLaughsAttackProtectionActivationThreshold( See http://semver.org. */ #define XML_MAJOR_VERSION 2 -#define XML_MINOR_VERSION 4 -#define XML_MICRO_VERSION 9 +#define XML_MINOR_VERSION 5 +#define XML_MICRO_VERSION 0 #ifdef __cplusplus } diff --git a/Modules/expat/xmlparse.c b/Modules/expat/xmlparse.c index c0bece51d700..b6c2eca97567 100644 --- a/Modules/expat/xmlparse.c +++ b/Modules/expat/xmlparse.c @@ -1,4 +1,4 @@ -/* 90815a2b2c80c03b2b889fe1d427bb2b9e3282aa065e42784e001db4f23de324 (2.4.9+) +/* 5ab094ffadd6edfc94c3eee53af44a86951f9f1f0933ada3114bbce2bfb02c99 (2.5.0+) __ __ _ ___\ \/ /_ __ __ _| |_ / _ \\ /| '_ \ / _` | __| @@ -35,6 +35,7 @@ Copyright (c) 2021 Dong-hee Na Copyright (c) 2022 Samanta Navarro Copyright (c) 2022 Jeffrey Walton + Copyright (c) 2022 Jann Horn Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -1068,6 +1069,14 @@ parserCreate(const XML_Char *encodingName, parserInit(parser, encodingName); if (encodingName && ! parser->m_protocolEncodingName) { + if (dtd) { + // We need to stop the upcoming call to XML_ParserFree from happily + // destroying parser->m_dtd because the DTD is shared with the parent + // parser and the only guard that keeps XML_ParserFree from destroying + // parser->m_dtd is parser->m_isParamEntity but it will be set to + // XML_TRUE only later in XML_ExternalEntityParserCreate (or not at all). + parser->m_dtd = NULL; + } XML_ParserFree(parser); return NULL; } @@ -3011,9 +3020,6 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, int len; const char *rawName; TAG *tag = parser->m_tagStack; - parser->m_tagStack = tag->parent; - tag->parent = parser->m_freeTagList; - parser->m_freeTagList = tag; rawName = s + enc->minBytesPerChar * 2; len = XmlNameLength(enc, rawName); if (len != tag->rawNameLength @@ -3021,6 +3027,9 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, *eventPP = rawName; return XML_ERROR_TAG_MISMATCH; } + parser->m_tagStack = tag->parent; + tag->parent = parser->m_freeTagList; + parser->m_freeTagList = tag; --parser->m_tagLevel; if (parser->m_endElementHandler) { const XML_Char *localPart; @@ -4975,10 +4984,10 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, parser->m_handlerArg, parser->m_declElementType->name, parser->m_declAttributeId->name, parser->m_declAttributeType, 0, role == XML_ROLE_REQUIRED_ATTRIBUTE_VALUE); - poolClear(&parser->m_tempPool); handleDefault = XML_FALSE; } } + poolClear(&parser->m_tempPool); break; case XML_ROLE_DEFAULT_ATTRIBUTE_VALUE: case XML_ROLE_FIXED_ATTRIBUTE_VALUE: @@ -5386,7 +5395,7 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, * * If 'standalone' is false, the DTD must have no * parameter entities or we wouldn't have passed the outer - * 'if' statement. That measn the only entity in the hash + * 'if' statement. That means the only entity in the hash * table is the external subset name "#" which cannot be * given as a parameter entity name in XML syntax, so the * lookup must have returned NULL and we don't even reach @@ -5798,19 +5807,27 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end, if (result != XML_ERROR_NONE) return result; - else if (textEnd != next - && parser->m_parsingStatus.parsing == XML_SUSPENDED) { + + if (textEnd != next && parser->m_parsingStatus.parsing == XML_SUSPENDED) { entity->processed = (int)(next - (const char *)entity->textPtr); return result; - } else { + } + #ifdef XML_DTD - entityTrackingOnClose(parser, entity, __LINE__); + entityTrackingOnClose(parser, entity, __LINE__); #endif - entity->open = XML_FALSE; - parser->m_openInternalEntities = openEntity->next; - /* put openEntity back in list of free instances */ - openEntity->next = parser->m_freeInternalEntities; - parser->m_freeInternalEntities = openEntity; + entity->open = XML_FALSE; + parser->m_openInternalEntities = openEntity->next; + /* put openEntity back in list of free instances */ + openEntity->next = parser->m_freeInternalEntities; + parser->m_freeInternalEntities = openEntity; + + // If there are more open entities we want to stop right here and have the + // upcoming call to XML_ResumeParser continue with entity content, or it would + // be ignored altogether. + if (parser->m_openInternalEntities != NULL + && parser->m_parsingStatus.parsing == XML_SUSPENDED) { + return XML_ERROR_NONE; } #ifdef XML_DTD diff --git a/Modules/expat/xmltok_impl.h b/Modules/expat/xmltok_impl.h index c518aada013d..3469c4ae138c 100644 --- a/Modules/expat/xmltok_impl.h +++ b/Modules/expat/xmltok_impl.h @@ -45,7 +45,7 @@ enum { BT_LF, /* line feed = "\n" */ BT_GT, /* greater than = ">" */ BT_QUOT, /* quotation character = "\"" */ - BT_APOS, /* aposthrophe = "'" */ + BT_APOS, /* apostrophe = "'" */ BT_EQUALS, /* equal sign = "=" */ BT_QUEST, /* question mark = "?" */ BT_EXCL, /* exclamation mark = "!" */ From webhook-mailer at python.org Fri Oct 28 02:43:22 2022 From: webhook-mailer at python.org (Fidget-Spinner) Date: Fri, 28 Oct 2022 06:43:22 -0000 Subject: [Python-checkins] gh-98789: Fix FOR_ITER assert on big-endian (GH-98792) Message-ID: https://github.com/python/cpython/commit/fbcafa6eeeb106c8d9e9bb4c3b44e34e070f79c9 commit: fbcafa6eeeb106c8d9e9bb4c3b44e34e070f79c9 branch: main author: Dennis Sweeney <36520290+sweeneyde at users.noreply.github.com> committer: Fidget-Spinner date: 2022-10-28T14:42:39+08:00 summary: gh-98789: Fix FOR_ITER assert on big-endian (GH-98792) Fix FOR_ITER assertion syntax files: M Python/ceval.c diff --git a/Python/ceval.c b/Python/ceval.c index ac995d7c178d..24af419d29c5 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -3852,7 +3852,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int _PyErr_Clear(tstate); } /* iterator ended normally */ - assert(_Py_OPCODE(next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg] == END_FOR)); + assert(_Py_OPCODE(next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg]) == END_FOR); STACK_SHRINK(1); Py_DECREF(iter); /* Skip END_FOR */ From webhook-mailer at python.org Fri Oct 28 03:51:49 2022 From: webhook-mailer at python.org (cjw296) Date: Fri, 28 Oct 2022 07:51:49 -0000 Subject: [Python-checkins] gh-98624 Add mutex to unittest.mock.NonCallableMock (#98688) Message-ID: https://github.com/python/cpython/commit/0346eddbe933b5f1f56151bdebf5bd49392bc275 commit: 0346eddbe933b5f1f56151bdebf5bd49392bc275 branch: main author: noah-weingarden <33741795+noah-weingarden at users.noreply.github.com> committer: cjw296 date: 2022-10-28T08:51:18+01:00 summary: gh-98624 Add mutex to unittest.mock.NonCallableMock (#98688) * Added lock to NonCallableMock in unittest.mock * Add blurb * Nitpick blurb * Edit comment based on @Jason-Y-Z's review * Add link to GH issue files: A Misc/NEWS.d/next/Library/2022-10-25-20-17-34.gh-issue-98624.YQUPFy.rst M Lib/unittest/mock.py diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py index cd46fea5162a..b8f4e57f0b49 100644 --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -35,6 +35,7 @@ from types import CodeType, ModuleType, MethodType from unittest.util import safe_repr from functools import wraps, partial +from threading import RLock class InvalidSpecError(Exception): @@ -402,6 +403,14 @@ def __init__(self, /, *args, **kwargs): class NonCallableMock(Base): """A non-callable version of `Mock`""" + # Store a mutex as a class attribute in order to protect concurrent access + # to mock attributes. Using a class attribute allows all NonCallableMock + # instances to share the mutex for simplicity. + # + # See https://github.com/python/cpython/issues/98624 for why this is + # necessary. + _lock = RLock() + def __new__(cls, /, *args, **kw): # every instance has its own class # so we can create magic methods on the @@ -644,35 +653,36 @@ def __getattr__(self, name): f"{name!r} is not a valid assertion. Use a spec " f"for the mock if {name!r} is meant to be an attribute.") - result = self._mock_children.get(name) - if result is _deleted: - raise AttributeError(name) - elif result is None: - wraps = None - if self._mock_wraps is not None: - # XXXX should we get the attribute without triggering code - # execution? - wraps = getattr(self._mock_wraps, name) - - result = self._get_child_mock( - parent=self, name=name, wraps=wraps, _new_name=name, - _new_parent=self - ) - self._mock_children[name] = result - - elif isinstance(result, _SpecState): - try: - result = create_autospec( - result.spec, result.spec_set, result.instance, - result.parent, result.name + with NonCallableMock._lock: + result = self._mock_children.get(name) + if result is _deleted: + raise AttributeError(name) + elif result is None: + wraps = None + if self._mock_wraps is not None: + # XXXX should we get the attribute without triggering code + # execution? + wraps = getattr(self._mock_wraps, name) + + result = self._get_child_mock( + parent=self, name=name, wraps=wraps, _new_name=name, + _new_parent=self ) - except InvalidSpecError: - target_name = self.__dict__['_mock_name'] or self - raise InvalidSpecError( - f'Cannot autospec attr {name!r} from target ' - f'{target_name!r} as it has already been mocked out. ' - f'[target={self!r}, attr={result.spec!r}]') - self._mock_children[name] = result + self._mock_children[name] = result + + elif isinstance(result, _SpecState): + try: + result = create_autospec( + result.spec, result.spec_set, result.instance, + result.parent, result.name + ) + except InvalidSpecError: + target_name = self.__dict__['_mock_name'] or self + raise InvalidSpecError( + f'Cannot autospec attr {name!r} from target ' + f'{target_name!r} as it has already been mocked out. ' + f'[target={self!r}, attr={result.spec!r}]') + self._mock_children[name] = result return result diff --git a/Misc/NEWS.d/next/Library/2022-10-25-20-17-34.gh-issue-98624.YQUPFy.rst b/Misc/NEWS.d/next/Library/2022-10-25-20-17-34.gh-issue-98624.YQUPFy.rst new file mode 100644 index 000000000000..fb3a2b837fc3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-25-20-17-34.gh-issue-98624.YQUPFy.rst @@ -0,0 +1,2 @@ +Add a mutex to unittest.mock.NonCallableMock to protect concurrent access +to mock attributes. From webhook-mailer at python.org Fri Oct 28 05:13:10 2022 From: webhook-mailer at python.org (zooba) Date: Fri, 28 Oct 2022 09:13:10 -0000 Subject: [Python-checkins] gh-98745: Allow py.exe launcher to install 3.11 by default and 3.12 on request (GH-98780) Message-ID: https://github.com/python/cpython/commit/25811d9010510d24bbe35acca9da86b064f239c0 commit: 25811d9010510d24bbe35acca9da86b064f239c0 branch: main author: Steve Dower committer: zooba date: 2022-10-28T10:12:22+01:00 summary: gh-98745: Allow py.exe launcher to install 3.11 by default and 3.12 on request (GH-98780) files: A Misc/NEWS.d/next/Windows/2022-10-27-20-30-16.gh-issue-98745.v06p4r.rst M PC/launcher2.c diff --git a/Misc/NEWS.d/next/Windows/2022-10-27-20-30-16.gh-issue-98745.v06p4r.rst b/Misc/NEWS.d/next/Windows/2022-10-27-20-30-16.gh-issue-98745.v06p4r.rst new file mode 100644 index 000000000000..caf73db280f3 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2022-10-27-20-30-16.gh-issue-98745.v06p4r.rst @@ -0,0 +1 @@ +Update :file:`py.exe` launcher to install 3.11 by default and 3.12 on request. diff --git a/PC/launcher2.c b/PC/launcher2.c index 1f6f97b82092..b1ad5f066ede 100644 --- a/PC/launcher2.c +++ b/PC/launcher2.c @@ -1673,6 +1673,7 @@ struct AppxSearchInfo { struct AppxSearchInfo APPX_SEARCH[] = { // Releases made through the Store + { L"PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0", L"3.12", 10 }, { L"PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0", L"3.11", 10 }, { L"PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0", L"3.10", 10 }, { L"PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0", L"3.9", 10 }, @@ -1681,6 +1682,7 @@ struct AppxSearchInfo APPX_SEARCH[] = { // Side-loadable releases. Note that the publisher ID changes whenever we // renew our code-signing certificate, so the newer ID has a higher // priority (lower sortKey) + { L"PythonSoftwareFoundation.Python.3.12_3847v3x7pw1km", L"3.12", 11 }, { L"PythonSoftwareFoundation.Python.3.11_3847v3x7pw1km", L"3.11", 11 }, { L"PythonSoftwareFoundation.Python.3.11_hd69rhyc2wevp", L"3.11", 12 }, { L"PythonSoftwareFoundation.Python.3.10_3847v3x7pw1km", L"3.10", 11 }, @@ -1755,7 +1757,8 @@ struct StoreSearchInfo { struct StoreSearchInfo STORE_SEARCH[] = { - { L"3", /* 3.10 */ L"9PJPW5LDXLZ5" }, + { L"3", /* 3.11 */ L"9NRWMJP3717K" }, + { L"3.12", L"9NCVDN91XZQP" }, { L"3.11", L"9NRWMJP3717K" }, { L"3.10", L"9PJPW5LDXLZ5" }, { L"3.9", L"9P7QFQMJRFP7" }, From webhook-mailer at python.org Fri Oct 28 05:40:09 2022 From: webhook-mailer at python.org (miss-islington) Date: Fri, 28 Oct 2022 09:40:09 -0000 Subject: [Python-checkins] gh-98745: Allow py.exe launcher to install 3.11 by default and 3.12 on request (GH-98780) Message-ID: https://github.com/python/cpython/commit/9f01a2793ad1bb6e5b9b36b4d0eee3d44f617430 commit: 9f01a2793ad1bb6e5b9b36b4d0eee3d44f617430 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-28T02:40:00-07:00 summary: gh-98745: Allow py.exe launcher to install 3.11 by default and 3.12 on request (GH-98780) (cherry picked from commit 25811d9010510d24bbe35acca9da86b064f239c0) Co-authored-by: Steve Dower files: A Misc/NEWS.d/next/Windows/2022-10-27-20-30-16.gh-issue-98745.v06p4r.rst M PC/launcher2.c diff --git a/Misc/NEWS.d/next/Windows/2022-10-27-20-30-16.gh-issue-98745.v06p4r.rst b/Misc/NEWS.d/next/Windows/2022-10-27-20-30-16.gh-issue-98745.v06p4r.rst new file mode 100644 index 000000000000..caf73db280f3 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2022-10-27-20-30-16.gh-issue-98745.v06p4r.rst @@ -0,0 +1 @@ +Update :file:`py.exe` launcher to install 3.11 by default and 3.12 on request. diff --git a/PC/launcher2.c b/PC/launcher2.c index 1f6f97b82092..b1ad5f066ede 100644 --- a/PC/launcher2.c +++ b/PC/launcher2.c @@ -1673,6 +1673,7 @@ struct AppxSearchInfo { struct AppxSearchInfo APPX_SEARCH[] = { // Releases made through the Store + { L"PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0", L"3.12", 10 }, { L"PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0", L"3.11", 10 }, { L"PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0", L"3.10", 10 }, { L"PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0", L"3.9", 10 }, @@ -1681,6 +1682,7 @@ struct AppxSearchInfo APPX_SEARCH[] = { // Side-loadable releases. Note that the publisher ID changes whenever we // renew our code-signing certificate, so the newer ID has a higher // priority (lower sortKey) + { L"PythonSoftwareFoundation.Python.3.12_3847v3x7pw1km", L"3.12", 11 }, { L"PythonSoftwareFoundation.Python.3.11_3847v3x7pw1km", L"3.11", 11 }, { L"PythonSoftwareFoundation.Python.3.11_hd69rhyc2wevp", L"3.11", 12 }, { L"PythonSoftwareFoundation.Python.3.10_3847v3x7pw1km", L"3.10", 11 }, @@ -1755,7 +1757,8 @@ struct StoreSearchInfo { struct StoreSearchInfo STORE_SEARCH[] = { - { L"3", /* 3.10 */ L"9PJPW5LDXLZ5" }, + { L"3", /* 3.11 */ L"9NRWMJP3717K" }, + { L"3.12", L"9NCVDN91XZQP" }, { L"3.11", L"9NRWMJP3717K" }, { L"3.10", L"9PJPW5LDXLZ5" }, { L"3.9", L"9P7QFQMJRFP7" }, From webhook-mailer at python.org Fri Oct 28 06:07:13 2022 From: webhook-mailer at python.org (ambv) Date: Fri, 28 Oct 2022 10:07:13 -0000 Subject: [Python-checkins] [3.7] gh-98739: Update libexpat from 2.4.9 to 2.5.0 (GH-98742) (#98788) Message-ID: https://github.com/python/cpython/commit/64e95f2bab5f3e0aff8cce486daf980e99c31e82 commit: 64e95f2bab5f3e0aff8cce486daf980e99c31e82 branch: 3.7 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-28T12:06:50+02:00 summary: [3.7] gh-98739: Update libexpat from 2.4.9 to 2.5.0 (GH-98742) (#98788) Update libexpat from 2.4.9 to 2.5.0 to address CVE-2022-43680. Co-authored-by: Shaun Walbridge (cherry picked from commit 3e07f827b359617664ad0880f218f17ae4483299) files: A Misc/NEWS.d/next/Security/2022-10-26-21-04-23.gh-issue-98739.keBWcY.rst M Modules/expat/expat.h M Modules/expat/xmlparse.c M Modules/expat/xmltok_impl.h diff --git a/Misc/NEWS.d/next/Security/2022-10-26-21-04-23.gh-issue-98739.keBWcY.rst b/Misc/NEWS.d/next/Security/2022-10-26-21-04-23.gh-issue-98739.keBWcY.rst new file mode 100644 index 000000000000..b63a54b3676c --- /dev/null +++ b/Misc/NEWS.d/next/Security/2022-10-26-21-04-23.gh-issue-98739.keBWcY.rst @@ -0,0 +1 @@ +Update bundled libexpat to 2.5.0 diff --git a/Modules/expat/expat.h b/Modules/expat/expat.h index 2b47ce2a8d3a..1c83563cbf68 100644 --- a/Modules/expat/expat.h +++ b/Modules/expat/expat.h @@ -1054,8 +1054,8 @@ XML_SetBillionLaughsAttackProtectionActivationThreshold( See http://semver.org. */ #define XML_MAJOR_VERSION 2 -#define XML_MINOR_VERSION 4 -#define XML_MICRO_VERSION 9 +#define XML_MINOR_VERSION 5 +#define XML_MICRO_VERSION 0 #ifdef __cplusplus } diff --git a/Modules/expat/xmlparse.c b/Modules/expat/xmlparse.c index c0bece51d700..b6c2eca97567 100644 --- a/Modules/expat/xmlparse.c +++ b/Modules/expat/xmlparse.c @@ -1,4 +1,4 @@ -/* 90815a2b2c80c03b2b889fe1d427bb2b9e3282aa065e42784e001db4f23de324 (2.4.9+) +/* 5ab094ffadd6edfc94c3eee53af44a86951f9f1f0933ada3114bbce2bfb02c99 (2.5.0+) __ __ _ ___\ \/ /_ __ __ _| |_ / _ \\ /| '_ \ / _` | __| @@ -35,6 +35,7 @@ Copyright (c) 2021 Dong-hee Na Copyright (c) 2022 Samanta Navarro Copyright (c) 2022 Jeffrey Walton + Copyright (c) 2022 Jann Horn Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -1068,6 +1069,14 @@ parserCreate(const XML_Char *encodingName, parserInit(parser, encodingName); if (encodingName && ! parser->m_protocolEncodingName) { + if (dtd) { + // We need to stop the upcoming call to XML_ParserFree from happily + // destroying parser->m_dtd because the DTD is shared with the parent + // parser and the only guard that keeps XML_ParserFree from destroying + // parser->m_dtd is parser->m_isParamEntity but it will be set to + // XML_TRUE only later in XML_ExternalEntityParserCreate (or not at all). + parser->m_dtd = NULL; + } XML_ParserFree(parser); return NULL; } @@ -3011,9 +3020,6 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, int len; const char *rawName; TAG *tag = parser->m_tagStack; - parser->m_tagStack = tag->parent; - tag->parent = parser->m_freeTagList; - parser->m_freeTagList = tag; rawName = s + enc->minBytesPerChar * 2; len = XmlNameLength(enc, rawName); if (len != tag->rawNameLength @@ -3021,6 +3027,9 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, *eventPP = rawName; return XML_ERROR_TAG_MISMATCH; } + parser->m_tagStack = tag->parent; + tag->parent = parser->m_freeTagList; + parser->m_freeTagList = tag; --parser->m_tagLevel; if (parser->m_endElementHandler) { const XML_Char *localPart; @@ -4975,10 +4984,10 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, parser->m_handlerArg, parser->m_declElementType->name, parser->m_declAttributeId->name, parser->m_declAttributeType, 0, role == XML_ROLE_REQUIRED_ATTRIBUTE_VALUE); - poolClear(&parser->m_tempPool); handleDefault = XML_FALSE; } } + poolClear(&parser->m_tempPool); break; case XML_ROLE_DEFAULT_ATTRIBUTE_VALUE: case XML_ROLE_FIXED_ATTRIBUTE_VALUE: @@ -5386,7 +5395,7 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, * * If 'standalone' is false, the DTD must have no * parameter entities or we wouldn't have passed the outer - * 'if' statement. That measn the only entity in the hash + * 'if' statement. That means the only entity in the hash * table is the external subset name "#" which cannot be * given as a parameter entity name in XML syntax, so the * lookup must have returned NULL and we don't even reach @@ -5798,19 +5807,27 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end, if (result != XML_ERROR_NONE) return result; - else if (textEnd != next - && parser->m_parsingStatus.parsing == XML_SUSPENDED) { + + if (textEnd != next && parser->m_parsingStatus.parsing == XML_SUSPENDED) { entity->processed = (int)(next - (const char *)entity->textPtr); return result; - } else { + } + #ifdef XML_DTD - entityTrackingOnClose(parser, entity, __LINE__); + entityTrackingOnClose(parser, entity, __LINE__); #endif - entity->open = XML_FALSE; - parser->m_openInternalEntities = openEntity->next; - /* put openEntity back in list of free instances */ - openEntity->next = parser->m_freeInternalEntities; - parser->m_freeInternalEntities = openEntity; + entity->open = XML_FALSE; + parser->m_openInternalEntities = openEntity->next; + /* put openEntity back in list of free instances */ + openEntity->next = parser->m_freeInternalEntities; + parser->m_freeInternalEntities = openEntity; + + // If there are more open entities we want to stop right here and have the + // upcoming call to XML_ResumeParser continue with entity content, or it would + // be ignored altogether. + if (parser->m_openInternalEntities != NULL + && parser->m_parsingStatus.parsing == XML_SUSPENDED) { + return XML_ERROR_NONE; } #ifdef XML_DTD diff --git a/Modules/expat/xmltok_impl.h b/Modules/expat/xmltok_impl.h index c518aada013d..3469c4ae138c 100644 --- a/Modules/expat/xmltok_impl.h +++ b/Modules/expat/xmltok_impl.h @@ -45,7 +45,7 @@ enum { BT_LF, /* line feed = "\n" */ BT_GT, /* greater than = ">" */ BT_QUOT, /* quotation character = "\"" */ - BT_APOS, /* aposthrophe = "'" */ + BT_APOS, /* apostrophe = "'" */ BT_EQUALS, /* equal sign = "=" */ BT_QUEST, /* question mark = "?" */ BT_EXCL, /* exclamation mark = "!" */ From webhook-mailer at python.org Fri Oct 28 06:07:20 2022 From: webhook-mailer at python.org (ambv) Date: Fri, 28 Oct 2022 10:07:20 -0000 Subject: [Python-checkins] [3.8] gh-98739: Update libexpat from 2.4.9 to 2.5.0 (GH-98742) (#98787) Message-ID: https://github.com/python/cpython/commit/0037d46378a64dce664ea1dded34141ecdd330e0 commit: 0037d46378a64dce664ea1dded34141ecdd330e0 branch: 3.8 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-28T12:07:14+02:00 summary: [3.8] gh-98739: Update libexpat from 2.4.9 to 2.5.0 (GH-98742) (#98787) Update libexpat from 2.4.9 to 2.5.0 to address CVE-2022-43680. Co-authored-by: Shaun Walbridge (cherry picked from commit 3e07f827b359617664ad0880f218f17ae4483299) files: A Misc/NEWS.d/next/Security/2022-10-26-21-04-23.gh-issue-98739.keBWcY.rst M Modules/expat/expat.h M Modules/expat/xmlparse.c M Modules/expat/xmltok_impl.h diff --git a/Misc/NEWS.d/next/Security/2022-10-26-21-04-23.gh-issue-98739.keBWcY.rst b/Misc/NEWS.d/next/Security/2022-10-26-21-04-23.gh-issue-98739.keBWcY.rst new file mode 100644 index 000000000000..b63a54b3676c --- /dev/null +++ b/Misc/NEWS.d/next/Security/2022-10-26-21-04-23.gh-issue-98739.keBWcY.rst @@ -0,0 +1 @@ +Update bundled libexpat to 2.5.0 diff --git a/Modules/expat/expat.h b/Modules/expat/expat.h index 2b47ce2a8d3a..1c83563cbf68 100644 --- a/Modules/expat/expat.h +++ b/Modules/expat/expat.h @@ -1054,8 +1054,8 @@ XML_SetBillionLaughsAttackProtectionActivationThreshold( See http://semver.org. */ #define XML_MAJOR_VERSION 2 -#define XML_MINOR_VERSION 4 -#define XML_MICRO_VERSION 9 +#define XML_MINOR_VERSION 5 +#define XML_MICRO_VERSION 0 #ifdef __cplusplus } diff --git a/Modules/expat/xmlparse.c b/Modules/expat/xmlparse.c index c0bece51d700..b6c2eca97567 100644 --- a/Modules/expat/xmlparse.c +++ b/Modules/expat/xmlparse.c @@ -1,4 +1,4 @@ -/* 90815a2b2c80c03b2b889fe1d427bb2b9e3282aa065e42784e001db4f23de324 (2.4.9+) +/* 5ab094ffadd6edfc94c3eee53af44a86951f9f1f0933ada3114bbce2bfb02c99 (2.5.0+) __ __ _ ___\ \/ /_ __ __ _| |_ / _ \\ /| '_ \ / _` | __| @@ -35,6 +35,7 @@ Copyright (c) 2021 Dong-hee Na Copyright (c) 2022 Samanta Navarro Copyright (c) 2022 Jeffrey Walton + Copyright (c) 2022 Jann Horn Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -1068,6 +1069,14 @@ parserCreate(const XML_Char *encodingName, parserInit(parser, encodingName); if (encodingName && ! parser->m_protocolEncodingName) { + if (dtd) { + // We need to stop the upcoming call to XML_ParserFree from happily + // destroying parser->m_dtd because the DTD is shared with the parent + // parser and the only guard that keeps XML_ParserFree from destroying + // parser->m_dtd is parser->m_isParamEntity but it will be set to + // XML_TRUE only later in XML_ExternalEntityParserCreate (or not at all). + parser->m_dtd = NULL; + } XML_ParserFree(parser); return NULL; } @@ -3011,9 +3020,6 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, int len; const char *rawName; TAG *tag = parser->m_tagStack; - parser->m_tagStack = tag->parent; - tag->parent = parser->m_freeTagList; - parser->m_freeTagList = tag; rawName = s + enc->minBytesPerChar * 2; len = XmlNameLength(enc, rawName); if (len != tag->rawNameLength @@ -3021,6 +3027,9 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, *eventPP = rawName; return XML_ERROR_TAG_MISMATCH; } + parser->m_tagStack = tag->parent; + tag->parent = parser->m_freeTagList; + parser->m_freeTagList = tag; --parser->m_tagLevel; if (parser->m_endElementHandler) { const XML_Char *localPart; @@ -4975,10 +4984,10 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, parser->m_handlerArg, parser->m_declElementType->name, parser->m_declAttributeId->name, parser->m_declAttributeType, 0, role == XML_ROLE_REQUIRED_ATTRIBUTE_VALUE); - poolClear(&parser->m_tempPool); handleDefault = XML_FALSE; } } + poolClear(&parser->m_tempPool); break; case XML_ROLE_DEFAULT_ATTRIBUTE_VALUE: case XML_ROLE_FIXED_ATTRIBUTE_VALUE: @@ -5386,7 +5395,7 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, * * If 'standalone' is false, the DTD must have no * parameter entities or we wouldn't have passed the outer - * 'if' statement. That measn the only entity in the hash + * 'if' statement. That means the only entity in the hash * table is the external subset name "#" which cannot be * given as a parameter entity name in XML syntax, so the * lookup must have returned NULL and we don't even reach @@ -5798,19 +5807,27 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end, if (result != XML_ERROR_NONE) return result; - else if (textEnd != next - && parser->m_parsingStatus.parsing == XML_SUSPENDED) { + + if (textEnd != next && parser->m_parsingStatus.parsing == XML_SUSPENDED) { entity->processed = (int)(next - (const char *)entity->textPtr); return result; - } else { + } + #ifdef XML_DTD - entityTrackingOnClose(parser, entity, __LINE__); + entityTrackingOnClose(parser, entity, __LINE__); #endif - entity->open = XML_FALSE; - parser->m_openInternalEntities = openEntity->next; - /* put openEntity back in list of free instances */ - openEntity->next = parser->m_freeInternalEntities; - parser->m_freeInternalEntities = openEntity; + entity->open = XML_FALSE; + parser->m_openInternalEntities = openEntity->next; + /* put openEntity back in list of free instances */ + openEntity->next = parser->m_freeInternalEntities; + parser->m_freeInternalEntities = openEntity; + + // If there are more open entities we want to stop right here and have the + // upcoming call to XML_ResumeParser continue with entity content, or it would + // be ignored altogether. + if (parser->m_openInternalEntities != NULL + && parser->m_parsingStatus.parsing == XML_SUSPENDED) { + return XML_ERROR_NONE; } #ifdef XML_DTD diff --git a/Modules/expat/xmltok_impl.h b/Modules/expat/xmltok_impl.h index c518aada013d..3469c4ae138c 100644 --- a/Modules/expat/xmltok_impl.h +++ b/Modules/expat/xmltok_impl.h @@ -45,7 +45,7 @@ enum { BT_LF, /* line feed = "\n" */ BT_GT, /* greater than = ">" */ BT_QUOT, /* quotation character = "\"" */ - BT_APOS, /* aposthrophe = "'" */ + BT_APOS, /* apostrophe = "'" */ BT_EQUALS, /* equal sign = "=" */ BT_QUEST, /* question mark = "?" */ BT_EXCL, /* exclamation mark = "!" */ From webhook-mailer at python.org Fri Oct 28 06:07:37 2022 From: webhook-mailer at python.org (ambv) Date: Fri, 28 Oct 2022 10:07:37 -0000 Subject: [Python-checkins] [3.9] gh-98739: Update libexpat from 2.4.9 to 2.5.0 (GH-98742) (#98786) Message-ID: https://github.com/python/cpython/commit/71a075aaee97f8950ecf6de4a10562e66afec17b commit: 71a075aaee97f8950ecf6de4a10562e66afec17b branch: 3.9 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-28T12:07:32+02:00 summary: [3.9] gh-98739: Update libexpat from 2.4.9 to 2.5.0 (GH-98742) (#98786) Update libexpat from 2.4.9 to 2.5.0 to address CVE-2022-43680. Co-authored-by: Shaun Walbridge (cherry picked from commit 3e07f827b359617664ad0880f218f17ae4483299) files: A Misc/NEWS.d/next/Security/2022-10-26-21-04-23.gh-issue-98739.keBWcY.rst M Modules/expat/expat.h M Modules/expat/xmlparse.c M Modules/expat/xmltok_impl.h diff --git a/Misc/NEWS.d/next/Security/2022-10-26-21-04-23.gh-issue-98739.keBWcY.rst b/Misc/NEWS.d/next/Security/2022-10-26-21-04-23.gh-issue-98739.keBWcY.rst new file mode 100644 index 000000000000..b63a54b3676c --- /dev/null +++ b/Misc/NEWS.d/next/Security/2022-10-26-21-04-23.gh-issue-98739.keBWcY.rst @@ -0,0 +1 @@ +Update bundled libexpat to 2.5.0 diff --git a/Modules/expat/expat.h b/Modules/expat/expat.h index 2b47ce2a8d3a..1c83563cbf68 100644 --- a/Modules/expat/expat.h +++ b/Modules/expat/expat.h @@ -1054,8 +1054,8 @@ XML_SetBillionLaughsAttackProtectionActivationThreshold( See http://semver.org. */ #define XML_MAJOR_VERSION 2 -#define XML_MINOR_VERSION 4 -#define XML_MICRO_VERSION 9 +#define XML_MINOR_VERSION 5 +#define XML_MICRO_VERSION 0 #ifdef __cplusplus } diff --git a/Modules/expat/xmlparse.c b/Modules/expat/xmlparse.c index c0bece51d700..b6c2eca97567 100644 --- a/Modules/expat/xmlparse.c +++ b/Modules/expat/xmlparse.c @@ -1,4 +1,4 @@ -/* 90815a2b2c80c03b2b889fe1d427bb2b9e3282aa065e42784e001db4f23de324 (2.4.9+) +/* 5ab094ffadd6edfc94c3eee53af44a86951f9f1f0933ada3114bbce2bfb02c99 (2.5.0+) __ __ _ ___\ \/ /_ __ __ _| |_ / _ \\ /| '_ \ / _` | __| @@ -35,6 +35,7 @@ Copyright (c) 2021 Dong-hee Na Copyright (c) 2022 Samanta Navarro Copyright (c) 2022 Jeffrey Walton + Copyright (c) 2022 Jann Horn Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -1068,6 +1069,14 @@ parserCreate(const XML_Char *encodingName, parserInit(parser, encodingName); if (encodingName && ! parser->m_protocolEncodingName) { + if (dtd) { + // We need to stop the upcoming call to XML_ParserFree from happily + // destroying parser->m_dtd because the DTD is shared with the parent + // parser and the only guard that keeps XML_ParserFree from destroying + // parser->m_dtd is parser->m_isParamEntity but it will be set to + // XML_TRUE only later in XML_ExternalEntityParserCreate (or not at all). + parser->m_dtd = NULL; + } XML_ParserFree(parser); return NULL; } @@ -3011,9 +3020,6 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, int len; const char *rawName; TAG *tag = parser->m_tagStack; - parser->m_tagStack = tag->parent; - tag->parent = parser->m_freeTagList; - parser->m_freeTagList = tag; rawName = s + enc->minBytesPerChar * 2; len = XmlNameLength(enc, rawName); if (len != tag->rawNameLength @@ -3021,6 +3027,9 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, *eventPP = rawName; return XML_ERROR_TAG_MISMATCH; } + parser->m_tagStack = tag->parent; + tag->parent = parser->m_freeTagList; + parser->m_freeTagList = tag; --parser->m_tagLevel; if (parser->m_endElementHandler) { const XML_Char *localPart; @@ -4975,10 +4984,10 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, parser->m_handlerArg, parser->m_declElementType->name, parser->m_declAttributeId->name, parser->m_declAttributeType, 0, role == XML_ROLE_REQUIRED_ATTRIBUTE_VALUE); - poolClear(&parser->m_tempPool); handleDefault = XML_FALSE; } } + poolClear(&parser->m_tempPool); break; case XML_ROLE_DEFAULT_ATTRIBUTE_VALUE: case XML_ROLE_FIXED_ATTRIBUTE_VALUE: @@ -5386,7 +5395,7 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, * * If 'standalone' is false, the DTD must have no * parameter entities or we wouldn't have passed the outer - * 'if' statement. That measn the only entity in the hash + * 'if' statement. That means the only entity in the hash * table is the external subset name "#" which cannot be * given as a parameter entity name in XML syntax, so the * lookup must have returned NULL and we don't even reach @@ -5798,19 +5807,27 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end, if (result != XML_ERROR_NONE) return result; - else if (textEnd != next - && parser->m_parsingStatus.parsing == XML_SUSPENDED) { + + if (textEnd != next && parser->m_parsingStatus.parsing == XML_SUSPENDED) { entity->processed = (int)(next - (const char *)entity->textPtr); return result; - } else { + } + #ifdef XML_DTD - entityTrackingOnClose(parser, entity, __LINE__); + entityTrackingOnClose(parser, entity, __LINE__); #endif - entity->open = XML_FALSE; - parser->m_openInternalEntities = openEntity->next; - /* put openEntity back in list of free instances */ - openEntity->next = parser->m_freeInternalEntities; - parser->m_freeInternalEntities = openEntity; + entity->open = XML_FALSE; + parser->m_openInternalEntities = openEntity->next; + /* put openEntity back in list of free instances */ + openEntity->next = parser->m_freeInternalEntities; + parser->m_freeInternalEntities = openEntity; + + // If there are more open entities we want to stop right here and have the + // upcoming call to XML_ResumeParser continue with entity content, or it would + // be ignored altogether. + if (parser->m_openInternalEntities != NULL + && parser->m_parsingStatus.parsing == XML_SUSPENDED) { + return XML_ERROR_NONE; } #ifdef XML_DTD diff --git a/Modules/expat/xmltok_impl.h b/Modules/expat/xmltok_impl.h index c518aada013d..3469c4ae138c 100644 --- a/Modules/expat/xmltok_impl.h +++ b/Modules/expat/xmltok_impl.h @@ -45,7 +45,7 @@ enum { BT_LF, /* line feed = "\n" */ BT_GT, /* greater than = ">" */ BT_QUOT, /* quotation character = "\"" */ - BT_APOS, /* aposthrophe = "'" */ + BT_APOS, /* apostrophe = "'" */ BT_EQUALS, /* equal sign = "=" */ BT_QUEST, /* question mark = "?" */ BT_EXCL, /* exclamation mark = "!" */ From webhook-mailer at python.org Fri Oct 28 06:07:56 2022 From: webhook-mailer at python.org (ambv) Date: Fri, 28 Oct 2022 10:07:56 -0000 Subject: [Python-checkins] [3.8] gh-98517: Fix buffer overflows in _sha3 module (GH-98519) (#98527) Message-ID: https://github.com/python/cpython/commit/948c6794711458fd148a3fa62296cadeeb2ed631 commit: 948c6794711458fd148a3fa62296cadeeb2ed631 branch: 3.8 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-28T12:07:50+02:00 summary: [3.8] gh-98517: Fix buffer overflows in _sha3 module (GH-98519) (#98527) This is a port of the applicable part of XKCP's fix [1] for CVE-2022-37454 and avoids the segmentation fault and the infinite loop in the test cases published in [2]. [1]: https://github.com/XKCP/XKCP/commit/fdc6fef075f4e81d6b1bc38364248975e08e340a [2]: https://mouha.be/sha-3-buffer-overflow/ Regression test added by: Gregory P. Smith [Google LLC] (cherry picked from commit 0e4e058602d93b88256ff90bbef501ba20be9dd3) Co-authored-by: Theo Buehler files: A Misc/NEWS.d/next/Security/2022-10-21-13-31-47.gh-issue-98517.SXXGfV.rst M Lib/test/test_hashlib.py M Modules/_sha3/kcp/KeccakSponge.inc diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py index 8b53d23ef525..e6cec4e306e5 100644 --- a/Lib/test/test_hashlib.py +++ b/Lib/test/test_hashlib.py @@ -434,6 +434,15 @@ def test_case_md5_huge(self, size): def test_case_md5_uintmax(self, size): self.check('md5', b'A'*size, '28138d306ff1b8281f1a9067e1a1a2b3') + @unittest.skipIf(sys.maxsize < _4G - 1, 'test cannot run on 32-bit systems') + @bigmemtest(size=_4G - 1, memuse=1, dry_run=False) + def test_sha3_update_overflow(self, size): + """Regression test for gh-98517 CVE-2022-37454.""" + h = hashlib.sha3_224() + h.update(b'\x01') + h.update(b'\x01'*0xffff_ffff) + self.assertEqual(h.hexdigest(), '80762e8ce6700f114fec0f621fd97c4b9c00147fa052215294cceeed') + # use the three examples from Federal Information Processing Standards # Publication 180-1, Secure Hash Standard, 1995 April 17 # http://www.itl.nist.gov/div897/pubs/fip180-1.htm diff --git a/Misc/NEWS.d/next/Security/2022-10-21-13-31-47.gh-issue-98517.SXXGfV.rst b/Misc/NEWS.d/next/Security/2022-10-21-13-31-47.gh-issue-98517.SXXGfV.rst new file mode 100644 index 000000000000..2d23a6ad93c7 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2022-10-21-13-31-47.gh-issue-98517.SXXGfV.rst @@ -0,0 +1 @@ +Port XKCP's fix for the buffer overflows in SHA-3 (CVE-2022-37454). diff --git a/Modules/_sha3/kcp/KeccakSponge.inc b/Modules/_sha3/kcp/KeccakSponge.inc index e10739deafa8..cf92e4db4d36 100644 --- a/Modules/_sha3/kcp/KeccakSponge.inc +++ b/Modules/_sha3/kcp/KeccakSponge.inc @@ -171,7 +171,7 @@ int SpongeAbsorb(SpongeInstance *instance, const unsigned char *data, size_t dat i = 0; curData = data; while(i < dataByteLen) { - if ((instance->byteIOIndex == 0) && (dataByteLen >= (i + rateInBytes))) { + if ((instance->byteIOIndex == 0) && (dataByteLen-i >= rateInBytes)) { #ifdef SnP_FastLoop_Absorb /* processing full blocks first */ @@ -199,10 +199,10 @@ int SpongeAbsorb(SpongeInstance *instance, const unsigned char *data, size_t dat } else { /* normal lane: using the message queue */ - - partialBlock = (unsigned int)(dataByteLen - i); - if (partialBlock+instance->byteIOIndex > rateInBytes) + if (dataByteLen-i > rateInBytes-instance->byteIOIndex) partialBlock = rateInBytes-instance->byteIOIndex; + else + partialBlock = (unsigned int)(dataByteLen - i); #ifdef KeccakReference displayBytes(1, "Block to be absorbed (part)", curData, partialBlock); #endif @@ -281,7 +281,7 @@ int SpongeSqueeze(SpongeInstance *instance, unsigned char *data, size_t dataByte i = 0; curData = data; while(i < dataByteLen) { - if ((instance->byteIOIndex == rateInBytes) && (dataByteLen >= (i + rateInBytes))) { + if ((instance->byteIOIndex == rateInBytes) && (dataByteLen-i >= rateInBytes)) { for(j=dataByteLen-i; j>=rateInBytes; j-=rateInBytes) { SnP_Permute(instance->state); SnP_ExtractBytes(instance->state, curData, 0, rateInBytes); @@ -299,9 +299,10 @@ int SpongeSqueeze(SpongeInstance *instance, unsigned char *data, size_t dataByte SnP_Permute(instance->state); instance->byteIOIndex = 0; } - partialBlock = (unsigned int)(dataByteLen - i); - if (partialBlock+instance->byteIOIndex > rateInBytes) + if (dataByteLen-i > rateInBytes-instance->byteIOIndex) partialBlock = rateInBytes-instance->byteIOIndex; + else + partialBlock = (unsigned int)(dataByteLen - i); i += partialBlock; SnP_ExtractBytes(instance->state, curData, instance->byteIOIndex, partialBlock); From webhook-mailer at python.org Fri Oct 28 06:08:12 2022 From: webhook-mailer at python.org (ambv) Date: Fri, 28 Oct 2022 10:08:12 -0000 Subject: [Python-checkins] [3.9] gh-98517: Fix buffer overflows in _sha3 module (GH-98519) (#98526) Message-ID: https://github.com/python/cpython/commit/857efee6d2d43c5c12fc7e377ce437144c728ab8 commit: 857efee6d2d43c5c12fc7e377ce437144c728ab8 branch: 3.9 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-28T12:08:06+02:00 summary: [3.9] gh-98517: Fix buffer overflows in _sha3 module (GH-98519) (#98526) This is a port of the applicable part of XKCP's fix [1] for CVE-2022-37454 and avoids the segmentation fault and the infinite loop in the test cases published in [2]. [1]: https://github.com/XKCP/XKCP/commit/fdc6fef075f4e81d6b1bc38364248975e08e340a [2]: https://mouha.be/sha-3-buffer-overflow/ Regression test added by: Gregory P. Smith [Google LLC] (cherry picked from commit 0e4e058602d93b88256ff90bbef501ba20be9dd3) Co-authored-by: Theo Buehler files: A Misc/NEWS.d/next/Security/2022-10-21-13-31-47.gh-issue-98517.SXXGfV.rst M Lib/test/test_hashlib.py M Modules/_sha3/kcp/KeccakSponge.inc diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py index f845c7a76e7c..bc11a8d8986b 100644 --- a/Lib/test/test_hashlib.py +++ b/Lib/test/test_hashlib.py @@ -497,6 +497,15 @@ def test_case_md5_huge(self, size): def test_case_md5_uintmax(self, size): self.check('md5', b'A'*size, '28138d306ff1b8281f1a9067e1a1a2b3') + @unittest.skipIf(sys.maxsize < _4G - 1, 'test cannot run on 32-bit systems') + @bigmemtest(size=_4G - 1, memuse=1, dry_run=False) + def test_sha3_update_overflow(self, size): + """Regression test for gh-98517 CVE-2022-37454.""" + h = hashlib.sha3_224() + h.update(b'\x01') + h.update(b'\x01'*0xffff_ffff) + self.assertEqual(h.hexdigest(), '80762e8ce6700f114fec0f621fd97c4b9c00147fa052215294cceeed') + # use the three examples from Federal Information Processing Standards # Publication 180-1, Secure Hash Standard, 1995 April 17 # http://www.itl.nist.gov/div897/pubs/fip180-1.htm diff --git a/Misc/NEWS.d/next/Security/2022-10-21-13-31-47.gh-issue-98517.SXXGfV.rst b/Misc/NEWS.d/next/Security/2022-10-21-13-31-47.gh-issue-98517.SXXGfV.rst new file mode 100644 index 000000000000..2d23a6ad93c7 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2022-10-21-13-31-47.gh-issue-98517.SXXGfV.rst @@ -0,0 +1 @@ +Port XKCP's fix for the buffer overflows in SHA-3 (CVE-2022-37454). diff --git a/Modules/_sha3/kcp/KeccakSponge.inc b/Modules/_sha3/kcp/KeccakSponge.inc index e10739deafa8..cf92e4db4d36 100644 --- a/Modules/_sha3/kcp/KeccakSponge.inc +++ b/Modules/_sha3/kcp/KeccakSponge.inc @@ -171,7 +171,7 @@ int SpongeAbsorb(SpongeInstance *instance, const unsigned char *data, size_t dat i = 0; curData = data; while(i < dataByteLen) { - if ((instance->byteIOIndex == 0) && (dataByteLen >= (i + rateInBytes))) { + if ((instance->byteIOIndex == 0) && (dataByteLen-i >= rateInBytes)) { #ifdef SnP_FastLoop_Absorb /* processing full blocks first */ @@ -199,10 +199,10 @@ int SpongeAbsorb(SpongeInstance *instance, const unsigned char *data, size_t dat } else { /* normal lane: using the message queue */ - - partialBlock = (unsigned int)(dataByteLen - i); - if (partialBlock+instance->byteIOIndex > rateInBytes) + if (dataByteLen-i > rateInBytes-instance->byteIOIndex) partialBlock = rateInBytes-instance->byteIOIndex; + else + partialBlock = (unsigned int)(dataByteLen - i); #ifdef KeccakReference displayBytes(1, "Block to be absorbed (part)", curData, partialBlock); #endif @@ -281,7 +281,7 @@ int SpongeSqueeze(SpongeInstance *instance, unsigned char *data, size_t dataByte i = 0; curData = data; while(i < dataByteLen) { - if ((instance->byteIOIndex == rateInBytes) && (dataByteLen >= (i + rateInBytes))) { + if ((instance->byteIOIndex == rateInBytes) && (dataByteLen-i >= rateInBytes)) { for(j=dataByteLen-i; j>=rateInBytes; j-=rateInBytes) { SnP_Permute(instance->state); SnP_ExtractBytes(instance->state, curData, 0, rateInBytes); @@ -299,9 +299,10 @@ int SpongeSqueeze(SpongeInstance *instance, unsigned char *data, size_t dataByte SnP_Permute(instance->state); instance->byteIOIndex = 0; } - partialBlock = (unsigned int)(dataByteLen - i); - if (partialBlock+instance->byteIOIndex > rateInBytes) + if (dataByteLen-i > rateInBytes-instance->byteIOIndex) partialBlock = rateInBytes-instance->byteIOIndex; + else + partialBlock = (unsigned int)(dataByteLen - i); i += partialBlock; SnP_ExtractBytes(instance->state, curData, instance->byteIOIndex, partialBlock); From webhook-mailer at python.org Fri Oct 28 06:08:36 2022 From: webhook-mailer at python.org (ambv) Date: Fri, 28 Oct 2022 10:08:36 -0000 Subject: [Python-checkins] [3.9] gh-97514: Don't use Linux abstract sockets for multiprocessing (GH-98501) (#98504) Message-ID: https://github.com/python/cpython/commit/b43496c01a554cf41ae654a0379efae18609ad39 commit: b43496c01a554cf41ae654a0379efae18609ad39 branch: 3.9 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-28T12:08:30+02:00 summary: [3.9] gh-97514: Don't use Linux abstract sockets for multiprocessing (GH-98501) (#98504) Linux abstract sockets are insecure as they lack any form of filesystem permissions so their use allows anyone on the system to inject code into the process. This removes the default preference for abstract sockets in multiprocessing introduced in Python 3.9+ via https://github.com/python/cpython/pull/18866 while fixing https://github.com/python/cpython/issues/84031. Explicit use of an abstract socket by a user now generates a RuntimeWarning. If we choose to keep this warning, it should be backported to the 3.7 and 3.8 branches. (cherry picked from commit 49f61068f49747164988ffc5a442d2a63874fc17) Co-authored-by: Gregory P. Smith files: A Misc/NEWS.d/next/Security/2022-09-07-10-42-00.gh-issue-97514.Yggdsl.rst M Lib/multiprocessing/connection.py diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py index 510e4b5aba44..8e2facf92a94 100644 --- a/Lib/multiprocessing/connection.py +++ b/Lib/multiprocessing/connection.py @@ -73,11 +73,6 @@ def arbitrary_address(family): if family == 'AF_INET': return ('localhost', 0) elif family == 'AF_UNIX': - # Prefer abstract sockets if possible to avoid problems with the address - # size. When coding portable applications, some implementations have - # sun_path as short as 92 bytes in the sockaddr_un struct. - if util.abstract_sockets_supported: - return f"\0listener-{os.getpid()}-{next(_mmap_counter)}" return tempfile.mktemp(prefix='listener-', dir=util.get_temp_dir()) elif family == 'AF_PIPE': return tempfile.mktemp(prefix=r'\\.\pipe\pyc-%d-%d-' % diff --git a/Misc/NEWS.d/next/Security/2022-09-07-10-42-00.gh-issue-97514.Yggdsl.rst b/Misc/NEWS.d/next/Security/2022-09-07-10-42-00.gh-issue-97514.Yggdsl.rst new file mode 100644 index 000000000000..02d95b570520 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2022-09-07-10-42-00.gh-issue-97514.Yggdsl.rst @@ -0,0 +1,15 @@ +On Linux the :mod:`multiprocessing` module returns to using filesystem backed +unix domain sockets for communication with the *forkserver* process instead of +the Linux abstract socket namespace. Only code that chooses to use the +:ref:`"forkserver" start method ` is affected. + +Abstract sockets have no permissions and could allow any user on the system in +the same `network namespace +`_ (often the +whole system) to inject code into the multiprocessing *forkserver* process. +This was a potential privilege escalation. Filesystem based socket permissions +restrict this to the *forkserver* process user as was the default in Python 3.8 +and earlier. + +This prevents Linux `CVE-2022-42919 +`_. From webhook-mailer at python.org Fri Oct 28 06:10:58 2022 From: webhook-mailer at python.org (ambv) Date: Fri, 28 Oct 2022 10:10:58 -0000 Subject: [Python-checkins] [3.10] Add more tkinter.Canvas tests (GH-98475) (#98477) Message-ID: https://github.com/python/cpython/commit/97106d3136b067a26434d6f88a7b0c8b65576c1f commit: 97106d3136b067a26434d6f88a7b0c8b65576c1f branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-28T12:10:41+02:00 summary: [3.10] Add more tkinter.Canvas tests (GH-98475) (#98477) Add more tkinter.Canvas tests (GH-98475) It is a prerequisite for GH-94473. Add tests for the coords() method and for creation of some Canvas items. (cherry picked from commit ff173ed2f6b07f38ec18f854daba6451bf1a9000) Co-authored-by: Serhiy Storchaka Co-authored-by: Alex Waygood files: M Lib/tkinter/test/test_tkinter/test_widgets.py diff --git a/Lib/tkinter/test/test_tkinter/test_widgets.py b/Lib/tkinter/test/test_tkinter/test_widgets.py index 562f4718cd21..7c512a05ee06 100644 --- a/Lib/tkinter/test/test_tkinter/test_widgets.py +++ b/Lib/tkinter/test/test_tkinter/test_widgets.py @@ -781,6 +781,164 @@ def test_configure_yscrollincrement(self): self.checkPixelsParam(widget, 'yscrollincrement', 10, 0, 11.2, 13.6, -10, '0.1i') + def _test_option_joinstyle(self, c, factory): + for joinstyle in 'bevel', 'miter', 'round': + i = factory(joinstyle=joinstyle) + self.assertEqual(c.itemcget(i, 'joinstyle'), joinstyle) + self.assertRaises(TclError, factory, joinstyle='spam') + + def _test_option_smooth(self, c, factory): + for smooth in 1, True, '1', 'true', 'yes', 'on': + i = factory(smooth=smooth) + self.assertEqual(c.itemcget(i, 'smooth'), 'true') + for smooth in 0, False, '0', 'false', 'no', 'off': + i = factory(smooth=smooth) + self.assertEqual(c.itemcget(i, 'smooth'), '0') + i = factory(smooth=True, splinestep=30) + self.assertEqual(c.itemcget(i, 'smooth'), 'true') + self.assertEqual(c.itemcget(i, 'splinestep'), '30') + i = factory(smooth='raw', splinestep=30) + self.assertEqual(c.itemcget(i, 'smooth'), 'raw') + self.assertEqual(c.itemcget(i, 'splinestep'), '30') + self.assertRaises(TclError, factory, smooth='spam') + + def test_create_rectangle(self): + c = self.create() + i1 = c.create_rectangle(20, 30, 60, 10) + self.assertEqual(c.coords(i1), [20.0, 10.0, 60.0, 30.0]) + self.assertEqual(c.bbox(i1), (19, 9, 61, 31)) + + i2 = c.create_rectangle([21, 31, 61, 11]) + self.assertEqual(c.coords(i2), [21.0, 11.0, 61.0, 31.0]) + self.assertEqual(c.bbox(i2), (20, 10, 62, 32)) + + i3 = c.create_rectangle((22, 32), (62, 12)) + self.assertEqual(c.coords(i3), [22.0, 12.0, 62.0, 32.0]) + self.assertEqual(c.bbox(i3), (21, 11, 63, 33)) + + i4 = c.create_rectangle([(23, 33), (63, 13)]) + self.assertEqual(c.coords(i4), [23.0, 13.0, 63.0, 33.0]) + self.assertEqual(c.bbox(i4), (22, 12, 64, 34)) + + self.assertRaises(TclError, c.create_rectangle, 20, 30, 60) + self.assertRaises(TclError, c.create_rectangle, [20, 30, 60]) + self.assertRaises(TclError, c.create_rectangle, 20, 30, 40, 50, 60, 10) + self.assertRaises(TclError, c.create_rectangle, [20, 30, 40, 50, 60, 10]) + self.assertRaises(TclError, c.create_rectangle, 20, 30) + self.assertRaises(TclError, c.create_rectangle, [20, 30]) + self.assertRaises(IndexError, c.create_rectangle) + self.assertRaises(IndexError, c.create_rectangle, []) + + def test_create_line(self): + c = self.create() + i1 = c.create_line(20, 30, 40, 50, 60, 10) + self.assertEqual(c.coords(i1), [20.0, 30.0, 40.0, 50.0, 60.0, 10.0]) + self.assertEqual(c.bbox(i1), (18, 8, 62, 52)) + self.assertEqual(c.itemcget(i1, 'arrow'), 'none') + self.assertEqual(c.itemcget(i1, 'arrowshape'), '8 10 3') + self.assertEqual(c.itemcget(i1, 'capstyle'), 'butt') + self.assertEqual(c.itemcget(i1, 'joinstyle'), 'round') + self.assertEqual(c.itemcget(i1, 'smooth'), '0') + self.assertEqual(c.itemcget(i1, 'splinestep'), '12') + + i2 = c.create_line([21, 31, 41, 51, 61, 11]) + self.assertEqual(c.coords(i2), [21.0, 31.0, 41.0, 51.0, 61.0, 11.0]) + self.assertEqual(c.bbox(i2), (19, 9, 63, 53)) + + i3 = c.create_line((22, 32), (42, 52), (62, 12)) + self.assertEqual(c.coords(i3), [22.0, 32.0, 42.0, 52.0, 62.0, 12.0]) + self.assertEqual(c.bbox(i3), (20, 10, 64, 54)) + + i4 = c.create_line([(23, 33), (43, 53), (63, 13)]) + self.assertEqual(c.coords(i4), [23.0, 33.0, 43.0, 53.0, 63.0, 13.0]) + self.assertEqual(c.bbox(i4), (21, 11, 65, 55)) + + self.assertRaises(TclError, c.create_line, 20, 30, 60) + self.assertRaises(TclError, c.create_line, [20, 30, 60]) + self.assertRaises(TclError, c.create_line, 20, 30) + self.assertRaises(TclError, c.create_line, [20, 30]) + self.assertRaises(IndexError, c.create_line) + self.assertRaises(IndexError, c.create_line, []) + + for arrow in 'none', 'first', 'last', 'both': + i = c.create_line(20, 30, 60, 10, arrow=arrow) + self.assertEqual(c.itemcget(i, 'arrow'), arrow) + i = c.create_line(20, 30, 60, 10, arrow='first', arrowshape=[10, 15, 5]) + self.assertEqual(c.itemcget(i, 'arrowshape'), '10 15 5') + self.assertRaises(TclError, c.create_line, 20, 30, 60, 10, arrow='spam') + + for capstyle in 'butt', 'projecting', 'round': + i = c.create_line(20, 30, 60, 10, capstyle=capstyle) + self.assertEqual(c.itemcget(i, 'capstyle'), capstyle) + self.assertRaises(TclError, c.create_line, 20, 30, 60, 10, capstyle='spam') + + self._test_option_joinstyle(c, + lambda **kwargs: c.create_line(20, 30, 40, 50, 60, 10, **kwargs)) + self._test_option_smooth(c, + lambda **kwargs: c.create_line(20, 30, 60, 10, **kwargs)) + + def test_create_polygon(self): + c = self.create() + i1 = c.create_polygon(20, 30, 40, 50, 60, 10) + self.assertEqual(c.coords(i1), [20.0, 30.0, 40.0, 50.0, 60.0, 10.0]) + self.assertEqual(c.bbox(i1), (19, 9, 61, 51)) + self.assertEqual(c.itemcget(i1, 'joinstyle'), 'round') + self.assertEqual(c.itemcget(i1, 'smooth'), '0') + self.assertEqual(c.itemcget(i1, 'splinestep'), '12') + + i2 = c.create_polygon([21, 31, 41, 51, 61, 11]) + self.assertEqual(c.coords(i2), [21.0, 31.0, 41.0, 51.0, 61.0, 11.0]) + self.assertEqual(c.bbox(i2), (20, 10, 62, 52)) + + i3 = c.create_polygon((22, 32), (42, 52), (62, 12)) + self.assertEqual(c.coords(i3), [22.0, 32.0, 42.0, 52.0, 62.0, 12.0]) + self.assertEqual(c.bbox(i3), (21, 11, 63, 53)) + + i4 = c.create_polygon([(23, 33), (43, 53), (63, 13)]) + self.assertEqual(c.coords(i4), [23.0, 33.0, 43.0, 53.0, 63.0, 13.0]) + self.assertEqual(c.bbox(i4), (22, 12, 64, 54)) + + self.assertRaises(TclError, c.create_polygon, 20, 30, 60) + self.assertRaises(TclError, c.create_polygon, [20, 30, 60]) + self.assertRaises(IndexError, c.create_polygon) + self.assertRaises(IndexError, c.create_polygon, []) + + self._test_option_joinstyle(c, + lambda **kwargs: c.create_polygon(20, 30, 40, 50, 60, 10, **kwargs)) + self._test_option_smooth(c, + lambda **kwargs: c.create_polygon(20, 30, 40, 50, 60, 10, **kwargs)) + + def test_coords(self): + c = self.create() + i = c.create_line(20, 30, 40, 50, 60, 10, tags='x') + self.assertEqual(c.coords(i), [20.0, 30.0, 40.0, 50.0, 60.0, 10.0]) + self.assertEqual(c.coords('x'), [20.0, 30.0, 40.0, 50.0, 60.0, 10.0]) + self.assertEqual(c.bbox(i), (18, 8, 62, 52)) + + c.coords(i, 50, 60, 70, 80, 90, 40) + self.assertEqual(c.coords(i), [50.0, 60.0, 70.0, 80.0, 90.0, 40.0]) + self.assertEqual(c.bbox(i), (48, 38, 92, 82)) + + c.coords(i, [21, 31, 41, 51, 61, 11]) + self.assertEqual(c.coords(i), [21.0, 31.0, 41.0, 51.0, 61.0, 11.0]) + + c.coords(i, 20, 30, 60, 10) + self.assertEqual(c.coords(i), [20.0, 30.0, 60.0, 10.0]) + self.assertEqual(c.bbox(i), (18, 8, 62, 32)) + + self.assertRaises(TclError, c.coords, i, 20, 30, 60) + self.assertRaises(TclError, c.coords, i, [20, 30, 60]) + self.assertRaises(TclError, c.coords, i, 20, 30) + self.assertRaises(TclError, c.coords, i, [20, 30]) + + c.coords(i, '20', '30c', '60i', '10p') + coords = c.coords(i) + self.assertIsInstance(coords, list) + self.assertEqual(len(coords), 4) + self.assertEqual(coords[0], 20) + for i in range(4): + self.assertIsInstance(coords[i], float) + @requires_tcl(8, 6) def test_moveto(self): widget = self.create() From webhook-mailer at python.org Fri Oct 28 06:11:32 2022 From: webhook-mailer at python.org (ambv) Date: Fri, 28 Oct 2022 10:11:32 -0000 Subject: [Python-checkins] [3.10] bpo-2716: add license for audioop module (GH-19972) (#98532) Message-ID: https://github.com/python/cpython/commit/586bb1fd8b6ec26eaa5339beef420f00b6497188 commit: 586bb1fd8b6ec26eaa5339beef420f00b6497188 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-28T12:11:26+02:00 summary: [3.10] bpo-2716: add license for audioop module (GH-19972) (#98532) bpo-2716: add license for audioop module (GH-19972) (cherry picked from commit 4c1145bb3796c550d477c8c154ff980d566fe4a2) Co-authored-by: Furkan Onder files: M Doc/license.rst M Modules/audioop.c diff --git a/Doc/license.rst b/Doc/license.rst index 00691b30ba6d..ea1edc432556 100644 --- a/Doc/license.rst +++ b/Doc/license.rst @@ -984,3 +984,28 @@ https://www.w3.org/TR/xml-c14n2-testcases/ and is distributed under the THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Audioop +------- +The audioop module uses the code base in g771.c file of the SoX project:: + Programming the AdLib/Sound Blaster + FM Music Chips + Version 2.0 (24 Feb 1992) + Copyright (c) 1991, 1992 by Jeffrey S. Lee + jlee at smylex.uucp + Warranty and Copyright Policy + This document is provided on an "as-is" basis, and its author makes + no warranty or representation, express or implied, with respect to + its quality performance or fitness for a particular purpose. In no + event will the author of this document be liable for direct, indirect, + special, incidental, or consequential damages arising out of the use + or inability to use the information contained within. Use of this + document is at your own risk. + This file may be used and copied freely so long as the applicable + copyright notices are retained, and no modifications are made to the + text of the document. No money shall be charged for its distribution + beyond reasonable shipping, handling and duplication costs, nor shall + proprietary changes be made to this document so that it cannot be + distributed freely. This document may not be included in published + material or commercial packages without the written consent of its + author. diff --git a/Modules/audioop.c b/Modules/audioop.c index 2a5d805c053c..798e3c46c472 100644 --- a/Modules/audioop.c +++ b/Modules/audioop.c @@ -1,3 +1,33 @@ +/* The audioop module uses the code base in g777.c file of the Sox project. + * Source: https://web.archive.org/web/19970716121258/http://www.spies.com/Sox/Archive/soxgamma.tar.gz + * Programming the AdLib/Sound Blaster + * FM Music Chips + * Version 2.0 (24 Feb 1992) + * + * Copyright (c) 1991, 1992 by Jeffrey S. Lee + * + * jlee at smylex.uucp + * + * + * + * Warranty and Copyright Policy + * + * This document is provided on an "as-is" basis, and its author makes + * no warranty or representation, express or implied, with respect to + * its quality performance or fitness for a particular purpose. In no + * event will the author of this document be liable for direct, indirect, + * special, incidental, or consequential damages arising out of the use + * or inability to use the information contained within. Use of this + * document is at your own risk. + * + * This file may be used and copied freely so long as the applicable + * copyright notices are retained, and no modifications are made to the + * text of the document. No money shall be charged for its distribution + * beyond reasonable shipping, handling and duplication costs, nor shall + * proprietary changes be made to this document so that it cannot be + * distributed freely. This document may not be included in published + * material or commercial packages without the written consent of its + * author. */ /* audioopmodule - Module to detect peak values in arrays */ @@ -28,20 +58,6 @@ fbound(double val, double minval, double maxval) } -/* Code shamelessly stolen from sox, 12.17.7, g711.c -** (c) Craig Reese, Joe Campbell and Jeff Poskanzer 1989 */ - -/* From g711.c: - * - * December 30, 1994: - * Functions linear2alaw, linear2ulaw have been updated to correctly - * convert unquantized 16 bit values. - * Tables for direct u- to A-law and A- to u-law conversions have been - * corrected. - * Borge Lindberg, Center for PersonKommunikation, Aalborg University. - * bli at cpk.auc.dk - * - */ #define BIAS 0x84 /* define the add-in bias for 16 bit samples */ #define CLIP 32635 #define SIGN_BIT (0x80) /* Sign bit for an A-law byte. */ From webhook-mailer at python.org Fri Oct 28 06:12:37 2022 From: webhook-mailer at python.org (ambv) Date: Fri, 28 Oct 2022 10:12:37 -0000 Subject: [Python-checkins] [3.11] gh-98548: Fix `-ne` shell operator spelling (#98556) Message-ID: https://github.com/python/cpython/commit/194588decc05fa12f04cd90c3b78cc081151b19e commit: 194588decc05fa12f04cd90c3b78cc081151b19e branch: 3.11 author: sterliakov <50529348+sterliakov at users.noreply.github.com> committer: ambv date: 2022-10-28T12:12:31+02:00 summary: [3.11] gh-98548: Fix `-ne` shell operator spelling (#98556) files: M .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 38dbb131575a..328714e87714 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -84,8 +84,7 @@ jobs: make -j4 - name: Check for changes in the ABI run: | - make check-abidump - if [ $? -neq 0 ] ; then + if ! make check-abidump; then echo "Generated ABI file is not up to date." echo "Please, add the release manager of this branch as a reviewer of this PR." echo "" From webhook-mailer at python.org Fri Oct 28 06:12:48 2022 From: webhook-mailer at python.org (ambv) Date: Fri, 28 Oct 2022 10:12:48 -0000 Subject: [Python-checkins] [3.10] gh-98548: Fix `-ne` shell operator spelling (#98555) Message-ID: https://github.com/python/cpython/commit/db1c3d6316f0239c6728ffcab48ee61903c8268a commit: db1c3d6316f0239c6728ffcab48ee61903c8268a branch: 3.10 author: sterliakov <50529348+sterliakov at users.noreply.github.com> committer: ambv date: 2022-10-28T12:12:42+02:00 summary: [3.10] gh-98548: Fix `-ne` shell operator spelling (#98555) files: M .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 630c238c9918..e47f0eb51bce 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -81,8 +81,7 @@ jobs: make -j4 - name: Check for changes in the ABI run: | - make check-abidump - if [ $? -neq 0 ] ; then + if ! make check-abidump; then echo "Generated ABI file is not up to date." echo "Please, add the release manager of this branch as a reviewer of this PR." echo "" From webhook-mailer at python.org Fri Oct 28 06:13:50 2022 From: webhook-mailer at python.org (ambv) Date: Fri, 28 Oct 2022 10:13:50 -0000 Subject: [Python-checkins] [3.10] GH-98671: bpo-46670: Fix #ifdef in sha3module.c (GH-90828) (#98677) Message-ID: https://github.com/python/cpython/commit/af204e4c47babdefb307b3f25eb152732c73a533 commit: af204e4c47babdefb307b3f25eb152732c73a533 branch: 3.10 author: samypr100 <3933065+samypr100 at users.noreply.github.com> committer: ambv date: 2022-10-28T12:13:44+02:00 summary: [3.10] GH-98671: bpo-46670: Fix #ifdef in sha3module.c (GH-90828) (#98677) files: A Misc/NEWS.d/next/Build/2022-10-25-14-43-00.gh-issue-98671.a42a6d.rst M Modules/_sha3/sha3module.c diff --git a/Misc/NEWS.d/next/Build/2022-10-25-14-43-00.gh-issue-98671.a42a6d.rst b/Misc/NEWS.d/next/Build/2022-10-25-14-43-00.gh-issue-98671.a42a6d.rst new file mode 100644 index 000000000000..54b78ed9f2e6 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2022-10-25-14-43-00.gh-issue-98671.a42a6d.rst @@ -0,0 +1,3 @@ +Fix ``NO_MISALIGNED_ACCESSES`` being not defined for the SHA3 extension +when ``HAVE_ALIGNED_REQUIRED`` is set. Allowing builds on hardware that +unaligned memory accesses are not allowed. diff --git a/Modules/_sha3/sha3module.c b/Modules/_sha3/sha3module.c index 3974e0b6b47f..a2f9d8c75467 100644 --- a/Modules/_sha3/sha3module.c +++ b/Modules/_sha3/sha3module.c @@ -65,7 +65,7 @@ #endif /* Prevent bus errors on platforms requiring aligned accesses such ARM. */ -#if HAVE_ALIGNED_REQUIRED && !defined(NO_MISALIGNED_ACCESSES) +#if defined(HAVE_ALIGNED_REQUIRED) && !defined(NO_MISALIGNED_ACCESSES) #define NO_MISALIGNED_ACCESSES #endif From webhook-mailer at python.org Fri Oct 28 06:15:40 2022 From: webhook-mailer at python.org (ambv) Date: Fri, 28 Oct 2022 10:15:40 -0000 Subject: [Python-checkins] [3.11] Python documents state elsewhere that a comma is not an operator (GH-98736) (#98757) Message-ID: https://github.com/python/cpython/commit/434943e0b461f5d4c8e772a4117bbf99e99d1fa3 commit: 434943e0b461f5d4c8e772a4117bbf99e99d1fa3 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-28T12:15:34+02:00 summary: [3.11] Python documents state elsewhere that a comma is not an operator (GH-98736) (#98757) Python documents state elsewhere that a comma is not an operator, so calling it an operator here is confusing. See https://docs.python.org/3/reference/lexical_analysis.htmlGH-operators and https://docs.python.org/3/faq/programming.htmlGH-id22. (cherry picked from commit d578aaea6257458c199328100cbb5af64c6a043e) Co-authored-by: Gerardwx files: M Doc/reference/expressions.rst diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst index cc969752d5d7..0cdf91e75b34 100644 --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -154,7 +154,7 @@ tuple may or may not yield the same object). single: , (comma) Note that tuples are not formed by the parentheses, but rather by use of the -comma operator. The exception is the empty tuple, for which parentheses *are* +comma. The exception is the empty tuple, for which parentheses *are* required --- allowing unparenthesized "nothing" in expressions would cause ambiguities and allow common typos to pass uncaught. From webhook-mailer at python.org Fri Oct 28 06:16:58 2022 From: webhook-mailer at python.org (ambv) Date: Fri, 28 Oct 2022 10:16:58 -0000 Subject: [Python-checkins] [3.10] gh-98624 Add mutex to unittest.mock.NonCallableMock (GH-98688) (#98798) Message-ID: https://github.com/python/cpython/commit/3f0f74387b8b4fa8dc4def7c2cace67c0331b532 commit: 3f0f74387b8b4fa8dc4def7c2cace67c0331b532 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-28T12:16:53+02:00 summary: [3.10] gh-98624 Add mutex to unittest.mock.NonCallableMock (GH-98688) (#98798) (cherry picked from commit 0346eddbe933b5f1f56151bdebf5bd49392bc275) Co-authored-by: noah-weingarden <33741795+noah-weingarden at users.noreply.github.com> files: A Misc/NEWS.d/next/Library/2022-10-25-20-17-34.gh-issue-98624.YQUPFy.rst M Lib/unittest/mock.py diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py index 3f7185b9671e..b49030a876d5 100644 --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -34,6 +34,7 @@ from types import CodeType, ModuleType, MethodType from unittest.util import safe_repr from functools import wraps, partial +from threading import RLock class InvalidSpecError(Exception): @@ -401,6 +402,14 @@ def __init__(self, /, *args, **kwargs): class NonCallableMock(Base): """A non-callable version of `Mock`""" + # Store a mutex as a class attribute in order to protect concurrent access + # to mock attributes. Using a class attribute allows all NonCallableMock + # instances to share the mutex for simplicity. + # + # See https://github.com/python/cpython/issues/98624 for why this is + # necessary. + _lock = RLock() + def __new__(cls, /, *args, **kw): # every instance has its own class # so we can create magic methods on the @@ -640,35 +649,36 @@ def __getattr__(self, name): f"{name!r} is not a valid assertion. Use a spec " f"for the mock if {name!r} is meant to be an attribute.") - result = self._mock_children.get(name) - if result is _deleted: - raise AttributeError(name) - elif result is None: - wraps = None - if self._mock_wraps is not None: - # XXXX should we get the attribute without triggering code - # execution? - wraps = getattr(self._mock_wraps, name) - - result = self._get_child_mock( - parent=self, name=name, wraps=wraps, _new_name=name, - _new_parent=self - ) - self._mock_children[name] = result - - elif isinstance(result, _SpecState): - try: - result = create_autospec( - result.spec, result.spec_set, result.instance, - result.parent, result.name + with NonCallableMock._lock: + result = self._mock_children.get(name) + if result is _deleted: + raise AttributeError(name) + elif result is None: + wraps = None + if self._mock_wraps is not None: + # XXXX should we get the attribute without triggering code + # execution? + wraps = getattr(self._mock_wraps, name) + + result = self._get_child_mock( + parent=self, name=name, wraps=wraps, _new_name=name, + _new_parent=self ) - except InvalidSpecError: - target_name = self.__dict__['_mock_name'] or self - raise InvalidSpecError( - f'Cannot autospec attr {name!r} from target ' - f'{target_name!r} as it has already been mocked out. ' - f'[target={self!r}, attr={result.spec!r}]') - self._mock_children[name] = result + self._mock_children[name] = result + + elif isinstance(result, _SpecState): + try: + result = create_autospec( + result.spec, result.spec_set, result.instance, + result.parent, result.name + ) + except InvalidSpecError: + target_name = self.__dict__['_mock_name'] or self + raise InvalidSpecError( + f'Cannot autospec attr {name!r} from target ' + f'{target_name!r} as it has already been mocked out. ' + f'[target={self!r}, attr={result.spec!r}]') + self._mock_children[name] = result return result diff --git a/Misc/NEWS.d/next/Library/2022-10-25-20-17-34.gh-issue-98624.YQUPFy.rst b/Misc/NEWS.d/next/Library/2022-10-25-20-17-34.gh-issue-98624.YQUPFy.rst new file mode 100644 index 000000000000..fb3a2b837fc3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-25-20-17-34.gh-issue-98624.YQUPFy.rst @@ -0,0 +1,2 @@ +Add a mutex to unittest.mock.NonCallableMock to protect concurrent access +to mock attributes. From webhook-mailer at python.org Fri Oct 28 06:17:25 2022 From: webhook-mailer at python.org (ambv) Date: Fri, 28 Oct 2022 10:17:25 -0000 Subject: [Python-checkins] [3.11] gh-98624 Add mutex to unittest.mock.NonCallableMock (GH-98688) (#98797) Message-ID: https://github.com/python/cpython/commit/725efe421974c5ce44b15c919adcfb2677a6e814 commit: 725efe421974c5ce44b15c919adcfb2677a6e814 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2022-10-28T12:17:19+02:00 summary: [3.11] gh-98624 Add mutex to unittest.mock.NonCallableMock (GH-98688) (#98797) (cherry picked from commit 0346eddbe933b5f1f56151bdebf5bd49392bc275) Co-authored-by: noah-weingarden <33741795+noah-weingarden at users.noreply.github.com> files: A Misc/NEWS.d/next/Library/2022-10-25-20-17-34.gh-issue-98624.YQUPFy.rst M Lib/unittest/mock.py diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py index cd46fea5162a..b8f4e57f0b49 100644 --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -35,6 +35,7 @@ from types import CodeType, ModuleType, MethodType from unittest.util import safe_repr from functools import wraps, partial +from threading import RLock class InvalidSpecError(Exception): @@ -402,6 +403,14 @@ def __init__(self, /, *args, **kwargs): class NonCallableMock(Base): """A non-callable version of `Mock`""" + # Store a mutex as a class attribute in order to protect concurrent access + # to mock attributes. Using a class attribute allows all NonCallableMock + # instances to share the mutex for simplicity. + # + # See https://github.com/python/cpython/issues/98624 for why this is + # necessary. + _lock = RLock() + def __new__(cls, /, *args, **kw): # every instance has its own class # so we can create magic methods on the @@ -644,35 +653,36 @@ def __getattr__(self, name): f"{name!r} is not a valid assertion. Use a spec " f"for the mock if {name!r} is meant to be an attribute.") - result = self._mock_children.get(name) - if result is _deleted: - raise AttributeError(name) - elif result is None: - wraps = None - if self._mock_wraps is not None: - # XXXX should we get the attribute without triggering code - # execution? - wraps = getattr(self._mock_wraps, name) - - result = self._get_child_mock( - parent=self, name=name, wraps=wraps, _new_name=name, - _new_parent=self - ) - self._mock_children[name] = result - - elif isinstance(result, _SpecState): - try: - result = create_autospec( - result.spec, result.spec_set, result.instance, - result.parent, result.name + with NonCallableMock._lock: + result = self._mock_children.get(name) + if result is _deleted: + raise AttributeError(name) + elif result is None: + wraps = None + if self._mock_wraps is not None: + # XXXX should we get the attribute without triggering code + # execution? + wraps = getattr(self._mock_wraps, name) + + result = self._get_child_mock( + parent=self, name=name, wraps=wraps, _new_name=name, + _new_parent=self ) - except InvalidSpecError: - target_name = self.__dict__['_mock_name'] or self - raise InvalidSpecError( - f'Cannot autospec attr {name!r} from target ' - f'{target_name!r} as it has already been mocked out. ' - f'[target={self!r}, attr={result.spec!r}]') - self._mock_children[name] = result + self._mock_children[name] = result + + elif isinstance(result, _SpecState): + try: + result = create_autospec( + result.spec, result.spec_set, result.instance, + result.parent, result.name + ) + except InvalidSpecError: + target_name = self.__dict__['_mock_name'] or self + raise InvalidSpecError( + f'Cannot autospec attr {name!r} from target ' + f'{target_name!r} as it has already been mocked out. ' + f'[target={self!r}, attr={result.spec!r}]') + self._mock_children[name] = result return result diff --git a/Misc/NEWS.d/next/Library/2022-10-25-20-17-34.gh-issue-98624.YQUPFy.rst b/Misc/NEWS.d/next/Library/2022-10-25-20-17-34.gh-issue-98624.YQUPFy.rst new file mode 100644 index 000000000000..fb3a2b837fc3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-25-20-17-34.gh-issue-98624.YQUPFy.rst @@ -0,0 +1,2 @@ +Add a mutex to unittest.mock.NonCallableMock to protect concurrent access +to mock attributes. From webhook-mailer at python.org Fri Oct 28 06:21:34 2022 From: webhook-mailer at python.org (ambv) Date: Fri, 28 Oct 2022 10:21:34 -0000 Subject: [Python-checkins] gh-65002: Make note that null bytes are used to pad bytes (#98635) Message-ID: https://github.com/python/cpython/commit/8cd21c2c5d34a5c5e857782da58d773f29ff8821 commit: 8cd21c2c5d34a5c5e857782da58d773f29ff8821 branch: main author: Stanley <46876382+slateny at users.noreply.github.com> committer: ambv date: 2022-10-28T12:21:28+02:00 summary: gh-65002: Make note that null bytes are used to pad bytes (#98635) files: M Doc/library/struct.rst diff --git a/Doc/library/struct.rst b/Doc/library/struct.rst index d12a5732fa4a..620f50376beb 100644 --- a/Doc/library/struct.rst +++ b/Doc/library/struct.rst @@ -194,7 +194,7 @@ platform-dependent. +--------+--------------------------+--------------------+----------------+------------+ | Format | C Type | Python type | Standard size | Notes | +========+==========================+====================+================+============+ -| ``x`` | pad byte | no value | | | +| ``x`` | pad byte | no value | | \(7) | +--------+--------------------------+--------------------+----------------+------------+ | ``c`` | :c:expr:`char` | bytes of length 1 | 1 | | +--------+--------------------------+--------------------+----------------+------------+ @@ -291,6 +291,9 @@ Notes: operations. See the Wikipedia page on the `half-precision floating-point format `_ for more information. +(7) + For padding, ``x`` inserts null bytes. + A format character may be preceded by an integral repeat count. For example, the format string ``'4h'`` means exactly the same as ``'hhhh'``. From webhook-mailer at python.org Fri Oct 28 06:26:07 2022 From: webhook-mailer at python.org (nanjekyejoannah) Date: Fri, 28 Oct 2022 10:26:07 -0000 Subject: [Python-checkins] gh-98657: [docs] `array.typecodes` is a module-level attribute (#98729) Message-ID: https://github.com/python/cpython/commit/c144e57b316e97a58ed5ad813c847fa8d2341dd7 commit: c144e57b316e97a58ed5ad813c847fa8d2341dd7 branch: main author: Nikita Sobolev committer: nanjekyejoannah <33177550+nanjekyejoannah at users.noreply.github.com> date: 2022-10-28T12:26:01+02:00 summary: gh-98657: [docs] `array.typecodes` is a module-level attribute (#98729) * gh-98657: [docs] `array.typecodes` is a module-level attribute * Update array.rst files: M Doc/library/array.rst diff --git a/Doc/library/array.rst b/Doc/library/array.rst index 975670cc81a2..95f1eaf401b0 100644 --- a/Doc/library/array.rst +++ b/Doc/library/array.rst @@ -62,6 +62,14 @@ The actual representation of values is determined by the machine architecture (strictly speaking, by the C implementation). The actual size can be accessed through the :attr:`itemsize` attribute. +The module defines the following item: + + +.. data:: typecodes + + A string with all available type codes. + + The module defines the following type: @@ -79,9 +87,6 @@ The module defines the following type: .. audit-event:: array.__new__ typecode,initializer array.array -.. data:: typecodes - - A string with all available type codes. Array objects support the ordinary sequence operations of indexing, slicing, concatenation, and multiplication. When using slice assignment, the assigned From webhook-mailer at python.org Fri Oct 28 07:32:22 2022 From: webhook-mailer at python.org (miss-islington) Date: Fri, 28 Oct 2022 11:32:22 -0000 Subject: [Python-checkins] gh-98776: Fix make regen-test-levenshtein for out-of-tree builds (GH-98779) Message-ID: https://github.com/python/cpython/commit/5a8c4b9464fedb7c0e1150d69d3e12b479138d07 commit: 5a8c4b9464fedb7c0e1150d69d3e12b479138d07 branch: main author: Miro Hron?ok committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-28T04:31:33-07:00 summary: gh-98776: Fix make regen-test-levenshtein for out-of-tree builds (GH-98779) Fixes https://github.com/python/cpython/issues/98776 Automerge-Triggered-By: GH:erlend-aasland files: A Misc/NEWS.d/next/Build/2022-10-27-19-47-31.gh-issue-98776.lt_UOG.rst M Makefile.pre.in diff --git a/Makefile.pre.in b/Makefile.pre.in index 6ab1422c7898..9b35398c4fe7 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -961,7 +961,7 @@ regen-test-frozenmain: $(BUILDPYTHON) .PHONY: regen-test-levenshtein regen-test-levenshtein: # Regenerate Lib/test/levenshtein_examples.json - $(PYTHON_FOR_REGEN) $(srcdir)/Tools/build/generate_levenshtein_examples.py Lib/test/levenshtein_examples.json + $(PYTHON_FOR_REGEN) $(srcdir)/Tools/build/generate_levenshtein_examples.py $(srcdir)/Lib/test/levenshtein_examples.json .PHONY: regen-re regen-re: $(BUILDPYTHON) diff --git a/Misc/NEWS.d/next/Build/2022-10-27-19-47-31.gh-issue-98776.lt_UOG.rst b/Misc/NEWS.d/next/Build/2022-10-27-19-47-31.gh-issue-98776.lt_UOG.rst new file mode 100644 index 000000000000..049f13463b8c --- /dev/null +++ b/Misc/NEWS.d/next/Build/2022-10-27-19-47-31.gh-issue-98776.lt_UOG.rst @@ -0,0 +1 @@ +Fix ``make regen-test-levenshtein`` for out-of-tree builds. From webhook-mailer at python.org Fri Oct 28 08:16:28 2022 From: webhook-mailer at python.org (AlexWaygood) Date: Fri, 28 Oct 2022 12:16:28 -0000 Subject: [Python-checkins] `argparse` docs: normalize constant references (#98765) Message-ID: https://github.com/python/cpython/commit/b27b57c6e44a276c8a9843fd37d4cf65b2827d5c commit: b27b57c6e44a276c8a9843fd37d4cf65b2827d5c branch: main author: Skip Montanaro committer: AlexWaygood date: 2022-10-28T13:15:39+01:00 summary: `argparse` docs: normalize constant references (#98765) files: M Doc/library/argparse.rst diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index 5d76ab017ede..c55d94421e5b 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -63,7 +63,7 @@ Name Description action_ Specify how an argument should be handled ``'store'``, ``'store_const'``, ``'store_true'``, ``'append'``, ``'append_const'``, ``'count'``, ``'help'``, ``'version'`` choices_ Limit values to a specific set of choices ``['foo', 'bar']``, ``range(1, 10)``, or :class:`~collections.abc.Container` instance const_ Store a constant value -default_ Default value used when an argument is not provided Defaults to *None* +default_ Default value used when an argument is not provided Defaults to ``None`` dest_ Specify the attribute name used in the result namespace help_ Help message for an argument metavar_ Alternate display name for the argument as shown in help @@ -201,9 +201,10 @@ ArgumentParser objects * usage_ - The string describing the program usage (default: generated from arguments added to parser) - * description_ - Text to display before the argument help (default: none) + * description_ - Text to display before the argument help + (by default, no text) - * epilog_ - Text to display after the argument help (default: none) + * epilog_ - Text to display after the argument help (by default, no text) * parents_ - A list of :class:`ArgumentParser` objects whose arguments should also be included @@ -1926,8 +1927,8 @@ FileType objects Namespace(out=<_io.TextIOWrapper name='file.txt' mode='w' encoding='UTF-8'>, raw=<_io.FileIO name='raw.dat' mode='wb'>) FileType objects understand the pseudo-argument ``'-'`` and automatically - convert this into ``sys.stdin`` for readable :class:`FileType` objects and - ``sys.stdout`` for writable :class:`FileType` objects:: + convert this into :data:`sys.stdin` for readable :class:`FileType` objects and + :data:`sys.stdout` for writable :class:`FileType` objects:: >>> parser = argparse.ArgumentParser() >>> parser.add_argument('infile', type=argparse.FileType('r')) From webhook-mailer at python.org Fri Oct 28 08:16:44 2022 From: webhook-mailer at python.org (erlend-aasland) Date: Fri, 28 Oct 2022 12:16:44 -0000 Subject: [Python-checkins] [3.10] gh-94328: Update Windows installer to use SQLite 3.39.4 (GH-98640) (#98678) Message-ID: https://github.com/python/cpython/commit/a3b06fd1a2a7089fff00922bff8aee8464219007 commit: a3b06fd1a2a7089fff00922bff8aee8464219007 branch: 3.10 author: Erlend E. Aasland committer: erlend-aasland date: 2022-10-28T14:16:38+02:00 summary: [3.10] gh-94328: Update Windows installer to use SQLite 3.39.4 (GH-98640) (#98678) (cherry picked from commit 0c84593275969d9b8f42e75abb2638b69d5b5f4a) Co-authored-by: Erlend E. Aasland Co-authored-by: ?ukasz Langa files: A Misc/NEWS.d/next/Windows/2022-10-25-10-34-17.gh-issue-94328.19NhdU.rst M PCbuild/get_externals.bat M PCbuild/python.props M PCbuild/readme.txt diff --git a/Misc/NEWS.d/next/Windows/2022-10-25-10-34-17.gh-issue-94328.19NhdU.rst b/Misc/NEWS.d/next/Windows/2022-10-25-10-34-17.gh-issue-94328.19NhdU.rst new file mode 100644 index 000000000000..eb48ff9b6ec6 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2022-10-25-10-34-17.gh-issue-94328.19NhdU.rst @@ -0,0 +1 @@ +Update Windows installer to use SQLite 3.39.4. diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat index 208b573562dc..f72c8f6acb4a 100644 --- a/PCbuild/get_externals.bat +++ b/PCbuild/get_externals.bat @@ -54,7 +54,7 @@ set libraries= set libraries=%libraries% bzip2-1.0.8 if NOT "%IncludeLibffiSrc%"=="false" set libraries=%libraries% libffi-3.3.0 if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-1.1.1q -set libraries=%libraries% sqlite-3.37.2.0 +set libraries=%libraries% sqlite-3.39.4.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tcl-core-8.6.12.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tk-8.6.12.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tix-8.4.3.6 diff --git a/PCbuild/python.props b/PCbuild/python.props index b3604b19a10d..1db13d46a7ad 100644 --- a/PCbuild/python.props +++ b/PCbuild/python.props @@ -57,7 +57,7 @@ $(EXTERNALS_DIR) $([System.IO.Path]::GetFullPath(`$(PySourcePath)externals`)) $(ExternalsDir)\ - $(ExternalsDir)sqlite-3.37.2.0\ + $(ExternalsDir)sqlite-3.39.4.0\ $(ExternalsDir)bzip2-1.0.8\ $(ExternalsDir)xz-5.2.5\ $(ExternalsDir)libffi-3.3.0\ diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt index 3af4c5c7da18..155212625ccc 100644 --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -186,7 +186,7 @@ _ssl again when building. _sqlite3 - Wraps SQLite 3.37.2, which is itself built by sqlite3.vcxproj + Wraps SQLite 3.39.4, which is itself built by sqlite3.vcxproj Homepage: https://www.sqlite.org/ _tkinter From webhook-mailer at python.org Fri Oct 28 08:26:03 2022 From: webhook-mailer at python.org (miss-islington) Date: Fri, 28 Oct 2022 12:26:03 -0000 Subject: [Python-checkins] `argparse` docs: normalize constant references (GH-98765) Message-ID: https://github.com/python/cpython/commit/2d4b6e00f0f3dd7da5e0f0dceb0dca5008060e1b commit: 2d4b6e00f0f3dd7da5e0f0dceb0dca5008060e1b branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-28T05:25:58-07:00 summary: `argparse` docs: normalize constant references (GH-98765) (cherry picked from commit b27b57c6e44a276c8a9843fd37d4cf65b2827d5c) Co-authored-by: Skip Montanaro files: M Doc/library/argparse.rst diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index 76efed95bd4c..bcbb38a05e8b 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -63,7 +63,7 @@ Name Description action_ Specify how an argument should be handled ``'store'``, ``'store_const'``, ``'store_true'``, ``'append'``, ``'append_const'``, ``'count'``, ``'help'``, ``'version'`` choices_ Limit values to a specific set of choices ``['foo', 'bar']``, ``range(1, 10)``, or :class:`~collections.abc.Container` instance const_ Store a constant value -default_ Default value used when an argument is not provided Defaults to *None* +default_ Default value used when an argument is not provided Defaults to ``None`` dest_ Specify the attribute name used in the result namespace help_ Help message for an argument metavar_ Alternate display name for the argument as shown in help @@ -201,9 +201,10 @@ ArgumentParser objects * usage_ - The string describing the program usage (default: generated from arguments added to parser) - * description_ - Text to display before the argument help (default: none) + * description_ - Text to display before the argument help + (by default, no text) - * epilog_ - Text to display after the argument help (default: none) + * epilog_ - Text to display after the argument help (by default, no text) * parents_ - A list of :class:`ArgumentParser` objects whose arguments should also be included @@ -1914,8 +1915,8 @@ FileType objects Namespace(out=<_io.TextIOWrapper name='file.txt' mode='w' encoding='UTF-8'>, raw=<_io.FileIO name='raw.dat' mode='wb'>) FileType objects understand the pseudo-argument ``'-'`` and automatically - convert this into ``sys.stdin`` for readable :class:`FileType` objects and - ``sys.stdout`` for writable :class:`FileType` objects:: + convert this into :data:`sys.stdin` for readable :class:`FileType` objects and + :data:`sys.stdout` for writable :class:`FileType` objects:: >>> parser = argparse.ArgumentParser() >>> parser.add_argument('infile', type=argparse.FileType('r')) From webhook-mailer at python.org Fri Oct 28 13:17:47 2022 From: webhook-mailer at python.org (AlexWaygood) Date: Fri, 28 Oct 2022 17:17:47 -0000 Subject: [Python-checkins] [3.10] `argparse` docs: normalize constant references (#98765) (#98808) Message-ID: https://github.com/python/cpython/commit/4320115613c93470dd1e22ec2517f5fc875c5423 commit: 4320115613c93470dd1e22ec2517f5fc875c5423 branch: 3.10 author: Alex Waygood committer: AlexWaygood date: 2022-10-28T18:17:03+01:00 summary: [3.10] `argparse` docs: normalize constant references (#98765) (#98808) `argparse` docs: normalize constant references (#98765) (cherry picked from commit b27b57c6e44a276c8a9843fd37d4cf65b2827d5c) Co-authored-by: Skip Montanaro files: M Doc/library/argparse.rst diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index d96f17b80a5f..bdc2ccebb7bb 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -154,9 +154,10 @@ ArgumentParser objects * usage_ - The string describing the program usage (default: generated from arguments added to parser) - * description_ - Text to display before the argument help (default: none) + * description_ - Text to display before the argument help + (by default, no text) - * epilog_ - Text to display after the argument help (default: none) + * epilog_ - Text to display after the argument help (by default, no text) * parents_ - A list of :class:`ArgumentParser` objects whose arguments should also be included @@ -1831,8 +1832,8 @@ FileType objects Namespace(out=<_io.TextIOWrapper name='file.txt' mode='w' encoding='UTF-8'>, raw=<_io.FileIO name='raw.dat' mode='wb'>) FileType objects understand the pseudo-argument ``'-'`` and automatically - convert this into ``sys.stdin`` for readable :class:`FileType` objects and - ``sys.stdout`` for writable :class:`FileType` objects:: + convert this into :data:`sys.stdin` for readable :class:`FileType` objects and + :data:`sys.stdout` for writable :class:`FileType` objects:: >>> parser = argparse.ArgumentParser() >>> parser.add_argument('infile', type=argparse.FileType('r')) From webhook-mailer at python.org Fri Oct 28 14:17:50 2022 From: webhook-mailer at python.org (FFY00) Date: Fri, 28 Oct 2022 18:17:50 -0000 Subject: [Python-checkins] gh-92452: Avoid race in initialization of sysconfig._CONFIG_VARS Message-ID: https://github.com/python/cpython/commit/7ee3aca00a0dffc9cb5906a24005a8c61d5bce14 commit: 7ee3aca00a0dffc9cb5906a24005a8c61d5bce14 branch: main author: Gareth Rees committer: FFY00 date: 2022-10-28T19:17:04+01:00 summary: gh-92452: Avoid race in initialization of sysconfig._CONFIG_VARS Co-authored-by: Filipe La?ns files: A Misc/NEWS.d/next/Library/2022-05-08-08-47-32.gh-issue-92452.3pNHe6.rst M Lib/sysconfig.py diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py index ebe371182742..73c25684db20 100644 --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -2,6 +2,7 @@ import os import sys +import threading from os.path import pardir, realpath __all__ = [ @@ -172,7 +173,11 @@ def joinuser(*args): _BASE_PREFIX = os.path.normpath(sys.base_prefix) _EXEC_PREFIX = os.path.normpath(sys.exec_prefix) _BASE_EXEC_PREFIX = os.path.normpath(sys.base_exec_prefix) +# Mutex guarding initialization of _CONFIG_VARS. +_CONFIG_VARS_LOCK = threading.RLock() _CONFIG_VARS = None +# True iff _CONFIG_VARS has been fully initialized. +_CONFIG_VARS_INITIALIZED = False _USER_BASE = None # Regexes needed for parsing Makefile (and similar syntaxes, @@ -626,6 +631,71 @@ def get_path(name, scheme=get_default_scheme(), vars=None, expand=True): return get_paths(scheme, vars, expand)[name] +def _init_config_vars(): + global _CONFIG_VARS + _CONFIG_VARS = {} + # Normalized versions of prefix and exec_prefix are handy to have; + # in fact, these are the standard versions used most places in the + # Distutils. + _CONFIG_VARS['prefix'] = _PREFIX + _CONFIG_VARS['exec_prefix'] = _EXEC_PREFIX + _CONFIG_VARS['py_version'] = _PY_VERSION + _CONFIG_VARS['py_version_short'] = _PY_VERSION_SHORT + _CONFIG_VARS['py_version_nodot'] = _PY_VERSION_SHORT_NO_DOT + _CONFIG_VARS['installed_base'] = _BASE_PREFIX + _CONFIG_VARS['base'] = _PREFIX + _CONFIG_VARS['installed_platbase'] = _BASE_EXEC_PREFIX + _CONFIG_VARS['platbase'] = _EXEC_PREFIX + _CONFIG_VARS['projectbase'] = _PROJECT_BASE + _CONFIG_VARS['platlibdir'] = sys.platlibdir + try: + _CONFIG_VARS['abiflags'] = sys.abiflags + except AttributeError: + # sys.abiflags may not be defined on all platforms. + _CONFIG_VARS['abiflags'] = '' + try: + _CONFIG_VARS['py_version_nodot_plat'] = sys.winver.replace('.', '') + except AttributeError: + _CONFIG_VARS['py_version_nodot_plat'] = '' + + if os.name == 'nt': + _init_non_posix(_CONFIG_VARS) + _CONFIG_VARS['VPATH'] = sys._vpath + if os.name == 'posix': + _init_posix(_CONFIG_VARS) + if _HAS_USER_BASE: + # Setting 'userbase' is done below the call to the + # init function to enable using 'get_config_var' in + # the init-function. + _CONFIG_VARS['userbase'] = _getuserbase() + + # Always convert srcdir to an absolute path + srcdir = _CONFIG_VARS.get('srcdir', _PROJECT_BASE) + if os.name == 'posix': + if _PYTHON_BUILD: + # If srcdir is a relative path (typically '.' or '..') + # then it should be interpreted relative to the directory + # containing Makefile. + base = os.path.dirname(get_makefile_filename()) + srcdir = os.path.join(base, srcdir) + else: + # srcdir is not meaningful since the installation is + # spread about the filesystem. We choose the + # directory containing the Makefile since we know it + # exists. + srcdir = os.path.dirname(get_makefile_filename()) + _CONFIG_VARS['srcdir'] = _safe_realpath(srcdir) + + # OS X platforms require special customization to handle + # multi-architecture, multi-os-version installers + if sys.platform == 'darwin': + import _osx_support + _osx_support.customize_config_vars(_CONFIG_VARS) + + global _CONFIG_VARS_INITIALIZED + _CONFIG_VARS_INITIALIZED = True + + def get_config_vars(*args): """With no arguments, return a dictionary of all configuration variables relevant for the current platform. @@ -636,66 +706,16 @@ def get_config_vars(*args): With arguments, return a list of values that result from looking up each argument in the configuration variable dictionary. """ - global _CONFIG_VARS - if _CONFIG_VARS is None: - _CONFIG_VARS = {} - # Normalized versions of prefix and exec_prefix are handy to have; - # in fact, these are the standard versions used most places in the - # Distutils. - _CONFIG_VARS['prefix'] = _PREFIX - _CONFIG_VARS['exec_prefix'] = _EXEC_PREFIX - _CONFIG_VARS['py_version'] = _PY_VERSION - _CONFIG_VARS['py_version_short'] = _PY_VERSION_SHORT - _CONFIG_VARS['py_version_nodot'] = _PY_VERSION_SHORT_NO_DOT - _CONFIG_VARS['installed_base'] = _BASE_PREFIX - _CONFIG_VARS['base'] = _PREFIX - _CONFIG_VARS['installed_platbase'] = _BASE_EXEC_PREFIX - _CONFIG_VARS['platbase'] = _EXEC_PREFIX - _CONFIG_VARS['projectbase'] = _PROJECT_BASE - _CONFIG_VARS['platlibdir'] = sys.platlibdir - try: - _CONFIG_VARS['abiflags'] = sys.abiflags - except AttributeError: - # sys.abiflags may not be defined on all platforms. - _CONFIG_VARS['abiflags'] = '' - try: - _CONFIG_VARS['py_version_nodot_plat'] = sys.winver.replace('.', '') - except AttributeError: - _CONFIG_VARS['py_version_nodot_plat'] = '' - - if os.name == 'nt': - _init_non_posix(_CONFIG_VARS) - _CONFIG_VARS['VPATH'] = sys._vpath - if os.name == 'posix': - _init_posix(_CONFIG_VARS) - if _HAS_USER_BASE: - # Setting 'userbase' is done below the call to the - # init function to enable using 'get_config_var' in - # the init-function. - _CONFIG_VARS['userbase'] = _getuserbase() - - # Always convert srcdir to an absolute path - srcdir = _CONFIG_VARS.get('srcdir', _PROJECT_BASE) - if os.name == 'posix': - if _PYTHON_BUILD: - # If srcdir is a relative path (typically '.' or '..') - # then it should be interpreted relative to the directory - # containing Makefile. - base = os.path.dirname(get_makefile_filename()) - srcdir = os.path.join(base, srcdir) - else: - # srcdir is not meaningful since the installation is - # spread about the filesystem. We choose the - # directory containing the Makefile since we know it - # exists. - srcdir = os.path.dirname(get_makefile_filename()) - _CONFIG_VARS['srcdir'] = _safe_realpath(srcdir) - - # OS X platforms require special customization to handle - # multi-architecture, multi-os-version installers - if sys.platform == 'darwin': - import _osx_support - _osx_support.customize_config_vars(_CONFIG_VARS) + + # Avoid claiming the lock once initialization is complete. + if not _CONFIG_VARS_INITIALIZED: + with _CONFIG_VARS_LOCK: + # Test again with the lock held to avoid races. Note that + # we test _CONFIG_VARS here, not _CONFIG_VARS_INITIALIZED, + # to ensure that recursive calls to get_config_vars() + # don't re-enter init_config_vars(). + if _CONFIG_VARS is None: + _init_config_vars() if args: vals = [] diff --git a/Misc/NEWS.d/next/Library/2022-05-08-08-47-32.gh-issue-92452.3pNHe6.rst b/Misc/NEWS.d/next/Library/2022-05-08-08-47-32.gh-issue-92452.3pNHe6.rst new file mode 100644 index 000000000000..25d6477aa913 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-05-08-08-47-32.gh-issue-92452.3pNHe6.rst @@ -0,0 +1,2 @@ +Fixed a race condition that could cause :func:`sysconfig.get_config_var` to +incorrectly return :const:`None` in multi-threaded programs. From webhook-mailer at python.org Fri Oct 28 17:13:58 2022 From: webhook-mailer at python.org (AlexWaygood) Date: Fri, 28 Oct 2022 21:13:58 -0000 Subject: [Python-checkins] Fix typo in contextvars docs (#98823) Message-ID: https://github.com/python/cpython/commit/72fa57a8fe2e9df637170dc97f994ac70931e8e9 commit: 72fa57a8fe2e9df637170dc97f994ac70931e8e9 branch: main author: cburroughs committer: AlexWaygood date: 2022-10-28T22:13:48+01:00 summary: Fix typo in contextvars docs (#98823) files: M Doc/library/contextvars.rst diff --git a/Doc/library/contextvars.rst b/Doc/library/contextvars.rst index be1dd0c9eb57..08a7c7d74eab 100644 --- a/Doc/library/contextvars.rst +++ b/Doc/library/contextvars.rst @@ -110,7 +110,7 @@ Context Variables A read-only property. Set to the value the variable had before the :meth:`ContextVar.set` method call that created the token. - It points to :attr:`Token.MISSING` is the variable was not set + It points to :attr:`Token.MISSING` if the variable was not set before the call. .. attribute:: Token.MISSING From webhook-mailer at python.org Fri Oct 28 17:19:49 2022 From: webhook-mailer at python.org (miss-islington) Date: Fri, 28 Oct 2022 21:19:49 -0000 Subject: [Python-checkins] Fix typo in contextvars docs (GH-98823) Message-ID: https://github.com/python/cpython/commit/85f88f63d96b07208c98a725391af7cb710fe06b commit: 85f88f63d96b07208c98a725391af7cb710fe06b branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-28T14:19:43-07:00 summary: Fix typo in contextvars docs (GH-98823) (cherry picked from commit 72fa57a8fe2e9df637170dc97f994ac70931e8e9) Co-authored-by: cburroughs files: M Doc/library/contextvars.rst diff --git a/Doc/library/contextvars.rst b/Doc/library/contextvars.rst index be1dd0c9eb57..08a7c7d74eab 100644 --- a/Doc/library/contextvars.rst +++ b/Doc/library/contextvars.rst @@ -110,7 +110,7 @@ Context Variables A read-only property. Set to the value the variable had before the :meth:`ContextVar.set` method call that created the token. - It points to :attr:`Token.MISSING` is the variable was not set + It points to :attr:`Token.MISSING` if the variable was not set before the call. .. attribute:: Token.MISSING From webhook-mailer at python.org Fri Oct 28 17:23:32 2022 From: webhook-mailer at python.org (miss-islington) Date: Fri, 28 Oct 2022 21:23:32 -0000 Subject: [Python-checkins] Fix typo in contextvars docs (GH-98823) Message-ID: https://github.com/python/cpython/commit/12957d7cbd07bbbb80e3371f5300aa80f1997cc7 commit: 12957d7cbd07bbbb80e3371f5300aa80f1997cc7 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-28T14:23:26-07:00 summary: Fix typo in contextvars docs (GH-98823) (cherry picked from commit 72fa57a8fe2e9df637170dc97f994ac70931e8e9) Co-authored-by: cburroughs files: M Doc/library/contextvars.rst diff --git a/Doc/library/contextvars.rst b/Doc/library/contextvars.rst index be1dd0c9eb57..08a7c7d74eab 100644 --- a/Doc/library/contextvars.rst +++ b/Doc/library/contextvars.rst @@ -110,7 +110,7 @@ Context Variables A read-only property. Set to the value the variable had before the :meth:`ContextVar.set` method call that created the token. - It points to :attr:`Token.MISSING` is the variable was not set + It points to :attr:`Token.MISSING` if the variable was not set before the call. .. attribute:: Token.MISSING From webhook-mailer at python.org Fri Oct 28 19:20:31 2022 From: webhook-mailer at python.org (miss-islington) Date: Fri, 28 Oct 2022 23:20:31 -0000 Subject: [Python-checkins] gh-84538: add strict argument to pathlib.PurePath.relative_to (GH-19813) Message-ID: https://github.com/python/cpython/commit/e089f23bbbb27a84c6354147b99f7ec897ca9925 commit: e089f23bbbb27a84c6354147b99f7ec897ca9925 branch: main author: domragusa <64558788+domragusa at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-28T16:20:14-07:00 summary: gh-84538: add strict argument to pathlib.PurePath.relative_to (GH-19813) By default, :meth:`pathlib.PurePath.relative_to` doesn't deal with paths that are not a direct prefix of the other, raising an exception in that instance. This change adds a *walk_up* parameter that can be set to allow for using ``..`` to calculate the relative path. example: ``` >>> p = PurePosixPath('/etc/passwd') >>> p.relative_to('/etc') PurePosixPath('passwd') >>> p.relative_to('/usr') Traceback (most recent call last): File "", line 1, in File "pathlib.py", line 940, in relative_to raise ValueError(error_message.format(str(self), str(formatted))) ValueError: '/etc/passwd' does not start with '/usr' >>> p.relative_to('/usr', strict=False) PurePosixPath('../etc/passwd') ``` https://bugs.python.org/issue40358 Automerge-Triggered-By: GH:brettcannon files: A Misc/NEWS.d/next/Library/2020-04-30-02-15-08.bpo-40358.A4ygqe.rst M Doc/library/pathlib.rst M Doc/whatsnew/3.12.rst M Lib/pathlib.py M Lib/test/test_pathlib.py M Misc/ACKS diff --git a/Doc/library/pathlib.rst b/Doc/library/pathlib.rst index 4e9ea39895b4..a6daca9789a3 100644 --- a/Doc/library/pathlib.rst +++ b/Doc/library/pathlib.rst @@ -564,10 +564,10 @@ Pure paths provide the following methods and properties: True -.. method:: PurePath.relative_to(*other) +.. method:: PurePath.relative_to(*other, walk_up=False) Compute a version of this path relative to the path represented by - *other*. If it's impossible, ValueError is raised:: + *other*. If it's impossible, :exc:`ValueError` is raised:: >>> p = PurePosixPath('/etc/passwd') >>> p.relative_to('/') @@ -577,11 +577,33 @@ Pure paths provide the following methods and properties: >>> p.relative_to('/usr') Traceback (most recent call last): File "", line 1, in - File "pathlib.py", line 694, in relative_to - .format(str(self), str(formatted))) - ValueError: '/etc/passwd' is not in the subpath of '/usr' OR one path is relative and the other absolute. + File "pathlib.py", line 941, in relative_to + raise ValueError(error_message.format(str(self), str(formatted))) + ValueError: '/etc/passwd' is not in the subpath of '/usr' OR one path is relative and the other is absolute. + +When *walk_up* is False (the default), the path must start with *other*. + When the argument is True, ``..`` entries may be added to form the + relative path. In all other cases, such as the paths referencing + different drives, :exc:`ValueError` is raised.:: + + >>> p.relative_to('/usr', walk_up=True) + PurePosixPath('../etc/passwd') + >>> p.relative_to('foo', walk_up=True) + Traceback (most recent call last): + File "", line 1, in + File "pathlib.py", line 941, in relative_to + raise ValueError(error_message.format(str(self), str(formatted))) + ValueError: '/etc/passwd' is not on the same drive as 'foo' OR one path is relative and the other is absolute. - NOTE: This function is part of :class:`PurePath` and works with strings. It does not check or access the underlying file structure. + .. warning:: + This function is part of :class:`PurePath` and works with strings. + It does not check or access the underlying file structure. + This can impact the *walk_up* option as it assumes that no symlinks + are present in the path; call :meth:`~Path.resolve` first if + necessary to resolve symlinks. + + .. versionadded:: 3.12 + The *walk_up* argument (old behavior is the same as ``walk_up=False``). .. method:: PurePath.with_name(name) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 39ad3ac7118b..0eb28799a4f5 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -149,6 +149,11 @@ pathlib all file or directory names within them, similar to :func:`os.walk`. (Contributed by Stanislav Zmiev in :gh:`90385`.) +* Add *walk_up* optional parameter to :meth:`pathlib.PurePath.relative_to` + to allow the insertion of ``..`` entries in the result; this behavior is + more consistent with :func:`os.path.relpath`. + (Contributed by Domenico Ragusa in :issue:`40358`.) + dis --- diff --git a/Lib/pathlib.py b/Lib/pathlib.py index 0ea621cc6010..1498ce08be40 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -626,10 +626,13 @@ def with_suffix(self, suffix): return self._from_parsed_parts(self._drv, self._root, self._parts[:-1] + [name]) - def relative_to(self, *other): + def relative_to(self, *other, walk_up=False): """Return the relative path to another path identified by the passed arguments. If the operation is not possible (because this is not - a subpath of the other path), raise ValueError. + related to the other path), raise ValueError. + + The *walk_up* parameter controls whether `..` may be used to resolve + the path. """ # For the purpose of this method, drive and root are considered # separate parts, i.e.: @@ -644,20 +647,35 @@ def relative_to(self, *other): abs_parts = [drv, root] + parts[1:] else: abs_parts = parts - to_drv, to_root, to_parts = self._parse_args(other) - if to_root: - to_abs_parts = [to_drv, to_root] + to_parts[1:] + other_drv, other_root, other_parts = self._parse_args(other) + if other_root: + other_abs_parts = [other_drv, other_root] + other_parts[1:] + else: + other_abs_parts = other_parts + num_parts = len(other_abs_parts) + casefold = self._flavour.casefold_parts + num_common_parts = 0 + for part, other_part in zip(casefold(abs_parts), casefold(other_abs_parts)): + if part != other_part: + break + num_common_parts += 1 + if walk_up: + failure = root != other_root + if drv or other_drv: + failure = casefold([drv]) != casefold([other_drv]) or (failure and num_parts > 1) + error_message = "{!r} is not on the same drive as {!r}" + up_parts = (num_parts-num_common_parts)*['..'] else: - to_abs_parts = to_parts - n = len(to_abs_parts) - cf = self._flavour.casefold_parts - if (root or drv) if n == 0 else cf(abs_parts[:n]) != cf(to_abs_parts): - formatted = self._format_parsed_parts(to_drv, to_root, to_parts) - raise ValueError("{!r} is not in the subpath of {!r}" - " OR one path is relative and the other is absolute." - .format(str(self), str(formatted))) - return self._from_parsed_parts('', root if n == 1 else '', - abs_parts[n:]) + failure = (root or drv) if num_parts == 0 else num_common_parts != num_parts + error_message = "{!r} is not in the subpath of {!r}" + up_parts = [] + error_message += " OR one path is relative and the other is absolute." + if failure: + formatted = self._format_parsed_parts(other_drv, other_root, other_parts) + raise ValueError(error_message.format(str(self), str(formatted))) + path_parts = up_parts + abs_parts[num_common_parts:] + new_root = root if num_common_parts == 1 else '' + return self._from_parsed_parts('', new_root, path_parts) def is_relative_to(self, *other): """Return True if the path is relative to another path or False. diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index f324177ff855..3b1f302cc964 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -640,13 +640,29 @@ def test_relative_to_common(self): self.assertEqual(p.relative_to('a/'), P('b')) self.assertEqual(p.relative_to(P('a/b')), P()) self.assertEqual(p.relative_to('a/b'), P()) + self.assertEqual(p.relative_to(P(), walk_up=True), P('a/b')) + self.assertEqual(p.relative_to('', walk_up=True), P('a/b')) + self.assertEqual(p.relative_to(P('a'), walk_up=True), P('b')) + self.assertEqual(p.relative_to('a', walk_up=True), P('b')) + self.assertEqual(p.relative_to('a/', walk_up=True), P('b')) + self.assertEqual(p.relative_to(P('a/b'), walk_up=True), P()) + self.assertEqual(p.relative_to('a/b', walk_up=True), P()) + self.assertEqual(p.relative_to(P('a/c'), walk_up=True), P('../b')) + self.assertEqual(p.relative_to('a/c', walk_up=True), P('../b')) + self.assertEqual(p.relative_to(P('a/b/c'), walk_up=True), P('..')) + self.assertEqual(p.relative_to('a/b/c', walk_up=True), P('..')) + self.assertEqual(p.relative_to(P('c'), walk_up=True), P('../a/b')) + self.assertEqual(p.relative_to('c', walk_up=True), P('../a/b')) # With several args. self.assertEqual(p.relative_to('a', 'b'), P()) + self.assertEqual(p.relative_to('a', 'b', walk_up=True), P()) # Unrelated paths. self.assertRaises(ValueError, p.relative_to, P('c')) self.assertRaises(ValueError, p.relative_to, P('a/b/c')) self.assertRaises(ValueError, p.relative_to, P('a/c')) self.assertRaises(ValueError, p.relative_to, P('/a')) + self.assertRaises(ValueError, p.relative_to, P('/'), walk_up=True) + self.assertRaises(ValueError, p.relative_to, P('/a'), walk_up=True) p = P('/a/b') self.assertEqual(p.relative_to(P('/')), P('a/b')) self.assertEqual(p.relative_to('/'), P('a/b')) @@ -655,6 +671,19 @@ def test_relative_to_common(self): self.assertEqual(p.relative_to('/a/'), P('b')) self.assertEqual(p.relative_to(P('/a/b')), P()) self.assertEqual(p.relative_to('/a/b'), P()) + self.assertEqual(p.relative_to(P('/'), walk_up=True), P('a/b')) + self.assertEqual(p.relative_to('/', walk_up=True), P('a/b')) + self.assertEqual(p.relative_to(P('/a'), walk_up=True), P('b')) + self.assertEqual(p.relative_to('/a', walk_up=True), P('b')) + self.assertEqual(p.relative_to('/a/', walk_up=True), P('b')) + self.assertEqual(p.relative_to(P('/a/b'), walk_up=True), P()) + self.assertEqual(p.relative_to('/a/b', walk_up=True), P()) + self.assertEqual(p.relative_to(P('/a/c'), walk_up=True), P('../b')) + self.assertEqual(p.relative_to('/a/c', walk_up=True), P('../b')) + self.assertEqual(p.relative_to(P('/a/b/c'), walk_up=True), P('..')) + self.assertEqual(p.relative_to('/a/b/c', walk_up=True), P('..')) + self.assertEqual(p.relative_to(P('/c'), walk_up=True), P('../a/b')) + self.assertEqual(p.relative_to('/c', walk_up=True), P('../a/b')) # Unrelated paths. self.assertRaises(ValueError, p.relative_to, P('/c')) self.assertRaises(ValueError, p.relative_to, P('/a/b/c')) @@ -662,6 +691,8 @@ def test_relative_to_common(self): self.assertRaises(ValueError, p.relative_to, P()) self.assertRaises(ValueError, p.relative_to, '') self.assertRaises(ValueError, p.relative_to, P('a')) + self.assertRaises(ValueError, p.relative_to, P(''), walk_up=True) + self.assertRaises(ValueError, p.relative_to, P('a'), walk_up=True) def test_is_relative_to_common(self): P = self.cls @@ -1124,6 +1155,16 @@ def test_relative_to(self): self.assertEqual(p.relative_to('c:foO/'), P('Bar')) self.assertEqual(p.relative_to(P('c:foO/baR')), P()) self.assertEqual(p.relative_to('c:foO/baR'), P()) + self.assertEqual(p.relative_to(P('c:'), walk_up=True), P('Foo/Bar')) + self.assertEqual(p.relative_to('c:', walk_up=True), P('Foo/Bar')) + self.assertEqual(p.relative_to(P('c:foO'), walk_up=True), P('Bar')) + self.assertEqual(p.relative_to('c:foO', walk_up=True), P('Bar')) + self.assertEqual(p.relative_to('c:foO/', walk_up=True), P('Bar')) + self.assertEqual(p.relative_to(P('c:foO/baR'), walk_up=True), P()) + self.assertEqual(p.relative_to('c:foO/baR', walk_up=True), P()) + self.assertEqual(p.relative_to(P('C:Foo/Bar/Baz'), walk_up=True), P('..')) + self.assertEqual(p.relative_to(P('C:Foo/Baz'), walk_up=True), P('../Bar')) + self.assertEqual(p.relative_to(P('C:Baz/Bar'), walk_up=True), P('../../Foo/Bar')) # Unrelated paths. self.assertRaises(ValueError, p.relative_to, P()) self.assertRaises(ValueError, p.relative_to, '') @@ -1134,6 +1175,13 @@ def test_relative_to(self): self.assertRaises(ValueError, p.relative_to, P('C:/Foo')) self.assertRaises(ValueError, p.relative_to, P('C:Foo/Bar/Baz')) self.assertRaises(ValueError, p.relative_to, P('C:Foo/Baz')) + self.assertRaises(ValueError, p.relative_to, P(), walk_up=True) + self.assertRaises(ValueError, p.relative_to, '', walk_up=True) + self.assertRaises(ValueError, p.relative_to, P('d:'), walk_up=True) + self.assertRaises(ValueError, p.relative_to, P('/'), walk_up=True) + self.assertRaises(ValueError, p.relative_to, P('Foo'), walk_up=True) + self.assertRaises(ValueError, p.relative_to, P('/Foo'), walk_up=True) + self.assertRaises(ValueError, p.relative_to, P('C:/Foo'), walk_up=True) p = P('C:/Foo/Bar') self.assertEqual(p.relative_to(P('c:')), P('/Foo/Bar')) self.assertEqual(p.relative_to('c:'), P('/Foo/Bar')) @@ -1146,6 +1194,20 @@ def test_relative_to(self): self.assertEqual(p.relative_to('c:/foO/'), P('Bar')) self.assertEqual(p.relative_to(P('c:/foO/baR')), P()) self.assertEqual(p.relative_to('c:/foO/baR'), P()) + self.assertEqual(p.relative_to(P('c:'), walk_up=True), P('/Foo/Bar')) + self.assertEqual(p.relative_to('c:', walk_up=True), P('/Foo/Bar')) + self.assertEqual(str(p.relative_to(P('c:'), walk_up=True)), '\\Foo\\Bar') + self.assertEqual(str(p.relative_to('c:', walk_up=True)), '\\Foo\\Bar') + self.assertEqual(p.relative_to(P('c:/'), walk_up=True), P('Foo/Bar')) + self.assertEqual(p.relative_to('c:/', walk_up=True), P('Foo/Bar')) + self.assertEqual(p.relative_to(P('c:/foO'), walk_up=True), P('Bar')) + self.assertEqual(p.relative_to('c:/foO', walk_up=True), P('Bar')) + self.assertEqual(p.relative_to('c:/foO/', walk_up=True), P('Bar')) + self.assertEqual(p.relative_to(P('c:/foO/baR'), walk_up=True), P()) + self.assertEqual(p.relative_to('c:/foO/baR', walk_up=True), P()) + self.assertEqual(p.relative_to('C:/Baz', walk_up=True), P('../Foo/Bar')) + self.assertEqual(p.relative_to('C:/Foo/Bar/Baz', walk_up=True), P('..')) + self.assertEqual(p.relative_to('C:/Foo/Baz', walk_up=True), P('../Bar')) # Unrelated paths. self.assertRaises(ValueError, p.relative_to, P('C:/Baz')) self.assertRaises(ValueError, p.relative_to, P('C:/Foo/Bar/Baz')) @@ -1156,6 +1218,12 @@ def test_relative_to(self): self.assertRaises(ValueError, p.relative_to, P('/')) self.assertRaises(ValueError, p.relative_to, P('/Foo')) self.assertRaises(ValueError, p.relative_to, P('//C/Foo')) + self.assertRaises(ValueError, p.relative_to, P('C:Foo'), walk_up=True) + self.assertRaises(ValueError, p.relative_to, P('d:'), walk_up=True) + self.assertRaises(ValueError, p.relative_to, P('d:/'), walk_up=True) + self.assertRaises(ValueError, p.relative_to, P('/'), walk_up=True) + self.assertRaises(ValueError, p.relative_to, P('/Foo'), walk_up=True) + self.assertRaises(ValueError, p.relative_to, P('//C/Foo'), walk_up=True) # UNC paths. p = P('//Server/Share/Foo/Bar') self.assertEqual(p.relative_to(P('//sErver/sHare')), P('Foo/Bar')) @@ -1166,11 +1234,25 @@ def test_relative_to(self): self.assertEqual(p.relative_to('//sErver/sHare/Foo/'), P('Bar')) self.assertEqual(p.relative_to(P('//sErver/sHare/Foo/Bar')), P()) self.assertEqual(p.relative_to('//sErver/sHare/Foo/Bar'), P()) + self.assertEqual(p.relative_to(P('//sErver/sHare'), walk_up=True), P('Foo/Bar')) + self.assertEqual(p.relative_to('//sErver/sHare', walk_up=True), P('Foo/Bar')) + self.assertEqual(p.relative_to('//sErver/sHare/', walk_up=True), P('Foo/Bar')) + self.assertEqual(p.relative_to(P('//sErver/sHare/Foo'), walk_up=True), P('Bar')) + self.assertEqual(p.relative_to('//sErver/sHare/Foo', walk_up=True), P('Bar')) + self.assertEqual(p.relative_to('//sErver/sHare/Foo/', walk_up=True), P('Bar')) + self.assertEqual(p.relative_to(P('//sErver/sHare/Foo/Bar'), walk_up=True), P()) + self.assertEqual(p.relative_to('//sErver/sHare/Foo/Bar', walk_up=True), P()) + self.assertEqual(p.relative_to(P('//sErver/sHare/bar'), walk_up=True), P('../Foo/Bar')) + self.assertEqual(p.relative_to('//sErver/sHare/bar', walk_up=True), P('../Foo/Bar')) # Unrelated paths. self.assertRaises(ValueError, p.relative_to, P('/Server/Share/Foo')) self.assertRaises(ValueError, p.relative_to, P('c:/Server/Share/Foo')) self.assertRaises(ValueError, p.relative_to, P('//z/Share/Foo')) self.assertRaises(ValueError, p.relative_to, P('//Server/z/Foo')) + self.assertRaises(ValueError, p.relative_to, P('/Server/Share/Foo'), walk_up=True) + self.assertRaises(ValueError, p.relative_to, P('c:/Server/Share/Foo'), walk_up=True) + self.assertRaises(ValueError, p.relative_to, P('//z/Share/Foo'), walk_up=True) + self.assertRaises(ValueError, p.relative_to, P('//Server/z/Foo'), walk_up=True) def test_is_relative_to(self): P = self.cls diff --git a/Misc/ACKS b/Misc/ACKS index 985314851573..5d97067b85d3 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1440,6 +1440,7 @@ Pierre Quentel Brian Quinlan Anders Qvist Thomas Rachel +Domenico Ragusa Ram Rachum Jeffrey Rackauckas J?r?me Radix diff --git a/Misc/NEWS.d/next/Library/2020-04-30-02-15-08.bpo-40358.A4ygqe.rst b/Misc/NEWS.d/next/Library/2020-04-30-02-15-08.bpo-40358.A4ygqe.rst new file mode 100644 index 000000000000..a2815f54b031 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-04-30-02-15-08.bpo-40358.A4ygqe.rst @@ -0,0 +1 @@ +Add walk_up argument in :meth:`pathlib.PurePath.relative_to`. From webhook-mailer at python.org Fri Oct 28 19:31:43 2022 From: webhook-mailer at python.org (miss-islington) Date: Fri, 28 Oct 2022 23:31:43 -0000 Subject: [Python-checkins] gh-98240: Updated Path.rename docs, when it is atomic (GH-98245) Message-ID: https://github.com/python/cpython/commit/0023f51debeeeef483a6362ee12d67c4da086af3 commit: 0023f51debeeeef483a6362ee12d67c4da086af3 branch: main author: Mateusz committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-28T16:31:37-07:00 summary: gh-98240: Updated Path.rename docs, when it is atomic (GH-98245) files: M Doc/library/pathlib.rst diff --git a/Doc/library/pathlib.rst b/Doc/library/pathlib.rst index a6daca9789a3..944963e1e1ae 100644 --- a/Doc/library/pathlib.rst +++ b/Doc/library/pathlib.rst @@ -1186,6 +1186,8 @@ call fails (for example because the path doesn't exist). relative to the current working directory, *not* the directory of the Path object. + It is implemented in terms of :func:`os.rename` and gives the same guarantees. + .. versionchanged:: 3.8 Added return value, return the new Path instance. From webhook-mailer at python.org Sat Oct 29 01:46:06 2022 From: webhook-mailer at python.org (gpshead) Date: Sat, 29 Oct 2022 05:46:06 -0000 Subject: [Python-checkins] gh-98286: handle empty filename in ZipFile/ZipInfo properly (#98346) Message-ID: https://github.com/python/cpython/commit/7ea10567afe38e7770e82b4642c0b01659acaad5 commit: 7ea10567afe38e7770e82b4642c0b01659acaad5 branch: main author: FC Stegerman committer: gpshead date: 2022-10-28T22:45:46-07:00 summary: gh-98286: handle empty filename in ZipFile/ZipInfo properly (#98346) effectively code modernization and a meaningful exception. files: M Lib/zipfile.py diff --git a/Lib/zipfile.py b/Lib/zipfile.py index b6465373c107..77b643caf9fc 100644 --- a/Lib/zipfile.py +++ b/Lib/zipfile.py @@ -553,7 +553,7 @@ def from_file(cls, filename, arcname=None, *, strict_timestamps=True): def is_dir(self): """Return True if this archive member is a directory.""" - return self.filename[-1] == '/' + return self.filename.endswith('/') # ZIP encryption uses the CRC32 one-byte primitive for scrambling some @@ -1731,6 +1731,9 @@ def _extract_member(self, member, targetpath, pwd): # filter illegal characters on Windows arcname = self._sanitize_windows_name(arcname, os.path.sep) + if not arcname: + raise ValueError("Empty filename.") + targetpath = os.path.join(targetpath, arcname) targetpath = os.path.normpath(targetpath) @@ -1820,7 +1823,7 @@ def writestr(self, zinfo_or_arcname, data, date_time=time.localtime(time.time())[:6]) zinfo.compress_type = self.compression zinfo._compresslevel = self.compresslevel - if zinfo.filename[-1] == '/': + if zinfo.filename.endswith('/'): zinfo.external_attr = 0o40775 << 16 # drwxrwxr-x zinfo.external_attr |= 0x10 # MS-DOS directory flag else: From webhook-mailer at python.org Sat Oct 29 08:28:25 2022 From: webhook-mailer at python.org (pablogsal) Date: Sat, 29 Oct 2022 12:28:25 -0000 Subject: [Python-checkins] gh-98744: Prevent column-level decoding crashes on traceback module (#98824) Message-ID: https://github.com/python/cpython/commit/c0f2a5ef9125f2b44b32cab92e1b0b1bfe0e3fdc commit: c0f2a5ef9125f2b44b32cab92e1b0b1bfe0e3fdc branch: main author: Batuhan Taskaya committer: pablogsal date: 2022-10-29T13:28:20+01:00 summary: gh-98744: Prevent column-level decoding crashes on traceback module (#98824) files: A Misc/NEWS.d/next/Library/2022-10-28-23-44-17.gh-issue-98744.sGHDWm.rst M Lib/test/test_traceback.py M Lib/traceback.py diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index cf52d17ff8fa..56b168735d15 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -804,6 +804,56 @@ def f(): ] self.assertEqual(actual, expected) + def test_wide_characters_unicode_with_problematic_byte_offset(self): + def f(): + ????? + + actual = self.get_exception(f) + expected = [ + f"Traceback (most recent call last):", + f" File \"{__file__}\", line {self.callable_line}, in get_exception", + f" callable()", + f" File \"{__file__}\", line {f.__code__.co_firstlineno + 1}, in f", + f" ?????", + ] + self.assertEqual(actual, expected) + + + def test_byte_offset_with_wide_characters_middle(self): + def f(): + ????? = 1 + raise ValueError(?????) + + actual = self.get_exception(f) + expected = [ + f"Traceback (most recent call last):", + f" File \"{__file__}\", line {self.callable_line}, in get_exception", + f" callable()", + f" File \"{__file__}\", line {f.__code__.co_firstlineno + 2}, in f", + f" raise ValueError(?????)", + ] + self.assertEqual(actual, expected) + + def test_byte_offset_multiline(self): + def f(): + ??? = 1 + ?? = 0 + + print(1, ???( + ??)) + + actual = self.get_exception(f) + expected = [ + f"Traceback (most recent call last):", + f" File \"{__file__}\", line {self.callable_line}, in get_exception", + f" callable()", + f" File \"{__file__}\", line {f.__code__.co_firstlineno + 4}, in f", + f" print(1, ???(", + f" ^^^^", + ] + self.assertEqual(actual, expected) + + @requires_debug_ranges() class PurePythonTracebackErrorCaretTests( diff --git a/Lib/traceback.py b/Lib/traceback.py index 6270100348a6..0f0f2b317de2 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -476,32 +476,32 @@ def format_frame_summary(self, frame_summary): frame_summary.colno is not None and frame_summary.end_colno is not None ): - colno = _byte_offset_to_character_offset( - frame_summary._original_line, frame_summary.colno) - end_colno = _byte_offset_to_character_offset( - frame_summary._original_line, frame_summary.end_colno) + start_offset = _byte_offset_to_character_offset( + frame_summary._original_line, frame_summary.colno) + 1 + end_offset = _byte_offset_to_character_offset( + frame_summary._original_line, frame_summary.end_colno) + 1 anchors = None if frame_summary.lineno == frame_summary.end_lineno: with suppress(Exception): anchors = _extract_caret_anchors_from_line_segment( - frame_summary._original_line[colno - 1:end_colno - 1] + frame_summary._original_line[start_offset - 1:end_offset - 1] ) else: - end_colno = stripped_characters + len(stripped_line) + end_offset = stripped_characters + len(stripped_line) # show indicators if primary char doesn't span the frame line - if end_colno - colno < len(stripped_line) or ( + if end_offset - start_offset < len(stripped_line) or ( anchors and anchors.right_start_offset - anchors.left_end_offset > 0): row.append(' ') - row.append(' ' * (colno - stripped_characters)) + row.append(' ' * (start_offset - stripped_characters)) if anchors: row.append(anchors.primary_char * (anchors.left_end_offset)) row.append(anchors.secondary_char * (anchors.right_start_offset - anchors.left_end_offset)) - row.append(anchors.primary_char * (end_colno - colno - anchors.right_start_offset)) + row.append(anchors.primary_char * (end_offset - start_offset - anchors.right_start_offset)) else: - row.append('^' * (end_colno - colno)) + row.append('^' * (end_offset - start_offset)) row.append('\n') @@ -561,10 +561,7 @@ def format(self): def _byte_offset_to_character_offset(str, offset): as_utf8 = str.encode('utf-8') - if offset > len(as_utf8): - offset = len(as_utf8) - - return len(as_utf8[:offset + 1].decode("utf-8")) + return len(as_utf8[:offset].decode("utf-8", errors="replace")) _Anchors = collections.namedtuple( diff --git a/Misc/NEWS.d/next/Library/2022-10-28-23-44-17.gh-issue-98744.sGHDWm.rst b/Misc/NEWS.d/next/Library/2022-10-28-23-44-17.gh-issue-98744.sGHDWm.rst new file mode 100644 index 000000000000..cf99ea51bf7c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-28-23-44-17.gh-issue-98744.sGHDWm.rst @@ -0,0 +1,2 @@ +Prevent crashing in :mod:`traceback` when retrieving the byte-offset for +some source files that contain certain unicode characters. From webhook-mailer at python.org Sat Oct 29 10:12:21 2022 From: webhook-mailer at python.org (pablogsal) Date: Sat, 29 Oct 2022 14:12:21 -0000 Subject: [Python-checkins] [3.11] gh-98744: Prevent column-level decoding crashes on traceback module (#98850) Message-ID: https://github.com/python/cpython/commit/751da28febfb0d01ddb8a9b4cb3256386e5f6a81 commit: 751da28febfb0d01ddb8a9b4cb3256386e5f6a81 branch: 3.11 author: Batuhan Taskaya committer: pablogsal date: 2022-10-29T15:12:15+01:00 summary: [3.11] gh-98744: Prevent column-level decoding crashes on traceback module (#98850) Co-authored-by: Batuhan Taskaya files: A Misc/NEWS.d/next/Library/2022-10-28-23-44-17.gh-issue-98744.sGHDWm.rst M Lib/test/test_traceback.py M Lib/traceback.py diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 94ccc3f48d3e..6d155006568b 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -778,6 +778,56 @@ def f(): ] self.assertEqual(actual, expected) + def test_wide_characters_unicode_with_problematic_byte_offset(self): + def f(): + ????? + + actual = self.get_exception(f) + expected = [ + f"Traceback (most recent call last):", + f" File \"{__file__}\", line {self.callable_line}, in get_exception", + f" callable()", + f" File \"{__file__}\", line {f.__code__.co_firstlineno + 1}, in f", + f" ?????", + ] + self.assertEqual(actual, expected) + + + def test_byte_offset_with_wide_characters_middle(self): + def f(): + ????? = 1 + raise ValueError(?????) + + actual = self.get_exception(f) + expected = [ + f"Traceback (most recent call last):", + f" File \"{__file__}\", line {self.callable_line}, in get_exception", + f" callable()", + f" File \"{__file__}\", line {f.__code__.co_firstlineno + 2}, in f", + f" raise ValueError(?????)", + ] + self.assertEqual(actual, expected) + + def test_byte_offset_multiline(self): + def f(): + ??? = 1 + ?? = 0 + + print(1, ???( + ??)) + + actual = self.get_exception(f) + expected = [ + f"Traceback (most recent call last):", + f" File \"{__file__}\", line {self.callable_line}, in get_exception", + f" callable()", + f" File \"{__file__}\", line {f.__code__.co_firstlineno + 4}, in f", + f" print(1, ???(", + f" ^^^^", + ] + self.assertEqual(actual, expected) + + @cpython_only @requires_debug_ranges() class CPythonTracebackErrorCaretTests(TracebackErrorLocationCaretTests): diff --git a/Lib/traceback.py b/Lib/traceback.py index 55f808004405..fa2cc341aff3 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -475,32 +475,32 @@ def format_frame_summary(self, frame_summary): frame_summary.colno is not None and frame_summary.end_colno is not None ): - colno = _byte_offset_to_character_offset( - frame_summary._original_line, frame_summary.colno) - end_colno = _byte_offset_to_character_offset( - frame_summary._original_line, frame_summary.end_colno) + start_offset = _byte_offset_to_character_offset( + frame_summary._original_line, frame_summary.colno) + 1 + end_offset = _byte_offset_to_character_offset( + frame_summary._original_line, frame_summary.end_colno) + 1 anchors = None if frame_summary.lineno == frame_summary.end_lineno: with suppress(Exception): anchors = _extract_caret_anchors_from_line_segment( - frame_summary._original_line[colno - 1:end_colno - 1] + frame_summary._original_line[start_offset - 1:end_offset - 1] ) else: - end_colno = stripped_characters + len(stripped_line) + end_offset = stripped_characters + len(stripped_line) # show indicators if primary char doesn't span the frame line - if end_colno - colno < len(stripped_line) or ( + if end_offset - start_offset < len(stripped_line) or ( anchors and anchors.right_start_offset - anchors.left_end_offset > 0): row.append(' ') - row.append(' ' * (colno - stripped_characters)) + row.append(' ' * (start_offset - stripped_characters)) if anchors: row.append(anchors.primary_char * (anchors.left_end_offset)) row.append(anchors.secondary_char * (anchors.right_start_offset - anchors.left_end_offset)) - row.append(anchors.primary_char * (end_colno - colno - anchors.right_start_offset)) + row.append(anchors.primary_char * (end_offset - start_offset - anchors.right_start_offset)) else: - row.append('^' * (end_colno - colno)) + row.append('^' * (end_offset - start_offset)) row.append('\n') @@ -560,10 +560,7 @@ def format(self): def _byte_offset_to_character_offset(str, offset): as_utf8 = str.encode('utf-8') - if offset > len(as_utf8): - offset = len(as_utf8) - - return len(as_utf8[:offset + 1].decode("utf-8")) + return len(as_utf8[:offset].decode("utf-8", errors="replace")) _Anchors = collections.namedtuple( diff --git a/Misc/NEWS.d/next/Library/2022-10-28-23-44-17.gh-issue-98744.sGHDWm.rst b/Misc/NEWS.d/next/Library/2022-10-28-23-44-17.gh-issue-98744.sGHDWm.rst new file mode 100644 index 000000000000..cf99ea51bf7c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-28-23-44-17.gh-issue-98744.sGHDWm.rst @@ -0,0 +1,2 @@ +Prevent crashing in :mod:`traceback` when retrieving the byte-offset for +some source files that contain certain unicode characters. From webhook-mailer at python.org Sat Oct 29 12:43:47 2022 From: webhook-mailer at python.org (gvanrossum) Date: Sat, 29 Oct 2022 16:43:47 -0000 Subject: [Python-checkins] GH-90352: fix _SelectorDatagramTransport to inherit from DatagramTransport (#98844) Message-ID: https://github.com/python/cpython/commit/9bdec0aa4516650e51b998418fb6188427137fed commit: 9bdec0aa4516650e51b998418fb6188427137fed branch: main author: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> committer: gvanrossum date: 2022-10-29T09:43:42-07:00 summary: GH-90352: fix _SelectorDatagramTransport to inherit from DatagramTransport (#98844) files: A Misc/NEWS.d/next/Library/2022-10-29-09-42-20.gh-issue-90352.t8QEPt.rst M Lib/asyncio/selector_events.py M Lib/test/test_asyncio/test_selector_events.py diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py index d2ee49dd88f8..bfa4590154f3 100644 --- a/Lib/asyncio/selector_events.py +++ b/Lib/asyncio/selector_events.py @@ -1126,7 +1126,7 @@ def _reset_empty_waiter(self): self._empty_waiter = None -class _SelectorDatagramTransport(_SelectorTransport): +class _SelectorDatagramTransport(_SelectorTransport, transports.DatagramTransport): _buffer_factory = collections.deque diff --git a/Lib/test/test_asyncio/test_selector_events.py b/Lib/test/test_asyncio/test_selector_events.py index 796037bcf59c..ca555387dd24 100644 --- a/Lib/test/test_asyncio/test_selector_events.py +++ b/Lib/test/test_asyncio/test_selector_events.py @@ -1081,6 +1081,10 @@ def test_read_ready(self): self.protocol.datagram_received.assert_called_with( b'data', ('0.0.0.0', 1234)) + def test_transport_inheritance(self): + transport = self.datagram_transport() + self.assertIsInstance(transport, asyncio.DatagramTransport) + def test_read_ready_tryagain(self): transport = self.datagram_transport() diff --git a/Misc/NEWS.d/next/Library/2022-10-29-09-42-20.gh-issue-90352.t8QEPt.rst b/Misc/NEWS.d/next/Library/2022-10-29-09-42-20.gh-issue-90352.t8QEPt.rst new file mode 100644 index 000000000000..8e80eae512e6 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-29-09-42-20.gh-issue-90352.t8QEPt.rst @@ -0,0 +1 @@ +Fix ``_SelectorDatagramTransport`` to inherit from :class:`~asyncio.DatagramTransport` in :mod:`asyncio`. Patch by Kumar Aditya. From webhook-mailer at python.org Sat Oct 29 13:06:57 2022 From: webhook-mailer at python.org (AlexWaygood) Date: Sat, 29 Oct 2022 17:06:57 -0000 Subject: [Python-checkins] dataclasses docs: consistent indentation (4 spaces) in examples (#98855) Message-ID: https://github.com/python/cpython/commit/d10c2b97428bd07827f7bac4515d41ac08be7481 commit: d10c2b97428bd07827f7bac4515d41ac08be7481 branch: main author: FC Stegerman committer: AlexWaygood date: 2022-10-29T18:06:52+01:00 summary: dataclasses docs: consistent indentation (4 spaces) in examples (#98855) files: M Doc/library/dataclasses.rst diff --git a/Doc/library/dataclasses.rst b/Doc/library/dataclasses.rst index ab8df8b02c5f..c4895aa822bf 100644 --- a/Doc/library/dataclasses.rst +++ b/Doc/library/dataclasses.rst @@ -81,7 +81,7 @@ Module contents @dataclass(init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False, match_args=True, kw_only=False, slots=False, weakref_slot=False) class C: - ... + ... The parameters to :func:`dataclass` are: @@ -482,10 +482,10 @@ Module contents @dataclass class Point: - x: float - _: KW_ONLY - y: float - z: float + x: float + _: KW_ONLY + y: float + z: float p = Point(0, y=1.5, z=2.0) @@ -773,24 +773,24 @@ default value have the following special behaviors: :: class IntConversionDescriptor: - def __init__(self, *, default): - self._default = default + def __init__(self, *, default): + self._default = default - def __set_name__(self, owner, name): - self._name = "_" + name + def __set_name__(self, owner, name): + self._name = "_" + name - def __get__(self, obj, type): - if obj is None: - return self._default + def __get__(self, obj, type): + if obj is None: + return self._default - return getattr(obj, self._name, self._default) + return getattr(obj, self._name, self._default) - def __set__(self, obj, value): - setattr(obj, self._name, int(value)) + def __set__(self, obj, value): + setattr(obj, self._name, int(value)) @dataclass class InventoryItem: - quantity_on_hand: IntConversionDescriptor = IntConversionDescriptor(default=100) + quantity_on_hand: IntConversionDescriptor = IntConversionDescriptor(default=100) i = InventoryItem() print(i.quantity_on_hand) # 100 From webhook-mailer at python.org Sat Oct 29 13:15:22 2022 From: webhook-mailer at python.org (miss-islington) Date: Sat, 29 Oct 2022 17:15:22 -0000 Subject: [Python-checkins] dataclasses docs: consistent indentation (4 spaces) in examples (GH-98855) Message-ID: https://github.com/python/cpython/commit/e237bf6862eda71d0e7ac5ffba4626c234a7071a commit: e237bf6862eda71d0e7ac5ffba4626c234a7071a branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-29T10:15:16-07:00 summary: dataclasses docs: consistent indentation (4 spaces) in examples (GH-98855) (cherry picked from commit d10c2b97428bd07827f7bac4515d41ac08be7481) Co-authored-by: FC Stegerman files: M Doc/library/dataclasses.rst diff --git a/Doc/library/dataclasses.rst b/Doc/library/dataclasses.rst index ab8df8b02c5f..c4895aa822bf 100644 --- a/Doc/library/dataclasses.rst +++ b/Doc/library/dataclasses.rst @@ -81,7 +81,7 @@ Module contents @dataclass(init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False, match_args=True, kw_only=False, slots=False, weakref_slot=False) class C: - ... + ... The parameters to :func:`dataclass` are: @@ -482,10 +482,10 @@ Module contents @dataclass class Point: - x: float - _: KW_ONLY - y: float - z: float + x: float + _: KW_ONLY + y: float + z: float p = Point(0, y=1.5, z=2.0) @@ -773,24 +773,24 @@ default value have the following special behaviors: :: class IntConversionDescriptor: - def __init__(self, *, default): - self._default = default + def __init__(self, *, default): + self._default = default - def __set_name__(self, owner, name): - self._name = "_" + name + def __set_name__(self, owner, name): + self._name = "_" + name - def __get__(self, obj, type): - if obj is None: - return self._default + def __get__(self, obj, type): + if obj is None: + return self._default - return getattr(obj, self._name, self._default) + return getattr(obj, self._name, self._default) - def __set__(self, obj, value): - setattr(obj, self._name, int(value)) + def __set__(self, obj, value): + setattr(obj, self._name, int(value)) @dataclass class InventoryItem: - quantity_on_hand: IntConversionDescriptor = IntConversionDescriptor(default=100) + quantity_on_hand: IntConversionDescriptor = IntConversionDescriptor(default=100) i = InventoryItem() print(i.quantity_on_hand) # 100 From webhook-mailer at python.org Sat Oct 29 14:25:15 2022 From: webhook-mailer at python.org (AlexWaygood) Date: Sat, 29 Oct 2022 18:25:15 -0000 Subject: [Python-checkins] Fix comment typos in `_operator.c` (#98853) Message-ID: https://github.com/python/cpython/commit/1561e708c70c9fe6fdbaf8885a3ee4007715427e commit: 1561e708c70c9fe6fdbaf8885a3ee4007715427e branch: main author: David Buchanan committer: AlexWaygood date: 2022-10-29T19:25:09+01:00 summary: Fix comment typos in `_operator.c` (#98853) files: M Modules/_operator.c diff --git a/Modules/_operator.c b/Modules/_operator.c index 77eabdb57af9..3005845ec932 100644 --- a/Modules/_operator.c +++ b/Modules/_operator.c @@ -731,9 +731,9 @@ _operator_is_not_impl(PyObject *module, PyObject *a, PyObject *b) /* * timing safe compare * - * Returns 1 of the strings are equal. + * Returns 1 if the strings are equal. * In case of len(a) != len(b) the function tries to keep the timing - * dependent on the length of b. CPU cache locally may still alter timing + * dependent on the length of b. CPU cache locality may still alter timing * a bit. */ static int From webhook-mailer at python.org Sat Oct 29 14:46:48 2022 From: webhook-mailer at python.org (erlend-aasland) Date: Sat, 29 Oct 2022 18:46:48 -0000 Subject: [Python-checkins] gh-93358: Fix python-config docs for how to embed Python (#98649) Message-ID: https://github.com/python/cpython/commit/e063c23c65143a3afae3e201459dc0d52cb6fc96 commit: e063c23c65143a3afae3e201459dc0d52cb6fc96 branch: main author: Erlend E. Aasland committer: erlend-aasland date: 2022-10-29T20:46:34+02:00 summary: gh-93358: Fix python-config docs for how to embed Python (#98649) files: M Doc/extending/embedding.rst diff --git a/Doc/extending/embedding.rst b/Doc/extending/embedding.rst index 5f5abdf9c150..e64db3733440 100644 --- a/Doc/extending/embedding.rst +++ b/Doc/extending/embedding.rst @@ -298,16 +298,16 @@ be directly useful to you: .. code-block:: shell-session - $ /opt/bin/python3.4-config --cflags - -I/opt/include/python3.4m -I/opt/include/python3.4m -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes + $ /opt/bin/python3.11-config --cflags + -I/opt/include/python3.11 -I/opt/include/python3.11 -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -* ``pythonX.Y-config --ldflags`` will give you the recommended flags when - linking: +* ``pythonX.Y-config --ldflags --embed`` will give you the recommended flags + when linking: .. code-block:: shell-session - $ /opt/bin/python3.4-config --ldflags - -L/opt/lib/python3.4/config-3.4m -lpthread -ldl -lutil -lm -lpython3.4m -Xlinker -export-dynamic + $ /opt/bin/python3.11-config --ldflags --embed + -L/opt/lib/python3.11/config-3.11-x86_64-linux-gnu -L/opt/lib -lpython3.11 -lpthread -ldl -lutil -lm .. note:: To avoid confusion between several Python installations (and especially From webhook-mailer at python.org Sat Oct 29 14:53:59 2022 From: webhook-mailer at python.org (miss-islington) Date: Sat, 29 Oct 2022 18:53:59 -0000 Subject: [Python-checkins] gh-93358: Fix python-config docs for how to embed Python (GH-98649) Message-ID: https://github.com/python/cpython/commit/c76e70a409c8e744b5a306c8b2655173f8c69b7c commit: c76e70a409c8e744b5a306c8b2655173f8c69b7c branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-29T11:53:54-07:00 summary: gh-93358: Fix python-config docs for how to embed Python (GH-98649) (cherry picked from commit e063c23c65143a3afae3e201459dc0d52cb6fc96) Co-authored-by: Erlend E. Aasland files: M Doc/extending/embedding.rst diff --git a/Doc/extending/embedding.rst b/Doc/extending/embedding.rst index 5f5abdf9c150..e64db3733440 100644 --- a/Doc/extending/embedding.rst +++ b/Doc/extending/embedding.rst @@ -298,16 +298,16 @@ be directly useful to you: .. code-block:: shell-session - $ /opt/bin/python3.4-config --cflags - -I/opt/include/python3.4m -I/opt/include/python3.4m -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes + $ /opt/bin/python3.11-config --cflags + -I/opt/include/python3.11 -I/opt/include/python3.11 -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -* ``pythonX.Y-config --ldflags`` will give you the recommended flags when - linking: +* ``pythonX.Y-config --ldflags --embed`` will give you the recommended flags + when linking: .. code-block:: shell-session - $ /opt/bin/python3.4-config --ldflags - -L/opt/lib/python3.4/config-3.4m -lpthread -ldl -lutil -lm -lpython3.4m -Xlinker -export-dynamic + $ /opt/bin/python3.11-config --ldflags --embed + -L/opt/lib/python3.11/config-3.11-x86_64-linux-gnu -L/opt/lib -lpython3.11 -lpthread -ldl -lutil -lm .. note:: To avoid confusion between several Python installations (and especially From webhook-mailer at python.org Sat Oct 29 14:55:06 2022 From: webhook-mailer at python.org (miss-islington) Date: Sat, 29 Oct 2022 18:55:06 -0000 Subject: [Python-checkins] gh-93358: Fix python-config docs for how to embed Python (GH-98649) Message-ID: https://github.com/python/cpython/commit/f8fb0d8e77a0ed765170595a48ff058711eb7fd8 commit: f8fb0d8e77a0ed765170595a48ff058711eb7fd8 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-29T11:55:01-07:00 summary: gh-93358: Fix python-config docs for how to embed Python (GH-98649) (cherry picked from commit e063c23c65143a3afae3e201459dc0d52cb6fc96) Co-authored-by: Erlend E. Aasland files: M Doc/extending/embedding.rst diff --git a/Doc/extending/embedding.rst b/Doc/extending/embedding.rst index 5f5abdf9c150..e64db3733440 100644 --- a/Doc/extending/embedding.rst +++ b/Doc/extending/embedding.rst @@ -298,16 +298,16 @@ be directly useful to you: .. code-block:: shell-session - $ /opt/bin/python3.4-config --cflags - -I/opt/include/python3.4m -I/opt/include/python3.4m -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes + $ /opt/bin/python3.11-config --cflags + -I/opt/include/python3.11 -I/opt/include/python3.11 -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -* ``pythonX.Y-config --ldflags`` will give you the recommended flags when - linking: +* ``pythonX.Y-config --ldflags --embed`` will give you the recommended flags + when linking: .. code-block:: shell-session - $ /opt/bin/python3.4-config --ldflags - -L/opt/lib/python3.4/config-3.4m -lpthread -ldl -lutil -lm -lpython3.4m -Xlinker -export-dynamic + $ /opt/bin/python3.11-config --ldflags --embed + -L/opt/lib/python3.11/config-3.11-x86_64-linux-gnu -L/opt/lib -lpython3.11 -lpthread -ldl -lutil -lm .. note:: To avoid confusion between several Python installations (and especially From webhook-mailer at python.org Sat Oct 29 16:44:12 2022 From: webhook-mailer at python.org (rhettinger) Date: Sat, 29 Oct 2022 20:44:12 -0000 Subject: [Python-checkins] Fix typo in docs (GH-98863) Message-ID: https://github.com/python/cpython/commit/bfecff5f73741f095bb9ec2329467bf16cbbdf5a commit: bfecff5f73741f095bb9ec2329467bf16cbbdf5a branch: main author: Yuvi Panda committer: rhettinger date: 2022-10-29T15:44:06-05:00 summary: Fix typo in docs (GH-98863) files: M Doc/library/sys.rst diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 17bbfa50a2ed..f3fd16c4de75 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -1178,7 +1178,7 @@ always available. string, which means the current working directory. To not prepend this potentially unsafe path, use the :option:`-P` command - line option or the :envvar:`PYTHONSAFEPATH` environment variable? + line option or the :envvar:`PYTHONSAFEPATH` environment variable. A program is free to modify this list for its own purposes. Only strings should be added to :data:`sys.path`; all other data types are From webhook-mailer at python.org Sat Oct 29 16:56:32 2022 From: webhook-mailer at python.org (miss-islington) Date: Sat, 29 Oct 2022 20:56:32 -0000 Subject: [Python-checkins] Fix typo in docs (GH-98863) Message-ID: https://github.com/python/cpython/commit/d038307b109767f3ccb69d6a7bcd4ba8ac0cecf7 commit: d038307b109767f3ccb69d6a7bcd4ba8ac0cecf7 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-29T13:56:27-07:00 summary: Fix typo in docs (GH-98863) (cherry picked from commit bfecff5f73741f095bb9ec2329467bf16cbbdf5a) Co-authored-by: Yuvi Panda files: M Doc/library/sys.rst diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 542b08b1878e..0417d2752689 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -1178,7 +1178,7 @@ always available. string, which means the current working directory. To not prepend this potentially unsafe path, use the :option:`-P` command - line option or the :envvar:`PYTHONSAFEPATH` environment variable? + line option or the :envvar:`PYTHONSAFEPATH` environment variable. A program is free to modify this list for its own purposes. Only strings should be added to :data:`sys.path`; all other data types are From webhook-mailer at python.org Sat Oct 29 18:43:05 2022 From: webhook-mailer at python.org (miss-islington) Date: Sat, 29 Oct 2022 22:43:05 -0000 Subject: [Python-checkins] glossary.rst: Fix typo in package definition (GH-98865) Message-ID: https://github.com/python/cpython/commit/fc94d55ff453a3101e4c00a394d4e38ae2fece13 commit: fc94d55ff453a3101e4c00a394d4e38ae2fece13 branch: main author: ab committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-29T15:42:59-07:00 summary: glossary.rst: Fix typo in package definition (GH-98865) This is a tiny typo fix of package definition in glossary. According to https://devguide.python.org/documentation/help-documenting/ simple typos don?t require issues of their own, but, instead, a pull request can by submitted directly. Automerge-Triggered-By: GH:AlexWaygood files: M Doc/glossary.rst diff --git a/Doc/glossary.rst b/Doc/glossary.rst index 59f9426f6031..3d74d550dc34 100644 --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -882,7 +882,7 @@ Glossary package A Python :term:`module` which can contain submodules or recursively, - subpackages. Technically, a package is a Python module with an + subpackages. Technically, a package is a Python module with a ``__path__`` attribute. See also :term:`regular package` and :term:`namespace package`. From webhook-mailer at python.org Sat Oct 29 18:50:36 2022 From: webhook-mailer at python.org (miss-islington) Date: Sat, 29 Oct 2022 22:50:36 -0000 Subject: [Python-checkins] glossary.rst: Fix typo in package definition (GH-98865) Message-ID: https://github.com/python/cpython/commit/a55bd6f884daeed28c3db1a117fdfc30c5143b2d commit: a55bd6f884daeed28c3db1a117fdfc30c5143b2d branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-29T15:50:31-07:00 summary: glossary.rst: Fix typo in package definition (GH-98865) This is a tiny typo fix of package definition in glossary. According to https://devguide.python.org/documentation/help-documenting/ simple typos don?t require issues of their own, but, instead, a pull request can by submitted directly. Automerge-Triggered-By: GH:AlexWaygood (cherry picked from commit fc94d55ff453a3101e4c00a394d4e38ae2fece13) Co-authored-by: ab files: M Doc/glossary.rst diff --git a/Doc/glossary.rst b/Doc/glossary.rst index 59f9426f6031..3d74d550dc34 100644 --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -882,7 +882,7 @@ Glossary package A Python :term:`module` which can contain submodules or recursively, - subpackages. Technically, a package is a Python module with an + subpackages. Technically, a package is a Python module with a ``__path__`` attribute. See also :term:`regular package` and :term:`namespace package`. From webhook-mailer at python.org Sat Oct 29 18:52:11 2022 From: webhook-mailer at python.org (miss-islington) Date: Sat, 29 Oct 2022 22:52:11 -0000 Subject: [Python-checkins] glossary.rst: Fix typo in package definition (GH-98865) Message-ID: https://github.com/python/cpython/commit/23545fb277fdc8acc5574e81111cb05fca7a4d50 commit: 23545fb277fdc8acc5574e81111cb05fca7a4d50 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-29T15:52:05-07:00 summary: glossary.rst: Fix typo in package definition (GH-98865) This is a tiny typo fix of package definition in glossary. According to https://devguide.python.org/documentation/help-documenting/ simple typos don?t require issues of their own, but, instead, a pull request can by submitted directly. Automerge-Triggered-By: GH:AlexWaygood (cherry picked from commit fc94d55ff453a3101e4c00a394d4e38ae2fece13) Co-authored-by: ab files: M Doc/glossary.rst diff --git a/Doc/glossary.rst b/Doc/glossary.rst index c4231e772878..6e519df6a1e0 100644 --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -893,7 +893,7 @@ Glossary package A Python :term:`module` which can contain submodules or recursively, - subpackages. Technically, a package is a Python module with an + subpackages. Technically, a package is a Python module with a ``__path__`` attribute. See also :term:`regular package` and :term:`namespace package`. From webhook-mailer at python.org Sun Oct 30 00:35:05 2022 From: webhook-mailer at python.org (gvanrossum) Date: Sun, 30 Oct 2022 04:35:05 -0000 Subject: [Python-checkins] gh-98793: Fix typecheck in `overlapped.c` (#98835) Message-ID: https://github.com/python/cpython/commit/3ac8c0ab6ee819a14b1c8e0992acbaf376a46058 commit: 3ac8c0ab6ee819a14b1c8e0992acbaf376a46058 branch: main author: Charlie Zhao committer: gvanrossum date: 2022-10-29T21:34:46-07:00 summary: gh-98793: Fix typecheck in `overlapped.c` (#98835) Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> files: A Misc/NEWS.d/next/Library/2022-10-29-03-40-18.gh-issue-98793.WSPB4A.rst M Lib/test/test_asyncio/test_windows_events.py M Modules/clinic/overlapped.c.h M Modules/overlapped.c diff --git a/Lib/test/test_asyncio/test_windows_events.py b/Lib/test/test_asyncio/test_windows_events.py index 6b4f65c3376f..5033acc05248 100644 --- a/Lib/test/test_asyncio/test_windows_events.py +++ b/Lib/test/test_asyncio/test_windows_events.py @@ -239,6 +239,17 @@ def test_read_self_pipe_restart(self): self.close_loop(self.loop) self.assertFalse(self.loop.call_exception_handler.called) + def test_address_argument_type_error(self): + # Regression test for https://github.com/python/cpython/issues/98793 + proactor = self.loop._proactor + sock = socket.socket(type=socket.SOCK_DGRAM) + bad_address = None + with self.assertRaises(TypeError): + proactor.connect(sock, bad_address) + with self.assertRaises(TypeError): + proactor.sendto(sock, b'abc', addr=bad_address) + sock.close() + class WinPolicyTests(test_utils.TestCase): diff --git a/Misc/NEWS.d/next/Library/2022-10-29-03-40-18.gh-issue-98793.WSPB4A.rst b/Misc/NEWS.d/next/Library/2022-10-29-03-40-18.gh-issue-98793.WSPB4A.rst new file mode 100644 index 000000000000..7b67af06cf3d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-29-03-40-18.gh-issue-98793.WSPB4A.rst @@ -0,0 +1 @@ +Fix argument typechecks in :func:`!_overlapped.WSAConnect` and :func:`!_overlapped.Overlapped.WSASendTo` functions. diff --git a/Modules/clinic/overlapped.c.h b/Modules/clinic/overlapped.c.h index e8c2fe5653d1..9d9f2cbf6afd 100644 --- a/Modules/clinic/overlapped.c.h +++ b/Modules/clinic/overlapped.c.h @@ -1093,6 +1093,10 @@ _overlapped_WSAConnect(PyObject *module, PyObject *const *args, Py_ssize_t nargs if (!ConnectSocket && PyErr_Occurred()) { goto exit; } + if (!PyTuple_Check(args[1])) { + _PyArg_BadArgument("WSAConnect", "argument 2", "tuple", args[1]); + goto exit; + } AddressObj = args[1]; return_value = _overlapped_WSAConnect_impl(module, ConnectSocket, AddressObj); @@ -1140,6 +1144,10 @@ _overlapped_Overlapped_WSASendTo(OverlappedObject *self, PyObject *const *args, if (!_PyLong_UnsignedLong_Converter(args[2], &flags)) { goto exit; } + if (!PyTuple_Check(args[3])) { + _PyArg_BadArgument("WSASendTo", "argument 4", "tuple", args[3]); + goto exit; + } AddressObj = args[3]; return_value = _overlapped_Overlapped_WSASendTo_impl(self, handle, &bufobj, flags, AddressObj); @@ -1254,4 +1262,4 @@ _overlapped_Overlapped_WSARecvFromInto(OverlappedObject *self, PyObject *const * return return_value; } -/*[clinic end generated code: output=e0f866222bd5873b input=a9049054013a1b77]*/ +/*[clinic end generated code: output=b2e89694b8de3d00 input=a9049054013a1b77]*/ diff --git a/Modules/overlapped.c b/Modules/overlapped.c index 369b1beae84e..deb772e9eff4 100644 --- a/Modules/overlapped.c +++ b/Modules/overlapped.c @@ -1674,7 +1674,7 @@ Overlapped_traverse(OverlappedObject *self, visitproc visit, void *arg) _overlapped.WSAConnect client_handle as ConnectSocket: HANDLE - address_as_bytes as AddressObj: object + address_as_bytes as AddressObj: object(subclass_of='&PyTuple_Type') / Bind a remote address to a connectionless (UDP) socket. @@ -1683,7 +1683,7 @@ Bind a remote address to a connectionless (UDP) socket. static PyObject * _overlapped_WSAConnect_impl(PyObject *module, HANDLE ConnectSocket, PyObject *AddressObj) -/*[clinic end generated code: output=ea0b4391e94dad63 input=169f8075e9ae7fa4]*/ +/*[clinic end generated code: output=ea0b4391e94dad63 input=7cf65313d49c015a]*/ { char AddressBuf[sizeof(struct sockaddr_in6)]; SOCKADDR *Address = (SOCKADDR*)AddressBuf; @@ -1717,7 +1717,7 @@ _overlapped.Overlapped.WSASendTo handle: HANDLE buf as bufobj: Py_buffer flags: DWORD - address_as_bytes as AddressObj: object + address_as_bytes as AddressObj: object(subclass_of='&PyTuple_Type') / Start overlapped sendto over a connectionless (UDP) socket. @@ -1727,7 +1727,7 @@ static PyObject * _overlapped_Overlapped_WSASendTo_impl(OverlappedObject *self, HANDLE handle, Py_buffer *bufobj, DWORD flags, PyObject *AddressObj) -/*[clinic end generated code: output=3cdedc4cfaeb70cd input=b7c1749a62e2e374]*/ +/*[clinic end generated code: output=3cdedc4cfaeb70cd input=31f44cd4ab92fc33]*/ { char AddressBuf[sizeof(struct sockaddr_in6)]; SOCKADDR *Address = (SOCKADDR*)AddressBuf; From webhook-mailer at python.org Sun Oct 30 02:23:25 2022 From: webhook-mailer at python.org (sweeneyde) Date: Sun, 30 Oct 2022 06:23:25 -0000 Subject: [Python-checkins] gh-98783: Fix crashes when `str` subclasses are used in `_PyUnicode_Equal` (#98806) Message-ID: https://github.com/python/cpython/commit/76f989dc3e668d15b3ec9a90bf6530276530acac commit: 76f989dc3e668d15b3ec9a90bf6530276530acac branch: main author: Nikita Sobolev committer: sweeneyde <36520290+sweeneyde at users.noreply.github.com> date: 2022-10-30T02:23:20-04:00 summary: gh-98783: Fix crashes when `str` subclasses are used in `_PyUnicode_Equal` (#98806) files: A Misc/NEWS.d/next/Core and Builtins/2022-10-28-14-52-55.gh-issue-98783.iG0kMs.rst M Include/cpython/unicodeobject.h M Lib/test/test_descr.py M Lib/test/test_long.py M Objects/unicodeobject.c diff --git a/Include/cpython/unicodeobject.h b/Include/cpython/unicodeobject.h index 3ca6ace24c5f..8444507ade1b 100644 --- a/Include/cpython/unicodeobject.h +++ b/Include/cpython/unicodeobject.h @@ -945,7 +945,7 @@ PyAPI_FUNC(PyObject*) _PyUnicode_FromId(_Py_Identifier*); and where the hash values are equal (i.e. a very probable match) */ PyAPI_FUNC(int) _PyUnicode_EQ(PyObject *, PyObject *); -/* Equality check. Returns -1 on failure. */ +/* Equality check. */ PyAPI_FUNC(int) _PyUnicode_Equal(PyObject *, PyObject *); PyAPI_FUNC(int) _PyUnicode_WideCharString_Converter(PyObject *, void *); diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 037c859e97d4..40cf81ff0b33 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -1317,6 +1317,15 @@ class X(object): with self.assertRaisesRegex(AttributeError, "'X' object has no attribute 'a'"): X().a + # Test string subclass in `__slots__`, see gh-98783 + class SubStr(str): + pass + class X(object): + __slots__ = (SubStr('x'),) + X().x = 1 + with self.assertRaisesRegex(AttributeError, "'X' object has no attribute 'a'"): + X().a + def test_slots_special(self): # Testing __dict__ and __weakref__ in __slots__... class D(object): @@ -3589,6 +3598,16 @@ def __repr__(self): self.assertEqual(o.__str__(), '41') self.assertEqual(o.__repr__(), 'A repr') + def test_repr_with_module_str_subclass(self): + # gh-98783 + class StrSub(str): + pass + class Some: + pass + Some.__module__ = StrSub('example') + self.assertIsInstance(repr(Some), str) # should not crash + self.assertIsInstance(repr(Some()), str) # should not crash + def test_keyword_arguments(self): # Testing keyword arguments to __init__, __call__... def f(a): return a diff --git a/Lib/test/test_long.py b/Lib/test/test_long.py index b6407b5a7c88..77b37ca1fa4a 100644 --- a/Lib/test/test_long.py +++ b/Lib/test/test_long.py @@ -1334,6 +1334,12 @@ def equivalent_python(n, length, byteorder, signed=False): b'\xff\xff\xff\xff\xff') self.assertRaises(OverflowError, (1).to_bytes, 0, 'big') + # gh-98783 + class SubStr(str): + pass + self.assertEqual((0).to_bytes(1, SubStr('big')), b'\x00') + self.assertEqual((0).to_bytes(0, SubStr('little')), b'') + def test_from_bytes(self): def check(tests, byteorder, signed=False): def equivalent_python(byte_array, byteorder, signed=False): @@ -1534,6 +1540,12 @@ def __bytes__(self): self.assertRaises(TypeError, int.from_bytes, MissingBytes()) self.assertRaises(ZeroDivisionError, int.from_bytes, RaisingBytes()) + # gh-98783 + class SubStr(str): + pass + self.assertEqual(int.from_bytes(b'', SubStr('big')), 0) + self.assertEqual(int.from_bytes(b'\x00', SubStr('little')), 0) + @support.cpython_only def test_from_bytes_small(self): # bpo-46361 diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-28-14-52-55.gh-issue-98783.iG0kMs.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-28-14-52-55.gh-issue-98783.iG0kMs.rst new file mode 100644 index 000000000000..da1e61ea8504 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-28-14-52-55.gh-issue-98783.iG0kMs.rst @@ -0,0 +1,2 @@ +Fix multiple crashes in debug mode when ``str`` subclasses +are used instead of ``str`` itself. diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index d090915146f8..9dd0c42a0acd 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -10444,8 +10444,8 @@ unicode_compare_eq(PyObject *str1, PyObject *str2) int _PyUnicode_Equal(PyObject *str1, PyObject *str2) { - assert(PyUnicode_CheckExact(str1)); - assert(PyUnicode_CheckExact(str2)); + assert(PyUnicode_Check(str1)); + assert(PyUnicode_Check(str2)); if (str1 == str2) { return 1; } From webhook-mailer at python.org Sun Oct 30 08:01:35 2022 From: webhook-mailer at python.org (ncoghlan) Date: Sun, 30 Oct 2022 12:01:35 -0000 Subject: [Python-checkins] gh-96853: Restore test coverage for Py_Initialize(Ex) (GH-98212) Message-ID: https://github.com/python/cpython/commit/05e48865be69e1e5824f6915b588ff054717bb42 commit: 05e48865be69e1e5824f6915b588ff054717bb42 branch: main author: Nick Coghlan committer: ncoghlan date: 2022-10-30T22:01:30+10:00 summary: gh-96853: Restore test coverage for Py_Initialize(Ex) (GH-98212) * As most of `test_embed` now uses `Py_InitializeFromConfig`, add a specific test case to cover `Py_Initialize` (and `Py_InitializeEx`) * Rename `_testembed` init helper to clarify the API used * Add a `PyConfig_Clear` call in `Py_InitializeEx` to make the code more obviously correct (it already didn't leak as none of the dynamically allocated config fields were being populated, but it's clearer if the wrappers follow the documented API usage guidelines) files: A Misc/NEWS.d/next/C API/2022-10-16-15-00-25.gh-issue-96853.V0wiXP.rst A Misc/NEWS.d/next/Tests/2022-10-12-14-57-06.gh-issue-96853.ANe-bw.rst M Lib/test/test_embed.py M Programs/_testembed.c M Python/pylifecycle.c diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py index f622d443257f..930f76342f0e 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -340,6 +340,12 @@ def test_finalize_structseq(self): out, err = self.run_embedded_interpreter("test_repeated_init_exec", code) self.assertEqual(out, 'Tests passed\n' * INIT_LOOPS) + def test_simple_initialization_api(self): + # _testembed now uses Py_InitializeFromConfig by default + # This case specifically checks Py_Initialize(Ex) still works + out, err = self.run_embedded_interpreter("test_repeated_simple_init") + self.assertEqual(out, 'Finalized\n' * INIT_LOOPS) + def test_quickened_static_code_gets_unquickened_at_Py_FINALIZE(self): # https://github.com/python/cpython/issues/92031 diff --git a/Misc/NEWS.d/next/C API/2022-10-16-15-00-25.gh-issue-96853.V0wiXP.rst b/Misc/NEWS.d/next/C API/2022-10-16-15-00-25.gh-issue-96853.V0wiXP.rst new file mode 100644 index 000000000000..d7e3cc423ac8 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2022-10-16-15-00-25.gh-issue-96853.V0wiXP.rst @@ -0,0 +1,4 @@ +``Py_InitializeEx`` now correctly calls ``PyConfig_Clear`` after initializing +the interpreter (the omission didn't cause a memory leak only because none +of the dynamically allocated config fields are populated by the wrapper +function) diff --git a/Misc/NEWS.d/next/Tests/2022-10-12-14-57-06.gh-issue-96853.ANe-bw.rst b/Misc/NEWS.d/next/Tests/2022-10-12-14-57-06.gh-issue-96853.ANe-bw.rst new file mode 100644 index 000000000000..89958c577219 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2022-10-12-14-57-06.gh-issue-96853.ANe-bw.rst @@ -0,0 +1,3 @@ +Added explicit coverage of ``Py_Initialize`` (and hence ``Py_InitializeEx``) +back to the embedding tests (all other embedding tests migrated to +``Py_InitializeFromConfig`` in Python 3.11) diff --git a/Programs/_testembed.c b/Programs/_testembed.c index ba599591d3c4..adb4483ccbd3 100644 --- a/Programs/_testembed.c +++ b/Programs/_testembed.c @@ -22,7 +22,7 @@ char **main_argv; /********************************************************* * Embedded interpreter tests that need a custom exe * - * Executed via 'EmbeddingTests' in Lib/test/test_capi.py + * Executed via Lib/test/test_embed.py *********************************************************/ // Use to display the usage @@ -73,7 +73,7 @@ static void init_from_config_clear(PyConfig *config) } -static void _testembed_Py_Initialize(void) +static void _testembed_Py_InitializeFromConfig(void) { PyConfig config; _PyConfig_InitCompatConfig(&config); @@ -81,6 +81,12 @@ static void _testembed_Py_Initialize(void) init_from_config_clear(&config); } +static void _testembed_Py_Initialize(void) +{ + Py_SetProgramName(PROGRAM_NAME); + Py_Initialize(); +} + /***************************************************** * Test repeated initialisation and subinterpreters @@ -110,7 +116,7 @@ static int test_repeated_init_and_subinterpreters(void) for (int i=1; i <= INIT_LOOPS; i++) { printf("--- Pass %d ---\n", i); - _testembed_Py_Initialize(); + _testembed_Py_InitializeFromConfig(); mainstate = PyThreadState_Get(); PyEval_ReleaseThread(mainstate); @@ -168,7 +174,7 @@ static int test_repeated_init_exec(void) fprintf(stderr, "--- Loop #%d ---\n", i); fflush(stderr); - _testembed_Py_Initialize(); + _testembed_Py_InitializeFromConfig(); int err = PyRun_SimpleString(code); Py_Finalize(); if (err) { @@ -178,6 +184,23 @@ static int test_repeated_init_exec(void) return 0; } +/**************************************************************************** + * Test the Py_Initialize(Ex) convenience/compatibility wrappers + ***************************************************************************/ +// This is here to help ensure there are no wrapper resource leaks (gh-96853) +static int test_repeated_simple_init(void) +{ + for (int i=1; i <= INIT_LOOPS; i++) { + fprintf(stderr, "--- Loop #%d ---\n", i); + fflush(stderr); + + _testembed_Py_Initialize(); + Py_Finalize(); + printf("Finalized\n"); // Give test_embed some output to check + } + return 0; +} + /***************************************************** * Test forcing a particular IO encoding @@ -199,7 +222,7 @@ static void check_stdio_details(const char *encoding, const char * errors) fflush(stdout); /* Force the given IO encoding */ Py_SetStandardStreamEncoding(encoding, errors); - _testembed_Py_Initialize(); + _testembed_Py_InitializeFromConfig(); PyRun_SimpleString( "import sys;" "print('stdin: {0.encoding}:{0.errors}'.format(sys.stdin));" @@ -308,7 +331,7 @@ static int test_pre_initialization_sys_options(void) dynamic_xoption = NULL; _Py_EMBED_PREINIT_CHECK("Initializing interpreter\n"); - _testembed_Py_Initialize(); + _testembed_Py_InitializeFromConfig(); _Py_EMBED_PREINIT_CHECK("Check sys module contents\n"); PyRun_SimpleString("import sys; " "print('sys.warnoptions:', sys.warnoptions); " @@ -352,7 +375,7 @@ static int test_bpo20891(void) return 1; } - _testembed_Py_Initialize(); + _testembed_Py_InitializeFromConfig(); unsigned long thrd = PyThread_start_new_thread(bpo20891_thread, &lock); if (thrd == PYTHREAD_INVALID_THREAD_ID) { @@ -375,7 +398,7 @@ static int test_bpo20891(void) static int test_initialize_twice(void) { - _testembed_Py_Initialize(); + _testembed_Py_InitializeFromConfig(); /* bpo-33932: Calling Py_Initialize() twice should do nothing * (and not crash!). */ @@ -393,7 +416,7 @@ static int test_initialize_pymain(void) L"print(f'Py_Main() after Py_Initialize: " L"sys.argv={sys.argv}')"), L"arg2"}; - _testembed_Py_Initialize(); + _testembed_Py_InitializeFromConfig(); /* bpo-34008: Calling Py_Main() after Py_Initialize() must not crash */ Py_Main(Py_ARRAY_LENGTH(argv), argv); @@ -416,7 +439,7 @@ dump_config(void) static int test_init_initialize_config(void) { - _testembed_Py_Initialize(); + _testembed_Py_InitializeFromConfig(); dump_config(); Py_Finalize(); return 0; @@ -767,7 +790,7 @@ static int test_init_compat_env(void) /* Test initialization from environment variables */ Py_IgnoreEnvironmentFlag = 0; set_all_env_vars(); - _testembed_Py_Initialize(); + _testembed_Py_InitializeFromConfig(); dump_config(); Py_Finalize(); return 0; @@ -803,7 +826,7 @@ static int test_init_env_dev_mode(void) /* Test initialization from environment variables */ Py_IgnoreEnvironmentFlag = 0; set_all_env_vars_dev_mode(); - _testembed_Py_Initialize(); + _testembed_Py_InitializeFromConfig(); dump_config(); Py_Finalize(); return 0; @@ -816,7 +839,7 @@ static int test_init_env_dev_mode_alloc(void) Py_IgnoreEnvironmentFlag = 0; set_all_env_vars_dev_mode(); putenv("PYTHONMALLOC=malloc"); - _testembed_Py_Initialize(); + _testembed_Py_InitializeFromConfig(); dump_config(); Py_Finalize(); return 0; @@ -1156,7 +1179,7 @@ static int test_open_code_hook(void) } Py_IgnoreEnvironmentFlag = 0; - _testembed_Py_Initialize(); + _testembed_Py_InitializeFromConfig(); result = 0; PyObject *r = PyFile_OpenCode("$$test-filename"); @@ -1220,7 +1243,7 @@ static int _test_audit(Py_ssize_t setValue) Py_IgnoreEnvironmentFlag = 0; PySys_AddAuditHook(_audit_hook, &sawSet); - _testembed_Py_Initialize(); + _testembed_Py_InitializeFromConfig(); if (PySys_Audit("_testembed.raise", NULL) == 0) { printf("No error raised"); @@ -1276,7 +1299,7 @@ static int test_audit_subinterpreter(void) { Py_IgnoreEnvironmentFlag = 0; PySys_AddAuditHook(_audit_subinterpreter_hook, NULL); - _testembed_Py_Initialize(); + _testembed_Py_InitializeFromConfig(); Py_NewInterpreter(); Py_NewInterpreter(); @@ -1871,13 +1894,13 @@ static int test_unicode_id_init(void) _Py_IDENTIFIER(test_unicode_id_init); // Initialize Python once without using the identifier - _testembed_Py_Initialize(); + _testembed_Py_InitializeFromConfig(); Py_Finalize(); // Now initialize Python multiple times and use the identifier. // The first _PyUnicode_FromId() call initializes the identifier index. for (int i=0; i<3; i++) { - _testembed_Py_Initialize(); + _testembed_Py_InitializeFromConfig(); PyObject *str1, *str2; @@ -2021,7 +2044,7 @@ unwrap_allocator(PyMemAllocatorEx *allocator) static int test_get_incomplete_frame(void) { - _testembed_Py_Initialize(); + _testembed_Py_InitializeFromConfig(); PyMemAllocatorEx allocator; wrap_allocator(&allocator); // Force an allocation with an incomplete (generator) frame: @@ -2053,6 +2076,7 @@ struct TestCase static struct TestCase TestCases[] = { // Python initialization {"test_repeated_init_exec", test_repeated_init_exec}, + {"test_repeated_simple_init", test_repeated_simple_init}, {"test_forced_io_encoding", test_forced_io_encoding}, {"test_repeated_init_and_subinterpreters", test_repeated_init_and_subinterpreters}, {"test_repeated_init_and_inittab", test_repeated_init_and_inittab}, diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 334abfb191fe..d26ae74a0f17 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1313,6 +1313,7 @@ Py_InitializeEx(int install_sigs) config.install_signal_handlers = install_sigs; status = Py_InitializeFromConfig(&config); + PyConfig_Clear(&config); if (_PyStatus_EXCEPTION(status)) { Py_ExitStatusException(status); } From webhook-mailer at python.org Sun Oct 30 11:54:04 2022 From: webhook-mailer at python.org (jaraco) Date: Sun, 30 Oct 2022 15:54:04 -0000 Subject: [Python-checkins] gh-97966: Update uname docs to clarify the special nature of the platform attribute and to indicate when it became late-bound. (#97972) Message-ID: https://github.com/python/cpython/commit/018b2483c422031ba5a6084238ab66ba44ea9fcf commit: 018b2483c422031ba5a6084238ab66ba44ea9fcf branch: main author: Jason R. Coombs committer: jaraco date: 2022-10-30T11:53:58-04:00 summary: gh-97966: Update uname docs to clarify the special nature of the platform attribute and to indicate when it became late-bound. (#97972) files: A Misc/NEWS.d/next/Documentation/2022-10-06-13-00-28.gh-issue-97966.fz7kFg.rst M Doc/library/platform.rst diff --git a/Doc/library/platform.rst b/Doc/library/platform.rst index dc2d871b47d5..a0c9f63ab9f9 100644 --- a/Doc/library/platform.rst +++ b/Doc/library/platform.rst @@ -168,16 +168,20 @@ Cross Platform containing six attributes: :attr:`system`, :attr:`node`, :attr:`release`, :attr:`version`, :attr:`machine`, and :attr:`processor`. - Note that this adds a sixth attribute (:attr:`processor`) not present - in the :func:`os.uname` result. Also, the attribute names are different - for the first two attributes; :func:`os.uname` names them - :attr:`sysname` and :attr:`nodename`. + :attr:`processor` is resolved late, on demand. + + Note: the first two attribute names differ from the names presented by + :func:`os.uname`, where they are named :attr:`sysname` and + :attr:`nodename`. Entries which cannot be determined are set to ``''``. .. versionchanged:: 3.3 Result changed from a tuple to a :func:`~collections.namedtuple`. + .. versionchanged:: 3.9 + :attr:`processor` is resolved late instead of immediately. + Java Platform ------------- diff --git a/Misc/NEWS.d/next/Documentation/2022-10-06-13-00-28.gh-issue-97966.fz7kFg.rst b/Misc/NEWS.d/next/Documentation/2022-10-06-13-00-28.gh-issue-97966.fz7kFg.rst new file mode 100644 index 000000000000..8240442a3bcb --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2022-10-06-13-00-28.gh-issue-97966.fz7kFg.rst @@ -0,0 +1,2 @@ +Update uname docs to clarify the special nature of the platform attribute +and to indicate when it became late-bound. From webhook-mailer at python.org Sun Oct 30 14:30:14 2022 From: webhook-mailer at python.org (sweeneyde) Date: Sun, 30 Oct 2022 18:30:14 -0000 Subject: [Python-checkins] [3.11] gh-98783: Fix crashes when `str` subclasses are used in `_PyUnicode_Equal` (GH-98806) (#98871) Message-ID: https://github.com/python/cpython/commit/5efe2eead3b385da4f838a9687b186b21dc01659 commit: 5efe2eead3b385da4f838a9687b186b21dc01659 branch: 3.11 author: Dennis Sweeney <36520290+sweeneyde at users.noreply.github.com> committer: sweeneyde <36520290+sweeneyde at users.noreply.github.com> date: 2022-10-30T14:30:08-04:00 summary: [3.11] gh-98783: Fix crashes when `str` subclasses are used in `_PyUnicode_Equal` (GH-98806) (#98871) * gh-98783: Fix crashes when `str` subclasses are used in `_PyUnicode_Equal` (GH-98806) (cherry picked from commit 76f989dc3e668d15b3ec9a90bf6530276530acac) Co-authored-by: Nikita Sobolev files: A Misc/NEWS.d/next/Core and Builtins/2022-10-28-14-52-55.gh-issue-98783.iG0kMs.rst M Lib/test/test_descr.py M Lib/test/test_long.py M Objects/unicodeobject.c diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index afe0f7e9c7fd..3145dff81b4d 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -1310,6 +1310,15 @@ class X(object): with self.assertRaisesRegex(AttributeError, "'X' object has no attribute 'a'"): X().a + # Test string subclass in `__slots__`, see gh-98783 + class SubStr(str): + pass + class X(object): + __slots__ = (SubStr('x'),) + X().x = 1 + with self.assertRaisesRegex(AttributeError, "'X' object has no attribute 'a'"): + X().a + def test_slots_special(self): # Testing __dict__ and __weakref__ in __slots__... class D(object): @@ -3581,6 +3590,16 @@ def __repr__(self): self.assertEqual(o.__str__(), '41') self.assertEqual(o.__repr__(), 'A repr') + def test_repr_with_module_str_subclass(self): + # gh-98783 + class StrSub(str): + pass + class Some: + pass + Some.__module__ = StrSub('example') + self.assertIsInstance(repr(Some), str) # should not crash + self.assertIsInstance(repr(Some()), str) # should not crash + def test_keyword_arguments(self): # Testing keyword arguments to __init__, __call__... def f(a): return a diff --git a/Lib/test/test_long.py b/Lib/test/test_long.py index b6407b5a7c88..77b37ca1fa4a 100644 --- a/Lib/test/test_long.py +++ b/Lib/test/test_long.py @@ -1334,6 +1334,12 @@ def equivalent_python(n, length, byteorder, signed=False): b'\xff\xff\xff\xff\xff') self.assertRaises(OverflowError, (1).to_bytes, 0, 'big') + # gh-98783 + class SubStr(str): + pass + self.assertEqual((0).to_bytes(1, SubStr('big')), b'\x00') + self.assertEqual((0).to_bytes(0, SubStr('little')), b'') + def test_from_bytes(self): def check(tests, byteorder, signed=False): def equivalent_python(byte_array, byteorder, signed=False): @@ -1534,6 +1540,12 @@ def __bytes__(self): self.assertRaises(TypeError, int.from_bytes, MissingBytes()) self.assertRaises(ZeroDivisionError, int.from_bytes, RaisingBytes()) + # gh-98783 + class SubStr(str): + pass + self.assertEqual(int.from_bytes(b'', SubStr('big')), 0) + self.assertEqual(int.from_bytes(b'\x00', SubStr('little')), 0) + @support.cpython_only def test_from_bytes_small(self): # bpo-46361 diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-28-14-52-55.gh-issue-98783.iG0kMs.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-28-14-52-55.gh-issue-98783.iG0kMs.rst new file mode 100644 index 000000000000..da1e61ea8504 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-28-14-52-55.gh-issue-98783.iG0kMs.rst @@ -0,0 +1,2 @@ +Fix multiple crashes in debug mode when ``str`` subclasses +are used instead of ``str`` itself. diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index a7bd961c64a8..a19eaadcfc2e 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -11134,8 +11134,8 @@ unicode_compare_eq(PyObject *str1, PyObject *str2) int _PyUnicode_Equal(PyObject *str1, PyObject *str2) { - assert(PyUnicode_CheckExact(str1)); - assert(PyUnicode_CheckExact(str2)); + assert(PyUnicode_Check(str1)); + assert(PyUnicode_Check(str2)); if (str1 == str2) { return 1; } From webhook-mailer at python.org Sun Oct 30 19:07:17 2022 From: webhook-mailer at python.org (sweeneyde) Date: Sun, 30 Oct 2022 23:07:17 -0000 Subject: [Python-checkins] gh-98879: Remove unreachable error case from COMPARE_OP_STR_JUMP (GH-98882) Message-ID: https://github.com/python/cpython/commit/87b5fd9d9de11c68b9940d3a1dba902138129109 commit: 87b5fd9d9de11c68b9940d3a1dba902138129109 branch: main author: Dennis Sweeney <36520290+sweeneyde at users.noreply.github.com> committer: sweeneyde <36520290+sweeneyde at users.noreply.github.com> date: 2022-10-30T19:07:11-04:00 summary: gh-98879: Remove unreachable error case from COMPARE_OP_STR_JUMP (GH-98882) Thanks to PEP 623 changes, the comparison cannot fail. files: M Python/ceval.c diff --git a/Python/ceval.c b/Python/ceval.c index 24af419d29c5..f2250ffbc71f 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -3420,9 +3420,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); int res = _PyUnicode_Equal(left, right); - if (res < 0) { - goto error; - } assert(oparg == Py_EQ || oparg == Py_NE); JUMPBY(INLINE_CACHE_ENTRIES_COMPARE_OP); NEXTOPARG(); From webhook-mailer at python.org Sun Oct 30 19:15:37 2022 From: webhook-mailer at python.org (ncoghlan) Date: Sun, 30 Oct 2022 23:15:37 -0000 Subject: [Python-checkins] [3.11] gh-96853: Restore test coverage for Py_Initialize(Ex) (GH-98874) Message-ID: https://github.com/python/cpython/commit/57dd11038f22379770d9f16e527f787fdea978fd commit: 57dd11038f22379770d9f16e527f787fdea978fd branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ncoghlan date: 2022-10-31T09:15:12+10:00 summary: [3.11] gh-96853: Restore test coverage for Py_Initialize(Ex) (GH-98874) * As most of `test_embed` now uses `Py_InitializeFromConfig`, add a specific test case to cover `Py_Initialize` (and `Py_InitializeEx`) * Rename `_testembed` init helper to clarify the API used * Add a `PyConfig_Clear` call in `Py_InitializeEx` to make the code more obviously correct (it already didn't leak as none of the dynamically allocated config fields were being populated, but it's clearer if the wrappers follow the documented API usage guidelines) (cherry picked from commit 05e48865be69e1e5824f6915b588ff054717bb42) Co-authored-by: Nick Coghlan files: A Misc/NEWS.d/next/C API/2022-10-16-15-00-25.gh-issue-96853.V0wiXP.rst A Misc/NEWS.d/next/Tests/2022-10-12-14-57-06.gh-issue-96853.ANe-bw.rst M Lib/test/test_embed.py M Programs/_testembed.c M Python/pylifecycle.c diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py index b8e3c37bbda3..f4b371d917c8 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -341,6 +341,12 @@ def test_finalize_structseq(self): out, err = self.run_embedded_interpreter("test_repeated_init_exec", code) self.assertEqual(out, 'Tests passed\n' * INIT_LOOPS) + def test_simple_initialization_api(self): + # _testembed now uses Py_InitializeFromConfig by default + # This case specifically checks Py_Initialize(Ex) still works + out, err = self.run_embedded_interpreter("test_repeated_simple_init") + self.assertEqual(out, 'Finalized\n' * INIT_LOOPS) + def test_quickened_static_code_gets_unquickened_at_Py_FINALIZE(self): # https://github.com/python/cpython/issues/92031 diff --git a/Misc/NEWS.d/next/C API/2022-10-16-15-00-25.gh-issue-96853.V0wiXP.rst b/Misc/NEWS.d/next/C API/2022-10-16-15-00-25.gh-issue-96853.V0wiXP.rst new file mode 100644 index 000000000000..d7e3cc423ac8 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2022-10-16-15-00-25.gh-issue-96853.V0wiXP.rst @@ -0,0 +1,4 @@ +``Py_InitializeEx`` now correctly calls ``PyConfig_Clear`` after initializing +the interpreter (the omission didn't cause a memory leak only because none +of the dynamically allocated config fields are populated by the wrapper +function) diff --git a/Misc/NEWS.d/next/Tests/2022-10-12-14-57-06.gh-issue-96853.ANe-bw.rst b/Misc/NEWS.d/next/Tests/2022-10-12-14-57-06.gh-issue-96853.ANe-bw.rst new file mode 100644 index 000000000000..89958c577219 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2022-10-12-14-57-06.gh-issue-96853.ANe-bw.rst @@ -0,0 +1,3 @@ +Added explicit coverage of ``Py_Initialize`` (and hence ``Py_InitializeEx``) +back to the embedding tests (all other embedding tests migrated to +``Py_InitializeFromConfig`` in Python 3.11) diff --git a/Programs/_testembed.c b/Programs/_testembed.c index e5b138ce84bb..13eae178f91d 100644 --- a/Programs/_testembed.c +++ b/Programs/_testembed.c @@ -22,7 +22,7 @@ char **main_argv; /********************************************************* * Embedded interpreter tests that need a custom exe * - * Executed via 'EmbeddingTests' in Lib/test/test_capi.py + * Executed via Lib/test/test_embed.py *********************************************************/ // Use to display the usage @@ -73,7 +73,7 @@ static void init_from_config_clear(PyConfig *config) } -static void _testembed_Py_Initialize(void) +static void _testembed_Py_InitializeFromConfig(void) { PyConfig config; _PyConfig_InitCompatConfig(&config); @@ -81,6 +81,12 @@ static void _testembed_Py_Initialize(void) init_from_config_clear(&config); } +static void _testembed_Py_Initialize(void) +{ + Py_SetProgramName(PROGRAM_NAME); + Py_Initialize(); +} + /***************************************************** * Test repeated initialisation and subinterpreters @@ -110,7 +116,7 @@ static int test_repeated_init_and_subinterpreters(void) for (int i=1; i <= INIT_LOOPS; i++) { printf("--- Pass %d ---\n", i); - _testembed_Py_Initialize(); + _testembed_Py_InitializeFromConfig(); mainstate = PyThreadState_Get(); PyEval_ReleaseThread(mainstate); @@ -168,7 +174,7 @@ static int test_repeated_init_exec(void) fprintf(stderr, "--- Loop #%d ---\n", i); fflush(stderr); - _testembed_Py_Initialize(); + _testembed_Py_InitializeFromConfig(); int err = PyRun_SimpleString(code); Py_Finalize(); if (err) { @@ -178,6 +184,23 @@ static int test_repeated_init_exec(void) return 0; } +/**************************************************************************** + * Test the Py_Initialize(Ex) convenience/compatibility wrappers + ***************************************************************************/ +// This is here to help ensure there are no wrapper resource leaks (gh-96853) +static int test_repeated_simple_init(void) +{ + for (int i=1; i <= INIT_LOOPS; i++) { + fprintf(stderr, "--- Loop #%d ---\n", i); + fflush(stderr); + + _testembed_Py_Initialize(); + Py_Finalize(); + printf("Finalized\n"); // Give test_embed some output to check + } + return 0; +} + /***************************************************** * Test forcing a particular IO encoding @@ -199,7 +222,7 @@ static void check_stdio_details(const char *encoding, const char * errors) fflush(stdout); /* Force the given IO encoding */ Py_SetStandardStreamEncoding(encoding, errors); - _testembed_Py_Initialize(); + _testembed_Py_InitializeFromConfig(); PyRun_SimpleString( "import sys;" "print('stdin: {0.encoding}:{0.errors}'.format(sys.stdin));" @@ -308,7 +331,7 @@ static int test_pre_initialization_sys_options(void) dynamic_xoption = NULL; _Py_EMBED_PREINIT_CHECK("Initializing interpreter\n"); - _testembed_Py_Initialize(); + _testembed_Py_InitializeFromConfig(); _Py_EMBED_PREINIT_CHECK("Check sys module contents\n"); PyRun_SimpleString("import sys; " "print('sys.warnoptions:', sys.warnoptions); " @@ -352,7 +375,7 @@ static int test_bpo20891(void) return 1; } - _testembed_Py_Initialize(); + _testembed_Py_InitializeFromConfig(); unsigned long thrd = PyThread_start_new_thread(bpo20891_thread, &lock); if (thrd == PYTHREAD_INVALID_THREAD_ID) { @@ -375,7 +398,7 @@ static int test_bpo20891(void) static int test_initialize_twice(void) { - _testembed_Py_Initialize(); + _testembed_Py_InitializeFromConfig(); /* bpo-33932: Calling Py_Initialize() twice should do nothing * (and not crash!). */ @@ -393,7 +416,7 @@ static int test_initialize_pymain(void) L"print(f'Py_Main() after Py_Initialize: " L"sys.argv={sys.argv}')"), L"arg2"}; - _testembed_Py_Initialize(); + _testembed_Py_InitializeFromConfig(); /* bpo-34008: Calling Py_Main() after Py_Initialize() must not crash */ Py_Main(Py_ARRAY_LENGTH(argv), argv); @@ -416,7 +439,7 @@ dump_config(void) static int test_init_initialize_config(void) { - _testembed_Py_Initialize(); + _testembed_Py_InitializeFromConfig(); dump_config(); Py_Finalize(); return 0; @@ -765,7 +788,7 @@ static int test_init_compat_env(void) /* Test initialization from environment variables */ Py_IgnoreEnvironmentFlag = 0; set_all_env_vars(); - _testembed_Py_Initialize(); + _testembed_Py_InitializeFromConfig(); dump_config(); Py_Finalize(); return 0; @@ -801,7 +824,7 @@ static int test_init_env_dev_mode(void) /* Test initialization from environment variables */ Py_IgnoreEnvironmentFlag = 0; set_all_env_vars_dev_mode(); - _testembed_Py_Initialize(); + _testembed_Py_InitializeFromConfig(); dump_config(); Py_Finalize(); return 0; @@ -814,7 +837,7 @@ static int test_init_env_dev_mode_alloc(void) Py_IgnoreEnvironmentFlag = 0; set_all_env_vars_dev_mode(); putenv("PYTHONMALLOC=malloc"); - _testembed_Py_Initialize(); + _testembed_Py_InitializeFromConfig(); dump_config(); Py_Finalize(); return 0; @@ -1154,7 +1177,7 @@ static int test_open_code_hook(void) } Py_IgnoreEnvironmentFlag = 0; - _testembed_Py_Initialize(); + _testembed_Py_InitializeFromConfig(); result = 0; PyObject *r = PyFile_OpenCode("$$test-filename"); @@ -1218,7 +1241,7 @@ static int _test_audit(Py_ssize_t setValue) Py_IgnoreEnvironmentFlag = 0; PySys_AddAuditHook(_audit_hook, &sawSet); - _testembed_Py_Initialize(); + _testembed_Py_InitializeFromConfig(); if (PySys_Audit("_testembed.raise", NULL) == 0) { printf("No error raised"); @@ -1274,7 +1297,7 @@ static int test_audit_subinterpreter(void) { Py_IgnoreEnvironmentFlag = 0; PySys_AddAuditHook(_audit_subinterpreter_hook, NULL); - _testembed_Py_Initialize(); + _testembed_Py_InitializeFromConfig(); Py_NewInterpreter(); Py_NewInterpreter(); @@ -1869,13 +1892,13 @@ static int test_unicode_id_init(void) _Py_IDENTIFIER(test_unicode_id_init); // Initialize Python once without using the identifier - _testembed_Py_Initialize(); + _testembed_Py_InitializeFromConfig(); Py_Finalize(); // Now initialize Python multiple times and use the identifier. // The first _PyUnicode_FromId() call initializes the identifier index. for (int i=0; i<3; i++) { - _testembed_Py_Initialize(); + _testembed_Py_InitializeFromConfig(); PyObject *str1, *str2; @@ -2007,7 +2030,7 @@ unwrap_allocator(PyMemAllocatorEx *allocator) static int test_get_incomplete_frame(void) { - _testembed_Py_Initialize(); + _testembed_Py_InitializeFromConfig(); PyMemAllocatorEx allocator; wrap_allocator(&allocator); // Force an allocation with an incomplete (generator) frame: @@ -2039,6 +2062,7 @@ struct TestCase static struct TestCase TestCases[] = { // Python initialization {"test_repeated_init_exec", test_repeated_init_exec}, + {"test_repeated_simple_init", test_repeated_simple_init}, {"test_forced_io_encoding", test_forced_io_encoding}, {"test_repeated_init_and_subinterpreters", test_repeated_init_and_subinterpreters}, {"test_repeated_init_and_inittab", test_repeated_init_and_inittab}, diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 960a38aebef8..0363e2e1dcae 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1289,6 +1289,7 @@ Py_InitializeEx(int install_sigs) config.install_signal_handlers = install_sigs; status = Py_InitializeFromConfig(&config); + PyConfig_Clear(&config); if (_PyStatus_EXCEPTION(status)) { Py_ExitStatusException(status); } From webhook-mailer at python.org Mon Oct 31 08:31:36 2022 From: webhook-mailer at python.org (ericvsmith) Date: Mon, 31 Oct 2022 12:31:36 -0000 Subject: [Python-checkins] gh-96151: Use a private name for passing builtins to dataclass. This now allows for a field named BUILTIN (gh-98143) Message-ID: https://github.com/python/cpython/commit/29f98b46b77ee528477b9a7b335974b9682f7f14 commit: 29f98b46b77ee528477b9a7b335974b9682f7f14 branch: main author: Shantanu <12621235+hauntsaninja at users.noreply.github.com> committer: ericvsmith date: 2022-10-31T08:31:01-04:00 summary: gh-96151: Use a private name for passing builtins to dataclass. This now allows for a field named BUILTIN (gh-98143) files: A Misc/NEWS.d/next/Library/2022-10-10-07-07-31.gh-issue-96151.K9fwoq.rst M Lib/dataclasses.py M Lib/test/test_dataclasses.py diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index bf7f290af162..b54e16984cb1 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -426,13 +426,11 @@ def wrapper(self): def _create_fn(name, args, body, *, globals=None, locals=None, return_type=MISSING): - # Note that we mutate locals when exec() is called. Caller - # beware! The only callers are internal to this module, so no + # Note that we may mutate locals. Callers beware! + # The only callers are internal to this module, so no # worries about external callers. if locals is None: locals = {} - if 'BUILTINS' not in locals: - locals['BUILTINS'] = builtins return_annotation = '' if return_type is not MISSING: locals['_return_type'] = return_type @@ -462,7 +460,7 @@ def _field_assign(frozen, name, value, self_name): # self_name is what "self" is called in this function: don't # hard-code "self", since that might be a field name. if frozen: - return f'BUILTINS.object.__setattr__({self_name},{name!r},{value})' + return f'__dataclass_builtins_object__.__setattr__({self_name},{name!r},{value})' return f'{self_name}.{name}={value}' @@ -569,6 +567,7 @@ def _init_fn(fields, std_fields, kw_only_fields, frozen, has_post_init, locals.update({ 'MISSING': MISSING, '_HAS_DEFAULT_FACTORY': _HAS_DEFAULT_FACTORY, + '__dataclass_builtins_object__': object, }) body_lines = [] diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py index 637c456dd49e..01e66840085b 100644 --- a/Lib/test/test_dataclasses.py +++ b/Lib/test/test_dataclasses.py @@ -257,6 +257,14 @@ class C: c = C('foo') self.assertEqual(c.object, 'foo') + def test_field_named_BUILTINS_frozen(self): + # gh-96151 + @dataclass(frozen=True) + class C: + BUILTINS: int + c = C(5) + self.assertEqual(c.BUILTINS, 5) + def test_field_named_like_builtin(self): # Attribute names can shadow built-in names # since code generation is used. diff --git a/Misc/NEWS.d/next/Library/2022-10-10-07-07-31.gh-issue-96151.K9fwoq.rst b/Misc/NEWS.d/next/Library/2022-10-10-07-07-31.gh-issue-96151.K9fwoq.rst new file mode 100644 index 000000000000..700c9748735f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-10-07-07-31.gh-issue-96151.K9fwoq.rst @@ -0,0 +1 @@ +Allow ``BUILTINS`` to be a valid field name for frozen dataclasses. From webhook-mailer at python.org Mon Oct 31 09:08:09 2022 From: webhook-mailer at python.org (iritkatriel) Date: Mon, 31 Oct 2022 13:08:09 -0000 Subject: [Python-checkins] gh-98811: use full source location to simplify __future__ imports error checking. This also fixes an incorrect error offset. (GH-98812) Message-ID: https://github.com/python/cpython/commit/39448adc9db0c0444443a42f13a9d7e1441b88e8 commit: 39448adc9db0c0444443a42f13a9d7e1441b88e8 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2022-10-31T13:08:03Z summary: gh-98811: use full source location to simplify __future__ imports error checking. This also fixes an incorrect error offset. (GH-98812) files: A Misc/NEWS.d/next/Core and Builtins/2022-10-28-13-59-51.gh-issue-98811.XQypJa.rst M Include/cpython/compile.h M Lib/test/test_future.py M Python/compile.c M Python/future.c diff --git a/Include/cpython/compile.h b/Include/cpython/compile.h index 518a37649929..f5a62a8ec6dd 100644 --- a/Include/cpython/compile.h +++ b/Include/cpython/compile.h @@ -31,11 +31,26 @@ typedef struct { #define _PyCompilerFlags_INIT \ (PyCompilerFlags){.cf_flags = 0, .cf_feature_version = PY_MINOR_VERSION} +/* source location information */ +typedef struct { + int lineno; + int end_lineno; + int col_offset; + int end_col_offset; +} _PyCompilerSrcLocation; + +#define SRC_LOCATION_FROM_AST(n) \ + (_PyCompilerSrcLocation){ \ + .lineno = (n)->lineno, \ + .end_lineno = (n)->end_lineno, \ + .col_offset = (n)->col_offset, \ + .end_col_offset = (n)->end_col_offset } + /* Future feature support */ typedef struct { - int ff_features; /* flags set by future statements */ - int ff_lineno; /* line number of last future statement */ + int ff_features; /* flags set by future statements */ + _PyCompilerSrcLocation ff_location; /* location of last future statement */ } PyFutureFeatures; #define FUTURE_NESTED_SCOPES "nested_scopes" diff --git a/Lib/test/test_future.py b/Lib/test/test_future.py index 189cbdc4365b..b8b591a1bcf2 100644 --- a/Lib/test/test_future.py +++ b/Lib/test/test_future.py @@ -60,7 +60,7 @@ def test_badfuture6(self): def test_badfuture7(self): with self.assertRaises(SyntaxError) as cm: from test import badsyntax_future7 - self.check_syntax_error(cm.exception, "badsyntax_future7", 3, 53) + self.check_syntax_error(cm.exception, "badsyntax_future7", 3, 54) def test_badfuture8(self): with self.assertRaises(SyntaxError) as cm: diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-28-13-59-51.gh-issue-98811.XQypJa.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-28-13-59-51.gh-issue-98811.XQypJa.rst new file mode 100644 index 000000000000..ce90a516cf0d --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-28-13-59-51.gh-issue-98811.XQypJa.rst @@ -0,0 +1,4 @@ +Use complete source locations to simplify detection of ``__future__`` +imports which are not at the beginning of the file. Also corrects the offset +in the exception raised in one case, which was off by one and impeded +highlighting. diff --git a/Python/compile.c b/Python/compile.c index 779729119e2e..f8924789f4e9 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -125,18 +125,23 @@ (c->c_flags->cf_flags & PyCF_ALLOW_TOP_LEVEL_AWAIT) \ && (c->u->u_ste->ste_type == ModuleBlock)) -typedef struct location_ { - int lineno; - int end_lineno; - int col_offset; - int end_col_offset; -} location; +typedef _PyCompilerSrcLocation location; #define LOCATION(LNO, END_LNO, COL, END_COL) \ ((const location){(LNO), (END_LNO), (COL), (END_COL)}) static location NO_LOCATION = {-1, -1, -1, -1}; +/* Return true if loc1 starts after loc2 ends. */ +static inline bool +location_is_after(location loc1, location loc2) { + return (loc1.lineno > loc2.end_lineno) || + ((loc1.lineno == loc2.end_lineno) && + (loc1.col_offset > loc2.end_col_offset)); +} + +#define LOC(x) SRC_LOCATION_FROM_AST(x) + typedef struct jump_target_label_ { int id; } jump_target_label; @@ -1012,11 +1017,6 @@ basicblock_next_instr(basicblock *b) // Artificial instructions #define UNSET_LOC(c) -#define LOC(x) LOCATION((x)->lineno, \ - (x)->end_lineno, \ - (x)->col_offset, \ - (x)->end_col_offset) - /* Return the stack effect of opcode with argument oparg. @@ -3911,59 +3911,61 @@ compiler_import(struct compiler *c, stmt_ty s) static int compiler_from_import(struct compiler *c, stmt_ty s) { - location loc = LOC(s); - Py_ssize_t i, n = asdl_seq_LEN(s->v.ImportFrom.names); - PyObject *names; + Py_ssize_t n = asdl_seq_LEN(s->v.ImportFrom.names); - ADDOP_LOAD_CONST_NEW(c, loc, PyLong_FromLong(s->v.ImportFrom.level)); + ADDOP_LOAD_CONST_NEW(c, LOC(s), PyLong_FromLong(s->v.ImportFrom.level)); - names = PyTuple_New(n); - if (!names) + PyObject *names = PyTuple_New(n); + if (!names) { return 0; + } /* build up the names */ - for (i = 0; i < n; i++) { + for (Py_ssize_t i = 0; i < n; i++) { alias_ty alias = (alias_ty)asdl_seq_GET(s->v.ImportFrom.names, i); Py_INCREF(alias->name); PyTuple_SET_ITEM(names, i, alias->name); } - if (s->lineno > c->c_future->ff_lineno && s->v.ImportFrom.module && - _PyUnicode_EqualToASCIIString(s->v.ImportFrom.module, "__future__")) { + if (location_is_after(LOC(s), c->c_future->ff_location) && + s->v.ImportFrom.module && + _PyUnicode_EqualToASCIIString(s->v.ImportFrom.module, "__future__")) + { Py_DECREF(names); - return compiler_error(c, loc, "from __future__ imports must occur " + return compiler_error(c, LOC(s), "from __future__ imports must occur " "at the beginning of the file"); } - ADDOP_LOAD_CONST_NEW(c, loc, names); + ADDOP_LOAD_CONST_NEW(c, LOC(s), names); if (s->v.ImportFrom.module) { - ADDOP_NAME(c, loc, IMPORT_NAME, s->v.ImportFrom.module, names); + ADDOP_NAME(c, LOC(s), IMPORT_NAME, s->v.ImportFrom.module, names); } else { _Py_DECLARE_STR(empty, ""); - ADDOP_NAME(c, loc, IMPORT_NAME, &_Py_STR(empty), names); + ADDOP_NAME(c, LOC(s), IMPORT_NAME, &_Py_STR(empty), names); } - for (i = 0; i < n; i++) { + for (Py_ssize_t i = 0; i < n; i++) { alias_ty alias = (alias_ty)asdl_seq_GET(s->v.ImportFrom.names, i); identifier store_name; if (i == 0 && PyUnicode_READ_CHAR(alias->name, 0) == '*') { assert(n == 1); - ADDOP(c, loc, IMPORT_STAR); + ADDOP(c, LOC(s), IMPORT_STAR); return 1; } - ADDOP_NAME(c, loc, IMPORT_FROM, alias->name, names); + ADDOP_NAME(c, LOC(s), IMPORT_FROM, alias->name, names); store_name = alias->name; - if (alias->asname) + if (alias->asname) { store_name = alias->asname; + } - if (!compiler_nameop(c, loc, store_name, Store)) { + if (!compiler_nameop(c, LOC(s), store_name, Store)) { return 0; } } /* remove imported module */ - ADDOP(c, loc, POP_TOP); + ADDOP(c, LOC(s), POP_TOP); return 1; } diff --git a/Python/future.c b/Python/future.c index d465608ca454..2a45d2ebeab9 100644 --- a/Python/future.c +++ b/Python/future.c @@ -2,8 +2,6 @@ #include "pycore_ast.h" // _PyAST_GetDocString() #define UNDEFINED_FUTURE_FEATURE "future feature %.100s is not defined" -#define ERR_LATE_FUTURE \ -"from __future__ imports must occur at the beginning of the file" static int future_check_features(PyFutureFeatures *ff, stmt_ty s, PyObject *filename) @@ -56,59 +54,42 @@ future_check_features(PyFutureFeatures *ff, stmt_ty s, PyObject *filename) static int future_parse(PyFutureFeatures *ff, mod_ty mod, PyObject *filename) { - int i, done = 0, prev_line = 0; - - if (!(mod->kind == Module_kind || mod->kind == Interactive_kind)) + if (!(mod->kind == Module_kind || mod->kind == Interactive_kind)) { return 1; + } - if (asdl_seq_LEN(mod->v.Module.body) == 0) + Py_ssize_t n = asdl_seq_LEN(mod->v.Module.body); + if (n == 0) { return 1; + } - /* A subsequent pass will detect future imports that don't - appear at the beginning of the file. There's one case, - however, that is easier to handle here: A series of imports - joined by semi-colons, where the first import is a future - statement but some subsequent import has the future form - but is preceded by a regular import. - */ - - i = 0; - if (_PyAST_GetDocString(mod->v.Module.body) != NULL) + Py_ssize_t i = 0; + if (_PyAST_GetDocString(mod->v.Module.body) != NULL) { i++; + } - for (; i < asdl_seq_LEN(mod->v.Module.body); i++) { + for (; i < n; i++) { stmt_ty s = (stmt_ty)asdl_seq_GET(mod->v.Module.body, i); - if (done && s->lineno > prev_line) - return 1; - prev_line = s->lineno; - - /* The tests below will return from this function unless it is - still possible to find a future statement. The only things - that can precede a future statement are another future - statement and a doc string. - */ + /* The only things that can precede a future statement + * are another future statement and a doc string. + */ if (s->kind == ImportFrom_kind) { identifier modname = s->v.ImportFrom.module; if (modname && _PyUnicode_EqualToASCIIString(modname, "__future__")) { - if (done) { - PyErr_SetString(PyExc_SyntaxError, - ERR_LATE_FUTURE); - PyErr_SyntaxLocationObject(filename, s->lineno, s->col_offset); + if (!future_check_features(ff, s, filename)) { return 0; } - if (!future_check_features(ff, s, filename)) - return 0; - ff->ff_lineno = s->lineno; + ff->ff_location = SRC_LOCATION_FROM_AST(s); } else { - done = 1; + return 1; } } else { - done = 1; + return 1; } } return 1; @@ -126,7 +107,7 @@ _PyFuture_FromAST(mod_ty mod, PyObject *filename) return NULL; } ff->ff_features = 0; - ff->ff_lineno = -1; + ff->ff_location = (_PyCompilerSrcLocation){-1, -1, -1, -1}; if (!future_parse(ff, mod, filename)) { PyObject_Free(ff); From webhook-mailer at python.org Mon Oct 31 09:27:19 2022 From: webhook-mailer at python.org (pablogsal) Date: Mon, 31 Oct 2022 13:27:19 -0000 Subject: [Python-checkins] gh-98878: Use builtins from the bound frame when offering a suggestion (#98880) Message-ID: https://github.com/python/cpython/commit/a41de32942b7ac14524587a08d219f3bfe346415 commit: a41de32942b7ac14524587a08d219f3bfe346415 branch: main author: Batuhan Taskaya committer: pablogsal date: 2022-10-31T13:27:13Z summary: gh-98878: Use builtins from the bound frame when offering a suggestion (#98880) files: A Misc/NEWS.d/next/Library/2022-10-30-22-42-48.gh-issue-98878.fgrykp.rst M Lib/test/test_traceback.py M Lib/traceback.py diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 56b168735d15..149d0234fe8a 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -7,6 +7,7 @@ import types import inspect import importlib +import builtins import unittest import re import tempfile @@ -3209,6 +3210,14 @@ def func(): actual = self.get_suggestion(func) self.assertIn("'ZeroDivisionError'?", actual) + def test_name_error_suggestions_from_builtins_when_builtins_is_module(self): + def func(): + custom_globals = globals().copy() + custom_globals["__builtins__"] = builtins + print(eval("ZeroDivisionErrrrr", custom_globals)) + actual = self.get_suggestion(func) + self.assertIn("'ZeroDivisionError'?", actual) + def test_name_error_suggestions_do_not_trigger_for_long_names(self): def func(): somethingverywronghehehehehehe = None diff --git a/Lib/traceback.py b/Lib/traceback.py index 0f0f2b317de2..cf5f355ff04c 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -1035,7 +1035,7 @@ def _compute_suggestion_error(exc_value, tb, wrong_name): d = ( list(frame.f_locals) + list(frame.f_globals) - + list(frame.f_globals['__builtins__']) + + list(frame.f_builtins) ) if len(d) > _MAX_CANDIDATE_ITEMS: return None diff --git a/Misc/NEWS.d/next/Library/2022-10-30-22-42-48.gh-issue-98878.fgrykp.rst b/Misc/NEWS.d/next/Library/2022-10-30-22-42-48.gh-issue-98878.fgrykp.rst new file mode 100644 index 000000000000..e83422a77a22 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-30-22-42-48.gh-issue-98878.fgrykp.rst @@ -0,0 +1,2 @@ +Use the frame bound builtins when offering a name suggestion in +:mod:`traceback` to prevent crashing when ``__builtins__`` is not a dict. From webhook-mailer at python.org Mon Oct 31 10:02:06 2022 From: webhook-mailer at python.org (encukou) Date: Mon, 31 Oct 2022 14:02:06 -0000 Subject: [Python-checkins] gh-98410: move getbufferproc and releasebufferproc to buffer.h (#31158) Message-ID: https://github.com/python/cpython/commit/e98923c0be644c474ce0e318d40e0595e4484106 commit: e98923c0be644c474ce0e318d40e0595e4484106 branch: main author: David Hewitt <1939362+davidhewitt at users.noreply.github.com> committer: encukou date: 2022-10-31T15:01:32+01:00 summary: gh-98410: move getbufferproc and releasebufferproc to buffer.h (#31158) This adds them to the Limited API. files: A Misc/NEWS.d/next/C API/2022-10-25-17-50-43.gh-issue-98410.NSXYfm.rst M Doc/data/stable_abi.dat M Include/cpython/object.h M Include/pybuffer.h M Misc/stable_abi.toml diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat index 133658491c5a..db8fc15d93d1 100644 --- a/Doc/data/stable_abi.dat +++ b/Doc/data/stable_abi.dat @@ -865,6 +865,7 @@ type,descrsetfunc,3.2,, type,destructor,3.2,, type,getattrfunc,3.2,, type,getattrofunc,3.2,, +type,getbufferproc,3.12,, type,getiterfunc,3.2,, type,getter,3.2,, type,hashfunc,3.2,, @@ -875,6 +876,7 @@ type,lenfunc,3.2,, type,newfunc,3.2,, type,objobjargproc,3.2,, type,objobjproc,3.2,, +type,releasebufferproc,3.12,, type,reprfunc,3.2,, type,richcmpfunc,3.2,, type,setattrfunc,3.2,, diff --git a/Include/cpython/object.h b/Include/cpython/object.h index 900b52321dff..fa0cfb244849 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -51,10 +51,6 @@ typedef struct _Py_Identifier { #endif /* NEEDS_PY_IDENTIFIER */ -typedef int (*getbufferproc)(PyObject *, Py_buffer *, int); -typedef void (*releasebufferproc)(PyObject *, Py_buffer *); - - typedef struct { /* Number implementations must check *both* arguments for proper type and implement the necessary conversions diff --git a/Include/pybuffer.h b/Include/pybuffer.h index 6893505e66e3..bbac60972f51 100644 --- a/Include/pybuffer.h +++ b/Include/pybuffer.h @@ -32,6 +32,9 @@ typedef struct { void *internal; } Py_buffer; +typedef int (*getbufferproc)(PyObject *, Py_buffer *, int); +typedef void (*releasebufferproc)(PyObject *, Py_buffer *); + /* Return 1 if the getbuffer function is available, otherwise return 0. */ PyAPI_FUNC(int) PyObject_CheckBuffer(PyObject *obj); diff --git a/Misc/NEWS.d/next/C API/2022-10-25-17-50-43.gh-issue-98410.NSXYfm.rst b/Misc/NEWS.d/next/C API/2022-10-25-17-50-43.gh-issue-98410.NSXYfm.rst new file mode 100644 index 000000000000..d98bc4e81031 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2022-10-25-17-50-43.gh-issue-98410.NSXYfm.rst @@ -0,0 +1 @@ +Add ``getbufferproc`` and ``releasebufferproc`` to the stable API. diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml index e18a6e8f6a9c..0ba0f51b2de4 100644 --- a/Misc/stable_abi.toml +++ b/Misc/stable_abi.toml @@ -2299,3 +2299,7 @@ added = '3.12' [macro.PY_VECTORCALL_ARGUMENTS_OFFSET] added = '3.12' +[typedef.getbufferproc] + added = '3.12' +[typedef.releasebufferproc] + added = '3.12' From webhook-mailer at python.org Mon Oct 31 10:59:39 2022 From: webhook-mailer at python.org (ericvsmith) Date: Mon, 31 Oct 2022 14:59:39 -0000 Subject: [Python-checkins] [3.11] gh-96151: Use a private name for passing builtins to dataclass. This now allows for a field named BUILTIN (gh-98143) (gh-98900) Message-ID: https://github.com/python/cpython/commit/ca24e496bad2fcae0994b0de583f9cedc85bbd80 commit: ca24e496bad2fcae0994b0de583f9cedc85bbd80 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ericvsmith date: 2022-10-31T10:59:00-04:00 summary: [3.11] gh-96151: Use a private name for passing builtins to dataclass. This now allows for a field named BUILTIN (gh-98143) (gh-98900) gh-96151: Use a private name for passing builtins to dataclass. This now allows for a field named BUILTIN (gh-98143) (cherry picked from commit 29f98b46b77ee528477b9a7b335974b9682f7f14) Co-authored-by: Shantanu <12621235+hauntsaninja at users.noreply.github.com> Co-authored-by: Shantanu <12621235+hauntsaninja at users.noreply.github.com> files: A Misc/NEWS.d/next/Library/2022-10-10-07-07-31.gh-issue-96151.K9fwoq.rst M Lib/dataclasses.py M Lib/test/test_dataclasses.py diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index a567a33d646f..37e4ff702d61 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -412,13 +412,11 @@ def wrapper(self): def _create_fn(name, args, body, *, globals=None, locals=None, return_type=MISSING): - # Note that we mutate locals when exec() is called. Caller - # beware! The only callers are internal to this module, so no + # Note that we may mutate locals. Callers beware! + # The only callers are internal to this module, so no # worries about external callers. if locals is None: locals = {} - if 'BUILTINS' not in locals: - locals['BUILTINS'] = builtins return_annotation = '' if return_type is not MISSING: locals['_return_type'] = return_type @@ -444,7 +442,7 @@ def _field_assign(frozen, name, value, self_name): # self_name is what "self" is called in this function: don't # hard-code "self", since that might be a field name. if frozen: - return f'BUILTINS.object.__setattr__({self_name},{name!r},{value})' + return f'__dataclass_builtins_object__.__setattr__({self_name},{name!r},{value})' return f'{self_name}.{name}={value}' @@ -551,6 +549,7 @@ def _init_fn(fields, std_fields, kw_only_fields, frozen, has_post_init, locals.update({ 'MISSING': MISSING, '_HAS_DEFAULT_FACTORY': _HAS_DEFAULT_FACTORY, + '__dataclass_builtins_object__': object, }) body_lines = [] diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py index 63380ea0b680..0d809bd2eb9a 100644 --- a/Lib/test/test_dataclasses.py +++ b/Lib/test/test_dataclasses.py @@ -231,6 +231,14 @@ class C: c = C('foo') self.assertEqual(c.object, 'foo') + def test_field_named_BUILTINS_frozen(self): + # gh-96151 + @dataclass(frozen=True) + class C: + BUILTINS: int + c = C(5) + self.assertEqual(c.BUILTINS, 5) + def test_field_named_like_builtin(self): # Attribute names can shadow built-in names # since code generation is used. diff --git a/Misc/NEWS.d/next/Library/2022-10-10-07-07-31.gh-issue-96151.K9fwoq.rst b/Misc/NEWS.d/next/Library/2022-10-10-07-07-31.gh-issue-96151.K9fwoq.rst new file mode 100644 index 000000000000..700c9748735f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-10-07-07-31.gh-issue-96151.K9fwoq.rst @@ -0,0 +1 @@ +Allow ``BUILTINS`` to be a valid field name for frozen dataclasses. From webhook-mailer at python.org Mon Oct 31 10:59:39 2022 From: webhook-mailer at python.org (ericvsmith) Date: Mon, 31 Oct 2022 14:59:39 -0000 Subject: [Python-checkins] [3.10] gh-96151: Use a private name for passing builtins to dataclass. This now allows for a field named BUILTIN (gh-98143) (gh-98899) Message-ID: https://github.com/python/cpython/commit/789d1322f626e9a91ca1c186ee163197d4ffb842 commit: 789d1322f626e9a91ca1c186ee163197d4ffb842 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ericvsmith date: 2022-10-31T10:59:18-04:00 summary: [3.10] gh-96151: Use a private name for passing builtins to dataclass. This now allows for a field named BUILTIN (gh-98143) (gh-98899) gh-96151: Use a private name for passing builtins to dataclass. This now allows for a field named BUILTIN (gh-98143) (cherry picked from commit 29f98b46b77ee528477b9a7b335974b9682f7f14) Co-authored-by: Shantanu <12621235+hauntsaninja at users.noreply.github.com> Co-authored-by: Shantanu <12621235+hauntsaninja at users.noreply.github.com> files: A Misc/NEWS.d/next/Library/2022-10-10-07-07-31.gh-issue-96151.K9fwoq.rst M Lib/dataclasses.py M Lib/test/test_dataclasses.py diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index 105a95b95540..e1687a117d6f 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -411,13 +411,11 @@ def wrapper(self): def _create_fn(name, args, body, *, globals=None, locals=None, return_type=MISSING): - # Note that we mutate locals when exec() is called. Caller - # beware! The only callers are internal to this module, so no + # Note that we may mutate locals. Callers beware! + # The only callers are internal to this module, so no # worries about external callers. if locals is None: locals = {} - if 'BUILTINS' not in locals: - locals['BUILTINS'] = builtins return_annotation = '' if return_type is not MISSING: locals['_return_type'] = return_type @@ -443,7 +441,7 @@ def _field_assign(frozen, name, value, self_name): # self_name is what "self" is called in this function: don't # hard-code "self", since that might be a field name. if frozen: - return f'BUILTINS.object.__setattr__({self_name},{name!r},{value})' + return f'__dataclass_builtins_object__.__setattr__({self_name},{name!r},{value})' return f'{self_name}.{name}={value}' @@ -550,6 +548,7 @@ def _init_fn(fields, std_fields, kw_only_fields, frozen, has_post_init, locals.update({ 'MISSING': MISSING, '_HAS_DEFAULT_FACTORY': _HAS_DEFAULT_FACTORY, + '__dataclass_builtins_object__': object, }) body_lines = [] diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py index f72e81c31e61..e805f0cf4cc7 100644 --- a/Lib/test/test_dataclasses.py +++ b/Lib/test/test_dataclasses.py @@ -230,6 +230,14 @@ class C: c = C('foo') self.assertEqual(c.object, 'foo') + def test_field_named_BUILTINS_frozen(self): + # gh-96151 + @dataclass(frozen=True) + class C: + BUILTINS: int + c = C(5) + self.assertEqual(c.BUILTINS, 5) + def test_field_named_like_builtin(self): # Attribute names can shadow built-in names # since code generation is used. diff --git a/Misc/NEWS.d/next/Library/2022-10-10-07-07-31.gh-issue-96151.K9fwoq.rst b/Misc/NEWS.d/next/Library/2022-10-10-07-07-31.gh-issue-96151.K9fwoq.rst new file mode 100644 index 000000000000..700c9748735f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-10-07-07-31.gh-issue-96151.K9fwoq.rst @@ -0,0 +1 @@ +Allow ``BUILTINS`` to be a valid field name for frozen dataclasses. From webhook-mailer at python.org Mon Oct 31 11:02:09 2022 From: webhook-mailer at python.org (ericvsmith) Date: Mon, 31 Oct 2022 15:02:09 -0000 Subject: [Python-checkins] gh-98576: Fix types in dataclass.InitVar example (gh-98577) Message-ID: https://github.com/python/cpython/commit/880bafc574bcd811dd7244f9a82056430b489996 commit: 880bafc574bcd811dd7244f9a82056430b489996 branch: main author: Shantanu <12621235+hauntsaninja at users.noreply.github.com> committer: ericvsmith date: 2022-10-31T11:02:02-04:00 summary: gh-98576: Fix types in dataclass.InitVar example (gh-98577) files: M Doc/library/dataclasses.rst diff --git a/Doc/library/dataclasses.rst b/Doc/library/dataclasses.rst index c4895aa822bf..847299649d1e 100644 --- a/Doc/library/dataclasses.rst +++ b/Doc/library/dataclasses.rst @@ -578,8 +578,8 @@ value is not provided when creating the class:: @dataclass class C: i: int - j: int = None - database: InitVar[DatabaseType] = None + j: int | None = None + database: InitVar[DatabaseType | None] = None def __post_init__(self, database): if self.j is None and database is not None: From webhook-mailer at python.org Mon Oct 31 11:09:00 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 31 Oct 2022 15:09:00 -0000 Subject: [Python-checkins] gh-98576: Fix types in dataclass.InitVar example (gh-98577) Message-ID: https://github.com/python/cpython/commit/1907e5a7cca9b7348f76c3f1128058ddc4623f22 commit: 1907e5a7cca9b7348f76c3f1128058ddc4623f22 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-31T08:08:54-07:00 summary: gh-98576: Fix types in dataclass.InitVar example (gh-98577) (cherry picked from commit 880bafc574bcd811dd7244f9a82056430b489996) Co-authored-by: Shantanu <12621235+hauntsaninja at users.noreply.github.com> files: M Doc/library/dataclasses.rst diff --git a/Doc/library/dataclasses.rst b/Doc/library/dataclasses.rst index 02de64288d0d..f66010082ad1 100644 --- a/Doc/library/dataclasses.rst +++ b/Doc/library/dataclasses.rst @@ -561,8 +561,8 @@ value is not provided when creating the class:: @dataclass class C: i: int - j: int = None - database: InitVar[DatabaseType] = None + j: int | None = None + database: InitVar[DatabaseType | None] = None def __post_init__(self, database): if self.j is None and database is not None: From webhook-mailer at python.org Mon Oct 31 11:14:10 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 31 Oct 2022 15:14:10 -0000 Subject: [Python-checkins] gh-98576: Fix types in dataclass.InitVar example (gh-98577) Message-ID: https://github.com/python/cpython/commit/f6f07b252fa91ebc7c7e9ba41a3746ef96db0d78 commit: f6f07b252fa91ebc7c7e9ba41a3746ef96db0d78 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-31T08:14:04-07:00 summary: gh-98576: Fix types in dataclass.InitVar example (gh-98577) (cherry picked from commit 880bafc574bcd811dd7244f9a82056430b489996) Co-authored-by: Shantanu <12621235+hauntsaninja at users.noreply.github.com> files: M Doc/library/dataclasses.rst diff --git a/Doc/library/dataclasses.rst b/Doc/library/dataclasses.rst index c4895aa822bf..847299649d1e 100644 --- a/Doc/library/dataclasses.rst +++ b/Doc/library/dataclasses.rst @@ -578,8 +578,8 @@ value is not provided when creating the class:: @dataclass class C: i: int - j: int = None - database: InitVar[DatabaseType] = None + j: int | None = None + database: InitVar[DatabaseType | None] = None def __post_init__(self, database): if self.j is None and database is not None: From webhook-mailer at python.org Mon Oct 31 11:30:36 2022 From: webhook-mailer at python.org (JulienPalard) Date: Mon, 31 Oct 2022 15:30:36 -0000 Subject: [Python-checkins] Doc: Fix sphinx-lint issues (GH-98911) Message-ID: https://github.com/python/cpython/commit/c1c3be0f9dc414bfae9a5718451ca217751ac687 commit: c1c3be0f9dc414bfae9a5718451ca217751ac687 branch: main author: Julien Palard committer: JulienPalard date: 2022-10-31T16:30:29+01:00 summary: Doc: Fix sphinx-lint issues (GH-98911) They were introduced right between GH-98441 and GH-98408. files: M Doc/library/itertools.rst diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 4f5b61ce62cb..0b5978505a96 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -762,7 +762,7 @@ The primary purpose of the itertools recipes is educational. The recipes show various ways of thinking about individual tools ? for example, that ``chain.from_iterable`` is related to the concept of flattening. The recipes also give ideas about ways that the tools can be combined ? for example, how -`compress()` and `range()` can work together. The recipes also show patterns +``compress()`` and ``range()`` can work together. The recipes also show patterns for using itertools with the :mod:`operator` and :mod:`collections` modules as well as with the built-in itertools such as ``map()``, ``filter()``, ``reversed()``, and ``enumerate()``. From webhook-mailer at python.org Mon Oct 31 13:29:38 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 31 Oct 2022 17:29:38 -0000 Subject: [Python-checkins] Doc: Fix sphinx-lint issues (GH-98911) Message-ID: https://github.com/python/cpython/commit/43cbb3df9a1da7666ed76b83d206ad804618017f commit: 43cbb3df9a1da7666ed76b83d206ad804618017f branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-31T10:29:30-07:00 summary: Doc: Fix sphinx-lint issues (GH-98911) They were introduced right between GH-98441 and GH-98408. (cherry picked from commit c1c3be0f9dc414bfae9a5718451ca217751ac687) Co-authored-by: Julien Palard files: M Doc/library/itertools.rst diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index eb4c8088c771..3d93c2c0573e 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -723,7 +723,7 @@ The primary purpose of the itertools recipes is educational. The recipes show various ways of thinking about individual tools ? for example, that ``chain.from_iterable`` is related to the concept of flattening. The recipes also give ideas about ways that the tools can be combined ? for example, how -`compress()` and `range()` can work together. The recipes also show patterns +``compress()`` and ``range()`` can work together. The recipes also show patterns for using itertools with the :mod:`operator` and :mod:`collections` modules as well as with the built-in itertools such as ``map()``, ``filter()``, ``reversed()``, and ``enumerate()``. From webhook-mailer at python.org Mon Oct 31 13:58:26 2022 From: webhook-mailer at python.org (rhettinger) Date: Mon, 31 Oct 2022 17:58:26 -0000 Subject: [Python-checkins] Fix typo in sorting HOWTO (#98888) Message-ID: https://github.com/python/cpython/commit/3b86538661038ee23d0be80bb7593e2e7856f059 commit: 3b86538661038ee23d0be80bb7593e2e7856f059 branch: main author: partev committer: rhettinger date: 2022-10-31T12:58:13-05:00 summary: Fix typo in sorting HOWTO (#98888) files: M Doc/howto/sorting.rst diff --git a/Doc/howto/sorting.rst b/Doc/howto/sorting.rst index 588e895b04bd..decce12bf3fa 100644 --- a/Doc/howto/sorting.rst +++ b/Doc/howto/sorting.rst @@ -247,7 +247,7 @@ To accommodate those situations, Python provides :class:`functools.cmp_to_key` to wrap the comparison function to make it usable as a key function:: - sorted(words, key=cmp_to_key(strcoll) + sorted(words, key=cmp_to_key(strcoll)) # locale-aware sort order Odds and Ends ============= From webhook-mailer at python.org Mon Oct 31 14:07:40 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 31 Oct 2022 18:07:40 -0000 Subject: [Python-checkins] Fix typo in sorting HOWTO (GH-98888) Message-ID: https://github.com/python/cpython/commit/a4f8db19ad239fd0b4ef8d5d6f20666c8611e7a5 commit: a4f8db19ad239fd0b4ef8d5d6f20666c8611e7a5 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-31T11:07:14-07:00 summary: Fix typo in sorting HOWTO (GH-98888) (cherry picked from commit 3b86538661038ee23d0be80bb7593e2e7856f059) Co-authored-by: partev files: M Doc/howto/sorting.rst diff --git a/Doc/howto/sorting.rst b/Doc/howto/sorting.rst index 588e895b04bd..decce12bf3fa 100644 --- a/Doc/howto/sorting.rst +++ b/Doc/howto/sorting.rst @@ -247,7 +247,7 @@ To accommodate those situations, Python provides :class:`functools.cmp_to_key` to wrap the comparison function to make it usable as a key function:: - sorted(words, key=cmp_to_key(strcoll) + sorted(words, key=cmp_to_key(strcoll)) # locale-aware sort order Odds and Ends ============= From webhook-mailer at python.org Mon Oct 31 14:21:16 2022 From: webhook-mailer at python.org (gvanrossum) Date: Mon, 31 Oct 2022 18:21:16 -0000 Subject: [Python-checkins] [3.11] gh-98793: Fix typecheck in `overlapped.c` (GH-98835) (#98889) Message-ID: https://github.com/python/cpython/commit/2b0cbb90c311ccfed291c3b0f4f8268fdac214ee commit: 2b0cbb90c311ccfed291c3b0f4f8268fdac214ee branch: 3.11 author: Charlie Zhao committer: gvanrossum date: 2022-10-31T11:21:01-07:00 summary: [3.11] gh-98793: Fix typecheck in `overlapped.c` (GH-98835) (#98889) Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> (cherry picked from commit 3ac8c0ab6ee819a14b1c8e0992acbaf376a46058) files: A Misc/NEWS.d/next/Library/2022-10-29-03-40-18.gh-issue-98793.WSPB4A.rst M Lib/test/test_asyncio/test_windows_events.py M Modules/clinic/overlapped.c.h M Modules/overlapped.c diff --git a/Lib/test/test_asyncio/test_windows_events.py b/Lib/test/test_asyncio/test_windows_events.py index 6b4f65c3376f..5033acc05248 100644 --- a/Lib/test/test_asyncio/test_windows_events.py +++ b/Lib/test/test_asyncio/test_windows_events.py @@ -239,6 +239,17 @@ def test_read_self_pipe_restart(self): self.close_loop(self.loop) self.assertFalse(self.loop.call_exception_handler.called) + def test_address_argument_type_error(self): + # Regression test for https://github.com/python/cpython/issues/98793 + proactor = self.loop._proactor + sock = socket.socket(type=socket.SOCK_DGRAM) + bad_address = None + with self.assertRaises(TypeError): + proactor.connect(sock, bad_address) + with self.assertRaises(TypeError): + proactor.sendto(sock, b'abc', addr=bad_address) + sock.close() + class WinPolicyTests(test_utils.TestCase): diff --git a/Misc/NEWS.d/next/Library/2022-10-29-03-40-18.gh-issue-98793.WSPB4A.rst b/Misc/NEWS.d/next/Library/2022-10-29-03-40-18.gh-issue-98793.WSPB4A.rst new file mode 100644 index 000000000000..7b67af06cf3d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-29-03-40-18.gh-issue-98793.WSPB4A.rst @@ -0,0 +1 @@ +Fix argument typechecks in :func:`!_overlapped.WSAConnect` and :func:`!_overlapped.Overlapped.WSASendTo` functions. diff --git a/Modules/clinic/overlapped.c.h b/Modules/clinic/overlapped.c.h index 2f0520d3df4a..6673cbfe4623 100644 --- a/Modules/clinic/overlapped.c.h +++ b/Modules/clinic/overlapped.c.h @@ -851,8 +851,8 @@ _overlapped_WSAConnect(PyObject *module, PyObject *const *args, Py_ssize_t nargs HANDLE ConnectSocket; PyObject *AddressObj; - if (!_PyArg_ParseStack(args, nargs, ""F_HANDLE"O:WSAConnect", - &ConnectSocket, &AddressObj)) { + if (!_PyArg_ParseStack(args, nargs, ""F_HANDLE"O!:WSAConnect", + &ConnectSocket, &PyTuple_Type, &AddressObj)) { goto exit; } return_value = _overlapped_WSAConnect_impl(module, ConnectSocket, AddressObj); @@ -884,8 +884,8 @@ _overlapped_Overlapped_WSASendTo(OverlappedObject *self, PyObject *const *args, DWORD flags; PyObject *AddressObj; - if (!_PyArg_ParseStack(args, nargs, ""F_HANDLE"y*kO:WSASendTo", - &handle, &bufobj, &flags, &AddressObj)) { + if (!_PyArg_ParseStack(args, nargs, ""F_HANDLE"y*kO!:WSASendTo", + &handle, &bufobj, &flags, &PyTuple_Type, &AddressObj)) { goto exit; } return_value = _overlapped_Overlapped_WSASendTo_impl(self, handle, &bufobj, flags, AddressObj); @@ -968,4 +968,4 @@ _overlapped_Overlapped_WSARecvFromInto(OverlappedObject *self, PyObject *const * return return_value; } -/*[clinic end generated code: output=8532bc0e4e1958ac input=a9049054013a1b77]*/ +/*[clinic end generated code: output=5023f7748f0e073e input=a9049054013a1b77]*/ diff --git a/Modules/overlapped.c b/Modules/overlapped.c index 74fba8346c2e..9334dcaa2ee8 100644 --- a/Modules/overlapped.c +++ b/Modules/overlapped.c @@ -1684,7 +1684,7 @@ Overlapped_traverse(OverlappedObject *self, visitproc visit, void *arg) _overlapped.WSAConnect client_handle as ConnectSocket: HANDLE - address_as_bytes as AddressObj: object + address_as_bytes as AddressObj: object(subclass_of='&PyTuple_Type') / Bind a remote address to a connectionless (UDP) socket. @@ -1693,7 +1693,7 @@ Bind a remote address to a connectionless (UDP) socket. static PyObject * _overlapped_WSAConnect_impl(PyObject *module, HANDLE ConnectSocket, PyObject *AddressObj) -/*[clinic end generated code: output=ea0b4391e94dad63 input=169f8075e9ae7fa4]*/ +/*[clinic end generated code: output=ea0b4391e94dad63 input=7cf65313d49c015a]*/ { char AddressBuf[sizeof(struct sockaddr_in6)]; SOCKADDR *Address = (SOCKADDR*)AddressBuf; @@ -1727,7 +1727,7 @@ _overlapped.Overlapped.WSASendTo handle: HANDLE buf as bufobj: Py_buffer flags: DWORD - address_as_bytes as AddressObj: object + address_as_bytes as AddressObj: object(subclass_of='&PyTuple_Type') / Start overlapped sendto over a connectionless (UDP) socket. @@ -1737,7 +1737,7 @@ static PyObject * _overlapped_Overlapped_WSASendTo_impl(OverlappedObject *self, HANDLE handle, Py_buffer *bufobj, DWORD flags, PyObject *AddressObj) -/*[clinic end generated code: output=3cdedc4cfaeb70cd input=b7c1749a62e2e374]*/ +/*[clinic end generated code: output=3cdedc4cfaeb70cd input=31f44cd4ab92fc33]*/ { char AddressBuf[sizeof(struct sockaddr_in6)]; SOCKADDR *Address = (SOCKADDR*)AddressBuf; From webhook-mailer at python.org Mon Oct 31 14:22:08 2022 From: webhook-mailer at python.org (gvanrossum) Date: Mon, 31 Oct 2022 18:22:08 -0000 Subject: [Python-checkins] [3.10] gh-98793: Fix typecheck in `overlapped.c` (GH-98835) (#98890) Message-ID: https://github.com/python/cpython/commit/d3d1738acd4f62869d7f1e119c257e2ee46fd16f commit: d3d1738acd4f62869d7f1e119c257e2ee46fd16f branch: 3.10 author: Charlie Zhao committer: gvanrossum date: 2022-10-31T11:22:02-07:00 summary: [3.10] gh-98793: Fix typecheck in `overlapped.c` (GH-98835) (#98890) Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> (cherry picked from commit 3ac8c0ab6ee819a14b1c8e0992acbaf376a46058) files: A Misc/NEWS.d/next/Library/2022-10-29-03-40-18.gh-issue-98793.WSPB4A.rst M Lib/test/test_asyncio/test_windows_events.py M Modules/clinic/overlapped.c.h M Modules/overlapped.c diff --git a/Lib/test/test_asyncio/test_windows_events.py b/Lib/test/test_asyncio/test_windows_events.py index f276cd205a2f..afd30288b50f 100644 --- a/Lib/test/test_asyncio/test_windows_events.py +++ b/Lib/test/test_asyncio/test_windows_events.py @@ -239,6 +239,17 @@ def test_read_self_pipe_restart(self): self.close_loop(self.loop) self.assertFalse(self.loop.call_exception_handler.called) + def test_address_argument_type_error(self): + # Regression test for https://github.com/python/cpython/issues/98793 + proactor = self.loop._proactor + sock = socket.socket(type=socket.SOCK_DGRAM) + bad_address = None + with self.assertRaises(TypeError): + proactor.connect(sock, bad_address) + with self.assertRaises(TypeError): + proactor.sendto(sock, b'abc', addr=bad_address) + sock.close() + class WinPolicyTests(test_utils.TestCase): diff --git a/Misc/NEWS.d/next/Library/2022-10-29-03-40-18.gh-issue-98793.WSPB4A.rst b/Misc/NEWS.d/next/Library/2022-10-29-03-40-18.gh-issue-98793.WSPB4A.rst new file mode 100644 index 000000000000..7b67af06cf3d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-29-03-40-18.gh-issue-98793.WSPB4A.rst @@ -0,0 +1 @@ +Fix argument typechecks in :func:`!_overlapped.WSAConnect` and :func:`!_overlapped.Overlapped.WSASendTo` functions. diff --git a/Modules/clinic/overlapped.c.h b/Modules/clinic/overlapped.c.h index 43e14a9724b0..fab0633ac2ae 100644 --- a/Modules/clinic/overlapped.c.h +++ b/Modules/clinic/overlapped.c.h @@ -831,8 +831,8 @@ _overlapped_WSAConnect(PyObject *module, PyObject *const *args, Py_ssize_t nargs HANDLE ConnectSocket; PyObject *AddressObj; - if (!_PyArg_ParseStack(args, nargs, ""F_HANDLE"O:WSAConnect", - &ConnectSocket, &AddressObj)) { + if (!_PyArg_ParseStack(args, nargs, ""F_HANDLE"O!:WSAConnect", + &ConnectSocket, &PyTuple_Type, &AddressObj)) { goto exit; } return_value = _overlapped_WSAConnect_impl(module, ConnectSocket, AddressObj); @@ -864,8 +864,8 @@ _overlapped_Overlapped_WSASendTo(OverlappedObject *self, PyObject *const *args, DWORD flags; PyObject *AddressObj; - if (!_PyArg_ParseStack(args, nargs, ""F_HANDLE"OkO:WSASendTo", - &handle, &bufobj, &flags, &AddressObj)) { + if (!_PyArg_ParseStack(args, nargs, ""F_HANDLE"OkO!:WSASendTo", + &handle, &bufobj, &flags, &PyTuple_Type, &AddressObj)) { goto exit; } return_value = _overlapped_Overlapped_WSASendTo_impl(self, handle, bufobj, flags, AddressObj); @@ -905,4 +905,4 @@ _overlapped_Overlapped_WSARecvFrom(OverlappedObject *self, PyObject *const *args exit: return return_value; } -/*[clinic end generated code: output=d3215a6ca589735a input=a9049054013a1b77]*/ +/*[clinic end generated code: output=e685b61b3da0524d input=a9049054013a1b77]*/ diff --git a/Modules/overlapped.c b/Modules/overlapped.c index 7c4570896bc5..b9ca86cbd1f6 100644 --- a/Modules/overlapped.c +++ b/Modules/overlapped.c @@ -1638,7 +1638,7 @@ Overlapped_traverse(OverlappedObject *self, visitproc visit, void *arg) _overlapped.WSAConnect client_handle as ConnectSocket: HANDLE - address_as_bytes as AddressObj: object + address_as_bytes as AddressObj: object(subclass_of='&PyTuple_Type') / Bind a remote address to a connectionless (UDP) socket. @@ -1647,7 +1647,7 @@ Bind a remote address to a connectionless (UDP) socket. static PyObject * _overlapped_WSAConnect_impl(PyObject *module, HANDLE ConnectSocket, PyObject *AddressObj) -/*[clinic end generated code: output=ea0b4391e94dad63 input=169f8075e9ae7fa4]*/ +/*[clinic end generated code: output=ea0b4391e94dad63 input=7cf65313d49c015a]*/ { char AddressBuf[sizeof(struct sockaddr_in6)]; SOCKADDR *Address = (SOCKADDR*)AddressBuf; @@ -1681,7 +1681,7 @@ _overlapped.Overlapped.WSASendTo handle: HANDLE buf as bufobj: object flags: DWORD - address_as_bytes as AddressObj: object + address_as_bytes as AddressObj: object(subclass_of='&PyTuple_Type') / Start overlapped sendto over a connectionless (UDP) socket. @@ -1691,7 +1691,7 @@ static PyObject * _overlapped_Overlapped_WSASendTo_impl(OverlappedObject *self, HANDLE handle, PyObject *bufobj, DWORD flags, PyObject *AddressObj) -/*[clinic end generated code: output=fe0ff55eb60d65e1 input=f709e6ecebd9bc18]*/ +/*[clinic end generated code: output=fe0ff55eb60d65e1 input=932a34941465df43]*/ { char AddressBuf[sizeof(struct sockaddr_in6)]; SOCKADDR *Address = (SOCKADDR*)AddressBuf; From webhook-mailer at python.org Mon Oct 31 15:36:07 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 31 Oct 2022 19:36:07 -0000 Subject: [Python-checkins] gh-98610: Adjust the Optional Restrictions on Subinterpreters (GH-98618) Message-ID: https://github.com/python/cpython/commit/4702552885811d0af8f0e4545f494336801ad4dd commit: 4702552885811d0af8f0e4545f494336801ad4dd branch: main author: Eric Snow committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-31T12:35:54-07:00 summary: gh-98610: Adjust the Optional Restrictions on Subinterpreters (GH-98618) Previously, the optional restrictions on subinterpreters were: disallow fork, subprocess, and threads. By default, we were disallowing all three for "isolated" interpreters. We always allowed all three for the main interpreter and those created through the legacy `Py_NewInterpreter()` API. Those settings were a bit conservative, so here we've adjusted the optional restrictions to: fork, exec, threads, and daemon threads. The default for "isolated" interpreters disables fork, exec, and daemon threads. Regular threads are allowed by default. We continue always allowing everything For the main interpreter and the legacy API. In the code, we add `_PyInterpreterConfig.allow_exec` and `_PyInterpreterConfig.allow_daemon_threads`. We also add `Py_RTFLAGS_DAEMON_THREADS` and `Py_RTFLAGS_EXEC`. files: A Misc/NEWS.d/next/C API/2022-10-24-12-09-17.gh-issue-98610.PLX2Np.rst M Include/cpython/initconfig.h M Include/cpython/pystate.h M Lib/test/test__xxsubinterpreters.py M Lib/test/test_capi.py M Lib/test/test_embed.py M Lib/test/test_threading.py M Lib/threading.py M Modules/_posixsubprocess.c M Modules/_testcapimodule.c M Modules/_threadmodule.c M Modules/_winapi.c M Modules/_xxsubinterpretersmodule.c M Modules/posixmodule.c M Python/pylifecycle.c diff --git a/Include/cpython/initconfig.h b/Include/cpython/initconfig.h index 64748cf78beb..6ce42b4c0950 100644 --- a/Include/cpython/initconfig.h +++ b/Include/cpython/initconfig.h @@ -245,15 +245,25 @@ PyAPI_FUNC(PyStatus) PyConfig_SetWideStringList(PyConfig *config, typedef struct { int allow_fork; - int allow_subprocess; + int allow_exec; int allow_threads; + int allow_daemon_threads; } _PyInterpreterConfig; +#define _PyInterpreterConfig_INIT \ + { \ + .allow_fork = 0, \ + .allow_exec = 0, \ + .allow_threads = 1, \ + .allow_daemon_threads = 0, \ + } + #define _PyInterpreterConfig_LEGACY_INIT \ { \ .allow_fork = 1, \ - .allow_subprocess = 1, \ + .allow_exec = 1, \ .allow_threads = 1, \ + .allow_daemon_threads = 1, \ } /* --- Helper functions --------------------------------------- */ diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h index 7996bd34eac9..70c23427807e 100644 --- a/Include/cpython/pystate.h +++ b/Include/cpython/pystate.h @@ -11,16 +11,17 @@ is available in a given context. For example, forking the process might not be allowed in the current interpreter (i.e. os.fork() would fail). */ -// We leave the first 10 for less-specific features. - /* Set if threads are allowed. */ -#define Py_RTFLAGS_THREADS (1UL << 10) +#define Py_RTFLAGS_THREADS (1UL << 10) + +/* Set if daemon threads are allowed. */ +#define Py_RTFLAGS_DAEMON_THREADS (1UL << 11) /* Set if os.fork() is allowed. */ -#define Py_RTFLAGS_FORK (1UL << 15) +#define Py_RTFLAGS_FORK (1UL << 15) -/* Set if subprocesses are allowed. */ -#define Py_RTFLAGS_SUBPROCESS (1UL << 16) +/* Set if os.exec*() is allowed. */ +#define Py_RTFLAGS_EXEC (1UL << 16) PyAPI_FUNC(int) _PyInterpreterState_HasFeature(PyInterpreterState *interp, diff --git a/Lib/test/test__xxsubinterpreters.py b/Lib/test/test__xxsubinterpreters.py index f20aae8e21c6..66f29b95af10 100644 --- a/Lib/test/test__xxsubinterpreters.py +++ b/Lib/test/test__xxsubinterpreters.py @@ -801,7 +801,7 @@ def f(): self.assertEqual(out, 'it worked!') def test_create_thread(self): - subinterp = interpreters.create(isolated=False) + subinterp = interpreters.create() script, file = _captured_script(""" import threading def f(): @@ -817,6 +817,61 @@ def f(): self.assertEqual(out, 'it worked!') + def test_create_daemon_thread(self): + with self.subTest('isolated'): + expected = 'spam spam spam spam spam' + subinterp = interpreters.create(isolated=True) + script, file = _captured_script(f""" + import threading + def f(): + print('it worked!', end='') + + try: + t = threading.Thread(target=f, daemon=True) + t.start() + t.join() + except RuntimeError: + print('{expected}', end='') + """) + with file: + interpreters.run_string(subinterp, script) + out = file.read() + + self.assertEqual(out, expected) + + with self.subTest('not isolated'): + subinterp = interpreters.create(isolated=False) + script, file = _captured_script(""" + import threading + def f(): + print('it worked!', end='') + + t = threading.Thread(target=f, daemon=True) + t.start() + t.join() + """) + with file: + interpreters.run_string(subinterp, script) + out = file.read() + + self.assertEqual(out, 'it worked!') + + def test_os_exec(self): + expected = 'spam spam spam spam spam' + subinterp = interpreters.create() + script, file = _captured_script(f""" + import os, sys + try: + os.execl(sys.executable) + except RuntimeError: + print('{expected}', end='') + """) + with file: + interpreters.run_string(subinterp, script) + out = file.read() + + self.assertEqual(out, expected) + @support.requires_fork() def test_fork(self): import tempfile diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py index 2a35576fc57e..49f207ed953c 100644 --- a/Lib/test/test_capi.py +++ b/Lib/test/test_capi.py @@ -1148,15 +1148,16 @@ def test_configured_settings(self): import json THREADS = 1<<10 + DAEMON_THREADS = 1<<11 FORK = 1<<15 - SUBPROCESS = 1<<16 + EXEC = 1<<16 - features = ['fork', 'subprocess', 'threads'] + features = ['fork', 'exec', 'threads', 'daemon_threads'] kwlist = [f'allow_{n}' for n in features] for config, expected in { - (True, True, True): FORK | SUBPROCESS | THREADS, - (False, False, False): 0, - (False, True, True): SUBPROCESS | THREADS, + (True, True, True, True): FORK | EXEC | THREADS | DAEMON_THREADS, + (False, False, False, False): 0, + (False, False, True, False): THREADS, }.items(): kwargs = dict(zip(kwlist, config)) expected = { diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py index 930f76342f0e..fa9815c681e0 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -1655,11 +1655,12 @@ def test_init_use_frozen_modules(self): def test_init_main_interpreter_settings(self): THREADS = 1<<10 + DAEMON_THREADS = 1<<11 FORK = 1<<15 - SUBPROCESS = 1<<16 + EXEC = 1<<16 expected = { # All optional features should be enabled. - 'feature_flags': THREADS | FORK | SUBPROCESS, + 'feature_flags': FORK | EXEC | THREADS | DAEMON_THREADS, } out, err = self.run_embedded_interpreter( 'test_init_main_interpreter_settings', diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py index c66499623314..13ba5068ae20 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -1305,6 +1305,62 @@ def f(): self.assertIn("Fatal Python error: Py_EndInterpreter: " "not the last thread", err.decode()) + def _check_allowed(self, before_start='', *, + allowed=True, + daemon_allowed=True, + daemon=False, + ): + subinterp_code = textwrap.dedent(f""" + import test.support + import threading + def func(): + print('this should not have run!') + t = threading.Thread(target=func, daemon={daemon}) + {before_start} + t.start() + """) + script = textwrap.dedent(f""" + import test.support + test.support.run_in_subinterp_with_config( + {subinterp_code!r}, + allow_fork=True, + allow_exec=True, + allow_threads={allowed}, + allow_daemon_threads={daemon_allowed}, + ) + """) + with test.support.SuppressCrashReport(): + _, _, err = assert_python_ok("-c", script) + return err.decode() + + @cpython_only + def test_threads_not_allowed(self): + err = self._check_allowed( + allowed=False, + daemon_allowed=False, + daemon=False, + ) + self.assertIn('RuntimeError', err) + + @cpython_only + def test_daemon_threads_not_allowed(self): + with self.subTest('via Thread()'): + err = self._check_allowed( + allowed=True, + daemon_allowed=False, + daemon=True, + ) + self.assertIn('RuntimeError', err) + + with self.subTest('via Thread.daemon setter'): + err = self._check_allowed( + 't.daemon = True', + allowed=True, + daemon_allowed=False, + daemon=False, + ) + self.assertIn('RuntimeError', err) + class ThreadingExceptionTests(BaseTestCase): # A RuntimeError should be raised if Thread.start() is called diff --git a/Lib/threading.py b/Lib/threading.py index d030e1243623..723bd58bf5a6 100644 --- a/Lib/threading.py +++ b/Lib/threading.py @@ -33,6 +33,7 @@ # Rename some stuff so "from threading import *" is safe _start_new_thread = _thread.start_new_thread +_daemon_threads_allowed = _thread.daemon_threads_allowed _allocate_lock = _thread.allocate_lock _set_sentinel = _thread._set_sentinel get_ident = _thread.get_ident @@ -899,6 +900,8 @@ class is implemented. self._args = args self._kwargs = kwargs if daemon is not None: + if daemon and not _daemon_threads_allowed(): + raise RuntimeError('daemon threads are disabled in this (sub)interpreter') self._daemonic = daemon else: self._daemonic = current_thread().daemon @@ -1226,6 +1229,8 @@ def daemon(self): def daemon(self, daemonic): if not self._initialized: raise RuntimeError("Thread.__init__() not called") + if daemonic and not _daemon_threads_allowed(): + raise RuntimeError('daemon threads are disabled in this interpreter') if self._started.is_set(): raise RuntimeError("cannot set daemon status of active thread") self._daemonic = daemonic @@ -1432,7 +1437,8 @@ def __init__(self): class _DummyThread(Thread): def __init__(self): - Thread.__init__(self, name=_newname("Dummy-%d"), daemon=True) + Thread.__init__(self, name=_newname("Dummy-%d"), + daemon=_daemon_threads_allowed()) self._started.set() self._set_ident() diff --git a/Misc/NEWS.d/next/C API/2022-10-24-12-09-17.gh-issue-98610.PLX2Np.rst b/Misc/NEWS.d/next/C API/2022-10-24-12-09-17.gh-issue-98610.PLX2Np.rst new file mode 100644 index 000000000000..05bcfae1b61b --- /dev/null +++ b/Misc/NEWS.d/next/C API/2022-10-24-12-09-17.gh-issue-98610.PLX2Np.rst @@ -0,0 +1,9 @@ +Some configurable capabilities of sub-interpreters have changed. +They always allow subprocesses (:mod:`subprocess`) now, whereas before +subprocesses could be optionally disaallowed for a sub-interpreter. +Instead :func:`os.exec` can now be disallowed. +Disallowing daemon threads is now supported. Disallowing all threads +is still allowed, but is never done by default. +Note that the optional restrictions are only available through +``_Py_NewInterpreterFromConfig()``, which isn't a public API. +They do not affect the main interpreter, nor :c:func:`Py_NewInterpreter`. diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c index 8275b116093d..717b1cf22021 100644 --- a/Modules/_posixsubprocess.c +++ b/Modules/_posixsubprocess.c @@ -825,8 +825,8 @@ subprocess_fork_exec(PyObject *module, PyObject *args) &preexec_fn, &allow_vfork)) return NULL; - if ((preexec_fn != Py_None) && - (PyInterpreterState_Get() != PyInterpreterState_Main())) { + PyInterpreterState *interp = PyInterpreterState_Get(); + if ((preexec_fn != Py_None) && (interp != PyInterpreterState_Main())) { PyErr_SetString(PyExc_RuntimeError, "preexec_fn not supported within subinterpreters"); return NULL; @@ -841,13 +841,6 @@ subprocess_fork_exec(PyObject *module, PyObject *args) return NULL; } - PyInterpreterState *interp = PyInterpreterState_Get(); - if (!_PyInterpreterState_HasFeature(interp, Py_RTFLAGS_SUBPROCESS)) { - PyErr_SetString(PyExc_RuntimeError, - "subprocess not supported for isolated subinterpreters"); - return NULL; - } - /* We need to call gc.disable() when we'll be calling preexec_fn */ if (preexec_fn != Py_None) { need_to_reenable_gc = PyGC_Disable(); diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index bade0db64f51..19ceb108ed4e 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -3231,33 +3231,42 @@ run_in_subinterp_with_config(PyObject *self, PyObject *args, PyObject *kwargs) { const char *code; int allow_fork = -1; - int allow_subprocess = -1; + int allow_exec = -1; int allow_threads = -1; + int allow_daemon_threads = -1; int r; PyThreadState *substate, *mainstate; /* only initialise 'cflags.cf_flags' to test backwards compatibility */ PyCompilerFlags cflags = {0}; static char *kwlist[] = {"code", - "allow_fork", "allow_subprocess", "allow_threads", + "allow_fork", + "allow_exec", + "allow_threads", + "allow_daemon_threads", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "s$ppp:run_in_subinterp_with_config", kwlist, - &code, &allow_fork, &allow_subprocess, &allow_threads)) { + "s$pppp:run_in_subinterp_with_config", kwlist, + &code, &allow_fork, &allow_exec, + &allow_threads, &allow_daemon_threads)) { return NULL; } if (allow_fork < 0) { PyErr_SetString(PyExc_ValueError, "missing allow_fork"); return NULL; } - if (allow_subprocess < 0) { - PyErr_SetString(PyExc_ValueError, "missing allow_subprocess"); + if (allow_exec < 0) { + PyErr_SetString(PyExc_ValueError, "missing allow_exec"); return NULL; } if (allow_threads < 0) { PyErr_SetString(PyExc_ValueError, "missing allow_threads"); return NULL; } + if (allow_daemon_threads < 0) { + PyErr_SetString(PyExc_ValueError, "missing allow_daemon_threads"); + return NULL; + } mainstate = PyThreadState_Get(); @@ -3265,8 +3274,9 @@ run_in_subinterp_with_config(PyObject *self, PyObject *args, PyObject *kwargs) const _PyInterpreterConfig config = { .allow_fork = allow_fork, - .allow_subprocess = allow_subprocess, + .allow_exec = allow_exec, .allow_threads = allow_threads, + .allow_daemon_threads = allow_daemon_threads, }; substate = _Py_NewInterpreterFromConfig(&config); if (substate == NULL) { diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c index 93b3b8d85d66..5968d4e2e0ee 100644 --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -1102,6 +1102,24 @@ thread_run(void *boot_raw) // to open the libgcc_s.so library (ex: EMFILE error). } +static PyObject * +thread_daemon_threads_allowed(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + PyInterpreterState *interp = _PyInterpreterState_Get(); + if (interp->feature_flags & Py_RTFLAGS_DAEMON_THREADS) { + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } +} + +PyDoc_STRVAR(daemon_threads_allowed_doc, +"daemon_threads_allowed()\n\ +\n\ +Return True if daemon threads are allowed in the current interpreter,\n\ +and False otherwise.\n"); + static PyObject * thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs) { @@ -1543,6 +1561,8 @@ static PyMethodDef thread_methods[] = { METH_VARARGS, start_new_doc}, {"start_new", (PyCFunction)thread_PyThread_start_new_thread, METH_VARARGS, start_new_doc}, + {"daemon_threads_allowed", (PyCFunction)thread_daemon_threads_allowed, + METH_NOARGS, daemon_threads_allowed_doc}, {"allocate_lock", thread_PyThread_allocate_lock, METH_NOARGS, allocate_doc}, {"allocate", thread_PyThread_allocate_lock, diff --git a/Modules/_winapi.c b/Modules/_winapi.c index 2a916cc9f467..71e74d155cdc 100644 --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -1089,13 +1089,6 @@ _winapi_CreateProcess_impl(PyObject *module, return NULL; } - PyInterpreterState *interp = PyInterpreterState_Get(); - if (!_PyInterpreterState_HasFeature(interp, Py_RTFLAGS_SUBPROCESS)) { - PyErr_SetString(PyExc_RuntimeError, - "subprocess not supported for isolated subinterpreters"); - return NULL; - } - ZeroMemory(&si, sizeof(si)); si.StartupInfo.cb = sizeof(si); diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c index f38de57f69e2..9d979ef113e6 100644 --- a/Modules/_xxsubinterpretersmodule.c +++ b/Modules/_xxsubinterpretersmodule.c @@ -2003,11 +2003,9 @@ interp_create(PyObject *self, PyObject *args, PyObject *kwds) // Create and initialize the new interpreter. PyThreadState *save_tstate = _PyThreadState_GET(); - const _PyInterpreterConfig config = { - .allow_fork = !isolated, - .allow_subprocess = !isolated, - .allow_threads = !isolated, - }; + const _PyInterpreterConfig config = isolated + ? (_PyInterpreterConfig)_PyInterpreterConfig_INIT + : (_PyInterpreterConfig)_PyInterpreterConfig_LEGACY_INIT; // XXX Possible GILState issues? PyThreadState *tstate = _Py_NewInterpreterFromConfig(&config); PyThreadState_Swap(save_tstate); diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index a5eb86631211..d863f9f63248 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -5773,6 +5773,13 @@ os_execv_impl(PyObject *module, path_t *path, PyObject *argv) EXECV_CHAR **argvlist; Py_ssize_t argc; + PyInterpreterState *interp = _PyInterpreterState_GET(); + if (!_PyInterpreterState_HasFeature(interp, Py_RTFLAGS_EXEC)) { + PyErr_SetString(PyExc_RuntimeError, + "exec not supported for isolated subinterpreters"); + return NULL; + } + /* execv has two arguments: (path, argv), where argv is a list or tuple of strings. */ @@ -5839,6 +5846,13 @@ os_execve_impl(PyObject *module, path_t *path, PyObject *argv, PyObject *env) EXECV_CHAR **envlist; Py_ssize_t argc, envc; + PyInterpreterState *interp = _PyInterpreterState_GET(); + if (!_PyInterpreterState_HasFeature(interp, Py_RTFLAGS_EXEC)) { + PyErr_SetString(PyExc_RuntimeError, + "exec not supported for isolated subinterpreters"); + return NULL; + } + /* execve has three arguments: (path, argv, env), where argv is a list or tuple of strings and env is a dictionary like posix.environ. */ diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index d26ae74a0f17..e64849296c57 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -615,15 +615,21 @@ static void init_interp_settings(PyInterpreterState *interp, const _PyInterpreterConfig *config) { assert(interp->feature_flags == 0); + if (config->allow_fork) { interp->feature_flags |= Py_RTFLAGS_FORK; } - if (config->allow_subprocess) { - interp->feature_flags |= Py_RTFLAGS_SUBPROCESS; + if (config->allow_exec) { + interp->feature_flags |= Py_RTFLAGS_EXEC; } + // Note that fork+exec is always allowed. + if (config->allow_threads) { interp->feature_flags |= Py_RTFLAGS_THREADS; } + if (config->allow_daemon_threads) { + interp->feature_flags |= Py_RTFLAGS_DAEMON_THREADS; + } } From webhook-mailer at python.org Mon Oct 31 17:06:08 2022 From: webhook-mailer at python.org (zooba) Date: Mon, 31 Oct 2022 21:06:08 -0000 Subject: [Python-checkins] gh-98692: Enable treating shebang lines as executables in py.exe launcher (GH-98732) Message-ID: https://github.com/python/cpython/commit/88297e2a8a75898228360ee369628a4a6111e2ee commit: 88297e2a8a75898228360ee369628a4a6111e2ee branch: main author: Steve Dower committer: zooba date: 2022-10-31T21:05:50Z summary: gh-98692: Enable treating shebang lines as executables in py.exe launcher (GH-98732) files: A Misc/NEWS.d/next/Windows/2022-10-26-17-43-09.gh-issue-98692.bOopfZ.rst M Doc/using/windows.rst M Lib/test/test_launcher.py M PC/launcher2.c diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst index b5c2c8ca7120..fdbe4c15a200 100644 --- a/Doc/using/windows.rst +++ b/Doc/using/windows.rst @@ -866,7 +866,6 @@ minor version. I.e. ``/usr/bin/python3.7-32`` will request usage of the not provably i386/32-bit". To request a specific environment, use the new ``-V:`` argument with the complete tag. - The ``/usr/bin/env`` form of shebang line has one further special property. Before looking for installed Python interpreters, this form will search the executable :envvar:`PATH` for a Python executable. This corresponds to the @@ -876,6 +875,13 @@ be found, it will be handled as described below. Additionally, the environment variable :envvar:`PYLAUNCHER_NO_SEARCH_PATH` may be set (to any value) to skip this additional search. +Shebang lines that do not match any of these patterns are treated as **Windows** +paths that are absolute or relative to the directory containing the script file. +This is a convenience for Windows-only scripts, such as those generated by an +installer, since the behavior is not compatible with Unix-style shells. +These paths may be quoted, and may include multiple arguments, after which the +path to the script and any additional arguments will be appended. + Arguments in shebang lines -------------------------- diff --git a/Lib/test/test_launcher.py b/Lib/test/test_launcher.py index 432a44622b5f..6ad85dc9c300 100644 --- a/Lib/test/test_launcher.py +++ b/Lib/test/test_launcher.py @@ -516,6 +516,14 @@ def test_py_shebang(self): self.assertEqual("3.100", data["SearchInfo.tag"]) self.assertEqual(f"X.Y.exe -prearg {script} -postarg", data["stdout"].strip()) + def test_python_shebang(self): + with self.py_ini(TEST_PY_COMMANDS): + with self.script("#! python -prearg") as script: + data = self.run_py([script, "-postarg"]) + self.assertEqual("PythonTestSuite", data["SearchInfo.company"]) + self.assertEqual("3.100", data["SearchInfo.tag"]) + self.assertEqual(f"X.Y.exe -prearg {script} -postarg", data["stdout"].strip()) + def test_py2_shebang(self): with self.py_ini(TEST_PY_COMMANDS): with self.script("#! /usr/bin/python2 -prearg") as script: @@ -617,3 +625,42 @@ def test_install(self): self.assertIn("winget.exe", cmd) # Both command lines include the store ID self.assertIn("9PJPW5LDXLZ5", cmd) + + def test_literal_shebang_absolute(self): + with self.script(f"#! C:/some_random_app -witharg") as script: + data = self.run_py([script]) + self.assertEqual( + f"C:\\some_random_app -witharg {script}", + data["stdout"].strip(), + ) + + def test_literal_shebang_relative(self): + with self.script(f"#! ..\\some_random_app -witharg") as script: + data = self.run_py([script]) + self.assertEqual( + f"{script.parent.parent}\\some_random_app -witharg {script}", + data["stdout"].strip(), + ) + + def test_literal_shebang_quoted(self): + with self.script(f'#! "some random app" -witharg') as script: + data = self.run_py([script]) + self.assertEqual( + f'"{script.parent}\\some random app" -witharg {script}', + data["stdout"].strip(), + ) + + with self.script(f'#! some" random "app -witharg') as script: + data = self.run_py([script]) + self.assertEqual( + f'"{script.parent}\\some random app" -witharg {script}', + data["stdout"].strip(), + ) + + def test_literal_shebang_quoted_escape(self): + with self.script(f'#! some\\" random "app -witharg') as script: + data = self.run_py([script]) + self.assertEqual( + f'"{script.parent}\\some\\ random app" -witharg {script}', + data["stdout"].strip(), + ) diff --git a/Misc/NEWS.d/next/Windows/2022-10-26-17-43-09.gh-issue-98692.bOopfZ.rst b/Misc/NEWS.d/next/Windows/2022-10-26-17-43-09.gh-issue-98692.bOopfZ.rst new file mode 100644 index 000000000000..3a5efd9a1cfa --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2022-10-26-17-43-09.gh-issue-98692.bOopfZ.rst @@ -0,0 +1,2 @@ +Fix the :ref:`launcher` ignoring unrecognized shebang lines instead of +treating them as local paths diff --git a/PC/launcher2.c b/PC/launcher2.c index b1ad5f066ede..5bcd2ba8a067 100644 --- a/PC/launcher2.c +++ b/PC/launcher2.c @@ -871,6 +871,62 @@ _findCommand(SearchInfo *search, const wchar_t *command, int commandLength) } +int +_useShebangAsExecutable(SearchInfo *search, const wchar_t *shebang, int shebangLength) +{ + wchar_t buffer[MAXLEN]; + wchar_t script[MAXLEN]; + wchar_t command[MAXLEN]; + + int commandLength = 0; + int inQuote = 0; + + if (!shebang || !shebangLength) { + return 0; + } + + wchar_t *pC = command; + for (int i = 0; i < shebangLength; ++i) { + wchar_t c = shebang[i]; + if (isspace(c) && !inQuote) { + commandLength = i; + break; + } else if (c == L'"') { + inQuote = !inQuote; + } else if (c == L'/' || c == L'\\') { + *pC++ = L'\\'; + } else { + *pC++ = c; + } + } + *pC = L'\0'; + + if (!GetCurrentDirectoryW(MAXLEN, buffer) || + wcsncpy_s(script, MAXLEN, search->scriptFile, search->scriptFileLength) || + FAILED(PathCchCombineEx(buffer, MAXLEN, buffer, script, + PATHCCH_ALLOW_LONG_PATHS)) || + FAILED(PathCchRemoveFileSpec(buffer, MAXLEN)) || + FAILED(PathCchCombineEx(buffer, MAXLEN, buffer, command, + PATHCCH_ALLOW_LONG_PATHS)) + ) { + return RC_NO_MEMORY; + } + + int n = (int)wcsnlen(buffer, MAXLEN); + wchar_t *path = allocSearchInfoBuffer(search, n + 1); + if (!path) { + return RC_NO_MEMORY; + } + wcscpy_s(path, n + 1, buffer); + search->executablePath = path; + if (commandLength) { + search->executableArgs = &shebang[commandLength]; + search->executableArgsLength = shebangLength - commandLength; + } + return 0; +} + + int checkShebang(SearchInfo *search) { @@ -963,13 +1019,19 @@ checkShebang(SearchInfo *search) L"/usr/bin/env ", L"/usr/bin/", L"/usr/local/bin/", - L"", + L"python", NULL }; for (const wchar_t **tmpl = shebangTemplates; *tmpl; ++tmpl) { if (_shebangStartsWith(shebang, shebangLength, *tmpl, &command)) { commandLength = 0; + // Normally "python" is the start of the command, but we also need it + // as a shebang prefix for back-compat. We move the command marker back + // if we match on that one. + if (0 == wcscmp(*tmpl, L"python")) { + command -= 6; + } while (command[commandLength] && !isspace(command[commandLength])) { commandLength += 1; } @@ -1012,11 +1074,14 @@ checkShebang(SearchInfo *search) debug(L"# Found shebang command but could not execute it: %.*s\n", commandLength, command); } - break; + // search is done by this point + return 0; } } - return 0; + // Unrecognised commands are joined to the script's directory and treated + // as the executable path + return _useShebangAsExecutable(search, shebang, shebangLength); } From webhook-mailer at python.org Mon Oct 31 17:31:32 2022 From: webhook-mailer at python.org (miss-islington) Date: Mon, 31 Oct 2022 21:31:32 -0000 Subject: [Python-checkins] gh-98692: Enable treating shebang lines as executables in py.exe launcher (GH-98732) Message-ID: https://github.com/python/cpython/commit/46a3cf4fe3380b5d4560589cce8f602ba949832d commit: 46a3cf4fe3380b5d4560589cce8f602ba949832d branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-31T14:31:26-07:00 summary: gh-98692: Enable treating shebang lines as executables in py.exe launcher (GH-98732) (cherry picked from commit 88297e2a8a75898228360ee369628a4a6111e2ee) Co-authored-by: Steve Dower files: A Misc/NEWS.d/next/Windows/2022-10-26-17-43-09.gh-issue-98692.bOopfZ.rst M Doc/using/windows.rst M Lib/test/test_launcher.py M PC/launcher2.c diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst index 4ab68e140b9e..4526dc34872d 100644 --- a/Doc/using/windows.rst +++ b/Doc/using/windows.rst @@ -853,7 +853,6 @@ minor version. I.e. ``/usr/bin/python3.7-32`` will request usage of the not provably i386/32-bit". To request a specific environment, use the new ``-V:`` argument with the complete tag. - The ``/usr/bin/env`` form of shebang line has one further special property. Before looking for installed Python interpreters, this form will search the executable :envvar:`PATH` for a Python executable. This corresponds to the @@ -863,6 +862,13 @@ be found, it will be handled as described below. Additionally, the environment variable :envvar:`PYLAUNCHER_NO_SEARCH_PATH` may be set (to any value) to skip this additional search. +Shebang lines that do not match any of these patterns are treated as **Windows** +paths that are absolute or relative to the directory containing the script file. +This is a convenience for Windows-only scripts, such as those generated by an +installer, since the behavior is not compatible with Unix-style shells. +These paths may be quoted, and may include multiple arguments, after which the +path to the script and any additional arguments will be appended. + Arguments in shebang lines -------------------------- diff --git a/Lib/test/test_launcher.py b/Lib/test/test_launcher.py index ba6856b3e246..be6d0022693b 100644 --- a/Lib/test/test_launcher.py +++ b/Lib/test/test_launcher.py @@ -517,6 +517,14 @@ def test_py_shebang(self): self.assertEqual("3.100", data["SearchInfo.tag"]) self.assertEqual(f"X.Y.exe -prearg {script} -postarg", data["stdout"].strip()) + def test_python_shebang(self): + with self.py_ini(TEST_PY_COMMANDS): + with self.script("#! python -prearg") as script: + data = self.run_py([script, "-postarg"]) + self.assertEqual("PythonTestSuite", data["SearchInfo.company"]) + self.assertEqual("3.100", data["SearchInfo.tag"]) + self.assertEqual(f"X.Y.exe -prearg {script} -postarg", data["stdout"].strip()) + def test_py2_shebang(self): with self.py_ini(TEST_PY_COMMANDS): with self.script("#! /usr/bin/python2 -prearg") as script: @@ -618,3 +626,42 @@ def test_install(self): self.assertIn("winget.exe", cmd) # Both command lines include the store ID self.assertIn("9PJPW5LDXLZ5", cmd) + + def test_literal_shebang_absolute(self): + with self.script(f"#! C:/some_random_app -witharg") as script: + data = self.run_py([script]) + self.assertEqual( + f"C:\\some_random_app -witharg {script}", + data["stdout"].strip(), + ) + + def test_literal_shebang_relative(self): + with self.script(f"#! ..\\some_random_app -witharg") as script: + data = self.run_py([script]) + self.assertEqual( + f"{script.parent.parent}\\some_random_app -witharg {script}", + data["stdout"].strip(), + ) + + def test_literal_shebang_quoted(self): + with self.script(f'#! "some random app" -witharg') as script: + data = self.run_py([script]) + self.assertEqual( + f'"{script.parent}\\some random app" -witharg {script}', + data["stdout"].strip(), + ) + + with self.script(f'#! some" random "app -witharg') as script: + data = self.run_py([script]) + self.assertEqual( + f'"{script.parent}\\some random app" -witharg {script}', + data["stdout"].strip(), + ) + + def test_literal_shebang_quoted_escape(self): + with self.script(f'#! some\\" random "app -witharg') as script: + data = self.run_py([script]) + self.assertEqual( + f'"{script.parent}\\some\\ random app" -witharg {script}', + data["stdout"].strip(), + ) diff --git a/Misc/NEWS.d/next/Windows/2022-10-26-17-43-09.gh-issue-98692.bOopfZ.rst b/Misc/NEWS.d/next/Windows/2022-10-26-17-43-09.gh-issue-98692.bOopfZ.rst new file mode 100644 index 000000000000..3a5efd9a1cfa --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2022-10-26-17-43-09.gh-issue-98692.bOopfZ.rst @@ -0,0 +1,2 @@ +Fix the :ref:`launcher` ignoring unrecognized shebang lines instead of +treating them as local paths diff --git a/PC/launcher2.c b/PC/launcher2.c index b1ad5f066ede..5bcd2ba8a067 100644 --- a/PC/launcher2.c +++ b/PC/launcher2.c @@ -871,6 +871,62 @@ _findCommand(SearchInfo *search, const wchar_t *command, int commandLength) } +int +_useShebangAsExecutable(SearchInfo *search, const wchar_t *shebang, int shebangLength) +{ + wchar_t buffer[MAXLEN]; + wchar_t script[MAXLEN]; + wchar_t command[MAXLEN]; + + int commandLength = 0; + int inQuote = 0; + + if (!shebang || !shebangLength) { + return 0; + } + + wchar_t *pC = command; + for (int i = 0; i < shebangLength; ++i) { + wchar_t c = shebang[i]; + if (isspace(c) && !inQuote) { + commandLength = i; + break; + } else if (c == L'"') { + inQuote = !inQuote; + } else if (c == L'/' || c == L'\\') { + *pC++ = L'\\'; + } else { + *pC++ = c; + } + } + *pC = L'\0'; + + if (!GetCurrentDirectoryW(MAXLEN, buffer) || + wcsncpy_s(script, MAXLEN, search->scriptFile, search->scriptFileLength) || + FAILED(PathCchCombineEx(buffer, MAXLEN, buffer, script, + PATHCCH_ALLOW_LONG_PATHS)) || + FAILED(PathCchRemoveFileSpec(buffer, MAXLEN)) || + FAILED(PathCchCombineEx(buffer, MAXLEN, buffer, command, + PATHCCH_ALLOW_LONG_PATHS)) + ) { + return RC_NO_MEMORY; + } + + int n = (int)wcsnlen(buffer, MAXLEN); + wchar_t *path = allocSearchInfoBuffer(search, n + 1); + if (!path) { + return RC_NO_MEMORY; + } + wcscpy_s(path, n + 1, buffer); + search->executablePath = path; + if (commandLength) { + search->executableArgs = &shebang[commandLength]; + search->executableArgsLength = shebangLength - commandLength; + } + return 0; +} + + int checkShebang(SearchInfo *search) { @@ -963,13 +1019,19 @@ checkShebang(SearchInfo *search) L"/usr/bin/env ", L"/usr/bin/", L"/usr/local/bin/", - L"", + L"python", NULL }; for (const wchar_t **tmpl = shebangTemplates; *tmpl; ++tmpl) { if (_shebangStartsWith(shebang, shebangLength, *tmpl, &command)) { commandLength = 0; + // Normally "python" is the start of the command, but we also need it + // as a shebang prefix for back-compat. We move the command marker back + // if we match on that one. + if (0 == wcscmp(*tmpl, L"python")) { + command -= 6; + } while (command[commandLength] && !isspace(command[commandLength])) { commandLength += 1; } @@ -1012,11 +1074,14 @@ checkShebang(SearchInfo *search) debug(L"# Found shebang command but could not execute it: %.*s\n", commandLength, command); } - break; + // search is done by this point + return 0; } } - return 0; + // Unrecognised commands are joined to the script's directory and treated + // as the executable path + return _useShebangAsExecutable(search, shebang, shebangLength); } From webhook-mailer at python.org Mon Oct 31 22:18:38 2022 From: webhook-mailer at python.org (rhettinger) Date: Tue, 01 Nov 2022 02:18:38 -0000 Subject: [Python-checkins] GH-98897: fix memory leak if `math.dist` raises exception (GH-98898) Message-ID: https://github.com/python/cpython/commit/ab575050709e2b313ca9a9585f09b6f4b0560318 commit: ab575050709e2b313ca9a9585f09b6f4b0560318 branch: main author: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> committer: rhettinger date: 2022-10-31T21:18:32-05:00 summary: GH-98897: fix memory leak if `math.dist` raises exception (GH-98898) files: A Misc/NEWS.d/next/Library/2022-10-31-12-34-03.gh-issue-98897.rgNn4x.rst M Lib/test/test_math.py M Modules/mathmodule.c diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py index cfaf3b3ea26a..bf0d0a56e6ac 100644 --- a/Lib/test/test_math.py +++ b/Lib/test/test_math.py @@ -1006,6 +1006,11 @@ class T(tuple): self.assertEqual(math.dist(p, q), 5*scale) self.assertEqual(math.dist(q, p), 5*scale) + def test_math_dist_leak(self): + # gh-98897: Check for error handling does not leak memory + with self.assertRaises(ValueError): + math.dist([1, 2], [3, 4, 5]) + def testIsqrt(self): # Test a variety of inputs, large and small. test_values = ( diff --git a/Misc/NEWS.d/next/Library/2022-10-31-12-34-03.gh-issue-98897.rgNn4x.rst b/Misc/NEWS.d/next/Library/2022-10-31-12-34-03.gh-issue-98897.rgNn4x.rst new file mode 100644 index 000000000000..f61af2543c7f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-31-12-34-03.gh-issue-98897.rgNn4x.rst @@ -0,0 +1 @@ +Fix memory leak in :func:`math.dist` when both points don't have the same dimension. Patch by Kumar Aditya. diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index 48625c8c18d7..46427876b8f4 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -2717,13 +2717,13 @@ math_dist_impl(PyObject *module, PyObject *p, PyObject *q) if (m != n) { PyErr_SetString(PyExc_ValueError, "both points must have the same number of dimensions"); - return NULL; - + goto error_exit; } if (n > NUM_STACK_ELEMS) { diffs = (double *) PyObject_Malloc(n * sizeof(double)); if (diffs == NULL) { - return PyErr_NoMemory(); + PyErr_NoMemory(); + goto error_exit; } } for (i=0 ; i https://github.com/python/cpython/commit/d22bde983e58eaff9773f32a8324ddf9074e95e1 commit: d22bde983e58eaff9773f32a8324ddf9074e95e1 branch: main author: Manuel Kaufmann committer: rhettinger date: 2022-10-31T21:24:26-05:00 summary: Missing PS1 prompt in tutorial example (GH-98921) files: M Doc/tutorial/controlflow.rst diff --git a/Doc/tutorial/controlflow.rst b/Doc/tutorial/controlflow.rst index 99a77e7addd7..52db51e84cd5 100644 --- a/Doc/tutorial/controlflow.rst +++ b/Doc/tutorial/controlflow.rst @@ -840,8 +840,9 @@ will always bind to the first parameter. For example:: But using ``/`` (positional only arguments), it is possible since it allows ``name`` as a positional argument and ``'name'`` as a key in the keyword arguments:: - def foo(name, /, **kwds): - return 'name' in kwds + >>> def foo(name, /, **kwds): + ... return 'name' in kwds + ... >>> foo(1, **{'name': 2}) True From webhook-mailer at python.org Mon Oct 31 22:40:36 2022 From: webhook-mailer at python.org (miss-islington) Date: Tue, 01 Nov 2022 02:40:36 -0000 Subject: [Python-checkins] GH-98897: fix memory leak if `math.dist` raises exception (GH-98898) Message-ID: https://github.com/python/cpython/commit/8495af8963234aa1c6fe34846e9552a79eaac7af commit: 8495af8963234aa1c6fe34846e9552a79eaac7af branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-31T19:40:30-07:00 summary: GH-98897: fix memory leak if `math.dist` raises exception (GH-98898) (cherry picked from commit ab575050709e2b313ca9a9585f09b6f4b0560318) Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> files: A Misc/NEWS.d/next/Library/2022-10-31-12-34-03.gh-issue-98897.rgNn4x.rst M Lib/test/test_math.py M Modules/mathmodule.c diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py index cfaf3b3ea26a..bf0d0a56e6ac 100644 --- a/Lib/test/test_math.py +++ b/Lib/test/test_math.py @@ -1006,6 +1006,11 @@ class T(tuple): self.assertEqual(math.dist(p, q), 5*scale) self.assertEqual(math.dist(q, p), 5*scale) + def test_math_dist_leak(self): + # gh-98897: Check for error handling does not leak memory + with self.assertRaises(ValueError): + math.dist([1, 2], [3, 4, 5]) + def testIsqrt(self): # Test a variety of inputs, large and small. test_values = ( diff --git a/Misc/NEWS.d/next/Library/2022-10-31-12-34-03.gh-issue-98897.rgNn4x.rst b/Misc/NEWS.d/next/Library/2022-10-31-12-34-03.gh-issue-98897.rgNn4x.rst new file mode 100644 index 000000000000..f61af2543c7f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-31-12-34-03.gh-issue-98897.rgNn4x.rst @@ -0,0 +1 @@ +Fix memory leak in :func:`math.dist` when both points don't have the same dimension. Patch by Kumar Aditya. diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index aa93e756c606..0a907a0c04ba 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -2703,13 +2703,13 @@ math_dist_impl(PyObject *module, PyObject *p, PyObject *q) if (m != n) { PyErr_SetString(PyExc_ValueError, "both points must have the same number of dimensions"); - return NULL; - + goto error_exit; } if (n > NUM_STACK_ELEMS) { diffs = (double *) PyObject_Malloc(n * sizeof(double)); if (diffs == NULL) { - return PyErr_NoMemory(); + PyErr_NoMemory(); + goto error_exit; } } for (i=0 ; i https://github.com/python/cpython/commit/078ce6891c2d663babaf81b1e89f1fef82c007bc commit: 078ce6891c2d663babaf81b1e89f1fef82c007bc branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-31T19:47:29-07:00 summary: GH-98897: fix memory leak if `math.dist` raises exception (GH-98898) (cherry picked from commit ab575050709e2b313ca9a9585f09b6f4b0560318) Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> files: A Misc/NEWS.d/next/Library/2022-10-31-12-34-03.gh-issue-98897.rgNn4x.rst M Lib/test/test_math.py M Modules/mathmodule.c diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py index e5f4e2bbadef..ada196a166b2 100644 --- a/Lib/test/test_math.py +++ b/Lib/test/test_math.py @@ -979,6 +979,11 @@ class T(tuple): self.assertEqual(math.dist(p, q), 5*scale) self.assertEqual(math.dist(q, p), 5*scale) + def test_math_dist_leak(self): + # gh-98897: Check for error handling does not leak memory + with self.assertRaises(ValueError): + math.dist([1, 2], [3, 4, 5]) + def testIsqrt(self): # Test a variety of inputs, large and small. test_values = ( diff --git a/Misc/NEWS.d/next/Library/2022-10-31-12-34-03.gh-issue-98897.rgNn4x.rst b/Misc/NEWS.d/next/Library/2022-10-31-12-34-03.gh-issue-98897.rgNn4x.rst new file mode 100644 index 000000000000..f61af2543c7f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-31-12-34-03.gh-issue-98897.rgNn4x.rst @@ -0,0 +1 @@ +Fix memory leak in :func:`math.dist` when both points don't have the same dimension. Patch by Kumar Aditya. diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index 4534176adce1..f31ca8327719 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -2658,13 +2658,13 @@ math_dist_impl(PyObject *module, PyObject *p, PyObject *q) if (m != n) { PyErr_SetString(PyExc_ValueError, "both points must have the same number of dimensions"); - return NULL; - + goto error_exit; } if (n > NUM_STACK_ELEMS) { diffs = (double *) PyObject_Malloc(n * sizeof(double)); if (diffs == NULL) { - return PyErr_NoMemory(); + PyErr_NoMemory(); + goto error_exit; } } for (i=0 ; i https://github.com/python/cpython/commit/f4d56292e943e822abf68f3c210ccf6b88c587ac commit: f4d56292e943e822abf68f3c210ccf6b88c587ac branch: main author: partev committer: rhettinger date: 2022-10-31T21:49:27-05:00 summary: Fix wording in Functional Programming HOWTO (GH-98939) files: M Doc/howto/functional.rst diff --git a/Doc/howto/functional.rst b/Doc/howto/functional.rst index 7d30c343e372..38a651b0f964 100644 --- a/Doc/howto/functional.rst +++ b/Doc/howto/functional.rst @@ -994,7 +994,7 @@ requesting iterator-2 and its corresponding key. The functools module ==================== -The :mod:`functools` module in Python 2.5 contains some higher-order functions. +The :mod:`functools` module contains some higher-order functions. A **higher-order function** takes one or more functions as input and returns a new function. The most useful tool in this module is the :func:`functools.partial` function. From webhook-mailer at python.org Mon Oct 31 22:53:40 2022 From: webhook-mailer at python.org (gvanrossum) Date: Tue, 01 Nov 2022 02:53:40 -0000 Subject: [Python-checkins] Rename JUMP_TO_INSTRUCTION to GO_TO_INSTRUCTION (#98934) Message-ID: https://github.com/python/cpython/commit/7640ede177682a06f03694478d64c819e39e03d9 commit: 7640ede177682a06f03694478d64c819e39e03d9 branch: main author: Guido van Rossum committer: gvanrossum date: 2022-10-31T19:53:32-07:00 summary: Rename JUMP_TO_INSTRUCTION to GO_TO_INSTRUCTION (#98934) This reduces confusion between jumps at the bytecode level (e.g. JUMPTO(), JUMPBY(), and various JUMP_*() opcodes) and jumps in the C code (which are 'goto' statements). files: M Python/ceval.c diff --git a/Python/ceval.c b/Python/ceval.c index f2250ffbc71f..100aa3d727e4 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -849,7 +849,7 @@ GETITEM(PyObject *v, Py_ssize_t i) { GETLOCAL(i) = value; \ Py_XDECREF(tmp); } while (0) -#define JUMP_TO_INSTRUCTION(op) goto PREDICT_ID(op) +#define GO_TO_INSTRUCTION(op) goto PREDICT_ID(op) #define DEOPT_IF(cond, instname) if (cond) { goto miss; } @@ -1168,7 +1168,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int TARGET(RESUME) { _PyCode_Warmup(frame->f_code); - JUMP_TO_INSTRUCTION(RESUME_QUICK); + GO_TO_INSTRUCTION(RESUME_QUICK); } TARGET(RESUME_QUICK) { @@ -1596,7 +1596,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int else { STAT_INC(BINARY_SUBSCR, deferred); DECREMENT_ADAPTIVE_COUNTER(cache); - JUMP_TO_INSTRUCTION(BINARY_SUBSCR); + GO_TO_INSTRUCTION(BINARY_SUBSCR); } } @@ -1759,7 +1759,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int else { STAT_INC(STORE_SUBSCR, deferred); DECREMENT_ADAPTIVE_COUNTER(cache); - JUMP_TO_INSTRUCTION(STORE_SUBSCR); + GO_TO_INSTRUCTION(STORE_SUBSCR); } } @@ -2275,7 +2275,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int else { STAT_INC(UNPACK_SEQUENCE, deferred); DECREMENT_ADAPTIVE_COUNTER(cache); - JUMP_TO_INSTRUCTION(UNPACK_SEQUENCE); + GO_TO_INSTRUCTION(UNPACK_SEQUENCE); } } @@ -2518,7 +2518,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int else { STAT_INC(LOAD_GLOBAL, deferred); DECREMENT_ADAPTIVE_COUNTER(cache); - JUMP_TO_INSTRUCTION(LOAD_GLOBAL); + GO_TO_INSTRUCTION(LOAD_GLOBAL); } } @@ -2976,7 +2976,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int else { STAT_INC(LOAD_ATTR, deferred); DECREMENT_ADAPTIVE_COUNTER(cache); - JUMP_TO_INSTRUCTION(LOAD_ATTR); + GO_TO_INSTRUCTION(LOAD_ATTR); } } @@ -3208,7 +3208,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int else { STAT_INC(STORE_ATTR, deferred); DECREMENT_ADAPTIVE_COUNTER(cache); - JUMP_TO_INSTRUCTION(STORE_ATTR); + GO_TO_INSTRUCTION(STORE_ATTR); } } @@ -3342,7 +3342,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int else { STAT_INC(COMPARE_OP, deferred); DECREMENT_ADAPTIVE_COUNTER(cache); - JUMP_TO_INSTRUCTION(COMPARE_OP); + GO_TO_INSTRUCTION(COMPARE_OP); } } @@ -3577,7 +3577,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int TARGET(JUMP_BACKWARD) { _PyCode_Warmup(frame->f_code); - JUMP_TO_INSTRUCTION(JUMP_BACKWARD_QUICK); + GO_TO_INSTRUCTION(JUMP_BACKWARD_QUICK); } TARGET(POP_JUMP_IF_FALSE) { @@ -3868,7 +3868,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int else { STAT_INC(FOR_ITER, deferred); DECREMENT_ADAPTIVE_COUNTER(cache); - JUMP_TO_INSTRUCTION(FOR_ITER); + GO_TO_INSTRUCTION(FOR_ITER); } } @@ -4147,7 +4147,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int PEEK(oparg + 1) = self; PEEK(oparg + 2) = meth; Py_DECREF(function); - JUMP_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); + GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); } TARGET(KW_NAMES) { @@ -4250,7 +4250,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int else { STAT_INC(CALL, deferred); DECREMENT_ADAPTIVE_COUNTER(cache); - JUMP_TO_INSTRUCTION(CALL); + GO_TO_INSTRUCTION(CALL); } } @@ -4979,7 +4979,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int else { STAT_INC(BINARY_OP, deferred); DECREMENT_ADAPTIVE_COUNTER(cache); - JUMP_TO_INSTRUCTION(BINARY_OP); + GO_TO_INSTRUCTION(BINARY_OP); } } From webhook-mailer at python.org Mon Oct 31 22:57:49 2022 From: webhook-mailer at python.org (miss-islington) Date: Tue, 01 Nov 2022 02:57:49 -0000 Subject: [Python-checkins] Fix wording in Functional Programming HOWTO (GH-98939) Message-ID: https://github.com/python/cpython/commit/217a31742544729a001dea9139cc272e64e33064 commit: 217a31742544729a001dea9139cc272e64e33064 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2022-10-31T19:57:42-07:00 summary: Fix wording in Functional Programming HOWTO (GH-98939) (cherry picked from commit f4d56292e943e822abf68f3c210ccf6b88c587ac) Co-authored-by: partev files: M Doc/howto/functional.rst diff --git a/Doc/howto/functional.rst b/Doc/howto/functional.rst index 1c3bd23f9fee..e68bc2ebb1cc 100644 --- a/Doc/howto/functional.rst +++ b/Doc/howto/functional.rst @@ -994,7 +994,7 @@ requesting iterator-2 and its corresponding key. The functools module ==================== -The :mod:`functools` module in Python 2.5 contains some higher-order functions. +The :mod:`functools` module contains some higher-order functions. A **higher-order function** takes one or more functions as input and returns a new function. The most useful tool in this module is the :func:`functools.partial` function.