gh-116126: Implement PEP 696 (#116129)

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com>
This commit is contained in:
Jelle Zijlstra 2024-05-03 06:17:32 -07:00 committed by GitHub
parent 852263e108
commit ca269e58c2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
28 changed files with 1924 additions and 623 deletions

View File

@ -1748,15 +1748,17 @@ Type parameters
:ref:`Type parameters <type-params>` can exist on classes, functions, and type
aliases.
.. class:: TypeVar(name, bound)
.. class:: TypeVar(name, bound, default_value)
A :class:`typing.TypeVar`. ``name`` is the name of the type variable.
``bound`` is the bound or constraints, if any. If ``bound`` is a :class:`Tuple`,
it represents constraints; otherwise it represents the bound.
A :class:`typing.TypeVar`. *name* is the name of the type variable.
*bound* is the bound or constraints, if any. If *bound* is a :class:`Tuple`,
it represents constraints; otherwise it represents the bound. *default_value*
is the default value; if the :class:`!TypeVar` has no default, this
attribute will be set to ``None``.
.. doctest::
>>> print(ast.dump(ast.parse("type Alias[T: int] = list[T]"), indent=4))
>>> print(ast.dump(ast.parse("type Alias[T: int = bool] = list[T]"), indent=4))
Module(
body=[
TypeAlias(
@ -1764,7 +1766,8 @@ aliases.
type_params=[
TypeVar(
name='T',
bound=Name(id='int', ctx=Load()))],
bound=Name(id='int', ctx=Load()),
default_value=Name(id='bool', ctx=Load()))],
value=Subscript(
value=Name(id='list', ctx=Load()),
slice=Name(id='T', ctx=Load()),
@ -1772,19 +1775,30 @@ aliases.
.. versionadded:: 3.12
.. class:: ParamSpec(name)
.. versionchanged:: 3.13
Added the *default_value* parameter.
A :class:`typing.ParamSpec`. ``name`` is the name of the parameter specification.
.. class:: ParamSpec(name, default_value)
A :class:`typing.ParamSpec`. *name* is the name of the parameter specification.
*default_value* is the default value; if the :class:`!ParamSpec` has no default,
this attribute will be set to ``None``.
.. doctest::
>>> print(ast.dump(ast.parse("type Alias[**P] = Callable[P, int]"), indent=4))
>>> print(ast.dump(ast.parse("type Alias[**P = (int, str)] = Callable[P, int]"), indent=4))
Module(
body=[
TypeAlias(
name=Name(id='Alias', ctx=Store()),
type_params=[
ParamSpec(name='P')],
ParamSpec(
name='P',
default_value=Tuple(
elts=[
Name(id='int', ctx=Load()),
Name(id='str', ctx=Load())],
ctx=Load()))],
value=Subscript(
value=Name(id='Callable', ctx=Load()),
slice=Tuple(
@ -1796,19 +1810,26 @@ aliases.
.. versionadded:: 3.12
.. class:: TypeVarTuple(name)
.. versionchanged:: 3.13
Added the *default_value* parameter.
A :class:`typing.TypeVarTuple`. ``name`` is the name of the type variable tuple.
.. class:: TypeVarTuple(name, default_value)
A :class:`typing.TypeVarTuple`. *name* is the name of the type variable tuple.
*default_value* is the default value; if the :class:`!TypeVarTuple` has no
default, this attribute will be set to ``None``.
.. doctest::
>>> print(ast.dump(ast.parse("type Alias[*Ts] = tuple[*Ts]"), indent=4))
>>> print(ast.dump(ast.parse("type Alias[*Ts = ()] = tuple[*Ts]"), indent=4))
Module(
body=[
TypeAlias(
name=Name(id='Alias', ctx=Store()),
type_params=[
TypeVarTuple(name='Ts')],
TypeVarTuple(
name='Ts',
default_value=Tuple(ctx=Load()))],
value=Subscript(
value=Name(id='tuple', ctx=Load()),
slice=Tuple(
@ -1821,6 +1842,9 @@ aliases.
.. versionadded:: 3.12
.. versionchanged:: 3.13
Added the *default_value* parameter.
Function and class definitions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -1614,7 +1614,7 @@ without the dedicated syntax, as documented below.
.. _typevar:
.. class:: TypeVar(name, *constraints, bound=None, covariant=False, contravariant=False, infer_variance=False)
.. class:: TypeVar(name, *constraints, bound=None, covariant=False, contravariant=False, infer_variance=False, default=typing.NoDefault)
Type variable.
@ -1752,15 +1752,35 @@ without the dedicated syntax, as documented below.
the constraints are evaluated only when the attribute is accessed, not when
the type variable is created (see :ref:`lazy-evaluation`).
.. attribute:: __default__
The default value of the type variable, or :data:`typing.NoDefault` if it
has no default.
.. versionadded:: 3.13
.. method:: has_default()
Return whether or not the type variable has a default value. This is equivalent
to checking whether :attr:`__default__` is not the :data:`typing.NoDefault`
singleton, except that it does not force evaluation of the
:ref:`lazily evaluated <lazy-evaluation>` default value.
.. versionadded:: 3.13
.. versionchanged:: 3.12
Type variables can now be declared using the
:ref:`type parameter <type-params>` syntax introduced by :pep:`695`.
The ``infer_variance`` parameter was added.
.. versionchanged:: 3.13
Support for default values was added.
.. _typevartuple:
.. class:: TypeVarTuple(name)
.. class:: TypeVarTuple(name, default=typing.NoDefault)
Type variable tuple. A specialized form of :ref:`type variable <typevar>`
that enables *variadic* generics.
@ -1870,6 +1890,22 @@ without the dedicated syntax, as documented below.
The name of the type variable tuple.
.. attribute:: __default__
The default value of the type variable tuple, or :data:`typing.NoDefault` if it
has no default.
.. versionadded:: 3.13
.. method:: has_default()
Return whether or not the type variable tuple has a default value. This is equivalent
to checking whether :attr:`__default__` is not the :data:`typing.NoDefault`
singleton, except that it does not force evaluation of the
:ref:`lazily evaluated <lazy-evaluation>` default value.
.. versionadded:: 3.13
.. versionadded:: 3.11
.. versionchanged:: 3.12
@ -1877,7 +1913,11 @@ without the dedicated syntax, as documented below.
Type variable tuples can now be declared using the
:ref:`type parameter <type-params>` syntax introduced by :pep:`695`.
.. class:: ParamSpec(name, *, bound=None, covariant=False, contravariant=False)
.. versionchanged:: 3.13
Support for default values was added.
.. class:: ParamSpec(name, *, bound=None, covariant=False, contravariant=False, default=typing.NoDefault)
Parameter specification variable. A specialized version of
:ref:`type variables <typevar>`.
@ -1946,6 +1986,22 @@ without the dedicated syntax, as documented below.
The name of the parameter specification.
.. attribute:: __default__
The default value of the parameter specification, or :data:`typing.NoDefault` if it
has no default.
.. versionadded:: 3.13
.. method:: has_default()
Return whether or not the parameter specification has a default value. This is equivalent
to checking whether :attr:`__default__` is not the :data:`typing.NoDefault`
singleton, except that it does not force evaluation of the
:ref:`lazily evaluated <lazy-evaluation>` default value.
.. versionadded:: 3.13
Parameter specification variables created with ``covariant=True`` or
``contravariant=True`` can be used to declare covariant or contravariant
generic types. The ``bound`` argument is also accepted, similar to
@ -1959,6 +2015,10 @@ without the dedicated syntax, as documented below.
Parameter specifications can now be declared using the
:ref:`type parameter <type-params>` syntax introduced by :pep:`695`.
.. versionchanged:: 3.13
Support for default values was added.
.. note::
Only parameter specification variables defined in global scope can
be pickled.
@ -3171,6 +3231,22 @@ Introspection helpers
.. versionadded:: 3.7.4
.. data:: NoDefault
A sentinel object used to indicate that a type parameter has no default
value. For example:
.. doctest::
>>> T = TypeVar("T")
>>> T.__default__ is typing.NoDefault
True
>>> S = TypeVar("S", default=None)
>>> S.__default__ is None
True
.. versionadded:: 3.13
Constant
--------

View File

@ -1620,15 +1620,18 @@ Type parameter lists
.. versionadded:: 3.12
.. versionchanged:: 3.13
Support for default values was added (see :pep:`696`).
.. index::
single: type parameters
.. productionlist:: python-grammar
type_params: "[" `type_param` ("," `type_param`)* "]"
type_param: `typevar` | `typevartuple` | `paramspec`
typevar: `identifier` (":" `expression`)?
typevartuple: "*" `identifier`
paramspec: "**" `identifier`
typevar: `identifier` (":" `expression`)? ("=" `expression`)?
typevartuple: "*" `identifier` ("=" `expression`)?
paramspec: "**" `identifier` ("=" `expression`)?
:ref:`Functions <def>` (including :ref:`coroutines <async def>`),
:ref:`classes <class>` and :ref:`type aliases <type>` may
@ -1694,19 +1697,31 @@ evaluated in a separate :ref:`annotation scope <annotation-scopes>`.
:data:`typing.TypeVarTuple`\ s and :data:`typing.ParamSpec`\ s cannot have bounds
or constraints.
All three flavors of type parameters can also have a *default value*, which is used
when the type parameter is not explicitly provided. This is added by appending
a single equals sign (``=``) followed by an expression. Like the bounds and
constraints of type variables, the default value is not evaluated when the
object is created, but only when the type parameter's ``__default__`` attribute
is accessed. To this end, the default value is evaluated in a separate
:ref:`annotation scope <annotation-scopes>`. If no default value is specified
for a type parameter, the ``__default__`` attribute is set to the special
sentinel object :data:`typing.NoDefault`.
The following example indicates the full set of allowed type parameter declarations::
def overly_generic[
SimpleTypeVar,
TypeVarWithDefault = int,
TypeVarWithBound: int,
TypeVarWithConstraints: (str, bytes),
*SimpleTypeVarTuple,
**SimpleParamSpec,
*SimpleTypeVarTuple = (int, float),
**SimpleParamSpec = (str, bytearray),
](
a: SimpleTypeVar,
b: TypeVarWithBound,
c: Callable[SimpleParamSpec, TypeVarWithConstraints],
*d: SimpleTypeVarTuple,
b: TypeVarWithDefault,
c: TypeVarWithBound,
d: Callable[SimpleParamSpec, TypeVarWithConstraints],
*e: SimpleTypeVarTuple,
): ...
.. _generic-functions:

View File

@ -205,7 +205,7 @@ Annotation scopes are used in the following contexts:
* Type parameter lists for :ref:`generic classes <generic-classes>`.
A generic class's base classes and
keyword arguments are executed within the annotation scope, but its decorators are not.
* The bounds and constraints for type variables
* The bounds, constraints, and default values for type parameters
(:ref:`lazily evaluated <lazy-evaluation>`).
* The value of type aliases (:ref:`lazily evaluated <lazy-evaluation>`).
@ -232,13 +232,17 @@ Annotation scopes differ from function scopes in the following ways:
.. versionadded:: 3.12
Annotation scopes were introduced in Python 3.12 as part of :pep:`695`.
.. versionchanged:: 3.13
Annotation scopes are also used for type parameter defaults, as
introduced by :pep:`696`.
.. _lazy-evaluation:
Lazy evaluation
---------------
The values of type aliases created through the :keyword:`type` statement are
*lazily evaluated*. The same applies to the bounds and constraints of type
*lazily evaluated*. The same applies to the bounds, constraints, and default values of type
variables created through the :ref:`type parameter syntax <type-params>`.
This means that they are not evaluated when the type alias or type variable is
created. Instead, they are only evaluated when doing so is necessary to resolve

View File

@ -89,6 +89,8 @@ Interpreter improvements:
New typing features:
* :pep:`696`: Type parameters (:data:`typing.TypeVar`, :data:`typing.ParamSpec`,
and :data:`typing.TypeVarTuple`) now support defaults.
* :pep:`742`: :data:`typing.TypeIs` was added, providing more intuitive
type narrowing behavior.
@ -850,6 +852,10 @@ typing
an item of a :class:`typing.TypedDict` as read-only for type checkers.
See :pep:`705` for more details.
* Add :data:`typing.NoDefault`, a sentinel object used to represent the defaults
of some parameters in the :mod:`typing` module. (Contributed by Jelle Zijlstra in
:gh:`116126`.)
unicodedata
-----------

View File

@ -647,21 +647,25 @@ type_params[asdl_type_param_seq*]: '[' t=type_param_seq ']' {
type_param_seq[asdl_type_param_seq*]: a[asdl_type_param_seq*]=','.type_param+ [','] { a }
type_param[type_param_ty] (memo):
| a=NAME b=[type_param_bound] { _PyAST_TypeVar(a->v.Name.id, b, EXTRA) }
| a=NAME b=[type_param_bound] c=[type_param_default] { _PyAST_TypeVar(a->v.Name.id, b, c, EXTRA) }
| '*' a=NAME colon=':' e=expression {
RAISE_SYNTAX_ERROR_STARTING_FROM(colon, e->kind == Tuple_kind
? "cannot use constraints with TypeVarTuple"
: "cannot use bound with TypeVarTuple")
}
| '*' a=NAME { _PyAST_TypeVarTuple(a->v.Name.id, EXTRA) }
| '*' a=NAME b=[type_param_starred_default] { _PyAST_TypeVarTuple(a->v.Name.id, b, EXTRA) }
| '**' a=NAME colon=':' e=expression {
RAISE_SYNTAX_ERROR_STARTING_FROM(colon, e->kind == Tuple_kind
? "cannot use constraints with ParamSpec"
: "cannot use bound with ParamSpec")
}
| '**' a=NAME { _PyAST_ParamSpec(a->v.Name.id, EXTRA) }
| '**' a=NAME b=[type_param_default] { _PyAST_ParamSpec(a->v.Name.id, b, EXTRA) }
type_param_bound[expr_ty]: ':' e=expression { e }
type_param_default[expr_ty]: '=' e=expression {
CHECK_VERSION(expr_ty, 13, "Type parameter defaults are", e) }
type_param_starred_default[expr_ty]: '=' e=star_expression {
CHECK_VERSION(expr_ty, 13, "Type parameter defaults are", e) }
# EXPRESSIONS
# -----------

View File

@ -657,14 +657,17 @@ struct _type_param {
struct {
identifier name;
expr_ty bound;
expr_ty default_value;
} TypeVar;
struct {
identifier name;
expr_ty default_value;
} ParamSpec;
struct {
identifier name;
expr_ty default_value;
} TypeVarTuple;
} v;
@ -892,14 +895,15 @@ pattern_ty _PyAST_MatchOr(asdl_pattern_seq * patterns, int lineno, int
col_offset, int end_lineno, int end_col_offset,
PyArena *arena);
type_ignore_ty _PyAST_TypeIgnore(int lineno, string tag, PyArena *arena);
type_param_ty _PyAST_TypeVar(identifier name, expr_ty bound, int lineno, int
col_offset, int end_lineno, int end_col_offset,
PyArena *arena);
type_param_ty _PyAST_ParamSpec(identifier name, int lineno, int col_offset, int
end_lineno, int end_col_offset, PyArena *arena);
type_param_ty _PyAST_TypeVarTuple(identifier name, int lineno, int col_offset,
int end_lineno, int end_col_offset, PyArena
*arena);
type_param_ty _PyAST_TypeVar(identifier name, expr_ty bound, expr_ty
default_value, int lineno, int col_offset, int
end_lineno, int end_col_offset, PyArena *arena);
type_param_ty _PyAST_ParamSpec(identifier name, expr_ty default_value, int
lineno, int col_offset, int end_lineno, int
end_col_offset, PyArena *arena);
type_param_ty _PyAST_TypeVarTuple(identifier name, expr_ty default_value, int
lineno, int col_offset, int end_lineno, int
end_col_offset, PyArena *arena);
PyObject* PyAST_mod2obj(mod_ty t);

View File

@ -184,6 +184,7 @@ struct ast_state {
PyObject *conversion;
PyObject *ctx;
PyObject *decorator_list;
PyObject *default_value;
PyObject *defaults;
PyObject *elt;
PyObject *elts;

View File

@ -28,8 +28,9 @@
#define INTRINSIC_TYPEVAR_WITH_BOUND 2
#define INTRINSIC_TYPEVAR_WITH_CONSTRAINTS 3
#define INTRINSIC_SET_FUNCTION_TYPE_PARAMS 4
#define INTRINSIC_SET_TYPEPARAM_DEFAULT 5
#define MAX_INTRINSIC_2 4
#define MAX_INTRINSIC_2 5
typedef PyObject *(*intrinsic_func1)(PyThreadState* tstate, PyObject *value);
typedef PyObject *(*intrinsic_func2)(PyThreadState* tstate, PyObject *value1, PyObject *value2);

View File

@ -13,10 +13,12 @@ extern PyObject *_Py_make_paramspec(PyThreadState *, PyObject *);
extern PyObject *_Py_make_typevartuple(PyThreadState *, PyObject *);
extern PyObject *_Py_make_typealias(PyThreadState *, PyObject *);
extern PyObject *_Py_subscript_generic(PyThreadState *, PyObject *);
extern PyObject *_Py_set_typeparam_default(PyThreadState *, PyObject *, PyObject *);
extern int _Py_initialize_generic(PyInterpreterState *);
extern void _Py_clear_generic_types(PyInterpreterState *);
extern PyTypeObject _PyTypeAlias_Type;
extern PyObject _Py_NoDefaultStruct;
#ifdef __cplusplus
}

View File

@ -1124,12 +1124,21 @@ class _Unparser(NodeVisitor):
if node.bound:
self.write(": ")
self.traverse(node.bound)
if node.default_value:
self.write(" = ")
self.traverse(node.default_value)
def visit_TypeVarTuple(self, node):
self.write("*" + node.name)
if node.default_value:
self.write(" = ")
self.traverse(node.default_value)
def visit_ParamSpec(self, node):
self.write("**" + node.name)
if node.default_value:
self.write(" = ")
self.traverse(node.default_value)
def visit_TypeAlias(self, node):
self.fill("type ")

View File

@ -195,16 +195,19 @@ exec_tests = [
"type X[T, *Ts, **P] = (T, Ts, P)",
"type X[T: int, *Ts, **P] = (T, Ts, P)",
"type X[T: (int, str), *Ts, **P] = (T, Ts, P)",
"type X[T: int = 1, *Ts = 2, **P =3] = (T, Ts, P)",
# Generic classes
"class X[T]: pass",
"class X[T, *Ts, **P]: pass",
"class X[T: int, *Ts, **P]: pass",
"class X[T: (int, str), *Ts, **P]: pass",
"class X[T: int = 1, *Ts = 2, **P = 3]: pass",
# Generic functions
"def f[T](): pass",
"def f[T, *Ts, **P](): pass",
"def f[T: int, *Ts, **P](): pass",
"def f[T: (int, str), *Ts, **P](): pass",
"def f[T: int = 1, *Ts = 2, **P = 3](): pass",
]
# These are compiled through "single"
@ -1108,6 +1111,18 @@ class AST_Tests(unittest.TestCase):
with self.assertRaises(SyntaxError):
ast.parse(sample, feature_version=(3, 11))
def test_type_params_default_feature_version(self):
samples = [
"type X[*Ts=int] = int",
"class X[T=int]: pass",
"def f[**P=int](): pass",
]
for sample in samples:
with self.subTest(sample):
ast.parse(sample)
with self.assertRaises(SyntaxError):
ast.parse(sample, feature_version=(3, 12))
def test_invalid_major_feature_version(self):
with self.assertRaises(ValueError):
ast.parse('pass', feature_version=(2, 7))
@ -3261,18 +3276,21 @@ exec_results = [
('Module', [('FunctionDef', (1, 0, 1, 42), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None)], None, [('arg', (1, 22, 1, 23), 'c', None, None)], [('Constant', (1, 24, 1, 25), 4, None)], ('arg', (1, 29, 1, 35), 'kwargs', None, None), [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None)]), [('Pass', (1, 38, 1, 42))], [], None, None, [])], []),
('Module', [('FunctionDef', (1, 0, 1, 40), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None)], None, [('arg', (1, 22, 1, 23), 'c', None, None)], [None], ('arg', (1, 27, 1, 33), 'kwargs', None, None), [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None)]), [('Pass', (1, 36, 1, 40))], [], None, None, [])], []),
('Module', [('TypeAlias', (1, 0, 1, 12), ('Name', (1, 5, 1, 6), 'X', ('Store',)), [], ('Name', (1, 9, 1, 12), 'int', ('Load',)))], []),
('Module', [('TypeAlias', (1, 0, 1, 15), ('Name', (1, 5, 1, 6), 'X', ('Store',)), [('TypeVar', (1, 7, 1, 8), 'T', None)], ('Name', (1, 12, 1, 15), 'int', ('Load',)))], []),
('Module', [('TypeAlias', (1, 0, 1, 32), ('Name', (1, 5, 1, 6), 'X', ('Store',)), [('TypeVar', (1, 7, 1, 8), 'T', None), ('TypeVarTuple', (1, 10, 1, 13), 'Ts'), ('ParamSpec', (1, 15, 1, 18), 'P')], ('Tuple', (1, 22, 1, 32), [('Name', (1, 23, 1, 24), 'T', ('Load',)), ('Name', (1, 26, 1, 28), 'Ts', ('Load',)), ('Name', (1, 30, 1, 31), 'P', ('Load',))], ('Load',)))], []),
('Module', [('TypeAlias', (1, 0, 1, 37), ('Name', (1, 5, 1, 6), 'X', ('Store',)), [('TypeVar', (1, 7, 1, 13), 'T', ('Name', (1, 10, 1, 13), 'int', ('Load',))), ('TypeVarTuple', (1, 15, 1, 18), 'Ts'), ('ParamSpec', (1, 20, 1, 23), 'P')], ('Tuple', (1, 27, 1, 37), [('Name', (1, 28, 1, 29), 'T', ('Load',)), ('Name', (1, 31, 1, 33), 'Ts', ('Load',)), ('Name', (1, 35, 1, 36), 'P', ('Load',))], ('Load',)))], []),
('Module', [('TypeAlias', (1, 0, 1, 44), ('Name', (1, 5, 1, 6), 'X', ('Store',)), [('TypeVar', (1, 7, 1, 20), 'T', ('Tuple', (1, 10, 1, 20), [('Name', (1, 11, 1, 14), 'int', ('Load',)), ('Name', (1, 16, 1, 19), 'str', ('Load',))], ('Load',))), ('TypeVarTuple', (1, 22, 1, 25), 'Ts'), ('ParamSpec', (1, 27, 1, 30), 'P')], ('Tuple', (1, 34, 1, 44), [('Name', (1, 35, 1, 36), 'T', ('Load',)), ('Name', (1, 38, 1, 40), 'Ts', ('Load',)), ('Name', (1, 42, 1, 43), 'P', ('Load',))], ('Load',)))], []),
('Module', [('ClassDef', (1, 0, 1, 16), 'X', [], [], [('Pass', (1, 12, 1, 16))], [], [('TypeVar', (1, 8, 1, 9), 'T', None)])], []),
('Module', [('ClassDef', (1, 0, 1, 26), 'X', [], [], [('Pass', (1, 22, 1, 26))], [], [('TypeVar', (1, 8, 1, 9), 'T', None), ('TypeVarTuple', (1, 11, 1, 14), 'Ts'), ('ParamSpec', (1, 16, 1, 19), 'P')])], []),
('Module', [('ClassDef', (1, 0, 1, 31), 'X', [], [], [('Pass', (1, 27, 1, 31))], [], [('TypeVar', (1, 8, 1, 14), 'T', ('Name', (1, 11, 1, 14), 'int', ('Load',))), ('TypeVarTuple', (1, 16, 1, 19), 'Ts'), ('ParamSpec', (1, 21, 1, 24), 'P')])], []),
('Module', [('ClassDef', (1, 0, 1, 38), 'X', [], [], [('Pass', (1, 34, 1, 38))], [], [('TypeVar', (1, 8, 1, 21), 'T', ('Tuple', (1, 11, 1, 21), [('Name', (1, 12, 1, 15), 'int', ('Load',)), ('Name', (1, 17, 1, 20), 'str', ('Load',))], ('Load',))), ('TypeVarTuple', (1, 23, 1, 26), 'Ts'), ('ParamSpec', (1, 28, 1, 31), 'P')])], []),
('Module', [('FunctionDef', (1, 0, 1, 16), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 12, 1, 16))], [], None, None, [('TypeVar', (1, 6, 1, 7), 'T', None)])], []),
('Module', [('FunctionDef', (1, 0, 1, 26), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 22, 1, 26))], [], None, None, [('TypeVar', (1, 6, 1, 7), 'T', None), ('TypeVarTuple', (1, 9, 1, 12), 'Ts'), ('ParamSpec', (1, 14, 1, 17), 'P')])], []),
('Module', [('FunctionDef', (1, 0, 1, 31), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 27, 1, 31))], [], None, None, [('TypeVar', (1, 6, 1, 12), 'T', ('Name', (1, 9, 1, 12), 'int', ('Load',))), ('TypeVarTuple', (1, 14, 1, 17), 'Ts'), ('ParamSpec', (1, 19, 1, 22), 'P')])], []),
('Module', [('FunctionDef', (1, 0, 1, 38), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 34, 1, 38))], [], None, None, [('TypeVar', (1, 6, 1, 19), 'T', ('Tuple', (1, 9, 1, 19), [('Name', (1, 10, 1, 13), 'int', ('Load',)), ('Name', (1, 15, 1, 18), 'str', ('Load',))], ('Load',))), ('TypeVarTuple', (1, 21, 1, 24), 'Ts'), ('ParamSpec', (1, 26, 1, 29), 'P')])], []),
('Module', [('TypeAlias', (1, 0, 1, 15), ('Name', (1, 5, 1, 6), 'X', ('Store',)), [('TypeVar', (1, 7, 1, 8), 'T', None, None)], ('Name', (1, 12, 1, 15), 'int', ('Load',)))], []),
('Module', [('TypeAlias', (1, 0, 1, 32), ('Name', (1, 5, 1, 6), 'X', ('Store',)), [('TypeVar', (1, 7, 1, 8), 'T', None, None), ('TypeVarTuple', (1, 10, 1, 13), 'Ts', None), ('ParamSpec', (1, 15, 1, 18), 'P', None)], ('Tuple', (1, 22, 1, 32), [('Name', (1, 23, 1, 24), 'T', ('Load',)), ('Name', (1, 26, 1, 28), 'Ts', ('Load',)), ('Name', (1, 30, 1, 31), 'P', ('Load',))], ('Load',)))], []),
('Module', [('TypeAlias', (1, 0, 1, 37), ('Name', (1, 5, 1, 6), 'X', ('Store',)), [('TypeVar', (1, 7, 1, 13), 'T', ('Name', (1, 10, 1, 13), 'int', ('Load',)), None), ('TypeVarTuple', (1, 15, 1, 18), 'Ts', None), ('ParamSpec', (1, 20, 1, 23), 'P', None)], ('Tuple', (1, 27, 1, 37), [('Name', (1, 28, 1, 29), 'T', ('Load',)), ('Name', (1, 31, 1, 33), 'Ts', ('Load',)), ('Name', (1, 35, 1, 36), 'P', ('Load',))], ('Load',)))], []),
('Module', [('TypeAlias', (1, 0, 1, 44), ('Name', (1, 5, 1, 6), 'X', ('Store',)), [('TypeVar', (1, 7, 1, 20), 'T', ('Tuple', (1, 10, 1, 20), [('Name', (1, 11, 1, 14), 'int', ('Load',)), ('Name', (1, 16, 1, 19), 'str', ('Load',))], ('Load',)), None), ('TypeVarTuple', (1, 22, 1, 25), 'Ts', None), ('ParamSpec', (1, 27, 1, 30), 'P', None)], ('Tuple', (1, 34, 1, 44), [('Name', (1, 35, 1, 36), 'T', ('Load',)), ('Name', (1, 38, 1, 40), 'Ts', ('Load',)), ('Name', (1, 42, 1, 43), 'P', ('Load',))], ('Load',)))], []),
('Module', [('TypeAlias', (1, 0, 1, 48), ('Name', (1, 5, 1, 6), 'X', ('Store',)), [('TypeVar', (1, 7, 1, 17), 'T', ('Name', (1, 10, 1, 13), 'int', ('Load',)), ('Constant', (1, 16, 1, 17), 1, None)), ('TypeVarTuple', (1, 19, 1, 26), 'Ts', ('Constant', (1, 25, 1, 26), 2, None)), ('ParamSpec', (1, 28, 1, 34), 'P', ('Constant', (1, 33, 1, 34), 3, None))], ('Tuple', (1, 38, 1, 48), [('Name', (1, 39, 1, 40), 'T', ('Load',)), ('Name', (1, 42, 1, 44), 'Ts', ('Load',)), ('Name', (1, 46, 1, 47), 'P', ('Load',))], ('Load',)))], []),
('Module', [('ClassDef', (1, 0, 1, 16), 'X', [], [], [('Pass', (1, 12, 1, 16))], [], [('TypeVar', (1, 8, 1, 9), 'T', None, None)])], []),
('Module', [('ClassDef', (1, 0, 1, 26), 'X', [], [], [('Pass', (1, 22, 1, 26))], [], [('TypeVar', (1, 8, 1, 9), 'T', None, None), ('TypeVarTuple', (1, 11, 1, 14), 'Ts', None), ('ParamSpec', (1, 16, 1, 19), 'P', None)])], []),
('Module', [('ClassDef', (1, 0, 1, 31), 'X', [], [], [('Pass', (1, 27, 1, 31))], [], [('TypeVar', (1, 8, 1, 14), 'T', ('Name', (1, 11, 1, 14), 'int', ('Load',)), None), ('TypeVarTuple', (1, 16, 1, 19), 'Ts', None), ('ParamSpec', (1, 21, 1, 24), 'P', None)])], []),
('Module', [('ClassDef', (1, 0, 1, 38), 'X', [], [], [('Pass', (1, 34, 1, 38))], [], [('TypeVar', (1, 8, 1, 21), 'T', ('Tuple', (1, 11, 1, 21), [('Name', (1, 12, 1, 15), 'int', ('Load',)), ('Name', (1, 17, 1, 20), 'str', ('Load',))], ('Load',)), None), ('TypeVarTuple', (1, 23, 1, 26), 'Ts', None), ('ParamSpec', (1, 28, 1, 31), 'P', None)])], []),
('Module', [('ClassDef', (1, 0, 1, 43), 'X', [], [], [('Pass', (1, 39, 1, 43))], [], [('TypeVar', (1, 8, 1, 18), 'T', ('Name', (1, 11, 1, 14), 'int', ('Load',)), ('Constant', (1, 17, 1, 18), 1, None)), ('TypeVarTuple', (1, 20, 1, 27), 'Ts', ('Constant', (1, 26, 1, 27), 2, None)), ('ParamSpec', (1, 29, 1, 36), 'P', ('Constant', (1, 35, 1, 36), 3, None))])], []),
('Module', [('FunctionDef', (1, 0, 1, 16), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 12, 1, 16))], [], None, None, [('TypeVar', (1, 6, 1, 7), 'T', None, None)])], []),
('Module', [('FunctionDef', (1, 0, 1, 26), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 22, 1, 26))], [], None, None, [('TypeVar', (1, 6, 1, 7), 'T', None, None), ('TypeVarTuple', (1, 9, 1, 12), 'Ts', None), ('ParamSpec', (1, 14, 1, 17), 'P', None)])], []),
('Module', [('FunctionDef', (1, 0, 1, 31), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 27, 1, 31))], [], None, None, [('TypeVar', (1, 6, 1, 12), 'T', ('Name', (1, 9, 1, 12), 'int', ('Load',)), None), ('TypeVarTuple', (1, 14, 1, 17), 'Ts', None), ('ParamSpec', (1, 19, 1, 22), 'P', None)])], []),
('Module', [('FunctionDef', (1, 0, 1, 38), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 34, 1, 38))], [], None, None, [('TypeVar', (1, 6, 1, 19), 'T', ('Tuple', (1, 9, 1, 19), [('Name', (1, 10, 1, 13), 'int', ('Load',)), ('Name', (1, 15, 1, 18), 'str', ('Load',))], ('Load',)), None), ('TypeVarTuple', (1, 21, 1, 24), 'Ts', None), ('ParamSpec', (1, 26, 1, 29), 'P', None)])], []),
('Module', [('FunctionDef', (1, 0, 1, 43), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 39, 1, 43))], [], None, None, [('TypeVar', (1, 6, 1, 16), 'T', ('Name', (1, 9, 1, 12), 'int', ('Load',)), ('Constant', (1, 15, 1, 16), 1, None)), ('TypeVarTuple', (1, 18, 1, 25), 'Ts', ('Constant', (1, 24, 1, 25), 2, None)), ('ParamSpec', (1, 27, 1, 34), 'P', ('Constant', (1, 33, 1, 34), 3, None))])], []),
]
single_results = [
('Interactive', [('Expr', (1, 0, 1, 3), ('BinOp', (1, 0, 1, 3), ('Constant', (1, 0, 1, 1), 1, None), ('Add',), ('Constant', (1, 2, 1, 3), 2, None)))]),

View File

@ -6,7 +6,7 @@ import pickle
import weakref
from test.support import requires_working_socket, check_syntax_error, run_code
from typing import Generic, Sequence, TypeVar, TypeVarTuple, ParamSpec, get_args
from typing import Generic, NoDefault, Sequence, TypeVar, TypeVarTuple, ParamSpec, get_args
class TypeParamsInvalidTest(unittest.TestCase):
@ -412,6 +412,14 @@ class TypeParamsAccessTest(unittest.TestCase):
func, = T.__bound__
self.assertEqual(func(), 1)
def test_comprehension_03(self):
def F[T: [lambda: T for T in (T, [1])[1]]](): return [lambda: T for T in T.__name__]
func, = F()
self.assertEqual(func(), "T")
T, = F.__type_params__
func, = T.__bound__
self.assertEqual(func(), 1)
def test_gen_exp_in_nested_class(self):
code = """
from test.test_type_params import make_base
@ -591,10 +599,12 @@ class TypeParamsLazyEvaluationTest(unittest.TestCase):
self.assertEqual(type_params[0].__name__, "T")
self.assertIs(type_params[0].__bound__, Foo)
self.assertEqual(type_params[0].__constraints__, ())
self.assertIs(type_params[0].__default__, NoDefault)
self.assertEqual(type_params[1].__name__, "U")
self.assertIs(type_params[1].__bound__, None)
self.assertEqual(type_params[1].__constraints__, (Foo, Foo))
self.assertIs(type_params[1].__default__, NoDefault)
def test_evaluation_error(self):
class Foo[T: Undefined, U: (Undefined,)]:
@ -605,6 +615,8 @@ class TypeParamsLazyEvaluationTest(unittest.TestCase):
type_params[0].__bound__
self.assertEqual(type_params[0].__constraints__, ())
self.assertIs(type_params[1].__bound__, None)
self.assertIs(type_params[0].__default__, NoDefault)
self.assertIs(type_params[1].__default__, NoDefault)
with self.assertRaises(NameError):
type_params[1].__constraints__
@ -1158,3 +1170,103 @@ class TypeParamsRuntimeTest(unittest.TestCase):
"""
with self.assertRaises(RuntimeError):
run_code(code)
class DefaultsTest(unittest.TestCase):
def test_defaults_on_func(self):
ns = run_code("""
def func[T=int, **U=float, *V=None]():
pass
""")
T, U, V = ns["func"].__type_params__
self.assertIs(T.__default__, int)
self.assertIs(U.__default__, float)
self.assertIs(V.__default__, None)
def test_defaults_on_class(self):
ns = run_code("""
class C[T=int, **U=float, *V=None]:
pass
""")
T, U, V = ns["C"].__type_params__
self.assertIs(T.__default__, int)
self.assertIs(U.__default__, float)
self.assertIs(V.__default__, None)
def test_defaults_on_type_alias(self):
ns = run_code("""
type Alias[T = int, **U = float, *V = None] = int
""")
T, U, V = ns["Alias"].__type_params__
self.assertIs(T.__default__, int)
self.assertIs(U.__default__, float)
self.assertIs(V.__default__, None)
def test_starred_invalid(self):
check_syntax_error(self, "type Alias[T = *int] = int")
check_syntax_error(self, "type Alias[**P = *int] = int")
def test_starred_typevartuple(self):
ns = run_code("""
default = tuple[int, str]
type Alias[*Ts = *default] = Ts
""")
Ts, = ns["Alias"].__type_params__
self.assertEqual(Ts.__default__, next(iter(ns["default"])))
def test_nondefault_after_default(self):
check_syntax_error(self, "def func[T=int, U](): pass", "non-default type parameter 'U' follows default type parameter")
check_syntax_error(self, "class C[T=int, U]: pass", "non-default type parameter 'U' follows default type parameter")
check_syntax_error(self, "type A[T=int, U] = int", "non-default type parameter 'U' follows default type parameter")
def test_lazy_evaluation(self):
ns = run_code("""
type Alias[T = Undefined, *U = Undefined, **V = Undefined] = int
""")
T, U, V = ns["Alias"].__type_params__
with self.assertRaises(NameError):
T.__default__
with self.assertRaises(NameError):
U.__default__
with self.assertRaises(NameError):
V.__default__
ns["Undefined"] = "defined"
self.assertEqual(T.__default__, "defined")
self.assertEqual(U.__default__, "defined")
self.assertEqual(V.__default__, "defined")
# Now it is cached
ns["Undefined"] = "redefined"
self.assertEqual(T.__default__, "defined")
self.assertEqual(U.__default__, "defined")
self.assertEqual(V.__default__, "defined")
def test_symtable_key_regression_default(self):
# Test against the bugs that would happen if we used .default_
# as the key in the symtable.
ns = run_code("""
type X[T = [T for T in [T]]] = T
""")
T, = ns["X"].__type_params__
self.assertEqual(T.__default__, [T])
def test_symtable_key_regression_name(self):
# Test against the bugs that would happen if we used .name
# as the key in the symtable.
ns = run_code("""
type X1[T = A] = T
type X2[T = B] = T
A = "A"
B = "B"
""")
self.assertEqual(ns["X1"].__type_params__[0].__default__, "A")
self.assertEqual(ns["X2"].__type_params__[0].__default__, "B")

View File

@ -38,7 +38,7 @@ from typing import Annotated, ForwardRef
from typing import Self, LiteralString
from typing import TypeAlias
from typing import ParamSpec, Concatenate, ParamSpecArgs, ParamSpecKwargs
from typing import TypeGuard, TypeIs
from typing import TypeGuard, TypeIs, NoDefault
import abc
import textwrap
import typing
@ -580,6 +580,174 @@ class TypeVarTests(BaseTestCase):
self.assertIs(T.__bound__, None)
class TypeParameterDefaultsTests(BaseTestCase):
def test_typevar(self):
T = TypeVar('T', default=int)
self.assertEqual(T.__default__, int)
self.assertTrue(T.has_default())
self.assertIsInstance(T, TypeVar)
class A(Generic[T]): ...
Alias = Optional[T]
def test_typevar_none(self):
U = TypeVar('U')
U_None = TypeVar('U_None', default=None)
self.assertIs(U.__default__, NoDefault)
self.assertFalse(U.has_default())
self.assertIs(U_None.__default__, None)
self.assertTrue(U_None.has_default())
class X[T]: ...
T, = X.__type_params__
self.assertIs(T.__default__, NoDefault)
self.assertFalse(T.has_default())
def test_paramspec(self):
P = ParamSpec('P', default=(str, int))
self.assertEqual(P.__default__, (str, int))
self.assertTrue(P.has_default())
self.assertIsInstance(P, ParamSpec)
class A(Generic[P]): ...
Alias = typing.Callable[P, None]
P_default = ParamSpec('P_default', default=...)
self.assertIs(P_default.__default__, ...)
def test_paramspec_none(self):
U = ParamSpec('U')
U_None = ParamSpec('U_None', default=None)
self.assertIs(U.__default__, NoDefault)
self.assertFalse(U.has_default())
self.assertIs(U_None.__default__, None)
self.assertTrue(U_None.has_default())
class X[**P]: ...
P, = X.__type_params__
self.assertIs(P.__default__, NoDefault)
self.assertFalse(P.has_default())
def test_typevartuple(self):
Ts = TypeVarTuple('Ts', default=Unpack[Tuple[str, int]])
self.assertEqual(Ts.__default__, Unpack[Tuple[str, int]])
self.assertTrue(Ts.has_default())
self.assertIsInstance(Ts, TypeVarTuple)
class A(Generic[Unpack[Ts]]): ...
Alias = Optional[Unpack[Ts]]
def test_typevartuple_specialization(self):
T = TypeVar("T")
Ts = TypeVarTuple('Ts', default=Unpack[Tuple[str, int]])
self.assertEqual(Ts.__default__, Unpack[Tuple[str, int]])
class A(Generic[T, Unpack[Ts]]): ...
self.assertEqual(A[float].__args__, (float, str, int))
self.assertEqual(A[float, range].__args__, (float, range))
self.assertEqual(A[float, *tuple[int, ...]].__args__, (float, *tuple[int, ...]))
def test_typevar_and_typevartuple_specialization(self):
T = TypeVar("T")
U = TypeVar("U", default=float)
Ts = TypeVarTuple('Ts', default=Unpack[Tuple[str, int]])
self.assertEqual(Ts.__default__, Unpack[Tuple[str, int]])
class A(Generic[T, U, Unpack[Ts]]): ...
self.assertEqual(A[int].__args__, (int, float, str, int))
self.assertEqual(A[int, str].__args__, (int, str, str, int))
self.assertEqual(A[int, str, range].__args__, (int, str, range))
self.assertEqual(A[int, str, *tuple[int, ...]].__args__, (int, str, *tuple[int, ...]))
def test_no_default_after_typevar_tuple(self):
T = TypeVar("T", default=int)
Ts = TypeVarTuple("Ts")
Ts_default = TypeVarTuple("Ts_default", default=Unpack[Tuple[str, int]])
with self.assertRaises(TypeError):
class X(Generic[*Ts, T]): ...
with self.assertRaises(TypeError):
class Y(Generic[*Ts_default, T]): ...
def test_paramspec_specialization(self):
T = TypeVar("T")
P = ParamSpec('P', default=[str, int])
self.assertEqual(P.__default__, [str, int])
class A(Generic[T, P]): ...
self.assertEqual(A[float].__args__, (float, (str, int)))
self.assertEqual(A[float, [range]].__args__, (float, (range,)))
def test_typevar_and_paramspec_specialization(self):
T = TypeVar("T")
U = TypeVar("U", default=float)
P = ParamSpec('P', default=[str, int])
self.assertEqual(P.__default__, [str, int])
class A(Generic[T, U, P]): ...
self.assertEqual(A[float].__args__, (float, float, (str, int)))
self.assertEqual(A[float, int].__args__, (float, int, (str, int)))
self.assertEqual(A[float, int, [range]].__args__, (float, int, (range,)))
def test_paramspec_and_typevar_specialization(self):
T = TypeVar("T")
P = ParamSpec('P', default=[str, int])
U = TypeVar("U", default=float)
self.assertEqual(P.__default__, [str, int])
class A(Generic[T, P, U]): ...
self.assertEqual(A[float].__args__, (float, (str, int), float))
self.assertEqual(A[float, [range]].__args__, (float, (range,), float))
self.assertEqual(A[float, [range], int].__args__, (float, (range,), int))
def test_typevartuple_none(self):
U = TypeVarTuple('U')
U_None = TypeVarTuple('U_None', default=None)
self.assertIs(U.__default__, NoDefault)
self.assertFalse(U.has_default())
self.assertIs(U_None.__default__, None)
self.assertTrue(U_None.has_default())
class X[**Ts]: ...
Ts, = X.__type_params__
self.assertIs(Ts.__default__, NoDefault)
self.assertFalse(Ts.has_default())
def test_no_default_after_non_default(self):
DefaultStrT = TypeVar('DefaultStrT', default=str)
T = TypeVar('T')
with self.assertRaisesRegex(
TypeError, r"Type parameter ~T without a default follows type parameter with a default"
):
Test = Generic[DefaultStrT, T]
def test_need_more_params(self):
DefaultStrT = TypeVar('DefaultStrT', default=str)
T = TypeVar('T')
U = TypeVar('U')
class A(Generic[T, U, DefaultStrT]): ...
A[int, bool]
A[int, bool, str]
with self.assertRaisesRegex(
TypeError, r"Too few arguments for .+; actual 1, expected at least 2"
):
Test = A[int]
def test_pickle(self):
global U, U_co, U_contra, U_default # pickle wants to reference the class by name
U = TypeVar('U')
U_co = TypeVar('U_co', covariant=True)
U_contra = TypeVar('U_contra', contravariant=True)
U_default = TypeVar('U_default', default=int)
for proto in range(pickle.HIGHEST_PROTOCOL):
for typevar in (U, U_co, U_contra, U_default):
z = pickle.loads(pickle.dumps(typevar, proto))
self.assertEqual(z.__name__, typevar.__name__)
self.assertEqual(z.__covariant__, typevar.__covariant__)
self.assertEqual(z.__contravariant__, typevar.__contravariant__)
self.assertEqual(z.__bound__, typevar.__bound__)
self.assertEqual(z.__default__, typevar.__default__)
def template_replace(templates: list[str], replacements: dict[str, list[str]]) -> list[tuple[str]]:
"""Renders templates with possible combinations of replacements.
@ -10001,6 +10169,26 @@ class DataclassTransformTests(BaseTestCase):
self.assertIsInstance(CustomerModel, Decorated)
class NoDefaultTests(BaseTestCase):
def test_pickling(self):
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
s = pickle.dumps(NoDefault, proto)
loaded = pickle.loads(s)
self.assertIs(NoDefault, loaded)
def test_constructor(self):
self.assertIs(NoDefault, type(NoDefault)())
with self.assertRaises(TypeError):
NoDefault(1)
def test_repr(self):
self.assertEqual(repr(NoDefault), 'typing.NoDefault')
def test_no_call(self):
with self.assertRaises(TypeError):
NoDefault()
class AllTests(BaseTestCase):
"""Tests for __all__."""

View File

@ -673,6 +673,20 @@ class CosmeticTestCase(ASTTestCase):
self.check_ast_roundtrip("""f'\\'{x:\\"}' """)
self.check_ast_roundtrip("""f'\\'{x:\\\\"}' """)
def test_type_params(self):
self.check_ast_roundtrip("type A = int")
self.check_ast_roundtrip("type A[T] = int")
self.check_ast_roundtrip("type A[T: int] = int")
self.check_ast_roundtrip("type A[T = int] = int")
self.check_ast_roundtrip("type A[T: int = int] = int")
self.check_ast_roundtrip("type A[**P] = int")
self.check_ast_roundtrip("type A[**P = int] = int")
self.check_ast_roundtrip("type A[*Ts] = int")
self.check_ast_roundtrip("type A[*Ts = int] = int")
self.check_ast_roundtrip("type A[*Ts = *int] = int")
self.check_ast_roundtrip("def f[T: int = int, **P = int, *Ts = *int]():\n pass")
self.check_ast_roundtrip("class C[T: int = int, **P = int, *Ts = *int]():\n pass")
class ManualASTCreationTestCase(unittest.TestCase):
"""Test that AST nodes created without a type_params field unparse correctly."""
@ -723,6 +737,20 @@ class ManualASTCreationTestCase(unittest.TestCase):
ast.fix_missing_locations(node)
self.assertEqual(ast.unparse(node), "def f[T: int]():\n pass")
def test_function_with_type_params_and_default(self):
node = ast.FunctionDef(
name="f",
args=ast.arguments(),
body=[ast.Pass()],
type_params=[
ast.TypeVar("T", default_value=ast.Constant(value=1)),
ast.TypeVarTuple("Ts", default_value=ast.Starred(value=ast.Constant(value=1), ctx=ast.Load())),
ast.ParamSpec("P", default_value=ast.Constant(value=1)),
],
)
ast.fix_missing_locations(node)
self.assertEqual(ast.unparse(node), "def f[T = 1, *Ts = *1, **P = 1]():\n pass")
def test_async_function(self):
node = ast.AsyncFunctionDef(
name="f",
@ -746,6 +774,20 @@ class ManualASTCreationTestCase(unittest.TestCase):
ast.fix_missing_locations(node)
self.assertEqual(ast.unparse(node), "async def f[T]():\n pass")
def test_async_function_with_type_params_and_default(self):
node = ast.AsyncFunctionDef(
name="f",
args=ast.arguments(),
body=[ast.Pass()],
type_params=[
ast.TypeVar("T", default_value=ast.Constant(value=1)),
ast.TypeVarTuple("Ts", default_value=ast.Starred(value=ast.Constant(value=1), ctx=ast.Load())),
ast.ParamSpec("P", default_value=ast.Constant(value=1)),
],
)
ast.fix_missing_locations(node)
self.assertEqual(ast.unparse(node), "async def f[T = 1, *Ts = *1, **P = 1]():\n pass")
class DirectoryTestCase(ASTTestCase):
"""Test roundtrip behaviour on all files in Lib and Lib/test."""

View File

@ -38,6 +38,7 @@ from _typing import (
ParamSpecKwargs,
TypeAliasType,
Generic,
NoDefault,
)
# Please keep __all__ alphabetized within each category.
@ -138,6 +139,7 @@ __all__ = [
'NewType',
'no_type_check',
'no_type_check_decorator',
'NoDefault',
'NoReturn',
'NotRequired',
'overload',
@ -266,6 +268,10 @@ def _collect_parameters(args):
>>> _collect_parameters((T, Callable[P, T]))
(~T, ~P)
"""
# required type parameter cannot appear after parameter with default
default_encountered = False
# or after TypeVarTuple
type_var_tuple_encountered = False
parameters = []
for t in args:
if isinstance(t, type):
@ -280,27 +286,58 @@ def _collect_parameters(args):
parameters.append(collected)
elif hasattr(t, '__typing_subst__'):
if t not in parameters:
if type_var_tuple_encountered and t.has_default():
raise TypeError('Type parameter with a default'
' follows TypeVarTuple')
if t.has_default():
default_encountered = True
elif default_encountered:
raise TypeError(f'Type parameter {t!r} without a default'
' follows type parameter with a default')
parameters.append(t)
else:
if _is_unpacked_typevartuple(t):
type_var_tuple_encountered = True
for x in getattr(t, '__parameters__', ()):
if x not in parameters:
parameters.append(x)
return tuple(parameters)
def _check_generic(cls, parameters, elen):
def _check_generic_specialization(cls, arguments):
"""Check correct count for parameters of a generic cls (internal helper).
This gives a nice error message in case of count mismatch.
"""
if not elen:
expected_len = len(cls.__parameters__)
if not expected_len:
raise TypeError(f"{cls} is not a generic class")
alen = len(parameters)
if alen != elen:
raise TypeError(f"Too {'many' if alen > elen else 'few'} arguments for {cls};"
f" actual {alen}, expected {elen}")
actual_len = len(arguments)
if actual_len != expected_len:
# deal with defaults
if actual_len < expected_len:
# If the parameter at index `actual_len` in the parameters list
# has a default, then all parameters after it must also have
# one, because we validated as much in _collect_parameters().
# That means that no error needs to be raised here, despite
# the number of arguments being passed not matching the number
# of parameters: all parameters that aren't explicitly
# specialized in this call are parameters with default values.
if cls.__parameters__[actual_len].has_default():
return
def _unpack_args(args):
expected_len -= sum(p.has_default() for p in cls.__parameters__)
expect_val = f"at least {expected_len}"
else:
expect_val = expected_len
raise TypeError(f"Too {'many' if actual_len > expected_len else 'few'} arguments"
f" for {cls}; actual {actual_len}, expected {expect_val}")
def _unpack_args(*args):
newargs = []
for arg in args:
subargs = getattr(arg, '__typing_unpacked_tuple_args__', None)
@ -1089,11 +1126,15 @@ def _typevartuple_prepare_subst(self, alias, args):
elif left + right > alen:
raise TypeError(f"Too few arguments for {alias};"
f" actual {alen}, expected at least {plen-1}")
if left == alen - right and self.has_default():
replacement = _unpack_args(self.__default__)
else:
replacement = args[left: alen - right]
return (
*args[:left],
*([fillarg]*(typevartuple_index - left)),
tuple(args[left: alen - right]),
replacement,
*([fillarg]*(plen - right - left - typevartuple_index - 1)),
*args[alen - right:],
)
@ -1111,6 +1152,8 @@ def _paramspec_subst(self, arg):
def _paramspec_prepare_subst(self, alias, args):
params = alias.__parameters__
i = params.index(self)
if i == len(args) and self.has_default():
args = [*args, self.__default__]
if i >= len(args):
raise TypeError(f"Too few arguments for {alias}")
# Special case where Z[[int, str, bool]] == Z[int, str, bool] in PEP 612.
@ -1124,33 +1167,33 @@ def _paramspec_prepare_subst(self, alias, args):
@_tp_cache
def _generic_class_getitem(cls, params):
def _generic_class_getitem(cls, args):
"""Parameterizes a generic class.
At least, parameterizing a generic class is the *main* thing this method
does. For example, for some generic class `Foo`, this is called when we
do `Foo[int]` - there, with `cls=Foo` and `params=int`.
do `Foo[int]` - there, with `cls=Foo` and `args=int`.
However, note that this method is also called when defining generic
classes in the first place with `class Foo(Generic[T]): ...`.
"""
if not isinstance(params, tuple):
params = (params,)
if not isinstance(args, tuple):
args = (args,)
params = tuple(_type_convert(p) for p in params)
args = tuple(_type_convert(p) for p in args)
is_generic_or_protocol = cls in (Generic, Protocol)
if is_generic_or_protocol:
# Generic and Protocol can only be subscripted with unique type variables.
if not params:
if not args:
raise TypeError(
f"Parameter list to {cls.__qualname__}[...] cannot be empty"
)
if not all(_is_typevar_like(p) for p in params):
if not all(_is_typevar_like(p) for p in args):
raise TypeError(
f"Parameters to {cls.__name__}[...] must all be type variables "
f"or parameter specification variables.")
if len(set(params)) != len(params):
if len(set(args)) != len(args):
raise TypeError(
f"Parameters to {cls.__name__}[...] must all be unique")
else:
@ -1158,18 +1201,18 @@ def _generic_class_getitem(cls, params):
for param in cls.__parameters__:
prepare = getattr(param, '__typing_prepare_subst__', None)
if prepare is not None:
params = prepare(cls, params)
_check_generic(cls, params, len(cls.__parameters__))
args = prepare(cls, args)
_check_generic_specialization(cls, args)
new_args = []
for param, new_arg in zip(cls.__parameters__, params):
for param, new_arg in zip(cls.__parameters__, args):
if isinstance(param, TypeVarTuple):
new_args.extend(new_arg)
else:
new_args.append(new_arg)
params = tuple(new_args)
args = tuple(new_args)
return _GenericAlias(cls, params)
return _GenericAlias(cls, args)
def _generic_init_subclass(cls, *args, **kwargs):
@ -1390,8 +1433,7 @@ class _GenericAlias(_BaseGenericAlias, _root=True):
# Preprocess `args`.
if not isinstance(args, tuple):
args = (args,)
args = tuple(_type_convert(p) for p in args)
args = _unpack_args(args)
args = _unpack_args(*(_type_convert(p) for p in args))
new_args = self._determine_new_args(args)
r = self.copy_with(new_args)
return r
@ -1552,7 +1594,12 @@ class _SpecialGenericAlias(_NotIterable, _BaseGenericAlias, _root=True):
params = (params,)
msg = "Parameters to generic types must be types."
params = tuple(_type_check(p, msg) for p in params)
_check_generic(self, params, self._nparams)
actual_len = len(params)
if actual_len != self._nparams:
if not self._nparams:
raise TypeError(f"{self} is not a generic class")
raise TypeError(f"Too {'many' if actual_len > self._nparams else 'few'} arguments for {self};"
f" actual {actual_len}, expected {self._nparams}")
return self.copy_with(params)
def copy_with(self, params):

View File

@ -0,0 +1,2 @@
Implement :pep:`696`, adding support for defaults on type parameters.
Patch by Jelle Zijlstra.

View File

@ -63,6 +63,9 @@ _typing_exec(PyObject *m)
if (PyModule_AddObjectRef(m, "TypeAliasType", (PyObject *)&_PyTypeAlias_Type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "NoDefault", (PyObject *)&_Py_NoDefaultStruct) < 0) {
return -1;
}
return 0;
}

View File

@ -9,16 +9,16 @@ preserve
#include "pycore_modsupport.h" // _PyArg_UnpackKeywordsWithVararg()
PyDoc_STRVAR(typevar_new__doc__,
"typevar(name, *constraints, bound=None, covariant=False,\n"
" contravariant=False, infer_variance=False)\n"
"typevar(name, *constraints, bound=None, default=typing.NoDefault,\n"
" covariant=False, contravariant=False, infer_variance=False)\n"
"--\n"
"\n"
"Create a TypeVar.");
static PyObject *
typevar_new_impl(PyTypeObject *type, PyObject *name, PyObject *constraints,
PyObject *bound, int covariant, int contravariant,
int infer_variance);
PyObject *bound, PyObject *default_value, int covariant,
int contravariant, int infer_variance);
static PyObject *
typevar_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
@ -26,14 +26,14 @@ typevar_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
#define NUM_KEYWORDS 5
#define NUM_KEYWORDS 6
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
PyObject *ob_item[NUM_KEYWORDS];
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_item = { &_Py_ID(name), &_Py_ID(bound), &_Py_ID(covariant), &_Py_ID(contravariant), &_Py_ID(infer_variance), },
.ob_item = { &_Py_ID(name), &_Py_ID(bound), &_Py_ID(default), &_Py_ID(covariant), &_Py_ID(contravariant), &_Py_ID(infer_variance), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
@ -42,20 +42,21 @@ typevar_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
static const char * const _keywords[] = {"name", "bound", "covariant", "contravariant", "infer_variance", NULL};
static const char * const _keywords[] = {"name", "bound", "default", "covariant", "contravariant", "infer_variance", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "typevar",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
PyObject *argsbuf[6];
PyObject *argsbuf[7];
PyObject * const *fastargs;
Py_ssize_t nargs = PyTuple_GET_SIZE(args);
Py_ssize_t noptargs = Py_MIN(nargs, 1) + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 1;
PyObject *name;
PyObject *constraints = NULL;
PyObject *bound = Py_None;
PyObject *default_value = &_Py_NoDefaultStruct;
int covariant = 0;
int contravariant = 0;
int infer_variance = 0;
@ -80,7 +81,13 @@ typevar_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
}
}
if (fastargs[3]) {
covariant = PyObject_IsTrue(fastargs[3]);
default_value = fastargs[3];
if (!--noptargs) {
goto skip_optional_kwonly;
}
}
if (fastargs[4]) {
covariant = PyObject_IsTrue(fastargs[4]);
if (covariant < 0) {
goto exit;
}
@ -88,8 +95,8 @@ typevar_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
goto skip_optional_kwonly;
}
}
if (fastargs[4]) {
contravariant = PyObject_IsTrue(fastargs[4]);
if (fastargs[5]) {
contravariant = PyObject_IsTrue(fastargs[5]);
if (contravariant < 0) {
goto exit;
}
@ -97,12 +104,12 @@ typevar_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
goto skip_optional_kwonly;
}
}
infer_variance = PyObject_IsTrue(fastargs[5]);
infer_variance = PyObject_IsTrue(fastargs[6]);
if (infer_variance < 0) {
goto exit;
}
skip_optional_kwonly:
return_value = typevar_new_impl(type, name, constraints, bound, covariant, contravariant, infer_variance);
return_value = typevar_new_impl(type, name, constraints, bound, default_value, covariant, contravariant, infer_variance);
exit:
Py_XDECREF(constraints);
@ -117,6 +124,36 @@ PyDoc_STRVAR(typevar_typing_subst__doc__,
#define TYPEVAR_TYPING_SUBST_METHODDEF \
{"__typing_subst__", (PyCFunction)typevar_typing_subst, METH_O, typevar_typing_subst__doc__},
PyDoc_STRVAR(typevar_typing_prepare_subst__doc__,
"__typing_prepare_subst__($self, alias, args, /)\n"
"--\n"
"\n");
#define TYPEVAR_TYPING_PREPARE_SUBST_METHODDEF \
{"__typing_prepare_subst__", _PyCFunction_CAST(typevar_typing_prepare_subst), METH_FASTCALL, typevar_typing_prepare_subst__doc__},
static PyObject *
typevar_typing_prepare_subst_impl(typevarobject *self, PyObject *alias,
PyObject *args);
static PyObject *
typevar_typing_prepare_subst(typevarobject *self, PyObject *const *args, Py_ssize_t nargs)
{
PyObject *return_value = NULL;
PyObject *alias;
PyObject *__clinic_args;
if (!_PyArg_CheckPositional("__typing_prepare_subst__", nargs, 2, 2)) {
goto exit;
}
alias = args[0];
__clinic_args = args[1];
return_value = typevar_typing_prepare_subst_impl(self, alias, __clinic_args);
exit:
return return_value;
}
PyDoc_STRVAR(typevar_reduce__doc__,
"__reduce__($self, /)\n"
"--\n"
@ -134,6 +171,23 @@ typevar_reduce(typevarobject *self, PyObject *Py_UNUSED(ignored))
return typevar_reduce_impl(self);
}
PyDoc_STRVAR(typevar_has_default__doc__,
"has_default($self, /)\n"
"--\n"
"\n");
#define TYPEVAR_HAS_DEFAULT_METHODDEF \
{"has_default", (PyCFunction)typevar_has_default, METH_NOARGS, typevar_has_default__doc__},
static PyObject *
typevar_has_default_impl(typevarobject *self);
static PyObject *
typevar_has_default(typevarobject *self, PyObject *Py_UNUSED(ignored))
{
return typevar_has_default_impl(self);
}
PyDoc_STRVAR(paramspecargs_new__doc__,
"paramspecargs(origin)\n"
"--\n"
@ -243,15 +297,16 @@ exit:
}
PyDoc_STRVAR(paramspec_new__doc__,
"paramspec(name, *, bound=None, covariant=False, contravariant=False,\n"
" infer_variance=False)\n"
"paramspec(name, *, bound=None, default=typing.NoDefault,\n"
" covariant=False, contravariant=False, infer_variance=False)\n"
"--\n"
"\n"
"Create a ParamSpec object.");
static PyObject *
paramspec_new_impl(PyTypeObject *type, PyObject *name, PyObject *bound,
int covariant, int contravariant, int infer_variance);
PyObject *default_value, int covariant, int contravariant,
int infer_variance);
static PyObject *
paramspec_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
@ -259,14 +314,14 @@ paramspec_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
#define NUM_KEYWORDS 5
#define NUM_KEYWORDS 6
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
PyObject *ob_item[NUM_KEYWORDS];
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_item = { &_Py_ID(name), &_Py_ID(bound), &_Py_ID(covariant), &_Py_ID(contravariant), &_Py_ID(infer_variance), },
.ob_item = { &_Py_ID(name), &_Py_ID(bound), &_Py_ID(default), &_Py_ID(covariant), &_Py_ID(contravariant), &_Py_ID(infer_variance), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
@ -275,19 +330,20 @@ paramspec_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
static const char * const _keywords[] = {"name", "bound", "covariant", "contravariant", "infer_variance", NULL};
static const char * const _keywords[] = {"name", "bound", "default", "covariant", "contravariant", "infer_variance", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "paramspec",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
PyObject *argsbuf[5];
PyObject *argsbuf[6];
PyObject * const *fastargs;
Py_ssize_t nargs = PyTuple_GET_SIZE(args);
Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 1;
PyObject *name;
PyObject *bound = Py_None;
PyObject *default_value = &_Py_NoDefaultStruct;
int covariant = 0;
int contravariant = 0;
int infer_variance = 0;
@ -311,7 +367,13 @@ paramspec_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
}
}
if (fastargs[2]) {
covariant = PyObject_IsTrue(fastargs[2]);
default_value = fastargs[2];
if (!--noptargs) {
goto skip_optional_kwonly;
}
}
if (fastargs[3]) {
covariant = PyObject_IsTrue(fastargs[3]);
if (covariant < 0) {
goto exit;
}
@ -319,8 +381,8 @@ paramspec_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
goto skip_optional_kwonly;
}
}
if (fastargs[3]) {
contravariant = PyObject_IsTrue(fastargs[3]);
if (fastargs[4]) {
contravariant = PyObject_IsTrue(fastargs[4]);
if (contravariant < 0) {
goto exit;
}
@ -328,12 +390,12 @@ paramspec_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
goto skip_optional_kwonly;
}
}
infer_variance = PyObject_IsTrue(fastargs[4]);
infer_variance = PyObject_IsTrue(fastargs[5]);
if (infer_variance < 0) {
goto exit;
}
skip_optional_kwonly:
return_value = paramspec_new_impl(type, name, bound, covariant, contravariant, infer_variance);
return_value = paramspec_new_impl(type, name, bound, default_value, covariant, contravariant, infer_variance);
exit:
return return_value;
@ -394,14 +456,32 @@ paramspec_reduce(paramspecobject *self, PyObject *Py_UNUSED(ignored))
return paramspec_reduce_impl(self);
}
PyDoc_STRVAR(paramspec_has_default__doc__,
"has_default($self, /)\n"
"--\n"
"\n");
#define PARAMSPEC_HAS_DEFAULT_METHODDEF \
{"has_default", (PyCFunction)paramspec_has_default, METH_NOARGS, paramspec_has_default__doc__},
static PyObject *
paramspec_has_default_impl(paramspecobject *self);
static PyObject *
paramspec_has_default(paramspecobject *self, PyObject *Py_UNUSED(ignored))
{
return paramspec_has_default_impl(self);
}
PyDoc_STRVAR(typevartuple__doc__,
"typevartuple(name)\n"
"typevartuple(name, *, default=typing.NoDefault)\n"
"--\n"
"\n"
"Create a new TypeVarTuple with the given name.");
static PyObject *
typevartuple_impl(PyTypeObject *type, PyObject *name);
typevartuple_impl(PyTypeObject *type, PyObject *name,
PyObject *default_value);
static PyObject *
typevartuple(PyTypeObject *type, PyObject *args, PyObject *kwargs)
@ -409,14 +489,14 @@ typevartuple(PyTypeObject *type, PyObject *args, PyObject *kwargs)
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
#define NUM_KEYWORDS 1
#define NUM_KEYWORDS 2
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
PyObject *ob_item[NUM_KEYWORDS];
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_item = { &_Py_ID(name), },
.ob_item = { &_Py_ID(name), &_Py_ID(default), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
@ -425,17 +505,19 @@ typevartuple(PyTypeObject *type, PyObject *args, PyObject *kwargs)
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
static const char * const _keywords[] = {"name", NULL};
static const char * const _keywords[] = {"name", "default", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "typevartuple",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
PyObject *argsbuf[1];
PyObject *argsbuf[2];
PyObject * const *fastargs;
Py_ssize_t nargs = PyTuple_GET_SIZE(args);
Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 1;
PyObject *name;
PyObject *default_value = &_Py_NoDefaultStruct;
fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 1, 1, 0, argsbuf);
if (!fastargs) {
@ -446,7 +528,12 @@ typevartuple(PyTypeObject *type, PyObject *args, PyObject *kwargs)
goto exit;
}
name = fastargs[0];
return_value = typevartuple_impl(type, name);
if (!noptargs) {
goto skip_optional_kwonly;
}
default_value = fastargs[1];
skip_optional_kwonly:
return_value = typevartuple_impl(type, name, default_value);
exit:
return return_value;
@ -507,6 +594,23 @@ typevartuple_reduce(typevartupleobject *self, PyObject *Py_UNUSED(ignored))
return typevartuple_reduce_impl(self);
}
PyDoc_STRVAR(typevartuple_has_default__doc__,
"has_default($self, /)\n"
"--\n"
"\n");
#define TYPEVARTUPLE_HAS_DEFAULT_METHODDEF \
{"has_default", (PyCFunction)typevartuple_has_default, METH_NOARGS, typevartuple_has_default__doc__},
static PyObject *
typevartuple_has_default_impl(typevartupleobject *self);
static PyObject *
typevartuple_has_default(typevartupleobject *self, PyObject *Py_UNUSED(ignored))
{
return typevartuple_has_default_impl(self);
}
PyDoc_STRVAR(typealias_reduce__doc__,
"__reduce__($self, /)\n"
"--\n"
@ -591,4 +695,4 @@ skip_optional_kwonly:
exit:
return return_value;
}
/*[clinic end generated code: output=5a582d9d89ad787b input=a9049054013a1b77]*/
/*[clinic end generated code: output=73b39e550e4e336c input=a9049054013a1b77]*/

View File

@ -23,6 +23,8 @@ typedef struct {
PyObject *evaluate_bound;
PyObject *constraints;
PyObject *evaluate_constraints;
PyObject *default_value;
PyObject *evaluate_default;
bool covariant;
bool contravariant;
bool infer_variance;
@ -31,12 +33,16 @@ typedef struct {
typedef struct {
PyObject_HEAD
PyObject *name;
PyObject *default_value;
PyObject *evaluate_default;
} typevartupleobject;
typedef struct {
PyObject_HEAD
PyObject *name;
PyObject *bound;
PyObject *default_value;
PyObject *evaluate_default;
bool covariant;
bool contravariant;
bool infer_variance;
@ -53,6 +59,64 @@ typedef struct {
#include "clinic/typevarobject.c.h"
/* NoDefault is a marker object to indicate that a parameter has no default. */
static PyObject *
NoDefault_repr(PyObject *op)
{
return PyUnicode_FromString("typing.NoDefault");
}
static PyObject *
NoDefault_reduce(PyObject *op, PyObject *Py_UNUSED(ignored))
{
return PyUnicode_FromString("NoDefault");
}
static PyMethodDef notimplemented_methods[] = {
{"__reduce__", NoDefault_reduce, METH_NOARGS, NULL},
{NULL, NULL}
};
static PyObject *
nodefault_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
{
if (PyTuple_GET_SIZE(args) || (kwargs && PyDict_GET_SIZE(kwargs))) {
PyErr_SetString(PyExc_TypeError, "NoDefaultType takes no arguments");
return NULL;
}
return &_Py_NoDefaultStruct;
}
static void
nodefault_dealloc(PyObject *nodefault)
{
/* This should never get called, but we also don't want to SEGV if
* we accidentally decref NoDefault out of existence. Instead,
* since NoDefault is an immortal object, re-set the reference count.
*/
_Py_SetImmortal(nodefault);
}
PyDoc_STRVAR(notimplemented_doc,
"NoDefaultType()\n"
"--\n\n"
"The type of the NoDefault singleton.");
PyTypeObject _PyNoDefault_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"NoDefaultType",
.tp_dealloc = nodefault_dealloc,
.tp_repr = NoDefault_repr,
.tp_flags = Py_TPFLAGS_DEFAULT,
.tp_doc = notimplemented_doc,
.tp_methods = notimplemented_methods,
.tp_new = nodefault_new,
};
PyObject _Py_NoDefaultStruct = _PyObject_HEAD_INIT(&_PyNoDefault_Type);
static PyObject *
call_typing_func_object(const char *name, PyObject **args, size_t nargs)
{
@ -200,6 +264,8 @@ typevar_dealloc(PyObject *self)
Py_XDECREF(tv->evaluate_bound);
Py_XDECREF(tv->constraints);
Py_XDECREF(tv->evaluate_constraints);
Py_XDECREF(tv->default_value);
Py_XDECREF(tv->evaluate_default);
PyObject_ClearManagedDict(self);
PyObject_ClearWeakRefs(self);
@ -216,6 +282,8 @@ typevar_traverse(PyObject *self, visitproc visit, void *arg)
Py_VISIT(tv->evaluate_bound);
Py_VISIT(tv->constraints);
Py_VISIT(tv->evaluate_constraints);
Py_VISIT(tv->default_value);
Py_VISIT(tv->evaluate_default);
PyObject_VisitManagedDict(self, visit, arg);
return 0;
}
@ -227,6 +295,8 @@ typevar_clear(typevarobject *self)
Py_CLEAR(self->evaluate_bound);
Py_CLEAR(self->constraints);
Py_CLEAR(self->evaluate_constraints);
Py_CLEAR(self->default_value);
Py_CLEAR(self->evaluate_default);
PyObject_ClearManagedDict((PyObject *)self);
return 0;
}
@ -266,6 +336,20 @@ typevar_bound(typevarobject *self, void *Py_UNUSED(ignored))
return bound;
}
static PyObject *
typevar_default(typevarobject *self, void *unused)
{
if (self->default_value != NULL) {
return Py_NewRef(self->default_value);
}
if (self->evaluate_default == NULL) {
return &_Py_NoDefaultStruct;
}
PyObject *default_value = PyObject_CallNoArgs(self->evaluate_default);
self->default_value = Py_XNewRef(default_value);
return default_value;
}
static PyObject *
typevar_constraints(typevarobject *self, void *Py_UNUSED(ignored))
{
@ -283,12 +367,14 @@ typevar_constraints(typevarobject *self, void *Py_UNUSED(ignored))
static PyGetSetDef typevar_getset[] = {
{"__bound__", (getter)typevar_bound, NULL, NULL, NULL},
{"__constraints__", (getter)typevar_constraints, NULL, NULL, NULL},
{"__default__", (getter)typevar_default, NULL, NULL, NULL},
{0}
};
static typevarobject *
typevar_alloc(PyObject *name, PyObject *bound, PyObject *evaluate_bound,
PyObject *constraints, PyObject *evaluate_constraints,
PyObject *default_value,
bool covariant, bool contravariant, bool infer_variance,
PyObject *module)
{
@ -305,6 +391,8 @@ typevar_alloc(PyObject *name, PyObject *bound, PyObject *evaluate_bound,
tv->evaluate_bound = Py_XNewRef(evaluate_bound);
tv->constraints = Py_XNewRef(constraints);
tv->evaluate_constraints = Py_XNewRef(evaluate_constraints);
tv->default_value = Py_XNewRef(default_value);
tv->evaluate_default = NULL;
tv->covariant = covariant;
tv->contravariant = contravariant;
@ -328,6 +416,7 @@ typevar.__new__ as typevar_new
name: object(subclass_of="&PyUnicode_Type")
*constraints: object
bound: object = None
default as default_value: object(c_default="&_Py_NoDefaultStruct") = typing.NoDefault
covariant: bool = False
contravariant: bool = False
infer_variance: bool = False
@ -337,9 +426,9 @@ Create a TypeVar.
static PyObject *
typevar_new_impl(PyTypeObject *type, PyObject *name, PyObject *constraints,
PyObject *bound, int covariant, int contravariant,
int infer_variance)
/*[clinic end generated code: output=1d200450ee99226d input=41ae33a916bfe76f]*/
PyObject *bound, PyObject *default_value, int covariant,
int contravariant, int infer_variance)
/*[clinic end generated code: output=d2b248ff074eaab6 input=836f97f631d7293a]*/
{
if (covariant && contravariant) {
PyErr_SetString(PyExc_ValueError,
@ -386,6 +475,7 @@ typevar_new_impl(PyTypeObject *type, PyObject *name, PyObject *constraints,
PyObject *tv = (PyObject *)typevar_alloc(name, bound, NULL,
constraints, NULL,
default_value,
covariant, contravariant,
infer_variance, module);
Py_XDECREF(bound);
@ -410,6 +500,66 @@ typevar_typing_subst(typevarobject *self, PyObject *arg)
return result;
}
/*[clinic input]
typevar.__typing_prepare_subst__ as typevar_typing_prepare_subst
alias: object
args: object
/
[clinic start generated code]*/
static PyObject *
typevar_typing_prepare_subst_impl(typevarobject *self, PyObject *alias,
PyObject *args)
/*[clinic end generated code: output=82c3f4691e0ded22 input=201a750415d14ffb]*/
{
PyObject *params = PyObject_GetAttrString(alias, "__parameters__");
if (params == NULL) {
return NULL;
}
Py_ssize_t i = PySequence_Index(params, (PyObject *)self);
if (i == -1) {
Py_DECREF(params);
return NULL;
}
Py_ssize_t args_len = PySequence_Length(args);
if (args_len == -1) {
Py_DECREF(params);
return NULL;
}
if (i < args_len) {
// We already have a value for our TypeVar
Py_DECREF(params);
return Py_NewRef(args);
}
else if (i == args_len) {
// If the TypeVar has a default, use it.
PyObject *dflt = typevar_default(self, NULL);
if (dflt == NULL) {
Py_DECREF(params);
return NULL;
}
if (dflt != &_Py_NoDefaultStruct) {
PyObject *new_args = PyTuple_Pack(1, dflt);
Py_DECREF(dflt);
if (new_args == NULL) {
Py_DECREF(params);
return NULL;
}
PyObject *result = PySequence_Concat(args, new_args);
Py_DECREF(params);
Py_DECREF(new_args);
return result;
}
}
Py_DECREF(params);
PyErr_Format(PyExc_TypeError,
"Too few arguments for %S; actual %d, expected at least %d",
alias, args_len, i + 1);
return NULL;
}
/*[clinic input]
typevar.__reduce__ as typevar_reduce
@ -422,6 +572,23 @@ typevar_reduce_impl(typevarobject *self)
return Py_NewRef(self->name);
}
/*[clinic input]
typevar.has_default as typevar_has_default
[clinic start generated code]*/
static PyObject *
typevar_has_default_impl(typevarobject *self)
/*[clinic end generated code: output=76bf0b8dc98b97dd input=31024aa030761cf6]*/
{
if (self->evaluate_default != NULL ||
(self->default_value != &_Py_NoDefaultStruct && self->default_value != NULL)) {
Py_RETURN_TRUE;
}
Py_RETURN_FALSE;
}
static PyObject *
typevar_mro_entries(PyObject *self, PyObject *args)
{
@ -432,7 +599,9 @@ typevar_mro_entries(PyObject *self, PyObject *args)
static PyMethodDef typevar_methods[] = {
TYPEVAR_TYPING_SUBST_METHODDEF
TYPEVAR_TYPING_PREPARE_SUBST_METHODDEF
TYPEVAR_REDUCE_METHODDEF
TYPEVAR_HAS_DEFAULT_METHODDEF
{"__mro_entries__", typevar_mro_entries, METH_O},
{0}
};
@ -457,12 +626,18 @@ variables::\n\
class StrOrBytesSequence[A: (str, bytes)]:\n\
...\n\
\n\
Type variables can also have defaults:\n\
\n\
class IntDefault[T = int]:\n\
...\n\
\n\
However, if desired, reusable type variables can also be constructed\n\
manually, like so::\n\
\n\
T = TypeVar('T') # Can be anything\n\
S = TypeVar('S', bound=str) # Can be any subtype of str\n\
A = TypeVar('A', str, bytes) # Must be exactly str or bytes\n\
D = TypeVar('D', default=int) # Defaults to int\n\
\n\
Type variables exist primarily for the benefit of static type\n\
checkers. They serve as the parameters for generic types as well\n\
@ -739,6 +914,8 @@ paramspec_dealloc(PyObject *self)
Py_DECREF(ps->name);
Py_XDECREF(ps->bound);
Py_XDECREF(ps->default_value);
Py_XDECREF(ps->evaluate_default);
PyObject_ClearManagedDict(self);
PyObject_ClearWeakRefs(self);
@ -752,6 +929,8 @@ paramspec_traverse(PyObject *self, visitproc visit, void *arg)
Py_VISIT(Py_TYPE(self));
paramspecobject *ps = (paramspecobject *)self;
Py_VISIT(ps->bound);
Py_VISIT(ps->default_value);
Py_VISIT(ps->evaluate_default);
PyObject_VisitManagedDict(self, visit, arg);
return 0;
}
@ -760,6 +939,8 @@ static int
paramspec_clear(paramspecobject *self)
{
Py_CLEAR(self->bound);
Py_CLEAR(self->default_value);
Py_CLEAR(self->evaluate_default);
PyObject_ClearManagedDict((PyObject *)self);
return 0;
}
@ -800,14 +981,29 @@ paramspec_kwargs(PyObject *self, void *unused)
return (PyObject *)paramspecattr_new(tp, self);
}
static PyObject *
paramspec_default(paramspecobject *self, void *unused)
{
if (self->default_value != NULL) {
return Py_NewRef(self->default_value);
}
if (self->evaluate_default == NULL) {
return &_Py_NoDefaultStruct;
}
PyObject *default_value = PyObject_CallNoArgs(self->evaluate_default);
self->default_value = Py_XNewRef(default_value);
return default_value;
}
static PyGetSetDef paramspec_getset[] = {
{"args", (getter)paramspec_args, NULL, PyDoc_STR("Represents positional arguments."), NULL},
{"kwargs", (getter)paramspec_kwargs, NULL, PyDoc_STR("Represents keyword arguments."), NULL},
{"__default__", (getter)paramspec_default, NULL, "The default value for this ParamSpec.", NULL},
{0},
};
static paramspecobject *
paramspec_alloc(PyObject *name, PyObject *bound, bool covariant,
paramspec_alloc(PyObject *name, PyObject *bound, PyObject *default_value, bool covariant,
bool contravariant, bool infer_variance, PyObject *module)
{
PyTypeObject *tp = _PyInterpreterState_GET()->cached_objects.paramspec_type;
@ -820,6 +1016,8 @@ paramspec_alloc(PyObject *name, PyObject *bound, bool covariant,
ps->covariant = covariant;
ps->contravariant = contravariant;
ps->infer_variance = infer_variance;
ps->default_value = Py_XNewRef(default_value);
ps->evaluate_default = NULL;
_PyObject_GC_TRACK(ps);
if (module != NULL) {
if (PyObject_SetAttrString((PyObject *)ps, "__module__", module) < 0) {
@ -837,6 +1035,7 @@ paramspec.__new__ as paramspec_new
name: object(subclass_of="&PyUnicode_Type")
*
bound: object = None
default as default_value: object(c_default="&_Py_NoDefaultStruct") = typing.NoDefault
covariant: bool = False
contravariant: bool = False
infer_variance: bool = False
@ -846,8 +1045,9 @@ Create a ParamSpec object.
static PyObject *
paramspec_new_impl(PyTypeObject *type, PyObject *name, PyObject *bound,
int covariant, int contravariant, int infer_variance)
/*[clinic end generated code: output=fd2daab79cba62da input=57c49c581979b952]*/
PyObject *default_value, int covariant, int contravariant,
int infer_variance)
/*[clinic end generated code: output=47ca9d63fa5a094d input=495e1565bc067ab9]*/
{
if (covariant && contravariant) {
PyErr_SetString(PyExc_ValueError, "Bivariant types are not supported.");
@ -869,7 +1069,7 @@ paramspec_new_impl(PyTypeObject *type, PyObject *name, PyObject *bound,
return NULL;
}
PyObject *ps = (PyObject *)paramspec_alloc(
name, bound, covariant, contravariant, infer_variance, module);
name, bound, default_value, covariant, contravariant, infer_variance, module);
Py_XDECREF(bound);
Py_DECREF(module);
return ps;
@ -925,6 +1125,22 @@ paramspec_reduce_impl(paramspecobject *self)
return Py_NewRef(self->name);
}
/*[clinic input]
paramspec.has_default as paramspec_has_default
[clinic start generated code]*/
static PyObject *
paramspec_has_default_impl(paramspecobject *self)
/*[clinic end generated code: output=daaae7467a6a4368 input=2112e97eeb76cd59]*/
{
if (self->evaluate_default != NULL ||
(self->default_value != &_Py_NoDefaultStruct && self->default_value != NULL)) {
Py_RETURN_TRUE;
}
Py_RETURN_FALSE;
}
static PyObject *
paramspec_mro_entries(PyObject *self, PyObject *args)
{
@ -936,6 +1152,7 @@ paramspec_mro_entries(PyObject *self, PyObject *args)
static PyMethodDef paramspec_methods[] = {
PARAMSPEC_TYPING_SUBST_METHODDEF
PARAMSPEC_TYPING_PREPARE_SUBST_METHODDEF
PARAMSPEC_HAS_DEFAULT_METHODDEF
PARAMSPEC_REDUCE_METHODDEF
{"__mro_entries__", paramspec_mro_entries, METH_O},
{0}
@ -950,10 +1167,17 @@ where the use of '**' creates a parameter specification::\n\
\n\
type IntFunc[**P] = Callable[P, int]\n\
\n\
The following syntax creates a parameter specification that defaults\n\
to a callable accepting two positional-only arguments of types int\n\
and str:\n\
\n\
type IntFuncDefault[**P = (int, str)] = Callable[P, int]\n\
\n\
For compatibility with Python 3.11 and earlier, ParamSpec objects\n\
can also be created as follows::\n\
\n\
P = ParamSpec('P')\n\
DefaultP = ParamSpec('DefaultP', default=(int, str))\n\
\n\
Parameter specification variables exist primarily for the benefit of\n\
static type checkers. They are used to forward the parameter types of\n\
@ -1021,6 +1245,8 @@ typevartuple_dealloc(PyObject *self)
typevartupleobject *tvt = (typevartupleobject *)self;
Py_DECREF(tvt->name);
Py_XDECREF(tvt->default_value);
Py_XDECREF(tvt->evaluate_default);
PyObject_ClearManagedDict(self);
PyObject_ClearWeakRefs(self);
@ -1060,7 +1286,7 @@ static PyMemberDef typevartuple_members[] = {
};
static typevartupleobject *
typevartuple_alloc(PyObject *name, PyObject *module)
typevartuple_alloc(PyObject *name, PyObject *module, PyObject *default_value)
{
PyTypeObject *tp = _PyInterpreterState_GET()->cached_objects.typevartuple_type;
typevartupleobject *tvt = PyObject_GC_New(typevartupleobject, tp);
@ -1068,6 +1294,8 @@ typevartuple_alloc(PyObject *name, PyObject *module)
return NULL;
}
tvt->name = Py_NewRef(name);
tvt->default_value = Py_XNewRef(default_value);
tvt->evaluate_default = NULL;
_PyObject_GC_TRACK(tvt);
if (module != NULL) {
if (PyObject_SetAttrString((PyObject *)tvt, "__module__", module) < 0) {
@ -1083,19 +1311,22 @@ typevartuple_alloc(PyObject *name, PyObject *module)
typevartuple.__new__
name: object(subclass_of="&PyUnicode_Type")
*
default as default_value: object(c_default="&_Py_NoDefaultStruct") = typing.NoDefault
Create a new TypeVarTuple with the given name.
[clinic start generated code]*/
static PyObject *
typevartuple_impl(PyTypeObject *type, PyObject *name)
/*[clinic end generated code: output=09d417a28f976202 input=00d28abcf1fc96bb]*/
typevartuple_impl(PyTypeObject *type, PyObject *name,
PyObject *default_value)
/*[clinic end generated code: output=9d6b76dfe95aae51 input=e149739929a866d0]*/
{
PyObject *module = caller();
if (module == NULL) {
return NULL;
}
PyObject *result = (PyObject *)typevartuple_alloc(name, module);
PyObject *result = (PyObject *)typevartuple_alloc(name, module, default_value);
Py_DECREF(module);
return result;
}
@ -1148,6 +1379,23 @@ typevartuple_reduce_impl(typevartupleobject *self)
return Py_NewRef(self->name);
}
/*[clinic input]
typevartuple.has_default as typevartuple_has_default
[clinic start generated code]*/
static PyObject *
typevartuple_has_default_impl(typevartupleobject *self)
/*[clinic end generated code: output=4895f602f56a5e29 input=9ef3250ddb2c1851]*/
{
if (self->evaluate_default != NULL ||
(self->default_value != &_Py_NoDefaultStruct && self->default_value != NULL)) {
Py_RETURN_TRUE;
}
Py_RETURN_FALSE;
}
static PyObject *
typevartuple_mro_entries(PyObject *self, PyObject *args)
{
@ -1160,6 +1408,8 @@ static int
typevartuple_traverse(PyObject *self, visitproc visit, void *arg)
{
Py_VISIT(Py_TYPE(self));
Py_VISIT(((typevartupleobject *)self)->default_value);
Py_VISIT(((typevartupleobject *)self)->evaluate_default);
PyObject_VisitManagedDict(self, visit, arg);
return 0;
}
@ -1167,14 +1417,36 @@ typevartuple_traverse(PyObject *self, visitproc visit, void *arg)
static int
typevartuple_clear(PyObject *self)
{
Py_CLEAR(((typevartupleobject *)self)->default_value);
Py_CLEAR(((typevartupleobject *)self)->evaluate_default);
PyObject_ClearManagedDict(self);
return 0;
}
static PyObject *
typevartuple_default(typevartupleobject *self, void *unused)
{
if (self->default_value != NULL) {
return Py_NewRef(self->default_value);
}
if (self->evaluate_default == NULL) {
return &_Py_NoDefaultStruct;
}
PyObject *default_value = PyObject_CallNoArgs(self->evaluate_default);
self->default_value = Py_XNewRef(default_value);
return default_value;
}
static PyGetSetDef typevartuple_getset[] = {
{"__default__", (getter)typevartuple_default, NULL, "The default value for this TypeVarTuple.", NULL},
{0},
};
static PyMethodDef typevartuple_methods[] = {
TYPEVARTUPLE_TYPING_SUBST_METHODDEF
TYPEVARTUPLE_TYPING_PREPARE_SUBST_METHODDEF
TYPEVARTUPLE_REDUCE_METHODDEF
TYPEVARTUPLE_HAS_DEFAULT_METHODDEF
{"__mro_entries__", typevartuple_mro_entries, METH_O},
{0}
};
@ -1190,10 +1462,15 @@ where a single '*' indicates a type variable tuple::\n\
def move_first_element_to_last[T, *Ts](tup: tuple[T, *Ts]) -> tuple[*Ts, T]:\n\
return (*tup[1:], tup[0])\n\
\n\
Type variables tuples can have default values:\n\
\n\
type AliasWithDefault[*Ts = (str, int)] = tuple[*Ts]\n\
\n\
For compatibility with Python 3.11 and earlier, TypeVarTuple objects\n\
can also be created as follows::\n\
\n\
Ts = TypeVarTuple('Ts') # Can be given any name\n\
DefaultTs = TypeVarTuple('Ts', default=(str, int))\n\
\n\
Just as a TypeVar (type variable) is a placeholder for a single type,\n\
a TypeVarTuple is a placeholder for an *arbitrary* number of types. For\n\
@ -1218,6 +1495,7 @@ PyType_Slot typevartuple_slots[] = {
{Py_tp_doc, (void *)typevartuple_doc},
{Py_tp_members, typevartuple_members},
{Py_tp_methods, typevartuple_methods},
{Py_tp_getset, typevartuple_getset},
{Py_tp_new, typevartuple},
{Py_tp_iter, typevartuple_iter},
{Py_tp_repr, typevartuple_repr},
@ -1241,21 +1519,21 @@ PyObject *
_Py_make_typevar(PyObject *name, PyObject *evaluate_bound, PyObject *evaluate_constraints)
{
return (PyObject *)typevar_alloc(name, NULL, evaluate_bound, NULL, evaluate_constraints,
false, false, true, NULL);
NULL, false, false, true, NULL);
}
PyObject *
_Py_make_paramspec(PyThreadState *Py_UNUSED(ignored), PyObject *v)
{
assert(PyUnicode_Check(v));
return (PyObject *)paramspec_alloc(v, NULL, false, false, true, NULL);
return (PyObject *)paramspec_alloc(v, NULL, NULL, false, false, true, NULL);
}
PyObject *
_Py_make_typevartuple(PyThreadState *Py_UNUSED(ignored), PyObject *v)
{
assert(PyUnicode_Check(v));
return (PyObject *)typevartuple_alloc(v, NULL);
return (PyObject *)typevartuple_alloc(v, NULL, NULL);
}
static void
@ -1687,3 +1965,24 @@ void _Py_clear_generic_types(PyInterpreterState *interp)
Py_CLEAR(interp->cached_objects.paramspecargs_type);
Py_CLEAR(interp->cached_objects.paramspeckwargs_type);
}
PyObject *
_Py_set_typeparam_default(PyThreadState *ts, PyObject *typeparam, PyObject *evaluate_default)
{
if (Py_IS_TYPE(typeparam, ts->interp->cached_objects.typevar_type)) {
Py_XSETREF(((typevarobject *)typeparam)->evaluate_default, Py_NewRef(evaluate_default));
return Py_NewRef(typeparam);
}
else if (Py_IS_TYPE(typeparam, ts->interp->cached_objects.paramspec_type)) {
Py_XSETREF(((paramspecobject *)typeparam)->evaluate_default, Py_NewRef(evaluate_default));
return Py_NewRef(typeparam);
}
else if (Py_IS_TYPE(typeparam, ts->interp->cached_objects.typevartuple_type)) {
Py_XSETREF(((typevartupleobject *)typeparam)->evaluate_default, Py_NewRef(evaluate_default));
return Py_NewRef(typeparam);
}
else {
PyErr_Format(PyExc_TypeError, "Expected a type param, got %R", typeparam);
return NULL;
}
}

View File

@ -145,8 +145,8 @@ module Python
type_ignore = TypeIgnore(int lineno, string tag)
type_param = TypeVar(identifier name, expr? bound)
| ParamSpec(identifier name)
| TypeVarTuple(identifier name)
type_param = TypeVar(identifier name, expr? bound, expr? default_value)
| ParamSpec(identifier name, expr? default_value)
| TypeVarTuple(identifier name, expr? default_value)
attributes (int lineno, int col_offset, int end_lineno, int end_col_offset)
}

991
Parser/parser.c generated

File diff suppressed because it is too large Load Diff

178
Python/Python-ast.c generated
View File

@ -203,6 +203,7 @@ void _PyAST_Fini(PyInterpreterState *interp)
Py_CLEAR(state->conversion);
Py_CLEAR(state->ctx);
Py_CLEAR(state->decorator_list);
Py_CLEAR(state->default_value);
Py_CLEAR(state->defaults);
Py_CLEAR(state->elt);
Py_CLEAR(state->elts);
@ -311,6 +312,7 @@ static int init_identifiers(struct ast_state *state)
if ((state->conversion = PyUnicode_InternFromString("conversion")) == NULL) return -1;
if ((state->ctx = PyUnicode_InternFromString("ctx")) == NULL) return -1;
if ((state->decorator_list = PyUnicode_InternFromString("decorator_list")) == NULL) return -1;
if ((state->default_value = PyUnicode_InternFromString("default_value")) == NULL) return -1;
if ((state->defaults = PyUnicode_InternFromString("defaults")) == NULL) return -1;
if ((state->elt = PyUnicode_InternFromString("elt")) == NULL) return -1;
if ((state->elts = PyUnicode_InternFromString("elts")) == NULL) return -1;
@ -809,12 +811,15 @@ static PyObject* ast2obj_type_param(struct ast_state *state, struct validator
static const char * const TypeVar_fields[]={
"name",
"bound",
"default_value",
};
static const char * const ParamSpec_fields[]={
"name",
"default_value",
};
static const char * const TypeVarTuple_fields[]={
"name",
"default_value",
};
@ -4913,6 +4918,22 @@ add_ast_annotations(struct ast_state *state)
return 0;
}
}
{
PyObject *type = state->expr_type;
type = _Py_union_type_or(type, Py_None);
cond = type != NULL;
if (!cond) {
Py_DECREF(TypeVar_annotations);
return 0;
}
cond = PyDict_SetItemString(TypeVar_annotations, "default_value", type)
== 0;
Py_DECREF(type);
if (!cond) {
Py_DECREF(TypeVar_annotations);
return 0;
}
}
cond = PyObject_SetAttrString(state->TypeVar_type, "_field_types",
TypeVar_annotations) == 0;
if (!cond) {
@ -4938,6 +4959,22 @@ add_ast_annotations(struct ast_state *state)
return 0;
}
}
{
PyObject *type = state->expr_type;
type = _Py_union_type_or(type, Py_None);
cond = type != NULL;
if (!cond) {
Py_DECREF(ParamSpec_annotations);
return 0;
}
cond = PyDict_SetItemString(ParamSpec_annotations, "default_value",
type) == 0;
Py_DECREF(type);
if (!cond) {
Py_DECREF(ParamSpec_annotations);
return 0;
}
}
cond = PyObject_SetAttrString(state->ParamSpec_type, "_field_types",
ParamSpec_annotations) == 0;
if (!cond) {
@ -4964,6 +5001,22 @@ add_ast_annotations(struct ast_state *state)
return 0;
}
}
{
PyObject *type = state->expr_type;
type = _Py_union_type_or(type, Py_None);
cond = type != NULL;
if (!cond) {
Py_DECREF(TypeVarTuple_annotations);
return 0;
}
cond = PyDict_SetItemString(TypeVarTuple_annotations, "default_value",
type) == 0;
Py_DECREF(type);
if (!cond) {
Py_DECREF(TypeVarTuple_annotations);
return 0;
}
}
cond = PyObject_SetAttrString(state->TypeVarTuple_type, "_field_types",
TypeVarTuple_annotations) == 0;
if (!cond) {
@ -6243,28 +6296,37 @@ init_types(struct ast_state *state)
if (!state->TypeIgnore_type) return -1;
state->type_param_type = make_type(state, "type_param", state->AST_type,
NULL, 0,
"type_param = TypeVar(identifier name, expr? bound)\n"
" | ParamSpec(identifier name)\n"
" | TypeVarTuple(identifier name)");
"type_param = TypeVar(identifier name, expr? bound, expr? default_value)\n"
" | ParamSpec(identifier name, expr? default_value)\n"
" | TypeVarTuple(identifier name, expr? default_value)");
if (!state->type_param_type) return -1;
if (add_attributes(state, state->type_param_type, type_param_attributes, 4)
< 0) return -1;
state->TypeVar_type = make_type(state, "TypeVar", state->type_param_type,
TypeVar_fields, 2,
"TypeVar(identifier name, expr? bound)");
TypeVar_fields, 3,
"TypeVar(identifier name, expr? bound, expr? default_value)");
if (!state->TypeVar_type) return -1;
if (PyObject_SetAttr(state->TypeVar_type, state->bound, Py_None) == -1)
return -1;
if (PyObject_SetAttr(state->TypeVar_type, state->default_value, Py_None) ==
-1)
return -1;
state->ParamSpec_type = make_type(state, "ParamSpec",
state->type_param_type, ParamSpec_fields,
1,
"ParamSpec(identifier name)");
2,
"ParamSpec(identifier name, expr? default_value)");
if (!state->ParamSpec_type) return -1;
if (PyObject_SetAttr(state->ParamSpec_type, state->default_value, Py_None)
== -1)
return -1;
state->TypeVarTuple_type = make_type(state, "TypeVarTuple",
state->type_param_type,
TypeVarTuple_fields, 1,
"TypeVarTuple(identifier name)");
TypeVarTuple_fields, 2,
"TypeVarTuple(identifier name, expr? default_value)");
if (!state->TypeVarTuple_type) return -1;
if (PyObject_SetAttr(state->TypeVarTuple_type, state->default_value,
Py_None) == -1)
return -1;
if (!add_ast_annotations(state)) {
return -1;
@ -8055,8 +8117,9 @@ _PyAST_TypeIgnore(int lineno, string tag, PyArena *arena)
}
type_param_ty
_PyAST_TypeVar(identifier name, expr_ty bound, int lineno, int col_offset, int
end_lineno, int end_col_offset, PyArena *arena)
_PyAST_TypeVar(identifier name, expr_ty bound, expr_ty default_value, int
lineno, int col_offset, int end_lineno, int end_col_offset,
PyArena *arena)
{
type_param_ty p;
if (!name) {
@ -8070,6 +8133,7 @@ _PyAST_TypeVar(identifier name, expr_ty bound, int lineno, int col_offset, int
p->kind = TypeVar_kind;
p->v.TypeVar.name = name;
p->v.TypeVar.bound = bound;
p->v.TypeVar.default_value = default_value;
p->lineno = lineno;
p->col_offset = col_offset;
p->end_lineno = end_lineno;
@ -8078,8 +8142,8 @@ _PyAST_TypeVar(identifier name, expr_ty bound, int lineno, int col_offset, int
}
type_param_ty
_PyAST_ParamSpec(identifier name, int lineno, int col_offset, int end_lineno,
int end_col_offset, PyArena *arena)
_PyAST_ParamSpec(identifier name, expr_ty default_value, int lineno, int
col_offset, int end_lineno, int end_col_offset, PyArena *arena)
{
type_param_ty p;
if (!name) {
@ -8092,6 +8156,7 @@ _PyAST_ParamSpec(identifier name, int lineno, int col_offset, int end_lineno,
return NULL;
p->kind = ParamSpec_kind;
p->v.ParamSpec.name = name;
p->v.ParamSpec.default_value = default_value;
p->lineno = lineno;
p->col_offset = col_offset;
p->end_lineno = end_lineno;
@ -8100,8 +8165,9 @@ _PyAST_ParamSpec(identifier name, int lineno, int col_offset, int end_lineno,
}
type_param_ty
_PyAST_TypeVarTuple(identifier name, int lineno, int col_offset, int
end_lineno, int end_col_offset, PyArena *arena)
_PyAST_TypeVarTuple(identifier name, expr_ty default_value, int lineno, int
col_offset, int end_lineno, int end_col_offset, PyArena
*arena)
{
type_param_ty p;
if (!name) {
@ -8114,6 +8180,7 @@ _PyAST_TypeVarTuple(identifier name, int lineno, int col_offset, int
return NULL;
p->kind = TypeVarTuple_kind;
p->v.TypeVarTuple.name = name;
p->v.TypeVarTuple.default_value = default_value;
p->lineno = lineno;
p->col_offset = col_offset;
p->end_lineno = end_lineno;
@ -10079,6 +10146,11 @@ ast2obj_type_param(struct ast_state *state, struct validator *vstate, void* _o)
if (PyObject_SetAttr(result, state->bound, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_expr(state, vstate, o->v.TypeVar.default_value);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->default_value, value) == -1)
goto failed;
Py_DECREF(value);
break;
case ParamSpec_kind:
tp = (PyTypeObject *)state->ParamSpec_type;
@ -10089,6 +10161,11 @@ ast2obj_type_param(struct ast_state *state, struct validator *vstate, void* _o)
if (PyObject_SetAttr(result, state->name, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_expr(state, vstate, o->v.ParamSpec.default_value);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->default_value, value) == -1)
goto failed;
Py_DECREF(value);
break;
case TypeVarTuple_kind:
tp = (PyTypeObject *)state->TypeVarTuple_type;
@ -10099,6 +10176,11 @@ ast2obj_type_param(struct ast_state *state, struct validator *vstate, void* _o)
if (PyObject_SetAttr(result, state->name, value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_expr(state, vstate, o->v.TypeVarTuple.default_value);
if (!value) goto failed;
if (PyObject_SetAttr(result, state->default_value, value) == -1)
goto failed;
Py_DECREF(value);
break;
}
value = ast2obj_int(state, vstate, o->lineno);
@ -16935,6 +17017,7 @@ obj2ast_type_param(struct ast_state *state, PyObject* obj, type_param_ty* out,
if (isinstance) {
identifier name;
expr_ty bound;
expr_ty default_value;
if (PyObject_GetOptionalAttr(obj, state->name, &tmp) < 0) {
return -1;
@ -16970,8 +17053,25 @@ obj2ast_type_param(struct ast_state *state, PyObject* obj, type_param_ty* out,
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
*out = _PyAST_TypeVar(name, bound, lineno, col_offset, end_lineno,
end_col_offset, arena);
if (PyObject_GetOptionalAttr(obj, state->default_value, &tmp) < 0) {
return -1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
default_value = NULL;
}
else {
int res;
if (_Py_EnterRecursiveCall(" while traversing 'TypeVar' node")) {
goto failed;
}
res = obj2ast_expr(state, tmp, &default_value, arena);
_Py_LeaveRecursiveCall();
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
*out = _PyAST_TypeVar(name, bound, default_value, lineno, col_offset,
end_lineno, end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
@ -16982,6 +17082,7 @@ obj2ast_type_param(struct ast_state *state, PyObject* obj, type_param_ty* out,
}
if (isinstance) {
identifier name;
expr_ty default_value;
if (PyObject_GetOptionalAttr(obj, state->name, &tmp) < 0) {
return -1;
@ -17000,8 +17101,25 @@ obj2ast_type_param(struct ast_state *state, PyObject* obj, type_param_ty* out,
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
*out = _PyAST_ParamSpec(name, lineno, col_offset, end_lineno,
end_col_offset, arena);
if (PyObject_GetOptionalAttr(obj, state->default_value, &tmp) < 0) {
return -1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
default_value = NULL;
}
else {
int res;
if (_Py_EnterRecursiveCall(" while traversing 'ParamSpec' node")) {
goto failed;
}
res = obj2ast_expr(state, tmp, &default_value, arena);
_Py_LeaveRecursiveCall();
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
*out = _PyAST_ParamSpec(name, default_value, lineno, col_offset,
end_lineno, end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
@ -17012,6 +17130,7 @@ obj2ast_type_param(struct ast_state *state, PyObject* obj, type_param_ty* out,
}
if (isinstance) {
identifier name;
expr_ty default_value;
if (PyObject_GetOptionalAttr(obj, state->name, &tmp) < 0) {
return -1;
@ -17030,8 +17149,25 @@ obj2ast_type_param(struct ast_state *state, PyObject* obj, type_param_ty* out,
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
*out = _PyAST_TypeVarTuple(name, lineno, col_offset, end_lineno,
end_col_offset, arena);
if (PyObject_GetOptionalAttr(obj, state->default_value, &tmp) < 0) {
return -1;
}
if (tmp == NULL || tmp == Py_None) {
Py_CLEAR(tmp);
default_value = NULL;
}
else {
int res;
if (_Py_EnterRecursiveCall(" while traversing 'TypeVarTuple' node")) {
goto failed;
}
res = obj2ast_expr(state, tmp, &default_value, arena);
_Py_LeaveRecursiveCall();
if (res != 0) goto failed;
Py_CLEAR(tmp);
}
*out = _PyAST_TypeVarTuple(name, default_value, lineno, col_offset,
end_lineno, end_col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}

View File

@ -1011,13 +1011,19 @@ validate_typeparam(struct validator *state, type_param_ty tp)
case TypeVar_kind:
ret = validate_name(tp->v.TypeVar.name) &&
(!tp->v.TypeVar.bound ||
validate_expr(state, tp->v.TypeVar.bound, Load));
validate_expr(state, tp->v.TypeVar.bound, Load)) &&
(!tp->v.TypeVar.default_value ||
validate_expr(state, tp->v.TypeVar.default_value, Load));
break;
case ParamSpec_kind:
ret = validate_name(tp->v.ParamSpec.name);
ret = validate_name(tp->v.ParamSpec.name) &&
(!tp->v.ParamSpec.default_value ||
validate_expr(state, tp->v.ParamSpec.default_value, Load));
break;
case TypeVarTuple_kind:
ret = validate_name(tp->v.TypeVarTuple.name);
ret = validate_name(tp->v.TypeVarTuple.name) &&
(!tp->v.TypeVarTuple.default_value ||
validate_expr(state, tp->v.TypeVarTuple.default_value, Load));
break;
}
return ret;

View File

@ -2116,6 +2116,36 @@ wrap_in_stopiteration_handler(struct compiler *c)
return SUCCESS;
}
static int
compiler_type_param_bound_or_default(struct compiler *c, expr_ty e,
identifier name, void *key,
bool allow_starred)
{
if (compiler_enter_scope(c, name, COMPILER_SCOPE_TYPEPARAMS,
key, e->lineno) == -1) {
return ERROR;
}
if (allow_starred && e->kind == Starred_kind) {
VISIT(c, expr, e->v.Starred.value);
ADDOP_I(c, LOC(e), UNPACK_SEQUENCE, (Py_ssize_t)1);
}
else {
VISIT(c, expr, e);
}
ADDOP_IN_SCOPE(c, LOC(e), RETURN_VALUE);
PyCodeObject *co = optimize_and_assemble(c, 1);
compiler_exit_scope(c);
if (co == NULL) {
return ERROR;
}
if (compiler_make_closure(c, LOC(e), co, 0) < 0) {
Py_DECREF(co);
return ERROR;
}
Py_DECREF(co);
return SUCCESS;
}
static int
compiler_type_params(struct compiler *c, asdl_type_param_seq *type_params)
{
@ -2123,6 +2153,7 @@ compiler_type_params(struct compiler *c, asdl_type_param_seq *type_params)
return SUCCESS;
}
Py_ssize_t n = asdl_seq_LEN(type_params);
bool seen_default = false;
for (Py_ssize_t i = 0; i < n; i++) {
type_param_ty typeparam = asdl_seq_GET(type_params, i);
@ -2132,22 +2163,10 @@ compiler_type_params(struct compiler *c, asdl_type_param_seq *type_params)
ADDOP_LOAD_CONST(c, loc, typeparam->v.TypeVar.name);
if (typeparam->v.TypeVar.bound) {
expr_ty bound = typeparam->v.TypeVar.bound;
if (compiler_enter_scope(c, typeparam->v.TypeVar.name, COMPILER_SCOPE_TYPEPARAMS,
(void *)typeparam, bound->lineno) == -1) {
if (compiler_type_param_bound_or_default(c, bound, typeparam->v.TypeVar.name,
(void *)typeparam, false) < 0) {
return ERROR;
}
VISIT_IN_SCOPE(c, expr, bound);
ADDOP_IN_SCOPE(c, loc, RETURN_VALUE);
PyCodeObject *co = optimize_and_assemble(c, 1);
compiler_exit_scope(c);
if (co == NULL) {
return ERROR;
}
if (compiler_make_closure(c, loc, co, 0) < 0) {
Py_DECREF(co);
return ERROR;
}
Py_DECREF(co);
int intrinsic = bound->kind == Tuple_kind
? INTRINSIC_TYPEVAR_WITH_CONSTRAINTS
@ -2157,18 +2176,60 @@ compiler_type_params(struct compiler *c, asdl_type_param_seq *type_params)
else {
ADDOP_I(c, loc, CALL_INTRINSIC_1, INTRINSIC_TYPEVAR);
}
if (typeparam->v.TypeVar.default_value) {
seen_default = true;
expr_ty default_ = typeparam->v.TypeVar.default_value;
if (compiler_type_param_bound_or_default(c, default_, typeparam->v.TypeVar.name,
(void *)((uintptr_t)typeparam + 1), false) < 0) {
return ERROR;
}
ADDOP_I(c, loc, CALL_INTRINSIC_2, INTRINSIC_SET_TYPEPARAM_DEFAULT);
}
else if (seen_default) {
return compiler_error(c, loc, "non-default type parameter '%U' "
"follows default type parameter",
typeparam->v.TypeVar.name);
}
ADDOP_I(c, loc, COPY, 1);
RETURN_IF_ERROR(compiler_nameop(c, loc, typeparam->v.TypeVar.name, Store));
break;
case TypeVarTuple_kind:
ADDOP_LOAD_CONST(c, loc, typeparam->v.TypeVarTuple.name);
ADDOP_I(c, loc, CALL_INTRINSIC_1, INTRINSIC_TYPEVARTUPLE);
if (typeparam->v.TypeVarTuple.default_value) {
expr_ty default_ = typeparam->v.TypeVarTuple.default_value;
if (compiler_type_param_bound_or_default(c, default_, typeparam->v.TypeVarTuple.name,
(void *)typeparam, true) < 0) {
return ERROR;
}
ADDOP_I(c, loc, CALL_INTRINSIC_2, INTRINSIC_SET_TYPEPARAM_DEFAULT);
seen_default = true;
}
else if (seen_default) {
return compiler_error(c, loc, "non-default type parameter '%U' "
"follows default type parameter",
typeparam->v.TypeVarTuple.name);
}
ADDOP_I(c, loc, COPY, 1);
RETURN_IF_ERROR(compiler_nameop(c, loc, typeparam->v.TypeVarTuple.name, Store));
break;
case ParamSpec_kind:
ADDOP_LOAD_CONST(c, loc, typeparam->v.ParamSpec.name);
ADDOP_I(c, loc, CALL_INTRINSIC_1, INTRINSIC_PARAMSPEC);
if (typeparam->v.ParamSpec.default_value) {
expr_ty default_ = typeparam->v.ParamSpec.default_value;
if (compiler_type_param_bound_or_default(c, default_, typeparam->v.ParamSpec.name,
(void *)typeparam, false) < 0) {
return ERROR;
}
ADDOP_I(c, loc, CALL_INTRINSIC_2, INTRINSIC_SET_TYPEPARAM_DEFAULT);
seen_default = true;
}
else if (seen_default) {
return compiler_error(c, loc, "non-default type parameter '%U' "
"follows default type parameter",
typeparam->v.ParamSpec.name);
}
ADDOP_I(c, loc, COPY, 1);
RETURN_IF_ERROR(compiler_nameop(c, loc, typeparam->v.ParamSpec.name, Store));
break;

View File

@ -265,6 +265,7 @@ _PyIntrinsics_BinaryFunctions[] = {
INTRINSIC_FUNC_ENTRY(INTRINSIC_TYPEVAR_WITH_BOUND, make_typevar_with_bound)
INTRINSIC_FUNC_ENTRY(INTRINSIC_TYPEVAR_WITH_CONSTRAINTS, make_typevar_with_constraints)
INTRINSIC_FUNC_ENTRY(INTRINSIC_SET_FUNCTION_TYPE_PARAMS, _Py_set_function_type_params)
INTRINSIC_FUNC_ENTRY(INTRINSIC_SET_TYPEPARAM_DEFAULT, _Py_set_typeparam_default)
};
#undef INTRINSIC_FUNC_ENTRY

View File

@ -2275,6 +2275,24 @@ symtable_visit_expr(struct symtable *st, expr_ty e)
VISIT_QUIT(st, 1);
}
static int
symtable_visit_type_param_bound_or_default(struct symtable *st, expr_ty e, identifier name, void *key)
{
if (e) {
int is_in_class = st->st_cur->ste_can_see_class_scope;
if (!symtable_enter_block(st, name, TypeVarBoundBlock, key, LOCATION(e)))
return 0;
st->st_cur->ste_can_see_class_scope = is_in_class;
if (is_in_class && !symtable_add_def(st, &_Py_ID(__classdict__), USE, LOCATION(e))) {
VISIT_QUIT(st, 0);
}
VISIT(st, expr, e);
if (!symtable_exit_block(st))
return 0;
}
return 1;
}
static int
symtable_visit_type_param(struct symtable *st, type_param_ty tp)
{
@ -2287,28 +2305,39 @@ symtable_visit_type_param(struct symtable *st, type_param_ty tp)
case TypeVar_kind:
if (!symtable_add_def(st, tp->v.TypeVar.name, DEF_TYPE_PARAM | DEF_LOCAL, LOCATION(tp)))
VISIT_QUIT(st, 0);
if (tp->v.TypeVar.bound) {
int is_in_class = st->st_cur->ste_can_see_class_scope;
if (!symtable_enter_block(st, tp->v.TypeVar.name,
TypeVarBoundBlock, (void *)tp,
LOCATION(tp)))
VISIT_QUIT(st, 0);
st->st_cur->ste_can_see_class_scope = is_in_class;
if (is_in_class && !symtable_add_def(st, &_Py_ID(__classdict__), USE, LOCATION(tp->v.TypeVar.bound))) {
VISIT_QUIT(st, 0);
}
VISIT(st, expr, tp->v.TypeVar.bound);
if (!symtable_exit_block(st))
VISIT_QUIT(st, 0);
// We must use a different key for the bound and default. The obvious choice would be to
// use the .bound and .default_value pointers, but that fails when the expression immediately
// inside the bound or default is a comprehension: we would reuse the same key for
// the comprehension scope. Therefore, use the address + 1 as the second key.
// The only requirement for the key is that it is unique and it matches the logic in
// compile.c where the scope is retrieved.
if (!symtable_visit_type_param_bound_or_default(st, tp->v.TypeVar.bound, tp->v.TypeVar.name,
(void *)tp)) {
VISIT_QUIT(st, 0);
}
if (!symtable_visit_type_param_bound_or_default(st, tp->v.TypeVar.default_value, tp->v.TypeVar.name,
(void *)((uintptr_t)tp + 1))) {
VISIT_QUIT(st, 0);
}
break;
case TypeVarTuple_kind:
if (!symtable_add_def(st, tp->v.TypeVarTuple.name, DEF_TYPE_PARAM | DEF_LOCAL, LOCATION(tp)))
if (!symtable_add_def(st, tp->v.TypeVarTuple.name, DEF_TYPE_PARAM | DEF_LOCAL, LOCATION(tp))) {
VISIT_QUIT(st, 0);
}
if (!symtable_visit_type_param_bound_or_default(st, tp->v.TypeVarTuple.default_value, tp->v.TypeVarTuple.name,
(void *)tp)) {
VISIT_QUIT(st, 0);
}
break;
case ParamSpec_kind:
if (!symtable_add_def(st, tp->v.ParamSpec.name, DEF_TYPE_PARAM | DEF_LOCAL, LOCATION(tp)))
if (!symtable_add_def(st, tp->v.ParamSpec.name, DEF_TYPE_PARAM | DEF_LOCAL, LOCATION(tp))) {
VISIT_QUIT(st, 0);
}
if (!symtable_visit_type_param_bound_or_default(st, tp->v.ParamSpec.default_value, tp->v.ParamSpec.name,
(void *)tp)) {
VISIT_QUIT(st, 0);
}
break;
}
VISIT_QUIT(st, 1);

View File

@ -92,6 +92,7 @@ Objects/typeobject.c - PyBaseObject_Type -
Objects/typeobject.c - PySuper_Type -
Objects/typeobject.c - PyType_Type -
Objects/typevarobject.c - _PyTypeAlias_Type -
Objects/typevarobject.c - _PyNoDefault_Type -
Objects/unicodeobject.c - PyUnicodeIter_Type -
Objects/unicodeobject.c - PyUnicode_Type -
Objects/weakrefobject.c - _PyWeakref_CallableProxyType -
@ -310,6 +311,7 @@ Objects/object.c - _Py_NotImplementedStruct -
Objects/setobject.c - _dummy_struct -
Objects/setobject.c - _PySet_Dummy -
Objects/sliceobject.c - _Py_EllipsisObject -
Objects/typevarobject.c - _Py_NoDefaultStruct -
Python/instrumentation.c - _PyInstrumentation_DISABLE -
Python/instrumentation.c - _PyInstrumentation_MISSING -

Can't render this file because it has a wrong number of fields in line 4.