Skip to content

Commit

Permalink
Merge branch 'main' into remove-ghccc
Browse files Browse the repository at this point in the history
  • Loading branch information
savannahostrowski committed Oct 18, 2024
2 parents 9827ade + f8ba9fb commit 4e32743
Show file tree
Hide file tree
Showing 106 changed files with 2,749 additions and 1,093 deletions.
9 changes: 7 additions & 2 deletions Doc/deprecations/pending-removal-in-future.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,13 @@ Pending removal in future versions
The following APIs will be removed in the future,
although there is currently no date scheduled for their removal.

* :mod:`argparse`: Nesting argument groups and nesting mutually exclusive
groups are deprecated.
* :mod:`argparse`:

* Nesting argument groups and nesting mutually exclusive
groups are deprecated.
* Passing the undocumented keyword argument *prefix_chars* to
:meth:`~argparse.ArgumentParser.add_argument_group` is now
deprecated.

* :mod:`array`'s ``'u'`` format code (:gh:`57281`)

Expand Down
47 changes: 47 additions & 0 deletions Doc/howto/argparse.rst
Original file line number Diff line number Diff line change
Expand Up @@ -841,6 +841,53 @@ translated messages.

To translate your own strings in the :mod:`argparse` output, use :mod:`gettext`.

Custom type converters
======================

The :mod:`argparse` module allows you to specify custom type converters for
your command-line arguments. This allows you to modify user input before it's
stored in the :class:`argparse.Namespace`. This can be useful when you need to
pre-process the input before it is used in your program.

When using a custom type converter, you can use any callable that takes a
single string argument (the argument value) and returns the converted value.
However, if you need to handle more complex scenarios, you can use a custom
action class with the **action** parameter instead.

For example, let's say you want to handle arguments with different prefixes and
process them accordingly::

import argparse

parser = argparse.ArgumentParser(prefix_chars='-+')

parser.add_argument('-a', metavar='<value>', action='append',
type=lambda x: ('-', x))
parser.add_argument('+a', metavar='<value>', action='append',
type=lambda x: ('+', x))

args = parser.parse_args()
print(args)

Output:

.. code-block:: shell-session
$ python prog.py -a value1 +a value2
Namespace(a=[('-', 'value1'), ('+', 'value2')])
In this example, we:

* Created a parser with custom prefix characters using the ``prefix_chars``
parameter.

* Defined two arguments, ``-a`` and ``+a``, which used the ``type`` parameter to
create custom type converters to store the value in a tuple with the prefix.

Without the custom type converters, the arguments would have treated the ``-a``
and ``+a`` as the same argument, which would have been undesirable. By using custom
type converters, we were able to differentiate between the two arguments.

Conclusion
==========

Expand Down
9 changes: 3 additions & 6 deletions Doc/library/_thread.rst
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,9 @@ Lock objects have the following methods:
.. versionchanged:: 3.2
Lock acquires can now be interrupted by signals on POSIX.

.. versionchanged:: 3.14
Lock acquires can now be interrupted by signals on Windows.


.. method:: lock.release()

Expand Down Expand Up @@ -219,12 +222,6 @@ In addition to these methods, lock objects can also be used via the
* Calling :func:`sys.exit` or raising the :exc:`SystemExit` exception is
equivalent to calling :func:`_thread.exit`.

* It is platform-dependent whether the :meth:`~threading.Lock.acquire` method
on a lock can be interrupted (so that the :exc:`KeyboardInterrupt` exception
will happen immediately, rather than only after the lock has been acquired or
the operation has timed out). It can be interrupted on POSIX, but not on
Windows.

* When the main thread exits, it is system defined whether the other threads
survive. On most systems, they are killed without executing
:keyword:`try` ... :keyword:`finally` clauses or executing object
Expand Down
32 changes: 31 additions & 1 deletion Doc/library/argparse.rst
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ ArgumentParser objects
formatter_class=argparse.HelpFormatter, \
prefix_chars='-', fromfile_prefix_chars=None, \
argument_default=None, conflict_handler='error', \
add_help=True, allow_abbrev=True, exit_on_error=True)
add_help=True, allow_abbrev=True, exit_on_error=True, \
suggest_on_error=False)

