@@ -89,13 +89,31 @@ Dictionary objects
8989 ``0 `` on success or ``-1 `` on failure. This function *does not * steal a
9090 reference to *val *.
9191
92+ .. note ::
93+
94+ In the :term: `free-threaded build `, key hashing via
95+ :meth: `~object.__hash__ ` and key comparison via :meth: `~object.__eq__ `
96+ can execute arbitrary Python code, during which the :term: `per-object
97+ lock ` may be temporarily released. For built-in key types
98+ (:class: `str `, :class: `int `, :class: `float `), the lock is not released
99+ during comparison.
100+
92101
93102.. c:function:: int PyDict_SetItemString(PyObject *p, const char *key, PyObject *val)
94103
95104 This is the same as :c:func: `PyDict_SetItem `, but *key * is
96105 specified as a :c:expr: `const char* ` UTF-8 encoded bytes string,
97106 rather than a :c:expr: `PyObject* `.
98107
108+ .. note ::
109+
110+ In the :term: `free-threaded build `, key hashing via
111+ :meth: `~object.__hash__ ` and key comparison via :meth: `~object.__eq__ `
112+ can execute arbitrary Python code, during which the :term: `per-object
113+ lock ` may be temporarily released. For built-in key types
114+ (:class: `str `, :class: `int `, :class: `float `), the lock is not released
115+ during comparison.
116+
99117
100118.. c:function:: int PyDict_DelItem(PyObject *p, PyObject *key)
101119
@@ -104,13 +122,31 @@ Dictionary objects
104122 If *key * is not in the dictionary, :exc: `KeyError ` is raised.
105123 Return ``0 `` on success or ``-1 `` on failure.
106124
125+ .. note ::
126+
127+ In the :term: `free-threaded build `, key hashing via
128+ :meth: `~object.__hash__ ` and key comparison via :meth: `~object.__eq__ `
129+ can execute arbitrary Python code, during which the :term: `per-object
130+ lock ` may be temporarily released. For built-in key types
131+ (:class: `str `, :class: `int `, :class: `float `), the lock is not released
132+ during comparison.
133+
107134
108135.. c:function:: int PyDict_DelItemString(PyObject *p, const char *key)
109136
110137 This is the same as :c:func: `PyDict_DelItem `, but *key * is
111138 specified as a :c:expr: `const char* ` UTF-8 encoded bytes string,
112139 rather than a :c:expr: `PyObject* `.
113140
141+ .. note ::
142+
143+ In the :term: `free-threaded build `, key hashing via
144+ :meth: `~object.__hash__ ` and key comparison via :meth: `~object.__eq__ `
145+ can execute arbitrary Python code, during which the :term: `per-object
146+ lock ` may be temporarily released. For built-in key types
147+ (:class: `str `, :class: `int `, :class: `float `), the lock is not released
148+ during comparison.
149+
114150
115151.. c:function:: int PyDict_GetItemRef(PyObject *p, PyObject *key, PyObject **result)
116152
@@ -139,6 +175,13 @@ Dictionary objects
139175 :meth: `~object.__eq__ ` methods are silently ignored.
140176 Prefer the :c:func: `PyDict_GetItemWithError ` function instead.
141177
178+ .. note ::
179+
180+ In the :term: `free-threaded build `, the returned
181+ :term: `borrowed reference ` may become invalid if another thread modifies
182+ the dictionary concurrently. Prefer :c:func: `PyDict_GetItemRef `, which
183+ returns a :term: `strong reference `.
184+
142185 .. versionchanged :: 3.10
143186 Calling this API without an :term: `attached thread state ` had been allowed for historical
144187 reason. It is no longer allowed.
@@ -151,6 +194,13 @@ Dictionary objects
151194 occurred. Return ``NULL `` **without ** an exception set if the key
152195 wasn't present.
153196
197+ .. note ::
198+
199+ In the :term: `free-threaded build `, the returned
200+ :term: `borrowed reference ` may become invalid if another thread modifies
201+ the dictionary concurrently. Prefer :c:func: `PyDict_GetItemRef `, which
202+ returns a :term: `strong reference `.
203+
154204
155205.. c :function :: PyObject* PyDict_GetItemString (PyObject *p, const char *key)
156206
@@ -166,6 +216,13 @@ Dictionary objects
166216 Prefer using the :c:func: `PyDict_GetItemWithError ` function with your own
167217 :c:func: `PyUnicode_FromString ` *key * instead.
168218
219+ .. note ::
220+
221+ In the :term: `free-threaded build `, the returned
222+ :term: `borrowed reference ` may become invalid if another thread modifies
223+ the dictionary concurrently. Prefer :c:func: `PyDict_GetItemStringRef `,
224+ which returns a :term: `strong reference `.
225+
169226
170227.. c :function :: int PyDict_GetItemStringRef (PyObject *p, const char *key, PyObject **result)
171228
@@ -186,6 +243,14 @@ Dictionary objects
186243
187244 .. versionadded :: 3.4
188245
246+ .. note ::
247+
248+ In the :term: `free-threaded build `, the returned
249+ :term: `borrowed reference ` may become invalid if another thread modifies
250+ the dictionary concurrently. Prefer :c:func: `PyDict_SetDefaultRef `,
251+ which returns a :term: `strong reference `.
252+
253+
189254
190255.. c :function :: int PyDict_SetDefaultRef (PyObject *p, PyObject *key, PyObject *default_value, PyObject **result)
191256
@@ -224,6 +289,15 @@ Dictionary objects
224289
225290 .. versionadded :: 3.13
226291
292+ .. note ::
293+
294+ In the :term: `free-threaded build `, key hashing via
295+ :meth: `~object.__hash__ ` and key comparison via :meth: `~object.__eq__ `
296+ can execute arbitrary Python code, during which the :term: `per-object
297+ lock ` may be temporarily released. For built-in key types
298+ (:class: `str `, :class: `int `, :class: `float `), the lock is not released
299+ during comparison.
300+
227301
228302.. c:function:: int PyDict_PopString(PyObject *p, const char *key, PyObject **result)
229303
@@ -233,6 +307,15 @@ Dictionary objects
233307
234308 .. versionadded :: 3.13
235309
310+ .. note ::
311+
312+ In the :term: `free-threaded build `, key hashing via
313+ :meth: `~object.__hash__ ` and key comparison via :meth: `~object.__eq__ `
314+ can execute arbitrary Python code, during which the :term: `per-object
315+ lock ` may be temporarily released. For built-in key types
316+ (:class: `str `, :class: `int `, :class: `float `), the lock is not released
317+ during comparison.
318+
236319
237320.. c:function:: PyObject* PyDict_Items(PyObject *p)
238321
@@ -338,6 +421,13 @@ Dictionary objects
338421 only be added if there is not a matching key in *a *. Return ``0 `` on
339422 success or ``-1 `` if an exception was raised.
340423
424+ .. note ::
425+
426+ In the :term: `free-threaded build `, when *b * is a
427+ :class: `dict ` (with the standard iterator), both *a* and *b* are locked
428+ for the duration of the operation. When *b* is a non-dict mapping, only
429+ *a* is locked; *b* may be concurrently modified by another thread.
430+
341431
342432 .. c :function :: int PyDict_Update (PyObject *a, PyObject *b)
343433
@@ -347,6 +437,13 @@ Dictionary objects
347437 argument has no "keys" attribute. Return ``0 `` on success or ``-1 `` if an
348438 exception was raised.
349439
440+ .. note ::
441+
442+ In the :term: `free-threaded build `, when *b * is a
443+ :class: `dict ` (with the standard iterator), both *a* and *b* are locked
444+ for the duration of the operation. When *b* is a non-dict mapping, only
445+ *a* is locked; *b* may be concurrently modified by another thread.
446+
350447
351448 .. c :function :: int PyDict_MergeFromSeq2 (PyObject *a, PyObject *seq2, int override)
352449
@@ -362,13 +459,27 @@ Dictionary objects
362459 if override or key not in a:
363460 a[key] = value
364461
462+ .. note ::
463+
464+ In the :term: `free-threaded <free threading> ` build, only *a * is locked.
465+ The iteration over *seq2 * is not synchronized; *seq2 * may be concurrently
466+ modified by another thread.
467+
468+
365469.. c :function :: int PyDict_AddWatcher (PyDict_WatchCallback callback)
366470
367471 Register *callback* as a dictionary watcher. Return a non-negative integer
368472 id which must be passed to future calls to :c:func:`PyDict_Watch`. In case
369473 of error (e.g. no more watcher IDs available), return ``-1`` and set an
370474 exception.
371475
476+ .. note::
477+
478+ This function is not internally synchronized. In the
479+ :term:`free-threaded <free threading>` build, callers should ensure no
480+ concurrent calls to :c:func:`PyDict_AddWatcher` or
481+ :c:func:`PyDict_ClearWatcher` are in progress.
482+
372483 .. versionadded:: 3.12
373484
374485.. c:function:: int PyDict_ClearWatcher(int watcher_id)
@@ -377,6 +488,13 @@ Dictionary objects
377488 :c:func:`PyDict_AddWatcher`. Return ``0`` on success, ``-1`` on error (e.g.
378489 if the given *watcher_id * was never registered.)
379490
491+ .. note::
492+
493+ This function is not internally synchronized. In the
494+ :term:`free-threaded <free threading>` build, callers should ensure no
495+ concurrent calls to :c:func:`PyDict_AddWatcher` or
496+ :c:func:`PyDict_ClearWatcher` are in progress.
497+
380498 .. versionadded:: 3.12
381499
382500.. c:function:: int PyDict_Watch(int watcher_id, PyObject *dict)
0 commit comments