Skip to content

Commit 024188e

Browse files
Merge branch 'main' of https://github.com/python/cpython into gh-155109-limited-c-stack
2 parents 4856144 + 416c346 commit 024188e

27 files changed

Lines changed: 414 additions & 101 deletions

Doc/library/asyncio-eventloop.rst

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -838,7 +838,7 @@ Creating network servers
838838
*, sock=None, backlog=100, ssl=None, \
839839
ssl_handshake_timeout=None, \
840840
ssl_shutdown_timeout=None, \
841-
start_serving=True, cleanup_socket=True)
841+
start_serving=True, cleanup_socket=True, mode=None)
842842
:async:
843843
844844
Similar to :meth:`loop.create_server` but works with the
@@ -853,6 +853,13 @@ Creating network servers
853853
be removed from the filesystem when the server is closed, unless the
854854
socket has been replaced after the server has been created.
855855

856+
If *mode* is not ``None``, the permissions of the socket file created
857+
for *path* are changed to *mode* (as accepted by :func:`os.chmod`)
858+
right after binding, before the server starts accepting connections,
859+
so a connection can never be accepted while the default,
860+
umask-derived permissions are still in effect. *mode* cannot be
861+
combined with *sock* and is not supported for abstract Unix sockets.
862+
856863
See the documentation of the :meth:`loop.create_server` method
857864
for information about arguments to this method.
858865

@@ -871,6 +878,10 @@ Creating network servers
871878

872879
Added the *cleanup_socket* parameter.
873880

881+
.. versionchanged:: 3.16
882+
883+
Added the *mode* parameter.
884+
874885

875886
.. method:: loop.connect_accepted_socket(protocol_factory, \
876887
sock, *, ssl=None, ssl_handshake_timeout=None, \

Doc/library/asyncio-stream.rst

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,8 @@ and work with streams:
171171
.. function:: start_unix_server(client_connected_cb, path=None, \
172172
*, limit=None, sock=None, backlog=100, ssl=None, \
173173
ssl_handshake_timeout=None, \
174-
ssl_shutdown_timeout=None, start_serving=True, cleanup_socket=True)
174+
ssl_shutdown_timeout=None, start_serving=True, \
175+
cleanup_socket=True, mode=None)
175176
:async:
176177
177178
Start a Unix socket server.
@@ -182,6 +183,9 @@ and work with streams:
182183
be removed from the filesystem when the server is closed, unless the
183184
socket has been replaced after the server has been created.
184185

186+
If *mode* is not ``None``, the permissions of the Unix socket file
187+
are set to *mode* before the server starts accepting connections.
188+
185189
See also the documentation of :meth:`loop.create_unix_server`.
186190

187191
.. note::
@@ -205,6 +209,9 @@ and work with streams:
205209
.. versionchanged:: 3.13
206210
Added the *cleanup_socket* parameter.
207211

212+
.. versionchanged:: 3.16
213+
Added the *mode* parameter.
214+
208215

209216
StreamReader
210217
============
@@ -382,6 +389,16 @@ StreamWriter
382389
be resumed. When there is nothing to wait for, the :meth:`drain`
383390
returns immediately.
384391

392+
.. note::
393+
394+
When the write buffer is below the high watermark,
395+
:meth:`drain` returns immediately without yielding to
396+
the event loop. As a result, code which repeatedly calls
397+
``write()`` followed by ``await drain()`` may prevent other
398+
tasks from running. To prevent blocking behavior, yield
399+
to the event loop explicitly with ``await asyncio.sleep(0)``
400+
(see :func:`asyncio.sleep`).
401+
385402
.. method:: start_tls(sslcontext, *, server_hostname=None, \
386403
ssl_handshake_timeout=None, ssl_shutdown_timeout=None)
387404
:async:

Doc/library/asyncio-task.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,17 @@ Creating tasks
288288
# completion:
289289
task.add_done_callback(background_tasks.discard)
290290

291+
Note that this approach never awaits the tasks, so if a task
292+
fails, its exception is never retrieved and asyncio logs a
293+
"Task exception was never retrieved" message when the task is
294+
garbage collected. To avoid this, use :class:`asyncio.TaskGroup`
295+
which keeps a strong reference to each task, awaits them and
296+
propagates their exceptions::
297+
298+
async with asyncio.TaskGroup() as tg:
299+
for i in range(10):
300+
tg.create_task(some_coro(param=i))
301+
291302
.. versionadded:: 3.7
292303

293304
.. versionchanged:: 3.8

Doc/library/stdtypes.rst

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4871,7 +4871,7 @@ copying.
48714871
.. versionadded:: 3.2
48724872