Create a new :class:`ArgumentParser` object. All parameters should be passed
as keyword arguments. Each parameter has its own more detailed description
Expand Down Expand Up @@ -103,6 +104,10 @@ ArgumentParser objects
* exit_on_error_ - Determines whether or not ArgumentParser exits with
error info when an error occurs. (default: ``True``)

* suggest_on_error_ - Enables suggestions for mistyped argument choices
and subparser names (default: ``False``)


.. versionchanged:: 3.5
*allow_abbrev* parameter was added.

Expand Down Expand Up @@ -559,6 +564,27 @@ If the user would like to catch errors manually, the feature can be enabled by s

.. versionadded:: 3.9

suggest_on_error
^^^^^^^^^^^^^^^^

By default, when a user passes an invalid argument choice or subparser name,
:class:`ArgumentParser` will exit with error info and list the permissible
argument choices (if specified) or subparser names as part of the error message.

If the user would like to enable suggestions for mistyped argument choices and
subparser names, the feature can be enabled by setting ``suggest_on_error`` to
``True``. Note that this only applies for arguments when the choices specified
are strings::

>>> parser = argparse.ArgumentParser(description='Process some integers.', suggest_on_error=True)
>>> parser.add_argument('--action', choices=['sum', 'max'])
>>> parser.add_argument('integers', metavar='N', type=int, nargs='+',
... help='an integer for the accumulator')
>>> parser.parse_args(['--action', 'sumn', 1, 2, 3])
tester.py: error: argument --action: invalid choice: 'sumn', maybe you meant 'sum'? (choose from 'sum', 'max')

.. versionadded:: 3.14


The add_argument() method
-------------------------
Expand Down Expand Up @@ -1868,6 +1894,10 @@ Argument groups
The function exists on the API by accident through inheritance and
will be removed in the future.

.. deprecated:: 3.14
Passing prefix_chars_ to :meth:`add_argument_group`
is now deprecated.


Mutual exclusion
^^^^^^^^^^^^^^^^
Expand Down
6 changes: 4 additions & 2 deletions Doc/library/asyncio-dev.rst
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ To handle signals the event loop must be
run in the main thread.

The :meth:`loop.run_in_executor` method can be used with a
:class:`concurrent.futures.ThreadPoolExecutor` to execute
:class:`concurrent.futures.ThreadPoolExecutor` or
:class:`~concurrent.futures.InterpreterPoolExecutor` to execute
blocking code in a different OS thread without blocking the OS thread
that the event loop runs in.

Expand All @@ -128,7 +129,8 @@ if a function performs a CPU-intensive calculation for 1 second,
all concurrent asyncio Tasks and IO operations would be delayed
by 1 second.

An executor can be used to run a task in a different thread or even in
An executor can be used to run a task in a different thread,
including in a different interpreter, or even in
a different process to avoid blocking the OS thread with the
event loop. See the :meth:`loop.run_in_executor` method for more
details.
Expand Down
9 changes: 8 additions & 1 deletion Doc/library/asyncio-eventloop.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1305,6 +1305,12 @@ Executing code in thread or process pools
pool, cpu_bound)
print('custom process pool', result)

# 4. Run in a custom interpreter pool:
with concurrent.futures.InterpreterPoolExecutor() as pool:
result = await loop.run_in_executor(
pool, cpu_bound)
print('custom interpreter pool', result)

if __name__ == '__main__':
asyncio.run(main())

Expand All @@ -1329,7 +1335,8 @@ Executing code in thread or process pools

Set *executor* as the default executor used by :meth:`run_in_executor`.
*executor* must be an instance of
:class:`~concurrent.futures.ThreadPoolExecutor`.
:class:`~concurrent.futures.ThreadPoolExecutor`, which includes
:class:`~concurrent.futures.InterpreterPoolExecutor`.

.. versionchanged:: 3.11
*executor* must be an instance of
Expand Down
2 changes: 1 addition & 1 deletion Doc/library/asyncio-llapi-index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ See also the main documentation section about the
- Invoke a callback *at* the given time.


