Skip to content

Commit 62ea35e

Browse files
Merge commit '788c3291172b55efa7cf' into resume_tracing
2 parents 5ccf8e9 + 788c329 commit 62ea35e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+2028
-1687
lines changed

.github/dependabot.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ updates:
1212
update-types:
1313
- "version-update:semver-minor"
1414
- "version-update:semver-patch"
15+
groups:
16+
actions:
17+
patterns:
18+
- "*"
1519
cooldown:
1620
# https://blog.yossarian.net/2025/11/21/We-should-all-be-using-dependency-cooldowns
1721
# Cooldowns protect against supply chain attacks by avoiding the

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,7 @@ jobs:
475475
-x test_subprocess \
476476
-x test_signal \
477477
-x test_sysconfig
478-
- uses: actions/upload-artifact@v6
478+
- uses: actions/upload-artifact@v7
479479
if: always()
480480
with:
481481
name: hypothesis-example-db

.github/workflows/reusable-check-c-api-docs.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ jobs:
1515
runs-on: ubuntu-latest
1616
timeout-minutes: 5
1717
steps:
18-
- uses: actions/checkout@v4
18+
- uses: actions/checkout@v6
1919
with:
2020
persist-credentials: false
21-
- uses: actions/setup-python@v5
21+
- uses: actions/setup-python@v6
2222
with:
2323
python-version: '3.x'
2424
- name: Check for undocumented C APIs

.github/workflows/reusable-cifuzz.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ jobs:
3434
sanitizer: ${{ inputs.sanitizer }}
3535
- name: Upload crash
3636
if: failure() && steps.build.outcome == 'success'
37-
uses: actions/upload-artifact@v6
37+
uses: actions/upload-artifact@v7
3838
with:
3939
name: ${{ inputs.sanitizer }}-artifacts
4040
path: ./out/artifacts

