mirror of https://github.com/python/cpython
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:
parent
852263e108
commit
ca269e58c2
|
@ -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
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
|
|
@ -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
|
||||
--------
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
-----------
|
||||
|
||||
|
|
|
@ -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
|
||||
# -----------
|
||||
|
|
|
@ -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
|
||||
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_TypeVarTuple(identifier name, 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);
|
||||
|
|
|
@ -184,6 +184,7 @@ struct ast_state {
|
|||
PyObject *conversion;
|
||||
PyObject *ctx;
|
||||
PyObject *decorator_list;
|
||||
PyObject *default_value;
|
||||
PyObject *defaults;
|
||||
PyObject *elt;
|
||||
PyObject *elts;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 ")
|
||||
|
|
|
@ -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)))]),
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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__."""
|
||||
|
||||
|
|
|
@ -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."""
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
Implement :pep:`696`, adding support for defaults on type parameters.
|
||||
Patch by Jelle Zijlstra.
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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]*/
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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;
|
||||
}
|
||||
|
|
12
Python/ast.c
12
Python/ast.c
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))) {
|
||||
|
||||
// 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);
|
||||
}
|
||||
VISIT(st, expr, tp->v.TypeVar.bound);
|
||||
if (!symtable_exit_block(st))
|
||||
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);
|
||||
|
|
|
@ -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.
|
Loading…
Reference in New Issue