Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/python/cpython into socket-…
Browse files Browse the repository at this point in the history
…threadsafe
  • Loading branch information
kumaraditya303 committed Dec 31, 2024
2 parents 12eeb63 + b2ac70a commit 808e3d1
Show file tree
Hide file tree
Showing 52 changed files with 1,127 additions and 769 deletions.
27 changes: 26 additions & 1 deletion Doc/deprecations/pending-removal-in-3.16.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,35 @@ Pending removal in Python 3.16
* :mod:`asyncio`:

* :func:`!asyncio.iscoroutinefunction` is deprecated
and will be removed in Python 3.16,
and will be removed in Python 3.16;
use :func:`inspect.iscoroutinefunction` instead.
(Contributed by Jiahao Li and Kumar Aditya in :gh:`122875`.)

* :mod:`asyncio` policy system is deprecated and will be removed in Python 3.16.
In particular, the following classes and functions are deprecated:

* :class:`asyncio.AbstractEventLoopPolicy`
* :class:`asyncio.DefaultEventLoopPolicy`
* :class:`asyncio.WindowsSelectorEventLoopPolicy`
* :class:`asyncio.WindowsProactorEventLoopPolicy`
* :func:`asyncio.get_event_loop_policy`
* :func:`asyncio.set_event_loop_policy`
* :func:`asyncio.set_event_loop`

Users should use :func:`asyncio.run` or :class:`asyncio.Runner` with
*loop_factory* to use the desired event loop implementation.

For example, to use :class:`asyncio.SelectorEventLoop` on Windows::

import asyncio

async def main():
...

asyncio.run(main(), loop_factory=asyncio.SelectorEventLoop)

(Contributed by Kumar Aditya in :gh:`127949`.)

* :mod:`builtins`:

* Bitwise inversion on boolean types, ``~True`` or ``~False``
Expand Down
16 changes: 11 additions & 5 deletions Doc/library/asyncio-eventloop.rst
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,13 @@ an event loop:
.. versionchanged:: 3.14
Raises a :exc:`RuntimeError` if there is no current event loop.

.. note::

The :mod:`!asyncio` policy system is deprecated and will be removed
in Python 3.16; from there on, this function will always return the
running event loop.


.. function:: set_event_loop(loop)

Set *loop* as the current event loop for the current OS thread.
Expand Down Expand Up @@ -1781,12 +1788,11 @@ By default asyncio is configured to use :class:`EventLoop`.
import asyncio
import selectors

class MyPolicy(asyncio.DefaultEventLoopPolicy):
def new_event_loop(self):
selector = selectors.SelectSelector()
return asyncio.SelectorEventLoop(selector)
async def main():
...

asyncio.set_event_loop_policy(MyPolicy())
loop_factory = lambda: asyncio.SelectorEventLoop(selectors.SelectSelector())
asyncio.run(main(), loop_factory=loop_factory)


.. availability:: Unix, Windows.
Expand Down
6 changes: 6 additions & 0 deletions Doc/library/asyncio-runner.rst
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,12 @@ Running an asyncio Program

*coro* can be any awaitable object.

.. note::

The :mod:`!asyncio` policy system is deprecated and will be removed
in Python 3.16; from there on, an explicit *loop_factory* is needed
to configure the event loop.


Runner context manager
======================
Expand Down
61 changes: 53 additions & 8 deletions Doc/library/asyncio-task.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1067,14 +1067,59 @@ Scheduling From Other Threads
This function is meant to be called from a different OS thread
than the one where the event loop is running. Example::

# Create a coroutine
coro = asyncio.sleep(1, result=3)

# Submit the coroutine to a given loop
future = asyncio.run_coroutine_threadsafe(coro, loop)

# Wait for the result with an optional timeout argument
assert future.result(timeout) == 3
def in_thread(loop: asyncio.AbstractEventLoop) -> None:
# Run some blocking IO
pathlib.Path("example.txt").write_text("hello world", encoding="utf8")

# Create a coroutine
coro = asyncio.sleep(1, result=3)

# Submit the coroutine to a given loop
future = asyncio.run_coroutine_threadsafe(coro, loop)

# Wait for the result with an optional timeout argument
assert future.result(timeout=2) == 3