.. rubric:: Thread/Process Pool
.. rubric:: Thread/Interpreter/Process Pool
.. list-table::
:widths: 50 50
:class: full-width-table
Expand Down
135 changes: 131 additions & 4 deletions Doc/library/concurrent.futures.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ The :mod:`concurrent.futures` module provides a high-level interface for
asynchronously executing callables.

The asynchronous execution can be performed with threads, using
:class:`ThreadPoolExecutor`, or separate processes, using
:class:`ProcessPoolExecutor`. Both implement the same interface, which is
defined by the abstract :class:`Executor` class.
:class:`ThreadPoolExecutor` or :class:`InterpreterPoolExecutor`,
or separate processes, using :class:`ProcessPoolExecutor`.
Each implements the same interface, which is defined
by the abstract :class:`Executor` class.

.. include:: ../includes/wasm-notavail.rst

Expand Down Expand Up @@ -63,7 +64,8 @@ Executor Objects
setting *chunksize* to a positive integer. For very long iterables,
using a large value for *chunksize* can significantly improve
performance compared to the default size of 1. With
:class:`ThreadPoolExecutor`, *chunksize* has no effect.
:class:`ThreadPoolExecutor` and :class:`InterpreterPoolExecutor`,
*chunksize* has no effect.

.. versionchanged:: 3.5
Added the *chunksize* argument.
Expand Down Expand Up @@ -227,6 +229,111 @@ ThreadPoolExecutor Example
print('%r page is %d bytes' % (url, len(data)))


InterpreterPoolExecutor
-----------------------

The :class:`InterpreterPoolExecutor` class uses a pool of interpreters
to execute calls asynchronously. It is a :class:`ThreadPoolExecutor`
subclass, which means each worker is running in its own thread.
The difference here is that each worker has its own interpreter,
and runs each task using that interpreter.

The biggest benefit to using interpreters instead of only threads
is true multi-core parallelism. Each interpreter has its own
:term:`Global Interpreter Lock <global interpreter lock>`, so code
running in one interpreter can run on one CPU core, while code in
another interpreter runs unblocked on a different core.

The tradeoff is that writing concurrent code for use with multiple
interpreters can take extra effort. However, this is because it
forces you to be deliberate about how and when interpreters interact,
and to be explicit about what data is shared between interpreters.
This results in several benefits that help balance the extra effort,
including true multi-core parallelism, For example, code written
this way can make it easier to reason about concurrency. Another
major benefit is that you don't have to deal with several of the
big pain points of using threads, like nrace conditions.

Each worker's interpreter is isolated from all the other interpreters.
"Isolated" means each interpreter has its own runtime state and
operates completely independently. For example, if you redirect
:data:`sys.stdout` in one interpreter, it will not be automatically
redirected any other interpreter. If you import a module in one
interpreter, it is not automatically imported in any other. You
would need to import the module separately in interpreter where
you need it. In fact, each module imported in an interpreter is
a completely separate object from the same module in a different
interpreter, including :mod:`sys`, :mod:`builtins`,
and even ``__main__``.

Isolation means a mutable object, or other data, cannot be used
by more than one interpreter at the same time. That effectively means
interpreters cannot actually share such objects or data. Instead,
each interpreter must have its own copy, and you will have to
synchronize any changes between the copies manually. Immutable
objects and data, like the builtin singletons, strings, and tuples
of immutable objects, don't have these limitations.

Communicating and synchronizing between interpreters is most effectively
done using dedicated tools, like those proposed in :pep:`734`. One less
efficient alternative is to serialize with :mod:`pickle` and then send
the bytes over a shared :mod:`socket <socket>` or
:func:`pipe <os.pipe>`.

.. class:: InterpreterPoolExecutor(max_workers=None, thread_name_prefix='', initializer=None, initargs=(), shared=None)

A :class:`ThreadPoolExecutor` subclass that executes calls asynchronously
using a pool of at most *max_workers* threads. Each thread runs
tasks in its own interpreter. The worker interpreters are isolated
from each other, which means each has its own runtime state and that
they can't share any mutable objects or other data. Each interpreter
has its own :term:`Global Interpreter Lock <global interpreter lock>`,
which means code run with this executor has true multi-core parallelism.