48734873
.. method:: cast(format, /)
4874-
cast(format, shape, /)
4874+
cast(format, shape, /, *, order='C')
48754875
48764876
Cast a memoryview to a new format or shape. *shape* defaults to
48774877
``[byte_length//new_itemsize]``, which means that the result view
@@ -4880,6 +4880,12 @@ copying.
48804880
1D -> C-:term:`contiguous`, C-contiguous -> 1D, and
48814881
F-contiguous -> 1D.
48824882

4883+
With a multidimensional *shape*, *order* selects the memory layout of
4884+
the result: ``'C'`` for C-contiguous (row-major, the default) or ``'F'``
4885+
for Fortran-contiguous (column-major). The buffer is still not copied,
4886+
so ``order='F'`` gives a zero-copy view over a buffer holding
4887+
column-major data.
4888+
48834889
The destination format is restricted to a single element native format in
48844890
:mod:`struct` syntax. One of the formats must be a byte format
48854891
('B', 'b' or 'c'). The byte length of the result must be the same
@@ -5031,8 +5037,20 @@ copying.
50315037
>>> y.nbytes
50325038
96
50335039

5040+
Interpret a flat buffer as a Fortran-contiguous (column-major) array::
5041+
5042+
>>> buf = bytes(range(6))
5043+
>>> y = memoryview(buf).cast('B', shape=[3, 2], order='F')
5044+
>>> y.f_contiguous
5045+
True
5046+
>>> y.tolist()
5047+
[[0, 3], [1, 4], [2, 5]]
5048+
50345049
.. versionadded:: 3.3
50355050

5051+
.. versionchanged:: next
5052+
Added the *order* parameter.
5053+
50365054
.. attribute:: readonly
50375055

50385056
A bool indicating whether the memory is read only.

Doc/whatsnew/3.16.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,12 @@ Other language changes
7979
F-contiguous view to a one-dimensional view.
8080
(Contributed by Jaemin Park in :gh:`91484`.)
8181

82+
* :meth:`memoryview.cast` now accepts an *order* parameter. With
83+
``order='F'`` it returns a zero-copy Fortran-contiguous (column-major)
84+
view of a flat buffer, which is useful for interfacing with column-major
85+
libraries.
86+
(Contributed by Serhiy Storchaka in :gh:`78959`.)
87+
8288
* :ref:`Frame objects <frame-objects>` now support :mod:`weak references
8389
<weakref>`. This allows associating extra data with active frames,
8490
for example in debuggers, without keeping the frames (and everything
@@ -95,6 +101,15 @@ New modules
95101
Improved modules
96102
================
97103

104+
asyncio
105+
-------
106+
107+
* Add the *mode* parameter to :meth:`asyncio.loop.create_unix_server` and
108+
:func:`asyncio.start_unix_server` to set the permissions of the Unix
109+
socket file created for *path*.
110+
(Contributed by Sam Bull in :gh:`94984`.)
111+
112+
98113
codecs
99114
------
100115

Lib/asyncio/events.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,7 @@ async def create_unix_server(
451451
sock=None, backlog=100, ssl=None,
452452
ssl_handshake_timeout=None,
453453
ssl_shutdown_timeout=None,
454-
start_serving=True):
454+
start_serving=True, mode=None):
455455
"""A coroutine which creates a UNIX Domain Socket server.
456456
457457
The return value is a Server object, which can be used to stop
@@ -480,6 +480,10 @@ async def create_unix_server(
480480
the user should await Server.start_serving() or
481481
Server.serve_forever() to make the server to start accepting
482482
connections.
483+
484+
mode, if not None, is applied to the socket file created for
485+
path with os.chmod() after binding and before the server
486+
starts accepting connections.
483487
"""
484488
raise NotImplementedError
485489

Lib/asyncio/unix_events.py

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ async def create_unix_server(
276276
sock=None, backlog=100, ssl=None,
277277
ssl_handshake_timeout=None,
278278
ssl_shutdown_timeout=None,
279-
start_serving=True, cleanup_socket=True):
279+
start_serving=True, cleanup_socket=True, mode=None):
280280
if isinstance(ssl, bool):
281281
raise TypeError('ssl argument must be an SSLContext or None')
282282

@@ -294,6 +294,9 @@ async def create_unix_server(
294294
'path and sock can not be specified at the same time')
295295

296296
path = os.fspath(path)
297+
if mode is not None and path and path[0] in (0, '\x00'):
298+
raise ValueError(
299+
'mode is not supported for abstract sockets')
297300
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
298301