async def amain() -> None:
# Get the running loop
loop = asyncio.get_running_loop()

# Run something in a thread
await asyncio.to_thread(in_thread, loop)

It's also possible to run the other way around. Example::

@contextlib.contextmanager
def loop_in_thread() -> Generator[asyncio.AbstractEventLoop]:
loop_fut = concurrent.futures.Future[asyncio.AbstractEventLoop]()
stop_event = asyncio.Event()

async def main() -> None:
loop_fut.set_result(asyncio.get_running_loop())
await stop_event.wait()

with concurrent.futures.ThreadPoolExecutor(1) as tpe:
complete_fut = tpe.submit(asyncio.run, main())
for fut in concurrent.futures.as_completed((loop_fut, complete_fut)):
if fut is loop_fut:
loop = loop_fut.result()
try:
yield loop
finally:
loop.call_soon_threadsafe(stop_event.set)
else:
fut.result()

# Create a loop in another thread
with loop_in_thread() as loop:
# Create a coroutine
coro = asyncio.sleep(1, result=3)

# Submit the coroutine to a given loop
future = asyncio.run_coroutine_threadsafe(coro, loop)

# Wait for the result with an optional timeout argument
assert future.result(timeout=2) == 3

If an exception is raised in the coroutine, the returned Future
will be notified. It can also be used to cancel the task in
Expand Down
8 changes: 8 additions & 0 deletions Doc/library/calendar.rst
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,14 @@ interpreted as prescribed by the ISO 8601 standard. Year 0 is 1 BC, year -1 is

:class:`TextCalendar` instances have the following methods:

.. method:: formatweek(theweek, w=0)

Return a single week in a string with no newline. If *w* is provided, it
specifies the width of the date columns, which are centered. Depends
on the first weekday as specified in the constructor or set by the
:meth:`setfirstweekday` method.


.. method:: formatmonth(theyear, themonth, w=0, l=0)

Return a month's calendar in a multi-line string. If *w* is provided, it
Expand Down
3 changes: 3 additions & 0 deletions Doc/library/urllib.request.rst
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,9 @@ The following classes are provided:
:ref:`http-password-mgr` for information on the interface that must be
supported.

.. versionchanged:: 3.14
Added support for HTTP digest authentication algorithm ``SHA-256``.


.. class:: HTTPDigestAuthHandler(password_mgr=None)

Expand Down
11 changes: 11 additions & 0 deletions Doc/library/zipfile.rst
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,17 @@ The module defines the following items:
formerly protected :attr:`!_compresslevel`. The older protected name
continues to work as a property for backwards compatibility.


.. method:: _for_archive(archive)

Resolve the date_time, compression attributes, and external attributes
to suitable defaults as used by :meth:`ZipFile.writestr`.

Returns self for chaining.

.. versionadded:: 3.14


.. function:: is_zipfile(filename)

Returns ``True`` if *filename* is a valid ZIP file based on its magic number,
Expand Down
20 changes: 18 additions & 2 deletions Doc/whatsnew/3.14.rst
Original file line number Diff line number Diff line change
Expand Up @@ -614,8 +614,8 @@ sys
sys.monitoring
--------------

Two new events are added: :monitoring-event:`BRANCH_LEFT` and
:monitoring-event:`BRANCH_RIGHT`. The ``BRANCH`` event is deprecated.
* Two new events are added: :monitoring-event:`BRANCH_LEFT` and
:monitoring-event:`BRANCH_RIGHT`. The ``BRANCH`` event is deprecated.

tkinter
-------
Expand Down Expand Up @@ -646,13 +646,29 @@ unittest
(Contributed by Jacob Walls in :gh:`80958`.)


urllib
------

* Upgrade HTTP digest authentication algorithm for :mod:`urllib.request` by
supporting SHA-256 digest authentication as specified in :rfc:`7616`.
(Contributed by Calvin Bui in :gh:`128193`.)


uuid
----

* Add support for UUID version 8 via :func:`uuid.uuid8` as specified
in :rfc:`9562`.
(Contributed by Bénédikt Tran in :gh:`89083`.)

zipinfo
-------

* Added :func:`ZipInfo._for_archive <zipfile.ZipInfo._for_archive>`
to resolve suitable defaults for a :class:`~zipfile.ZipInfo` object
as used by :func:`ZipFile.writestr <zipfile.ZipFile.writestr>`.