The optional *initializer* and *initargs* arguments have the same
meaning as for :class:`!ThreadPoolExecutor`: the initializer is run
when each worker is created, though in this case it is run.in
the worker's interpreter. The executor serializes the *initializer*
and *initargs* using :mod:`pickle` when sending them to the worker's
interpreter.

.. note::
Functions defined in the ``__main__`` module cannot be pickled
and thus cannot be used.

.. note::
The executor may replace uncaught exceptions from *initializer*
with :class:`~concurrent.futures.interpreter.ExecutionFailed`.

The optional *shared* argument is a :class:`dict` of objects that all
interpreters in the pool share. The *shared* items are added to each
interpreter's ``__main__`` module. Not all objects are shareable.
Shareable objects include the builtin singletons, :class:`str`
and :class:`bytes`, and :class:`memoryview`. See :pep:`734`
for more info.

Other caveats from parent :class:`ThreadPoolExecutor` apply here.

:meth:`~Executor.submit` and :meth:`~Executor.map` work like normal,
except the worker serializes the callable and arguments using
:mod:`pickle` when sending them to its interpreter. The worker
likewise serializes the return value when sending it back.

.. note::
Functions defined in the ``__main__`` module cannot be pickled
and thus cannot be used.

When a worker's current task raises an uncaught exception, the worker
always tries to preserve the exception as-is. If that is successful
then it also sets the ``__cause__`` to a corresponding
:class:`~concurrent.futures.interpreter.ExecutionFailed`
instance, which contains a summary of the original exception.
In the uncommon case that the worker is not able to preserve the
original as-is then it directly preserves the corresponding
:class:`~concurrent.futures.interpreter.ExecutionFailed`
instance instead.


ProcessPoolExecutor
-------------------

Expand Down Expand Up @@ -574,6 +681,26 @@ Exception classes

.. versionadded:: 3.7

.. currentmodule:: concurrent.futures.interpreter

.. exception:: BrokenInterpreterPool

Derived from :exc:`~concurrent.futures.thread.BrokenThreadPool`,
this exception class is raised when one of the workers
of a :class:`~concurrent.futures.InterpreterPoolExecutor`
has failed initializing.

.. versionadded:: next

.. exception:: ExecutionFailed

Raised from :class:`~concurrent.futures.InterpreterPoolExecutor` when
the given initializer fails or from
:meth:`~concurrent.futures.Executor.submit` when there's an uncaught
exception from the submitted task.

.. versionadded:: next

.. currentmodule:: concurrent.futures.process

.. exception:: BrokenProcessPool
Expand Down
4 changes: 2 additions & 2 deletions Doc/library/socket.rst
Original file line number Diff line number Diff line change
Expand Up @@ -451,8 +451,8 @@ Constants
network interface instead of its name.

.. versionchanged:: 3.14
Added missing ``IP_RECVERR``, ``IP_RECVTTL``, and ``IP_RECVORIGDSTADDR``
on Linux.
Added missing ``IP_RECVERR``, ``IPV6_RECVERR``, ``IP_RECVTTL``, and
``IP_RECVORIGDSTADDR`` on Linux.

.. versionchanged:: 3.14
Added support for ``TCP_QUICKACK`` on Windows platforms when available.
Expand Down
3 changes: 3 additions & 0 deletions Doc/library/threading.rst
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,9 @@ All methods are executed atomically.
Lock acquisition can now be interrupted by signals on POSIX if the
underlying threading implementation supports it.

.. versionchanged:: 3.14
Lock acquisition can now be interrupted by signals on Windows.


.. method:: release()

Expand Down
2 changes: 1 addition & 1 deletion Doc/tutorial/appendix.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ This one supports color, multiline editing, history browsing, and
paste mode. To disable color, see :ref:`using-on-controlling-color` for
details. Function keys provide some additional functionality.
:kbd:`F1` enters the interactive help browser :mod:`pydoc`.
:kbd:`F2` allows for browsing command-line history without output nor the
:kbd:`F2` allows for browsing command-line history with neither output nor the
:term:`>>>` and :term:`...` prompts. :kbd:`F3` enters "paste mode", which
makes pasting larger blocks of code easier. Press :kbd:`F3` to return to
the regular prompt.
Expand Down
Loading

0 comments on commit 4e32743

Please sign in to comment.