Skip to content

Commit 71d48c1

Browse files
committed
Merge branch 'main' into typewatch
* main: Minor edits to the Descriptor HowTo Guide (pythonGH-24901) Fix link to Lifecycle of a Pull Request in CONTRIBUTING (python#98102) pythonGH-94597: deprecate `SafeChildWatcher`, `FastChildWatcher` and `MultiLoopChildWatcher` child watchers (python#98089) Auto-cancel old builds when new commit pushed to branch (python#98009) pythongh-95011: Migrate syslog module to Argument Clinic (pythonGH-95012)
2 parents 4783e07 + 2d2e01a commit 71d48c1

File tree

17 files changed

+483
-117
lines changed

17 files changed

+483
-117
lines changed

.github/CONTRIBUTING.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ also suggestions on how you can most effectively help the project.
3838

3939
Please be aware that our workflow does deviate slightly from the typical GitHub
4040
project. Details on how to properly submit a pull request are covered in
41-
`Lifecycle of a Pull Request <https://devguide.python.org/pullrequest/>`_.
41+
`Lifecycle of a Pull Request <https://devguide.python.org/getting-started/pull-request-lifecycle.html>`_.
4242
We utilize various bots and status checks to help with this, so do follow the
4343
comments they leave and their "Details" links, respectively. The key points of
4444
our workflow that are not covered by a bot or status check are:

.github/workflows/build.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ on:
2525
permissions:
2626
contents: read
2727

28+
concurrency:
29+
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
30+
cancel-in-progress: true
31+
2832
jobs:
2933
check_source:
3034
name: 'Check for source changes'

.github/workflows/build_msi.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ on:
1818
permissions:
1919
contents: read
2020

21+
concurrency:
22+
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
23+
cancel-in-progress: true
24+
2125
jobs:
2226
build:
2327
name: Windows Installer

.github/workflows/doc.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ on:
2828
permissions:
2929
contents: read
3030

31+
concurrency:
32+
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
33+
cancel-in-progress: true
34+
3135
jobs:
3236
build_doc:
3337
name: 'Docs'

.github/workflows/verify-ensurepip-wheels.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ on:
1616
permissions:
1717
contents: read
1818

19+
concurrency:
20+
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
21+
cancel-in-progress: true
22+
1923
jobs:
2024
verify:
2125
runs-on: ubuntu-latest

Doc/howto/descriptor.rst

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -847,7 +847,7 @@ afterwards, :meth:`__set_name__` will need to be called manually.
847847
ORM example
848848
-----------
849849

850-
The following code is simplified skeleton showing how data descriptors could
850+
The following code is a simplified skeleton showing how data descriptors could
851851
be used to implement an `object relational mapping
852852
<https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping>`_.
853853

@@ -1535,6 +1535,8 @@ by member descriptors:
15351535
def __get__(self, obj, objtype=None):
15361536
'Emulate member_get() in Objects/descrobject.c'
15371537
# Also see PyMember_GetOne() in Python/structmember.c
1538+
if obj is None:
1539+
return self
15381540
value = obj._slotvalues[self.offset]
15391541
if value is null:
15401542
raise AttributeError(self.name)
@@ -1563,13 +1565,13 @@ variables:
15631565
class Type(type):
15641566
'Simulate how the type metaclass adds member objects for slots'
15651567

1566-
def __new__(mcls, clsname, bases, mapping):
1568+
def __new__(mcls, clsname, bases, mapping, **kwargs):
15671569
'Emulate type_new() in Objects/typeobject.c'
15681570
# type_new() calls PyTypeReady() which calls add_methods()
15691571
slot_names = mapping.get('slot_names', [])
15701572
for offset, name in enumerate(slot_names):
15711573
mapping[name] = Member(name, clsname, offset)
1572-
return type.__new__(mcls, clsname, bases, mapping)
1574+
return type.__new__(mcls, clsname, bases, mapping, **kwargs)
15731575
15741576
The :meth:`object.__new__` method takes care of creating instances that have
15751577
slots instead of an instance dictionary. Here is a rough simulation in pure
@@ -1580,7 +1582,7 @@ Python:
15801582
class Object:
15811583
'Simulate how object.__new__() allocates memory for __slots__'
15821584

1583-
def __new__(cls, *args):
1585+
def __new__(cls, *args, **kwargs):
15841586
'Emulate object_new() in Objects/typeobject.c'
15851587
inst = super().__new__(cls)
15861588
if hasattr(cls, 'slot_names'):
@@ -1593,7 +1595,7 @@ Python:
15931595
cls = type(self)
15941596
if hasattr(cls, 'slot_names') and name not in cls.slot_names:
15951597
raise AttributeError(
1596-
f'{type(self).__name__!r} object has no attribute {name!r}'
1598+
f'{cls.__name__!r} object has no attribute {name!r}'
15971599
)
15981600
super().__setattr__(name, value)
15991601

@@ -1602,7 +1604,7 @@ Python:
16021604
cls = type(self)
16031605
if hasattr(cls, 'slot_names') and name not in cls.slot_names:
16041606
raise AttributeError(
1605-
f'{type(self).__name__!r} object has no attribute {name!r}'
1607+
f'{cls.__name__!r} object has no attribute {name!r}'
16061608
)
16071609
super().__delattr__(name)
16081610

Doc/whatsnew/3.12.rst

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,24 @@ New Modules
109109
Improved Modules
110110
================
111111

112+
asyncio
113+
-------
114+
115+
* On Linux, :mod:`asyncio` uses :class:`~asyncio.PidfdChildWatcher` by default
116+
if :func:`os.pidfd_open` is available and functional instead of
117+
:class:`~asyncio.ThreadedChildWatcher`.
118+
(Contributed by Kumar Aditya in :gh:`98024`.)
119+
120+
* The child watcher classes :class:`~asyncio.MultiLoopChildWatcher`,
121+
:class:`~asyncio.FastChildWatcher` and
122+
:class:`~asyncio.SafeChildWatcher` are deprecated and
123+
will be removed in Python 3.14. It is recommended to not manually
124+
configure a child watcher as the event loop now uses the best available
125+
child watcher for each platform (:class:`~asyncio.PidfdChildWatcher`
126+
if supported and :class:`~asyncio.ThreadedChildWatcher` otherwise).
127+
(Contributed by Kumar Aditya in :gh:`94597`.)
128+
129+
112130
pathlib
113131
-------
114132

Include/internal/pycore_global_strings.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,7 @@ struct _Py_global_strings {
350350
STRUCT_FOR_ID(exception)
351351
STRUCT_FOR_ID(exp)
352352
STRUCT_FOR_ID(extend)
353+
STRUCT_FOR_ID(facility)
353354
STRUCT_FOR_ID(factory)
354355
STRUCT_FOR_ID(family)
355356
STRUCT_FOR_ID(fanout)
@@ -392,6 +393,7 @@ struct _Py_global_strings {
392393
STRUCT_FOR_ID(hi)
393394
STRUCT_FOR_ID(hook)
394395
STRUCT_FOR_ID(id)
396+
STRUCT_FOR_ID(ident)
395397
STRUCT_FOR_ID(ignore)
396398
STRUCT_FOR_ID(imag)
397399
STRUCT_FOR_ID(importlib)
@@ -447,6 +449,7 @@ struct _Py_global_strings {
447449
STRUCT_FOR_ID(lo)
448450
STRUCT_FOR_ID(locale)
449451
STRUCT_FOR_ID(locals)
452+
STRUCT_FOR_ID(logoption)
450453
STRUCT_FOR_ID(loop)
451454
STRUCT_FOR_ID(mapping)
452455
STRUCT_FOR_ID(match)

Include/internal/pycore_runtime_init_generated.h

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/asyncio/unix_events.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1022,6 +1022,13 @@ class SafeChildWatcher(BaseChildWatcher):
10221022
big number of children (O(n) each time SIGCHLD is raised)
10231023
"""
10241024

1025+
def __init__(self):
1026+
super().__init__()
1027+
warnings._deprecated("SafeChildWatcher",
1028+
"{name!r} is deprecated as of Python 3.12 and will be "
1029+
"removed in Python {remove}.",
1030+
remove=(3, 14))
1031+
10251032
def close(self):
10261033
self._callbacks.clear()
10271034
super().close()
@@ -1100,6 +1107,10 @@ def __init__(self):
11001107
self._lock = threading.Lock()
11011108
self._zombies = {}
11021109
self._forks = 0
1110+
warnings._deprecated("FastChildWatcher",
1111+
"{name!r} is deprecated as of Python 3.12 and will be "
1112+
"removed in Python {remove}.",
1113+
remove=(3, 14))
11031114

11041115
def close(self):
11051116
self._callbacks.clear()
@@ -1212,6 +1223,10 @@ class MultiLoopChildWatcher(AbstractChildWatcher):
12121223
def __init__(self):
12131224
self._callbacks = {}
12141225
self._saved_sighandler = None
1226+
warnings._deprecated("MultiLoopChildWatcher",
1227+
"{name!r} is deprecated as of Python 3.12 and will be "
1228+
"removed in Python {remove}.",
1229+
remove=(3, 14))
12151230

12161231
def is_active(self):
12171232
return self._saved_sighandler is not None

Lib/test/test_asyncio/test_events.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
import unittest
2323
from unittest import mock
2424
import weakref
25-
25+
import warnings
2626
if sys.platform not in ('win32', 'vxworks'):
2727
import tty
2828

@@ -2055,7 +2055,9 @@ def test_remove_fds_after_closing(self):
20552055
class UnixEventLoopTestsMixin(EventLoopTestsMixin):
20562056
def setUp(self):
20572057
super().setUp()
2058-
watcher = asyncio.SafeChildWatcher()
2058+
with warnings.catch_warnings():
2059+
warnings.simplefilter('ignore', DeprecationWarning)
2060+
watcher = asyncio.SafeChildWatcher()
20592061
watcher.attach_loop(self.loop)
20602062
asyncio.set_child_watcher(watcher)
20612063

@@ -2652,7 +2654,9 @@ def setUp(self):
26522654
asyncio.set_event_loop(self.loop)
26532655

26542656
if sys.platform != 'win32':
2655-
watcher = asyncio.SafeChildWatcher()
2657+
with warnings.catch_warnings():
2658+
warnings.simplefilter('ignore', DeprecationWarning)
2659+
watcher = asyncio.SafeChildWatcher()
26562660
watcher.attach_loop(self.loop)
26572661
asyncio.set_child_watcher(watcher)
26582662

Lib/test/test_asyncio/test_streams.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import threading
1010
import unittest
1111
from unittest import mock
12+
import warnings
1213
from test.support import socket_helper
1314
try:
1415
import ssl
@@ -791,8 +792,9 @@ def test_read_all_from_pipe_reader(self):
791792
protocol = asyncio.StreamReaderProtocol(reader, loop=self.loop)
792793
transport, _ = self.loop.run_until_complete(
793794
self.loop.connect_read_pipe(lambda: protocol, pipe))
794-
795-
watcher = asyncio.SafeChildWatcher()
795+
with warnings.catch_warnings():
796+
warnings.simplefilter('ignore', DeprecationWarning)
797+
watcher = asyncio.SafeChildWatcher()
796798
watcher.attach_loop(self.loop)
797799
try:
798800
asyncio.set_child_watcher(watcher)

0 commit comments

Comments
 (0)