(Contributed by Bénédikt Tran in :gh:`123424`.)

.. Add improved modules above alphabetically, not here at the end.
Expand Down
2 changes: 1 addition & 1 deletion Include/internal/pycore_uop_metadata.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 5 additions & 5 deletions InternalDocs/parser.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ an input string as its argument, and yields one of the following results:

Note that "failure" results do not imply that the program is incorrect, nor do
they necessarily mean that the parsing has failed. Since the choice operator is
ordered, a failure very often merely indicates "try the following option". A
ordered, a failure very often merely indicates "try the following option". A
direct implementation of a PEG parser as a recursive descent parser will present
exponential time performance in the worst case, because PEG parsers have
infinite lookahead (this means that they can consider an arbitrary number of
Expand Down Expand Up @@ -253,7 +253,7 @@ inside curly-braces, which specifies the return value of the alternative:
If the action is omitted, a default action is generated:

- If there is a single name in the rule, it gets returned.
- If there multiple names in the rule, a collection with all parsed
- If there are multiple names in the rule, a collection with all parsed
expressions gets returned (the type of the collection will be different
in C and Python).

Expand Down Expand Up @@ -447,7 +447,7 @@ parser (the one used by the interpreter) just execute:
$ make regen-pegen
```

using the `Makefile` in the main directory. If you are on Windows you can
using the `Makefile` in the main directory. If you are on Windows you can
use the Visual Studio project files to regenerate the parser or to execute:

```dos
Expand Down Expand Up @@ -539,7 +539,7 @@ memoization is used.
The C parser used by Python is highly optimized and memoization can be expensive
both in memory and time. Although the memory cost is obvious (the parser needs
memory for storing previous results in the cache) the execution time cost comes
for continuously checking if the given rule has a cache hit or not. In many
from continuously checking if the given rule has a cache hit or not. In many
situations, just parsing it again can be faster. Pegen **disables memoization
by default** except for rules with the special marker `memo` after the rule
name (and type, if present):
Expand Down Expand Up @@ -605,7 +605,7 @@ File "<stdin>", line 1
SyntaxError: invalid syntax
```

While soft keywords don't have this limitation if used in a context other the
While soft keywords don't have this limitation if used in a context other than
one where they are defined as keywords:

```pycon
Expand Down
1 change: 1 addition & 0 deletions Lib/asyncio/runners.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ def run(main, *, debug=None, loop_factory=None):
running in the same thread.
If debug is True, the event loop will be run in debug mode.
If loop_factory is passed, it is used for new event loop creation.
This function always creates a new event loop and closes it at the end.
It should be used as a main entry point for asyncio programs, and should
Expand Down
27 changes: 9 additions & 18 deletions Lib/copy.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,15 @@ def copy(x):

cls = type(x)

copier = _copy_dispatch.get(cls)
if copier:
return copier(x)
if cls in _copy_atomic_types:
return x
if cls in _copy_builtin_containers:
return cls.copy(x)


if issubclass(cls, type):
# treat it as a regular class:
return _copy_immutable(x)
return x

copier = getattr(cls, "__copy__", None)
if copier is not None:
Expand All @@ -98,23 +100,12 @@ def copy(x):
return _reconstruct(x, None, *rv)


_copy_dispatch = d = {}

def _copy_immutable(x):
return x
for t in (types.NoneType, int, float, bool, complex, str, tuple,
_copy_atomic_types = {types.NoneType, int, float, bool, complex, str, tuple,
bytes, frozenset, type, range, slice, property,
types.BuiltinFunctionType, types.EllipsisType,
types.NotImplementedType, types.FunctionType, types.CodeType,
weakref.ref, super):
d[t] = _copy_immutable

d[list] = list.copy
d[dict] = dict.copy
d[set] = set.copy
d[bytearray] = bytearray.copy

del d, t
weakref.ref, super}
_copy_builtin_containers = {list, dict, set, bytearray}

def deepcopy(x, memo=None, _nil=[]):
"""Deep copy operation on arbitrary Python objects.
Expand Down
Loading

0 comments on commit 808e3d1

Please sign in to comment.