@@ -65,6 +65,11 @@ Dictionary Objects
6565 *key *, return ``1 ``, otherwise return ``0 ``. On error, return ``-1 ``.
6666 This is equivalent to the Python expression ``key in p ``.
6767
68+ .. note ::
69+
70+ The operation is atomic on :term: `free threading <free-threaded build> `
71+ when *key * is :class: `str `, :class: `int `, :class: `float `, :class: `bool ` or :class: `bytes `.
72+
6873
6974.. c :function :: int PyDict_ContainsString (PyObject *p, const char *key)
7075
@@ -87,6 +92,11 @@ Dictionary Objects
8792 ``0 `` on success or ``-1 `` on failure. This function *does not * steal a
8893 reference to *val *.
8994
95+ .. note ::
96+
97+ The operation is atomic on :term: `free threading <free-threaded build> `
98+ when *key * is :class: `str `, :class: `int `, :class: `float `, :class: `bool ` or :class: `bytes `.
99+
90100
91101.. c :function :: int PyDict_SetItemString (PyObject *p, const char *key, PyObject *val)
92102
@@ -102,6 +112,11 @@ Dictionary Objects
102112 If *key * is not in the dictionary, :exc: `KeyError ` is raised.
103113 Return ``0 `` on success or ``-1 `` on failure.
104114
115+ .. note ::
116+
117+ The operation is atomic on :term: `free threading <free-threaded build> `
118+ when *key * is :class: `str `, :class: `int `, :class: `float `, :class: `bool ` or :class: `bytes `.
119+
105120
106121.. c :function :: int PyDict_DelItemString (PyObject *p, const char *key)
107122
@@ -120,6 +135,11 @@ Dictionary Objects
120135 * If the key is missing, set *\* result * to ``NULL `` and return ``0 ``.
121136 * On error, raise an exception and return ``-1 ``.
122137
138+ .. note ::
139+
140+ The operation is atomic on :term: `free threading <free-threaded build> `
141+ when *key * is :class: `str `, :class: `int `, :class: `float `, :class: `bool ` or :class: `bytes `.
142+
123143 .. versionadded :: 3.13
124144
125145 See also the :c:func: `PyObject_GetItem ` function.
@@ -137,6 +157,13 @@ Dictionary Objects
137157 :meth: `~object.__eq__ ` methods are silently ignored.
138158 Prefer the :c:func: `PyDict_GetItemWithError ` function instead.
139159
160+ .. note ::
161+
162+ In the :term: `free-threaded build `, the returned
163+ :term: `borrowed reference ` may become invalid if another thread modifies
164+ the dictionary concurrently. Prefer :c:func: `PyDict_GetItemRef `, which
165+ returns a :term: `strong reference `.
166+
140167 .. versionchanged :: 3.10
141168 Calling this API without an :term: `attached thread state ` had been allowed for historical
142169 reason. It is no longer allowed.
@@ -149,6 +176,13 @@ Dictionary Objects
149176 occurred. Return ``NULL `` **without ** an exception set if the key
150177 wasn't present.
151178
179+ .. note ::
180+
181+ In the :term: `free-threaded build `, the returned
182+ :term: `borrowed reference ` may become invalid if another thread modifies
183+ the dictionary concurrently. Prefer :c:func: `PyDict_GetItemRef `, which
184+ returns a :term: `strong reference `.
185+
152186
153187.. c :function :: PyObject* PyDict_GetItemString (PyObject *p, const char *key)
154188
@@ -164,6 +198,13 @@ Dictionary Objects
164198 Prefer using the :c:func: `PyDict_GetItemWithError ` function with your own
165199 :c:func: `PyUnicode_FromString ` *key * instead.
166200
201+ .. note ::
202+
203+ In the :term: `free-threaded build `, the returned
204+ :term: `borrowed reference ` may become invalid if another thread modifies
205+ the dictionary concurrently. Prefer :c:func: `PyDict_GetItemStringRef `,
206+ which returns a :term: `strong reference `.
207+
167208
168209.. c :function :: int PyDict_GetItemStringRef (PyObject *p, const char *key, PyObject **result)
169210
@@ -184,6 +225,14 @@ Dictionary Objects
184225
185226 .. versionadded :: 3.4
186227
228+ .. note ::
229+
230+ In the :term: `free-threaded build `, the returned
231+ :term: `borrowed reference ` may become invalid if another thread modifies
232+ the dictionary concurrently. Prefer :c:func: `PyDict_SetDefaultRef `,
233+ which returns a :term: `strong reference `.
234+
235+
187236
188237.. c :function :: int PyDict_SetDefaultRef (PyObject *p, PyObject *key, PyObject *default_value, PyObject **result)
189238
@@ -203,6 +252,11 @@ Dictionary Objects
203252 These may refer to the same object: in that case you hold two separate
204253 references to it.
205254
255+ .. note::
256+
257+ The operation is atomic on :term:`free threading <free-threaded build>`
258+ when *key* is :class:`str`, :class:`int`, :class:`float`, :class:`bool` or :class:`bytes`.
259+
206260 .. versionadded:: 3.13
207261
208262
@@ -220,6 +274,11 @@ Dictionary Objects
220274 Similar to :meth: `dict.pop `, but without the default value and
221275 not raising :exc: `KeyError ` if the key is missing.
222276
277+ .. note ::
278+
279+ The operation is atomic on :term: `free threading <free-threaded build> `
280+ when *key * is :class: `str `, :class: `int `, :class: `float `, :class: `bool ` or :class: `bytes `.
281+
223282 .. versionadded :: 3.13
224283
225284
@@ -336,6 +395,13 @@ Dictionary Objects
336395 only be added if there is not a matching key in *a *. Return ``0 `` on
337396 success or ``-1 `` if an exception was raised.
338397
398+ .. note ::
399+
400+ In the :term: `free-threaded build `, when *b * is a
401+ :class: `dict ` (with the standard iterator), both *a* and *b* are locked
402+ for the duration of the operation. When *b* is a non-dict mapping, only
403+ *a* is locked; *b* may be concurrently modified by another thread.
404+
339405
340406 .. c :function :: int PyDict_Update (PyObject *a, PyObject *b)
341407
@@ -345,6 +411,13 @@ Dictionary Objects
345411 argument has no "keys" attribute. Return ``0 `` on success or ``-1 `` if an
346412 exception was raised.
347413
414+ .. note ::
415+
416+ In the :term: `free-threaded build `, when *b * is a
417+ :class: `dict ` (with the standard iterator), both *a* and *b* are locked
418+ for the duration of the operation. When *b* is a non-dict mapping, only
419+ *a* is locked; *b* may be concurrently modified by another thread.
420+
348421
349422 .. c :function :: int PyDict_MergeFromSeq2 (PyObject *a, PyObject *seq2, int override)
350423
@@ -360,13 +433,27 @@ Dictionary Objects
360433 if override or key not in a:
361434 a[key] = value
362435
436+ .. note ::
437+
438+ In the :term: `free-threaded <free threading> ` build, only *a * is locked.
439+ The iteration over *seq2 * is not synchronized; *seq2 * may be concurrently
440+ modified by another thread.
441+
442+
363443.. c :function :: int PyDict_AddWatcher (PyDict_WatchCallback callback)
364444
365445 Register *callback* as a dictionary watcher. Return a non-negative integer
366446 id which must be passed to future calls to :c:func:`PyDict_Watch`. In case
367447 of error (e.g. no more watcher IDs available), return ``-1`` and set an
368448 exception.
369449
450+ .. note::
451+
452+ This function is not internally synchronized. In the
453+ :term:`free-threaded <free threading>` build, callers should ensure no
454+ concurrent calls to :c:func:`PyDict_AddWatcher` or
455+ :c:func:`PyDict_ClearWatcher` are in progress.
456+
370457 .. versionadded:: 3.12
371458
372459.. c:function:: int PyDict_ClearWatcher(int watcher_id)
@@ -375,6 +462,13 @@ Dictionary Objects
375462 :c:func:`PyDict_AddWatcher`. Return ``0`` on success, ``-1`` on error (e.g.
376463 if the given *watcher_id * was never registered.)
377464
465+ .. note::
466+
467+ This function is not internally synchronized. In the
468+ :term:`free-threaded <free threading>` build, callers should ensure no
469+ concurrent calls to :c:func:`PyDict_AddWatcher` or
470+ :c:func:`PyDict_ClearWatcher` are in progress.
471+
378472 .. versionadded:: 3.12
379473
380474.. c:function:: int PyDict_Watch(int watcher_id, PyObject *dict)
0 commit comments