Skip to content

Commit 95244c0

Browse files
ambvmeta-codesync[bot]
authored andcommitted
Sync pre-release CPython main branch from GitHub (2026-07-22)
Summary: Imported python/cpython `3.16.0a0` from upstream rev [`a84e780`](https://www.github.com/python/cpython/commit/a84e780707d3baa3b9f73981d8b7e293eb10d076) (committed 2026-07-22 05:01:25+00:00). # Commit Info - Base: (`3.16.0a0`) - [`20b7e8e`](https://www.github.com/python/cpython/commit/20b7e8e50b9a4a92989b36531429f9b51ee0a0bf) (commit date: 2026-07-21 00:46:48+00:00) - Imported: (`3.16.0a0`) - [`a84e780`](https://www.github.com/python/cpython/commit/a84e780707d3baa3b9f73981d8b7e293eb10d076) (commit date: 2026-07-22 05:01:25+00:00) # Noteworthy file changes - Native files (3 added): ``` + Include/internal/pycore_typecache.h + Modules/_testinternalcapi/typecache.c + Python/typecache.c ``` - Test files (2 added) - Low-signal files (9 added) (NEWS.d, docs, .github) Complete list of added/removed files: https://www.internalfb.com/intern/everpaste/?color=0&handle=GIJL9yn5u6zcrU0GALkS74GISjsqbr0LAAAz Reviewed By: itamaro Differential Revision: D113180323 fbshipit-source-id: ea358bbbeadbea38809557efd33bcc228c55beb9
1 parent d6aecde commit 95244c0

68 files changed

Lines changed: 1836 additions & 510 deletions

File tree

Some content is hidden

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

Doc/c-api/type.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ Type Objects
3737
3838
Clear the internal lookup cache. Return the current version tag.
3939
40+
.. versionchanged:: 3.16
41+
This function is now a no-op as the type cache is now implemented
42+
per-type. It still returns the current version tag.
43+
4044
.. c:function:: unsigned long PyType_GetFlags(PyTypeObject* type)
4145
4246
Return the :c:member:`~PyTypeObject.tp_flags` member of *type*. This function is primarily

Doc/library/annotationlib.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -535,9 +535,9 @@ following attributes:
535535
:attr:`~Format.VALUE_WITH_FAKE_GLOBALS`.
536536
* A :ref:`code object <code-objects>` ``__code__`` containing the compiled code for the
537537
annotate function.
538-
* Optional: A tuple of the function's positional defaults ``__kwdefaults__``, if the
538+
* Optional: A tuple of the function's positional defaults ``__defaults__``, if the
539539
function represented by ``__code__`` uses any positional defaults.
540-
* Optional: A dict of the function's keyword defaults ``__defaults__``, if the function
540+
* Optional: A dict of the function's keyword defaults ``__kwdefaults__``, if the function
541541
represented by ``__code__`` uses any keyword defaults.
542542
* Optional: All other :ref:`function attributes <inspect-types>`.
543543

Doc/library/asyncio-subprocess.rst

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,10 +240,34 @@ their completion.
240240
Note, that the data read is buffered in memory, so do not use
241241
this method if the data size is large or unlimited.
242242

243+
If this coroutine is cancelled (for example, when a timeout is
244+
set with :func:`~asyncio.wait_for`), the output that was already
245+
read is not lost: call :meth:`!communicate` again to read the
246+
remaining output and get the complete data::
247+
248+
try:
249+
stdout, stderr = await asyncio.wait_for(
250+
proc.communicate(), timeout=5.0)
251+
except TimeoutError:
252+
proc.kill()
253+
stdout, stderr = await proc.communicate()
254+
255+
Passing *input* after a previous :meth:`!communicate` call was
256+
cancelled raises :exc:`ValueError`; pass ``input=None`` to
257+
continue the communication, the original *input* is used.
258+
243259
.. versionchanged:: 3.12
244260

245261
*stdin* gets closed when ``input=None`` too.
246262

263+
.. versionchanged:: next
264+
265+
If :meth:`!communicate` is cancelled, the output that was
266+
already read is now preserved and returned by a subsequent
267+
:meth:`!communicate` call. Passing *input* to a
268+
:meth:`!communicate` call following a cancelled one now raises
269+
:exc:`ValueError`.
270+
247271
.. method:: send_signal(signal)
248272

249273
Sends the signal *signal* to the child process.

Doc/library/csv.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,22 @@ The :mod:`!csv` module defines the following classes:
312312
is given, it is interpreted as a string containing possible valid
313313
delimiter characters.
314314

315+
The dialect is deduced by parsing the sample with every plausible
316+
combination of parameters
317+
and choosing the combination which splits the sample into rows
318+
with the most consistent number of fields,
319+
so the returned dialect is consistent with how :func:`reader`
320+
will parse the sample.
321+
Raise :exc:`Error` if no combination fits the sample,
322+
in particular if it is a single column,
323+
so there is no delimiter to find.
324+
325+
.. versionchanged:: next
326+
The dialect is now deduced by trial parsing
327+
and the results may differ from those of earlier Python versions.
328+
The *escapechar* parameter can now be detected,
329+
and the requested *delimiters* are not restricted to ASCII.
330+
315331

316332
.. method:: has_header(sample)
317333

Doc/whatsnew/3.16.rst

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,21 @@ codecs
101101
even when a built-in codec of the same name exists.
102102
(Contributed by Serhiy Storchaka in :gh:`152997`.)
103103

104+
csv
105+
---
106+
107+
* :meth:`csv.Sniffer.sniff` now deduces the dialect by trial parsing
108+
instead of heuristics based on matching isolated fragments
109+
and on character frequencies,
110+
so the result is consistent with how :func:`csv.reader` will parse the sample.
111+
It can now detect the *escapechar* parameter,
112+
accepts non-ASCII delimiters in the *delimiters* argument,
113+
no longer misdetects the delimiter
114+
when the sample contains delimiter characters inside quoted fields,
115+
and no longer takes quadratic time on quoted samples.
116+
The results may differ from those of earlier Python versions.
117+
(Contributed by Serhiy Storchaka in :gh:`83273`.)
118+
104119
curses
105120
------
106121

@@ -800,7 +815,8 @@ New features
800815
Porting to Python 3.16
801816
----------------------
802817

803-
* TODO
818+
* :c:func:`PyType_ClearCache` is now a no-op as the type cache is now
819+
implemented per-type. It still returns the current version tag.
804820

805821
Deprecated C APIs
806822
-----------------

Include/cpython/object.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,8 @@ struct _typeobject {
246246
* This function must escape to any code that can result in
247247
* the GC being run, such as Py_DECREF. */
248248
_Py_iteritemfunc _tp_iteritem;
249+
250+
void *_tp_cache;
249251
};
250252

251253
#define _Py_ATTR_CACHE_UNUSED (30000) // (see tp_versions_used)

Include/cpython/pystats.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,9 @@ typedef struct _object_stats {
9696
uint64_t type_cache_misses;
9797
uint64_t type_cache_dunder_hits;
9898
uint64_t type_cache_dunder_misses;
99-
uint64_t type_cache_collisions;
99+
uint64_t type_cache_too_big;
100+
uint64_t type_cache_invalidations;
101+
uint64_t type_cache_resizes;
100102
/* Temporary value used during GC */
101103
uint64_t object_visits;
102104
} ObjectStats;

Include/internal/pycore_interp_structs.h

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -560,23 +560,6 @@ struct _types_runtime_state {
560560
};
561561

562562

563-
// Type attribute lookup cache: speed up attribute and method lookups,
564-
// see _PyType_Lookup().
565-
struct type_cache_entry {
566-
unsigned int version; // initialized from type->tp_version_tag
567-
#ifdef Py_GIL_DISABLED
568-
_PySeqLock sequence;
569-
#endif
570-
PyObject *name; // reference to exactly a str or None
571-
PyObject *value; // borrowed reference or NULL
572-
};
573-
574-
#define MCACHE_SIZE_EXP 12
575-
576-
struct type_cache {
577-
struct type_cache_entry hashtable[1 << MCACHE_SIZE_EXP];
578-
};
579-
580563
typedef struct {
581564
PyTypeObject *type;
582565
int isbuiltin;
@@ -591,6 +574,10 @@ typedef struct {
591574
are also some diagnostic uses for the list of weakrefs,
592575
so we still keep it. */
593576
PyObject *tp_weaklist;
577+
/* Per-interpreter attribute lookup cache (struct type_cache *).
578+
For static builtin types the cache must be per-interpreter
579+
because tp_dict and the values it stores are per-interpreter. */
580+
void *_tp_cache;
594581
} managed_static_type_state;
595582

596583
#define TYPE_VERSION_CACHE_SIZE (1<<12) /* Must be a power of 2 */
@@ -601,8 +588,6 @@ struct types_state {
601588
where all those lower numbers are used for core static types. */
602589
unsigned int next_version_tag;
603590

604-
struct type_cache type_cache;
605-
606591
/* Every static builtin type is initialized for each interpreter
607592
during its own initialization, including for the main interpreter
608593
during global runtime initialization. This is done by calling

Include/internal/pycore_object.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -285,8 +285,6 @@ _PyType_HasFeature(PyTypeObject *type, unsigned long feature) {
285285
return ((type->tp_flags) & feature) != 0;
286286
}
287287

288-
extern void _PyType_InitCache(PyInterpreterState *interp);
289-
290288
extern PyStatus _PyObject_InitState(PyInterpreterState *interp);
291289
extern void _PyObject_FiniState(PyInterpreterState *interp);
292290
extern bool _PyRefchain_IsTraced(PyInterpreterState *interp, PyObject *obj);
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#ifndef PY_INTERNAL_TYPECACHE_H
2+
#define PY_INTERNAL_TYPECACHE_H
3+
#ifdef __cplusplus
4+
extern "C" {
5+
#endif
6+
7+
#ifndef Py_BUILD_CORE
8+
# error "this header requires Py_BUILD_CORE define"
9+
#endif
10+
11+
#include "pycore_stackref.h"
12+
13+
14+
#define _Py_TYPECACHE_MINSIZE (1 << 3)
15+
#define _Py_TYPECACHE_MAXSIZE (1 << 16)
16+
17+
struct type_cache_entry {
18+
PyObject *name; // name of the attribute or method, interned string, NULL if the entry is empty
19+
PyObject *value; // borrowed reference or NULL
20+
};
21+
22+
// Per-type attribute lookup cache: speed up attribute and method lookups,
23+
// see _PyTypeCache_Lookup().
24+
struct type_cache {
25+
uint32_t mask; // mask for indexing into hashtable, i.e. size of hashtable is mask + 1
26+
uint32_t available; // number of available entries in hashtable
27+
uint32_t used; // number of used entries in hashtable
28+
unsigned int version_tag; // initialized from type->tp_version_tag
29+
struct type_cache_entry hashtable[_Py_TYPECACHE_MINSIZE]; // hashtable entries
30+
};
31+
32+
struct _PyTypeCacheLookupResult {
33+
_PyStackRef value; // value is a stack reference to the cached attribute or method, or NULL if not found
34+
int cache_hit; // 1 if the cache entry is valid and matches the type's version tag, 0 otherwise
35+
unsigned int version_tag; // version tag of the type when the value was cached
36+
};
37+
38+
39+
extern void _PyTypeCache_InitType(PyTypeObject *type);
40+
extern void _PyTypeCache_Insert(PyTypeObject *type, PyObject *name, PyObject *value);
41+
PyAPI_FUNC(struct _PyTypeCacheLookupResult) _PyTypeCache_Lookup(PyTypeObject *type, PyObject *name);
42+
PyAPI_FUNC(void) _PyTypeCache_Invalidate(PyTypeObject *type);
43+
44+
#ifdef __cplusplus
45+
}
46+
#endif
47+
#endif /* PY_INTERNAL_TYPECACHE_H */

0 commit comments

Comments
 (0)