.github/workflows/reusable-san.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ jobs:
9696
run: find "${GITHUB_WORKSPACE}" -name 'san_log.*' | xargs head -n 1000
9797
- name: Archive logs
9898
if: always()
99-
uses: actions/upload-artifact@v6
99+
uses: actions/upload-artifact@v7
100100
with:
101101
name: >-
102102
${{ inputs.sanitizer }}-logs-${{

.github/workflows/stale.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414

1515
steps:
1616
- name: "Check PRs"
17-
uses: actions/stale@v9
17+
uses: actions/stale@v10
1818
with:
1919
repo-token: ${{ secrets.GITHUB_TOKEN }}
2020
stale-pr-message: 'This PR is stale because it has been open for 30 days with no activity.'

Doc/c-api/bytes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,13 +371,17 @@ Getters
371371
372372
Get the writer size.
373373
374+
The function cannot fail.
375+
374376
.. c:function:: void* PyBytesWriter_GetData(PyBytesWriter *writer)
375377
376378
Get the writer data: start of the internal buffer.
377379
378380
The pointer is valid until :c:func:`PyBytesWriter_Finish` or
379381
:c:func:`PyBytesWriter_Discard` is called on *writer*.
380382
383+
The function cannot fail.
384+
381385
382386
Low-level API
383387
^^^^^^^^^^^^^

Doc/library/datetime.rst

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2611,8 +2611,10 @@ requires, and these work on all supported platforms.
26112611
| ``%M`` | Minute as a zero-padded | 00, 01, ..., 59 | \(9) |
26122612
| | decimal number. | | |
26132613
+-----------+--------------------------------+------------------------+-------+
2614-
| ``%n`` | The newline character | ``\n`` | \(0) |
2615-
| | (``'\n'``). | | |
2614+
| ``%n`` | The newline character | ``\n`` | |
2615+
| | (``'\n'``). For | | |
2616+
| | :meth:`!strptime`, zero or | | |
2617+
| | more whitespace. | | |
26162618
+-----------+--------------------------------+------------------------+-------+
26172619
| ``%p`` | Locale's equivalent of either || AM, PM (en_US); | \(1), |
26182620
| | AM or PM. || am, pm (de_DE) | \(3) |
@@ -2625,8 +2627,9 @@ requires, and these work on all supported platforms.
26252627
| ``%S`` | Second as a zero-padded | 00, 01, ..., 59 | \(4), |
26262628
| | decimal number. | | \(9) |
26272629
+-----------+--------------------------------+------------------------+-------+
2628-
| ``%t`` | The tab character | ``\t`` | \(0) |
2629-
| | (``'\t'``). | | |
2630+
| ``%t`` | The tab character (``'\t'``). | ``\t`` | |
2631+
| | For :meth:`!strptime`, | | |
2632+
| | zero or more whitespace. | | |
26302633
+-----------+--------------------------------+------------------------+-------+
26312634
| ``%T`` | ISO 8601 time format, | 10:01:59 | |
26322635
| | equivalent to ``%H:%M:%S``. | | |
@@ -2717,7 +2720,8 @@ differences between platforms in handling of unsupported format specifiers.
27172720
``%:z`` was added for :meth:`~.datetime.strftime`.
27182721

27192722
.. versionadded:: 3.15
2720-
``%:z``, ``%F``, and ``%D`` were added for :meth:`~.datetime.strptime`.
2723+
``%D``, ``%F``, ``%n``, ``%t``, and ``%:z`` were added for
2724+
:meth:`~.datetime.strptime`.
27212725

27222726

27232727
Technical detail

Doc/library/stdtypes.rst

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1286,7 +1286,7 @@ Mutable sequence types also support the following methods:
12861286
:no-typesetting:
12871287
.. method:: sequence.append(value, /)
12881288

1289-
Append *value* to the end of the sequence
1289+
Append *value* to the end of the sequence.
12901290
This is equivalent to writing ``seq[len(seq):len(seq)] = [value]``.
12911291

12921292
.. method:: bytearray.clear()
@@ -5251,6 +5251,11 @@ Note, the *elem* argument to the :meth:`~object.__contains__`,
52515251
:meth:`~set.discard` methods may be a set. To support searching for an equivalent
52525252
frozenset, a temporary one is created from *elem*.
52535253

5254+
.. seealso::
5255+
5256+
For detailed information on thread-safety guarantees for :class:`set`
5257+
objects, see :ref:`thread-safety-set`.
5258+
52545259

52555260
.. _typesmapping:
52565261

Doc/library/threadsafety.rst

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,3 +342,108 @@ thread, iterate over a copy:
342342
343343
Consider external synchronization when sharing :class:`dict` instances
344344
across threads.
345+
346+
347+
.. _thread-safety-set:
348+
349+
Thread safety for set objects
350+
==============================
351+
352+
The :func:`len` function is lock-free and :term:`atomic <atomic operation>`.
353+
354+
The following read operation is lock-free. It does not block concurrent
355+
modifications and may observe intermediate states from operations that
356+
hold the per-object lock:
357+
358+
.. code-block::
359+
:class: good
360+
361+
elem in s # set.__contains__
362+
363+
This operation may compare elements using :meth:`~object.__eq__`, which can
364+
execute arbitrary Python code. During such comparisons, the set may be
365+
modified by another thread. For built-in types like :class:`str`,
366+
:class:`int`, and :class:`float`, :meth:`!__eq__` does not release the
367+
underlying lock during comparisons and this is not a concern.
368+
369+
All other operations from here on hold the per-object lock.
370+
371+
Adding or removing a single element is safe to call from multiple threads
372+
and will not corrupt the set:
373+
374+
.. code-block::
375+
:class: good
376+
377+
s.add(elem) # add element
378+
s.remove(elem) # remove element, raise if missing
379+
s.discard(elem) # remove element if present
380+
s.pop() # remove and return arbitrary element
381+
382+
These operations also compare elements, so the same :meth:`~object.__eq__`
383+
considerations as above apply.
384+
385+
The :meth:`~set.copy` method returns a new object and holds the per-object lock
386+
for the duration so that it is always atomic.
387+
388+
The :meth:`~set.clear` method holds the lock for its duration. Other
389+
threads cannot observe elements being removed.
390+
391+
The following operations only accept :class:`set` or :class:`frozenset`
392+
as operands and always lock both objects:
393+
394+
.. code-block::
395+
:class: good
396+
397+
s |= other # other must be set/frozenset
398+
s &= other # other must be set/frozenset
399+
s -= other # other must be set/frozenset
400+
s ^= other # other must be set/frozenset
401+
s & other # other must be set/frozenset
402+
s | other # other must be set/frozenset
403+
s - other # other must be set/frozenset
404+
s ^ other # other must be set/frozenset
405+
406+
:meth:`set.update`, :meth:`set.union`, :meth:`set.intersection` and
407+
:meth:`set.difference` can take multiple iterables as arguments. They all
408+
iterate through all the passed iterables and do the following:
409+
410+
* :meth:`set.update` and :meth:`set.union` lock both objects only when
411+
the other operand is a :class:`set`, :class:`frozenset`, or :class:`dict`.
412+
* :meth:`set.intersection` and :meth:`set.difference` always try to lock
413+
all objects.
414+
415+
:meth:`set.symmetric_difference` tries to lock both objects.
416+
417+
The update variants of the above methods also have some differences between
418+
them:
419+
420+
* :meth:`set.difference_update` and :meth:`set.intersection_update` try
421+
to lock all objects one-by-one.
422+
* :meth:`set.symmetric_difference_update` only locks the arguments if it is
423+
of type :class:`set`, :class:`frozenset`, or :class:`dict`.
424+
425+
The following methods always try to lock both objects:
426+
427+
.. code-block::
428+
:class: good
429+
430+
s.isdisjoint(other) # both locked
431+
s.issubset(other) # both locked
432+
s.issuperset(other) # both locked
433+
434+
Operations that involve multiple accesses, as well as iteration, are never
435+
atomic:
436+
437+
.. code-block::
438+
:class: bad
439+
440+
# NOT atomic: check-then-act
441+
if elem in s:
442+
s.remove(elem)
443+
444+
# NOT thread-safe: iteration while modifying
445+
for elem in s:
446+
process(elem) # another thread may modify s
447+
448+
Consider external synchronization when sharing :class:`set` instances
449+
across threads. See :ref:`freethreading-python-howto` for more information.

0 commit comments

Comments
 (0)