299302
# Check for abstract socket. `str` and `bytes` paths are supported.
@@ -322,11 +325,26 @@ async def create_unix_server(
322325
except:
323326
sock.close()
324327
raise
328+
329+
if mode is not None:
330+
# The socket cannot accept connections until listen() is
331+
# called, which happens later in Server._start_serving(),
332+
# so no connection can be accepted while the socket still
333+
# has the default permissions.
334+
try:
335+
os.chmod(path, mode)
336+
except:
337+
sock.close()
338+
raise
325339
else:
326340
if sock is None:
327341
raise ValueError(
328342
'path was not specified, and no sock specified')
329343

344+
if mode is not None:
345+
raise ValueError(
346+
'mode is only meaningful with path')
347+
330348
if (sock.family != socket.AF_UNIX or
331349
sock.type != socket.SOCK_STREAM):
332350
raise ValueError(
@@ -658,19 +676,19 @@ def __init__(self, loop, pipe, protocol, waiter=None, extra=None):
658676
# On AIX, the reader trick (to be notified when the read end of the
659677
# socket is closed) only works for sockets. On other platforms it
660678
# works for pipes and sockets. (Exception: OS X 10.4? Issue #19294.)
661-
# On macOS, the trick misfires for named FIFOs (but not for pipes
662-
# created with os.pipe(), which have st_nlink == 0): the write end
663-
# polls as readable whenever unread data sits in the FIFO, and no
679+
# On macOS and Solaris, the trick misfires for named FIFOs (but not for
680+
# pipes created with os.pipe(), which have st_nlink == 0): the write
681+
# end polls as readable whenever unread data sits in the FIFO, and no
664682
# event is delivered when the read end is closed, so it can only
665-
# ever report a false disconnection (gh-145030). The same xnu
683+
# ever report a false disconnection (gh-145030). The same XNU
666684
# behaviour applies on iOS/tvOS/watchOS (sys.platform is not
667685
# "darwin" there).
668-
is_named_fifo_on_apple = (
669-
sys.platform in {"darwin", "ios", "tvos", "watchos"}
686+
is_named_fifo_without_close_event = (
687+
sys.platform in {"darwin", "ios", "tvos", "watchos", "sunos5"}
670688
and is_fifo and pipe_stat.st_nlink > 0)
671689
if is_socket or (is_fifo
672690
and not sys.platform.startswith("aix")
673-
and not is_named_fifo_on_apple):
691+
and not is_named_fifo_without_close_event):
674692
# only start reading when connection_made() has been called
675693
self._loop.call_soon(self._loop._add_reader,
676694
self._fileno, self._read_ready)

Lib/asyncio/windows_events.py

Lines changed: 42 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -760,6 +760,46 @@ def _get_accept_socket(self, family):
760760
s.settimeout(0)
761761
return s
762762

763+
def _process_completion_status(self, status):
764+
"""Process a single status from the completion port.
765+
766+
A caller that waits on the completion port itself can pass each
767+
status it receives here.
768+
"""
769+
err, transferred, key, address = status
770+
try:
771+
f, ov, obj, callback = self._cache.pop(address)
772+
except KeyError:
773+
if self._loop.get_debug():
774+
self._loop.call_exception_handler({
775+
'message': ('GetQueuedCompletionStatus() returned an '
776+
'unexpected event'),
777+
'status': ('err=%s transferred=%s key=%#x address=%#x'
778+
% (err, transferred, key, address)),
779+
})
780+
781+
# key is either zero, or it is used to return a pipe
782+
# handle which should be closed to avoid a leak.
783+
if key not in (0, _overlapped.INVALID_HANDLE_VALUE):
784+
_winapi.CloseHandle(key)
785+
return
786+
787+
if obj in self._stopped_serving:
788+
f.cancel()
789+
# Don't call the callback if _register() already read the result or
790+
# if the overlapped has been cancelled
791+
elif not f.done():
792+
try:
793+
value = callback(transferred, key, ov)
794+
except OSError as e:
795+
f.set_exception(e)
796+
self._results.append(f)
797+
else:
798+
f.set_result(value)
799+
self._results.append(f)
800+
finally:
801+
f = None
802+
763803
def _poll(self, timeout=None):
764804
if timeout is None:
765805
ms = INFINITE
@@ -778,39 +818,8 @@ def _poll(self, timeout=None):
778818
break
779819
ms = 0
780820

781-
err, transferred, key, address = status
782-
try:
783-
f, ov, obj, callback = self._cache.pop(address)
784-
except KeyError:
785-
if self._loop.get_debug():
786-
self._loop.call_exception_handler({
787-
'message': ('GetQueuedCompletionStatus() returned an '
788-
'unexpected event'),
789-
'status': ('err=%s transferred=%s key=%#x address=%#x'
790-
% (err, transferred, key, address)),
791-
})
792-
793-
# key is either zero, or it is used to return a pipe
794-
# handle which should be closed to avoid a leak.
795-
if key not in (0, _overlapped.INVALID_HANDLE_VALUE):
796-
_winapi.CloseHandle(key)
797-
continue
798-
799-
if obj in self._stopped_serving:
800-
f.cancel()
801-
# Don't call the callback if _register() already read the result or
802-
# if the overlapped has been cancelled
803-
elif not f.done():
804-
try:
805-
value = callback(transferred, key, ov)
806-
except OSError as e:
807-
f.set_exception(e)
808-
self._results.append(f)
809-
else:
810-
f.set_result(value)
811-
self._results.append(f)
812-
finally:
813-
f = None
821+
# gh-154971: split out so custom event loops can call it directly
822+
self._process_completion_status(status)
814823

815824
# Remove unregistered futures
816825
for ov in self._unregistered:

Lib/ensurepip/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111

1212
__all__ = ["version", "bootstrap"]
13-
_PIP_VERSION = "26.1.2"
13+
_PIP_VERSION = "26.2"
1414

1515
# Directory of system wheel packages. Some Linux distribution packaging
1616
# policies recommend against bundling dependencies. For example, Fedora
1.73 MB
Binary file not shown.

0 commit comments

Comments
 (0)