gh-119180: Add evaluate functions for type params and type aliases (#122212)

This commit is contained in:
Jelle Zijlstra 2024-07-27 10:24:10 -07:00 committed by GitHub
parent cbac8a3888
commit ae192262ad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 385 additions and 159 deletions

View File

@ -81,6 +81,7 @@ struct _Py_interp_cached_objects {
PyTypeObject *paramspec_type; PyTypeObject *paramspec_type;
PyTypeObject *paramspecargs_type; PyTypeObject *paramspecargs_type;
PyTypeObject *paramspeckwargs_type; PyTypeObject *paramspeckwargs_type;
PyTypeObject *constevaluator_type;
}; };
#define _Py_INTERP_STATIC_OBJECT(interp, NAME) \ #define _Py_INTERP_STATIC_OBJECT(interp, NAME) \

View File

@ -16,6 +16,7 @@ extern PyObject *_Py_subscript_generic(PyThreadState *, PyObject *);
extern PyObject *_Py_set_typeparam_default(PyThreadState *, PyObject *, PyObject *); extern PyObject *_Py_set_typeparam_default(PyThreadState *, PyObject *, PyObject *);
extern int _Py_initialize_generic(PyInterpreterState *); extern int _Py_initialize_generic(PyInterpreterState *);
extern void _Py_clear_generic_types(PyInterpreterState *); extern void _Py_clear_generic_types(PyInterpreterState *);
extern int _Py_typing_type_repr(PyUnicodeWriter *, PyObject *);
extern PyTypeObject _PyTypeAlias_Type; extern PyTypeObject _PyTypeAlias_Type;
extern PyTypeObject _PyNoDefault_Type; extern PyTypeObject _PyNoDefault_Type;

View File

@ -413,7 +413,16 @@ class _StringifierDict(dict):
return fwdref return fwdref
def call_annotate_function(annotate, format, owner=None): def call_evaluate_function(evaluate, format, *, owner=None):
"""Call an evaluate function. Evaluate functions are normally generated for
the value of type aliases and the bounds, constraints, and defaults of
type parameter objects.
"""
return call_annotate_function(evaluate, format, owner=owner, _is_evaluate=True)
def call_annotate_function(annotate, format, *, owner=None,
_is_evaluate=False):
"""Call an __annotate__ function. __annotate__ functions are normally """Call an __annotate__ function. __annotate__ functions are normally
generated by the compiler to defer the evaluation of annotations. They generated by the compiler to defer the evaluation of annotations. They
can be called with any of the format arguments in the Format enum, but can be called with any of the format arguments in the Format enum, but
@ -459,8 +468,11 @@ def call_annotate_function(annotate, format, owner=None):
closure = tuple(new_closure) closure = tuple(new_closure)
else: else:
closure = None closure = None
func = types.FunctionType(annotate.__code__, globals, closure=closure) func = types.FunctionType(annotate.__code__, globals, closure=closure,
argdefs=annotate.__defaults__, kwdefaults=annotate.__kwdefaults__)
annos = func(Format.VALUE) annos = func(Format.VALUE)
if _is_evaluate:
return annos if isinstance(annos, str) else repr(annos)
return { return {
key: val if isinstance(val, str) else repr(val) key: val if isinstance(val, str) else repr(val)
for key, val in annos.items() for key, val in annos.items()
@ -511,7 +523,8 @@ def call_annotate_function(annotate, format, owner=None):
closure = tuple(new_closure) closure = tuple(new_closure)
else: else:
closure = None closure = None
func = types.FunctionType(annotate.__code__, globals, closure=closure) func = types.FunctionType(annotate.__code__, globals, closure=closure,
argdefs=annotate.__defaults__, kwdefaults=annotate.__kwdefaults__)
result = func(Format.VALUE) result = func(Format.VALUE)
for obj in globals.stringifiers: for obj in globals.stringifiers:
obj.__class__ = ForwardRef obj.__class__ = ForwardRef

View File

@ -773,6 +773,25 @@ class TestGetAnnotations(unittest.TestCase):
) )
class TestCallEvaluateFunction(unittest.TestCase):
def test_evaluation(self):
def evaluate(format, exc=NotImplementedError):
if format != 1:
raise exc
return undefined
with self.assertRaises(NameError):
annotationlib.call_evaluate_function(evaluate, annotationlib.Format.VALUE)
self.assertEqual(
annotationlib.call_evaluate_function(evaluate, annotationlib.Format.FORWARDREF),
annotationlib.ForwardRef("undefined"),
)
self.assertEqual(
annotationlib.call_evaluate_function(evaluate, annotationlib.Format.SOURCE),
"undefined",
)
class MetaclassTests(unittest.TestCase): class MetaclassTests(unittest.TestCase):
def test_annotated_meta(self): def test_annotated_meta(self):
class Meta(type): class Meta(type):

View File

@ -1,3 +1,4 @@
import annotationlib
import asyncio import asyncio
import textwrap import textwrap
import types import types
@ -6,7 +7,7 @@ import pickle
import weakref import weakref
from test.support import requires_working_socket, check_syntax_error, run_code from test.support import requires_working_socket, check_syntax_error, run_code
from typing import Generic, NoDefault, Sequence, TypeVar, TypeVarTuple, ParamSpec, get_args from typing import Generic, NoDefault, Sequence, TypeAliasType, TypeVar, TypeVarTuple, ParamSpec, get_args
class TypeParamsInvalidTest(unittest.TestCase): class TypeParamsInvalidTest(unittest.TestCase):
@ -1394,3 +1395,43 @@ class DefaultsTest(unittest.TestCase):
self.assertEqual(ns["X1"].__type_params__[0].__default__, "A") self.assertEqual(ns["X1"].__type_params__[0].__default__, "A")
self.assertEqual(ns["X2"].__type_params__[0].__default__, "B") self.assertEqual(ns["X2"].__type_params__[0].__default__, "B")
class TestEvaluateFunctions(unittest.TestCase):
def test_general(self):
type Alias = int
Alias2 = TypeAliasType("Alias2", int)
def f[T: int = int, **P = int, *Ts = int](): pass
T, P, Ts = f.__type_params__
T2 = TypeVar("T2", bound=int, default=int)
P2 = ParamSpec("P2", default=int)
Ts2 = TypeVarTuple("Ts2", default=int)
cases = [
Alias.evaluate_value,
Alias2.evaluate_value,
T.evaluate_bound,
T.evaluate_default,
P.evaluate_default,
Ts.evaluate_default,
T2.evaluate_bound,
T2.evaluate_default,
P2.evaluate_default,
Ts2.evaluate_default,
]
for case in cases:
with self.subTest(case=case):
self.assertIs(case(1), int)
self.assertIs(annotationlib.call_evaluate_function(case, annotationlib.Format.VALUE), int)
self.assertIs(annotationlib.call_evaluate_function(case, annotationlib.Format.FORWARDREF), int)
self.assertEqual(annotationlib.call_evaluate_function(case, annotationlib.Format.SOURCE), 'int')
def test_constraints(self):
def f[T: (int, str)](): pass
T, = f.__type_params__
T2 = TypeVar("T2", int, str)
for case in [T, T2]:
with self.subTest(case=case):
self.assertEqual(case.evaluate_constraints(1), (int, str))
self.assertEqual(annotationlib.call_evaluate_function(case.evaluate_constraints, annotationlib.Format.VALUE), (int, str))
self.assertEqual(annotationlib.call_evaluate_function(case.evaluate_constraints, annotationlib.Format.FORWARDREF), (int, str))
self.assertEqual(annotationlib.call_evaluate_function(case.evaluate_constraints, annotationlib.Format.SOURCE), '(int, str)')

View File

@ -0,0 +1,7 @@
As part of :pep:`749`, add the following attributes for customizing
evaluation of annotation scopes:
* ``evaluate_value`` on :class:`typing.TypeAliasType`
* ``evaluate_bound``, ``evaluate_constraints``, and ``evaluate_default`` on :class:`typing.TypeVar`
* ``evaluate_default`` on :class:`typing.ParamSpec`
* ``evaluate_default`` on :class:`typing.TypeVarTuple`

View File

@ -4,6 +4,7 @@
#include "pycore_ceval.h" // _PyEval_GetBuiltin() #include "pycore_ceval.h" // _PyEval_GetBuiltin()
#include "pycore_modsupport.h" // _PyArg_NoKeywords() #include "pycore_modsupport.h" // _PyArg_NoKeywords()
#include "pycore_object.h" #include "pycore_object.h"
#include "pycore_typevarobject.h" // _Py_typing_type_repr
#include "pycore_unionobject.h" // _Py_union_type_or, _PyGenericAlias_Check #include "pycore_unionobject.h" // _Py_union_type_or, _PyGenericAlias_Check
@ -50,69 +51,6 @@ ga_traverse(PyObject *self, visitproc visit, void *arg)
return 0; return 0;
} }
static int
ga_repr_item(PyUnicodeWriter *writer, PyObject *p)
{
PyObject *qualname = NULL;
PyObject *module = NULL;
int rc;
if (p == Py_Ellipsis) {
// The Ellipsis object
rc = PyUnicodeWriter_WriteUTF8(writer, "...", 3);
goto done;
}
if ((rc = PyObject_HasAttrWithError(p, &_Py_ID(__origin__))) > 0 &&
(rc = PyObject_HasAttrWithError(p, &_Py_ID(__args__))) > 0)
{
// It looks like a GenericAlias
goto use_repr;
}
if (rc < 0) {
goto error;
}
if (PyObject_GetOptionalAttr(p, &_Py_ID(__qualname__), &qualname) < 0) {
goto error;
}
if (qualname == NULL) {
goto use_repr;
}
if (PyObject_GetOptionalAttr(p, &_Py_ID(__module__), &module) < 0) {
goto error;
}
if (module == NULL || module == Py_None) {
goto use_repr;
}
// Looks like a class
if (PyUnicode_Check(module) &&
_PyUnicode_EqualToASCIIString(module, "builtins"))
{
// builtins don't need a module name
rc = PyUnicodeWriter_WriteStr(writer, qualname);
goto done;
}
else {
rc = PyUnicodeWriter_Format(writer, "%S.%S", module, qualname);
goto done;
}
error:
rc = -1;
goto done;
use_repr:
rc = PyUnicodeWriter_WriteRepr(writer, p);
goto done;
done:
Py_XDECREF(qualname);
Py_XDECREF(module);
return rc;
}
static int static int
ga_repr_items_list(PyUnicodeWriter *writer, PyObject *p) ga_repr_items_list(PyUnicodeWriter *writer, PyObject *p)
{ {
@ -131,7 +69,7 @@ ga_repr_items_list(PyUnicodeWriter *writer, PyObject *p)
} }
} }
PyObject *item = PyList_GET_ITEM(p, i); PyObject *item = PyList_GET_ITEM(p, i);
if (ga_repr_item(writer, item) < 0) { if (_Py_typing_type_repr(writer, item) < 0) {
return -1; return -1;
} }
} }
@ -162,7 +100,7 @@ ga_repr(PyObject *self)
goto error; goto error;
} }
} }
if (ga_repr_item(writer, alias->origin) < 0) { if (_Py_typing_type_repr(writer, alias->origin) < 0) {
goto error; goto error;
} }
if (PyUnicodeWriter_WriteChar(writer, '[') < 0) { if (PyUnicodeWriter_WriteChar(writer, '[') < 0) {
@ -181,7 +119,7 @@ ga_repr(PyObject *self)
goto error; goto error;
} }
} }
else if (ga_repr_item(writer, p) < 0) { else if (_Py_typing_type_repr(writer, p) < 0) {
goto error; goto error;
} }
} }

View File

@ -116,6 +116,201 @@ PyTypeObject _PyNoDefault_Type = {
PyObject _Py_NoDefaultStruct = _PyObject_HEAD_INIT(&_PyNoDefault_Type); PyObject _Py_NoDefaultStruct = _PyObject_HEAD_INIT(&_PyNoDefault_Type);
typedef struct {
PyObject_HEAD
PyObject *value;
} constevaluatorobject;
static void
constevaluator_dealloc(PyObject *self)
{
PyTypeObject *tp = Py_TYPE(self);
constevaluatorobject *ce = (constevaluatorobject *)self;
_PyObject_GC_UNTRACK(self);
Py_XDECREF(ce->value);
Py_TYPE(self)->tp_free(self);
Py_DECREF(tp);
}
static int
constevaluator_traverse(PyObject *self, visitproc visit, void *arg)
{
constevaluatorobject *ce = (constevaluatorobject *)self;
Py_VISIT(ce->value);
return 0;
}
static int
constevaluator_clear(PyObject *self)
{
Py_CLEAR(((constevaluatorobject *)self)->value);
return 0;
}
static PyObject *
constevaluator_repr(PyObject *self, PyObject *repr)
{
PyObject *value = ((constevaluatorobject *)self)->value;
return PyUnicode_FromFormat("<constevaluator %R>", value);
}
static PyObject *
constevaluator_call(PyObject *self, PyObject *args, PyObject *kwargs)
{
if (!_PyArg_NoKeywords("constevaluator.__call__", kwargs)) {
return NULL;
}
int format;
if (!PyArg_ParseTuple(args, "i:constevaluator.__call__", &format)) {
return NULL;
}
PyObject *value = ((constevaluatorobject *)self)->value;
if (format == 3) { // SOURCE
_PyUnicodeWriter writer;
_PyUnicodeWriter_Init(&writer);
if (PyTuple_Check(value)) {
if (_PyUnicodeWriter_WriteASCIIString(&writer, "(", 1) < 0) {
_PyUnicodeWriter_Dealloc(&writer);
return NULL;
}
for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(value); i++) {
PyObject *item = PyTuple_GET_ITEM(value, i);
if (i > 0) {
if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ", 2) < 0) {
_PyUnicodeWriter_Dealloc(&writer);
return NULL;
}
}
if (_Py_typing_type_repr(&writer, item) < 0) {
_PyUnicodeWriter_Dealloc(&writer);
return NULL;
}
}
if (_PyUnicodeWriter_WriteASCIIString(&writer, ")", 1) < 0) {
_PyUnicodeWriter_Dealloc(&writer);
return NULL;
}
}
else {
if (_Py_typing_type_repr(&writer, value) < 0) {
_PyUnicodeWriter_Dealloc(&writer);
return NULL;
}
}
return _PyUnicodeWriter_Finish(&writer);
}
return Py_NewRef(value);
}
static PyObject *
constevaluator_alloc(PyObject *value)
{
PyTypeObject *tp = _PyInterpreterState_GET()->cached_objects.constevaluator_type;
assert(tp != NULL);
constevaluatorobject *ce = PyObject_GC_New(constevaluatorobject, tp);
if (ce == NULL) {
return NULL;
}
ce->value = Py_NewRef(value);
_PyObject_GC_TRACK(ce);
return (PyObject *)ce;
}
PyDoc_STRVAR(constevaluator_doc,
"_ConstEvaluator()\n"
"--\n\n"
"Internal type for implementing evaluation functions.");
static PyType_Slot constevaluator_slots[] = {
{Py_tp_doc, (void *)constevaluator_doc},
{Py_tp_dealloc, constevaluator_dealloc},
{Py_tp_traverse, constevaluator_traverse},
{Py_tp_clear, constevaluator_clear},
{Py_tp_repr, constevaluator_repr},
{Py_tp_call, constevaluator_call},
{Py_tp_alloc, PyType_GenericAlloc},
{Py_tp_free, PyObject_GC_Del},
{0, NULL},
};
PyType_Spec constevaluator_spec = {
.name = "_typing._ConstEvaluator",
.basicsize = sizeof(constevaluatorobject),
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE,
.slots = constevaluator_slots,
};
int
_Py_typing_type_repr(PyUnicodeWriter *writer, PyObject *p)
{
PyObject *qualname = NULL;
PyObject *module = NULL;
PyObject *r = NULL;
int rc;
if (p == Py_Ellipsis) {
// The Ellipsis object
r = PyUnicode_FromString("...");
goto exit;
}
if (p == (PyObject *)&_PyNone_Type) {
return _PyUnicodeWriter_WriteASCIIString(writer, "None", 4);
}
if ((rc = PyObject_HasAttrWithError(p, &_Py_ID(__origin__))) > 0 &&
(rc = PyObject_HasAttrWithError(p, &_Py_ID(__args__))) > 0)
{
// It looks like a GenericAlias
goto use_repr;
}
if (rc < 0) {
goto exit;
}
if (PyObject_GetOptionalAttr(p, &_Py_ID(__qualname__), &qualname) < 0) {
goto exit;
}
if (qualname == NULL) {
goto use_repr;
}
if (PyObject_GetOptionalAttr(p, &_Py_ID(__module__), &module) < 0) {
goto exit;
}
if (module == NULL || module == Py_None) {
goto use_repr;
}
// Looks like a class
if (PyUnicode_Check(module) &&
_PyUnicode_EqualToASCIIString(module, "builtins"))
{
// builtins don't need a module name
r = PyObject_Str(qualname);
goto exit;
}
else {
r = PyUnicode_FromFormat("%S.%S", module, qualname);
goto exit;
}
use_repr:
r = PyObject_Repr(p);
exit:
Py_XDECREF(qualname);
Py_XDECREF(module);
if (r == NULL) {
return -1;
}
rc = _PyUnicodeWriter_WriteStr(writer, r);
Py_DECREF(r);
return rc;
}
static PyObject * static PyObject *
call_typing_func_object(const char *name, PyObject **args, size_t nargs) call_typing_func_object(const char *name, PyObject **args, size_t nargs)
@ -364,10 +559,49 @@ typevar_constraints(typevarobject *self, void *Py_UNUSED(ignored))
return constraints; return constraints;
} }
static PyObject *
typevar_evaluate_bound(typevarobject *self, void *Py_UNUSED(ignored))
{
if (self->evaluate_bound != NULL) {
return Py_NewRef(self->evaluate_bound);
}
if (self->bound != NULL) {
return constevaluator_alloc(self->bound);
}
Py_RETURN_NONE;
}
static PyObject *
typevar_evaluate_constraints(typevarobject *self, void *Py_UNUSED(ignored))
{
if (self->evaluate_constraints != NULL) {
return Py_NewRef(self->evaluate_constraints);
}
if (self->constraints != NULL) {
return constevaluator_alloc(self->constraints);
}
Py_RETURN_NONE;
}
static PyObject *
typevar_evaluate_default(typevarobject *self, void *Py_UNUSED(ignored))
{
if (self->evaluate_default != NULL) {
return Py_NewRef(self->evaluate_default);
}
if (self->default_value != NULL) {
return constevaluator_alloc(self->default_value);
}
Py_RETURN_NONE;
}
static PyGetSetDef typevar_getset[] = { static PyGetSetDef typevar_getset[] = {
{"__bound__", (getter)typevar_bound, NULL, NULL, NULL}, {"__bound__", (getter)typevar_bound, NULL, NULL, NULL},
{"__constraints__", (getter)typevar_constraints, NULL, NULL, NULL}, {"__constraints__", (getter)typevar_constraints, NULL, NULL, NULL},
{"__default__", (getter)typevar_default, NULL, NULL, NULL}, {"__default__", (getter)typevar_default, NULL, NULL, NULL},
{"evaluate_bound", (getter)typevar_evaluate_bound, NULL, NULL, NULL},
{"evaluate_constraints", (getter)typevar_evaluate_constraints, NULL, NULL, NULL},
{"evaluate_default", (getter)typevar_evaluate_default, NULL, NULL, NULL},
{0} {0}
}; };
@ -995,10 +1229,23 @@ paramspec_default(paramspecobject *self, void *unused)
return default_value; return default_value;
} }
static PyObject *
paramspec_evaluate_default(paramspecobject *self, void *unused)
{
if (self->evaluate_default != NULL) {
return Py_NewRef(self->evaluate_default);
}
if (self->default_value != NULL) {
return constevaluator_alloc(self->default_value);
}
Py_RETURN_NONE;
}
static PyGetSetDef paramspec_getset[] = { static PyGetSetDef paramspec_getset[] = {
{"args", (getter)paramspec_args, NULL, PyDoc_STR("Represents positional arguments."), NULL}, {"args", (getter)paramspec_args, NULL, PyDoc_STR("Represents positional arguments."), NULL},
{"kwargs", (getter)paramspec_kwargs, NULL, PyDoc_STR("Represents keyword 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}, {"__default__", (getter)paramspec_default, NULL, "The default value for this ParamSpec.", NULL},
{"evaluate_default", (getter)paramspec_evaluate_default, NULL, NULL, NULL},
{0}, {0},
}; };
@ -1437,8 +1684,21 @@ typevartuple_default(typevartupleobject *self, void *unused)
return default_value; return default_value;
} }
static PyObject *
typevartuple_evaluate_default(typevartupleobject *self, void *unused)
{
if (self->evaluate_default != NULL) {
return Py_NewRef(self->evaluate_default);
}
if (self->default_value != NULL) {
return constevaluator_alloc(self->default_value);
}
Py_RETURN_NONE;
}
static PyGetSetDef typevartuple_getset[] = { static PyGetSetDef typevartuple_getset[] = {
{"__default__", (getter)typevartuple_default, NULL, "The default value for this TypeVarTuple.", NULL}, {"__default__", (getter)typevartuple_default, NULL, "The default value for this TypeVarTuple.", NULL},
{"evaluate_default", (getter)typevartuple_evaluate_default, NULL, NULL, NULL},
{0}, {0},
}; };
@ -1584,6 +1844,17 @@ typealias_value(PyObject *self, void *unused)
return typealias_get_value(ta); return typealias_get_value(ta);
} }
static PyObject *
typealias_evaluate_value(PyObject *self, void *unused)
{
typealiasobject *ta = (typealiasobject *)self;
if (ta->compute_value != NULL) {
return Py_NewRef(ta->compute_value);
}
assert(ta->value != NULL);
return constevaluator_alloc(ta->value);
}
static PyObject * static PyObject *
typealias_parameters(PyObject *self, void *unused) typealias_parameters(PyObject *self, void *unused)
{ {
@ -1627,6 +1898,7 @@ static PyGetSetDef typealias_getset[] = {
{"__parameters__", typealias_parameters, (setter)NULL, NULL, NULL}, {"__parameters__", typealias_parameters, (setter)NULL, NULL, NULL},
{"__type_params__", typealias_type_params, (setter)NULL, NULL, NULL}, {"__type_params__", typealias_type_params, (setter)NULL, NULL, NULL},
{"__value__", typealias_value, (setter)NULL, NULL, NULL}, {"__value__", typealias_value, (setter)NULL, NULL, NULL},
{"evaluate_value", typealias_evaluate_value, (setter)NULL, NULL, NULL},
{"__module__", typealias_module, (setter)NULL, NULL, NULL}, {"__module__", typealias_module, (setter)NULL, NULL, NULL},
{0} {0}
}; };
@ -1952,6 +2224,7 @@ int _Py_initialize_generic(PyInterpreterState *interp)
MAKE_TYPE(paramspec); MAKE_TYPE(paramspec);
MAKE_TYPE(paramspecargs); MAKE_TYPE(paramspecargs);
MAKE_TYPE(paramspeckwargs); MAKE_TYPE(paramspeckwargs);
MAKE_TYPE(constevaluator);
#undef MAKE_TYPE #undef MAKE_TYPE
return 0; return 0;
} }
@ -1964,6 +2237,7 @@ void _Py_clear_generic_types(PyInterpreterState *interp)
Py_CLEAR(interp->cached_objects.paramspec_type); Py_CLEAR(interp->cached_objects.paramspec_type);
Py_CLEAR(interp->cached_objects.paramspecargs_type); Py_CLEAR(interp->cached_objects.paramspecargs_type);
Py_CLEAR(interp->cached_objects.paramspeckwargs_type); Py_CLEAR(interp->cached_objects.paramspeckwargs_type);
Py_CLEAR(interp->cached_objects.constevaluator_type);
} }
PyObject * PyObject *

View File

@ -1,11 +1,10 @@
// types.UnionType -- used to represent e.g. Union[int, str], int | str // types.UnionType -- used to represent e.g. Union[int, str], int | str
#include "Python.h" #include "Python.h"
#include "pycore_object.h" // _PyObject_GC_TRACK/UNTRACK #include "pycore_object.h" // _PyObject_GC_TRACK/UNTRACK
#include "pycore_typevarobject.h" // _PyTypeAlias_Type #include "pycore_typevarobject.h" // _PyTypeAlias_Type, _Py_typing_type_repr
#include "pycore_unionobject.h" #include "pycore_unionobject.h"
static PyObject *make_union(PyObject *); static PyObject *make_union(PyObject *);
@ -181,67 +180,6 @@ _Py_union_type_or(PyObject* self, PyObject* other)
return new_union; return new_union;
} }
static int
union_repr_item(PyUnicodeWriter *writer, PyObject *p)
{
PyObject *qualname = NULL;
PyObject *module = NULL;
int rc;
if (p == (PyObject *)&_PyNone_Type) {
return PyUnicodeWriter_WriteUTF8(writer, "None", 4);
}
if ((rc = PyObject_HasAttrWithError(p, &_Py_ID(__origin__))) > 0 &&
(rc = PyObject_HasAttrWithError(p, &_Py_ID(__args__))) > 0)
{
// It looks like a GenericAlias
goto use_repr;
}
if (rc < 0) {
goto error;
}
if (PyObject_GetOptionalAttr(p, &_Py_ID(__qualname__), &qualname) < 0) {
goto error;
}
if (qualname == NULL) {
goto use_repr;
}
if (PyObject_GetOptionalAttr(p, &_Py_ID(__module__), &module) < 0) {
goto error;
}
if (module == NULL || module == Py_None) {
goto use_repr;
}
// Looks like a class
if (PyUnicode_Check(module) &&
_PyUnicode_EqualToASCIIString(module, "builtins"))
{
// builtins don't need a module name
rc = PyUnicodeWriter_WriteStr(writer, qualname);
goto done;
}
else {
rc = PyUnicodeWriter_Format(writer, "%S.%S", module, qualname);
goto done;
}
error:
rc = -1;
goto done;
use_repr:
rc = PyUnicodeWriter_WriteRepr(writer, p);
goto done;
done:
Py_XDECREF(qualname);
Py_XDECREF(module);
return rc;
}
static PyObject * static PyObject *
union_repr(PyObject *self) union_repr(PyObject *self)
{ {
@ -260,7 +198,7 @@ union_repr(PyObject *self)
goto error; goto error;
} }
PyObject *p = PyTuple_GET_ITEM(alias->args, i); PyObject *p = PyTuple_GET_ITEM(alias->args, i);
if (union_repr_item(writer, p) < 0) { if (_Py_typing_type_repr(writer, p) < 0) {
goto error; goto error;
} }
} }

View File

@ -1978,8 +1978,9 @@ compiler_type_param_bound_or_default(struct compiler *c, expr_ty e,
identifier name, void *key, identifier name, void *key,
bool allow_starred) bool allow_starred)
{ {
if (compiler_enter_scope(c, name, COMPILER_SCOPE_ANNOTATIONS, PyObject *defaults = PyTuple_Pack(1, _PyLong_GetOne());
key, e->lineno, NULL) == -1) { ADDOP_LOAD_CONST_NEW(c, LOC(e), defaults);
if (compiler_setup_annotations_scope(c, LOC(e), key, name) == -1) {
return ERROR; return ERROR;
} }
if (allow_starred && e->kind == Starred_kind) { if (allow_starred && e->kind == Starred_kind) {
@ -1995,7 +1996,7 @@ compiler_type_param_bound_or_default(struct compiler *c, expr_ty e,
if (co == NULL) { if (co == NULL) {
return ERROR; return ERROR;
} }
if (compiler_make_closure(c, LOC(e), co, 0) < 0) { if (compiler_make_closure(c, LOC(e), co, MAKE_FUNCTION_DEFAULTS) < 0) {
Py_DECREF(co); Py_DECREF(co);
return ERROR; return ERROR;
} }
@ -2566,8 +2567,10 @@ compiler_typealias_body(struct compiler *c, stmt_ty s)
{ {
location loc = LOC(s); location loc = LOC(s);
PyObject *name = s->v.TypeAlias.name->v.Name.id; PyObject *name = s->v.TypeAlias.name->v.Name.id;
PyObject *defaults = PyTuple_Pack(1, _PyLong_GetOne());
ADDOP_LOAD_CONST_NEW(c, loc, defaults);
RETURN_IF_ERROR( RETURN_IF_ERROR(
compiler_enter_scope(c, name, COMPILER_SCOPE_FUNCTION, s, loc.lineno, NULL)); compiler_setup_annotations_scope(c, LOC(s), s, name));
/* Make None the first constant, so the evaluate function can't have a /* Make None the first constant, so the evaluate function can't have a
docstring. */ docstring. */
RETURN_IF_ERROR(compiler_add_const(c, Py_None)); RETURN_IF_ERROR(compiler_add_const(c, Py_None));
@ -2578,7 +2581,7 @@ compiler_typealias_body(struct compiler *c, stmt_ty s)
if (co == NULL) { if (co == NULL) {
return ERROR; return ERROR;
} }
if (compiler_make_closure(c, loc, co, 0) < 0) { if (compiler_make_closure(c, loc, co, MAKE_FUNCTION_DEFAULTS) < 0) {
Py_DECREF(co); Py_DECREF(co);
return ERROR; return ERROR;
} }

View File

@ -260,6 +260,7 @@ static int symtable_visit_pattern(struct symtable *st, pattern_ty s);
static int symtable_raise_if_annotation_block(struct symtable *st, const char *, expr_ty); static int symtable_raise_if_annotation_block(struct symtable *st, const char *, expr_ty);
static int symtable_raise_if_not_coroutine(struct symtable *st, const char *msg, _Py_SourceLocation loc); static int symtable_raise_if_not_coroutine(struct symtable *st, const char *msg, _Py_SourceLocation loc);
static int symtable_raise_if_comprehension_block(struct symtable *st, expr_ty); static int symtable_raise_if_comprehension_block(struct symtable *st, expr_ty);
static int symtable_add_def(struct symtable *st, PyObject *name, int flag, _Py_SourceLocation loc);
/* For debugging purposes only */ /* For debugging purposes only */
#if _PY_DUMP_SYMTABLE #if _PY_DUMP_SYMTABLE
@ -1388,6 +1389,16 @@ symtable_enter_block(struct symtable *st, identifier name, _Py_block_ty block,
return 0; return 0;
int result = symtable_enter_existing_block(st, ste); int result = symtable_enter_existing_block(st, ste);
Py_DECREF(ste); Py_DECREF(ste);
if (block == AnnotationBlock || block == TypeVariableBlock || block == TypeAliasBlock) {
_Py_DECLARE_STR(format, ".format");
// We need to insert code that reads this "parameter" to the function.
if (!symtable_add_def(st, &_Py_STR(format), DEF_PARAM, loc)) {
return 0;
}
if (!symtable_add_def(st, &_Py_STR(format), USE, loc)) {
return 0;
}
}
return result; return result;
} }
@ -2630,18 +2641,6 @@ symtable_visit_annotation(struct symtable *st, expr_ty annotation, void *key)
return 0; return 0;
} }
} }
_Py_DECLARE_STR(format, ".format");
// The generated __annotate__ function takes a single parameter with the
// internal name ".format".
if (!symtable_add_def(st, &_Py_STR(format), DEF_PARAM,
LOCATION(annotation))) {
return 0;
}
if (!symtable_add_def(st, &_Py_STR(format), USE,
LOCATION(annotation))) {
return 0;
}
} }
else { else {
if (!symtable_enter_existing_block(st, parent_ste->ste_annotation_block)) { if (!symtable_enter_existing_block(st, parent_ste->ste_annotation_block)) {
@ -2690,14 +2689,6 @@ symtable_visit_annotations(struct symtable *st, stmt_ty o, arguments_ty a, expr_
return 0; return 0;
} }
} }
_Py_DECLARE_STR(format, ".format");
// We need to insert code that reads this "parameter" to the function.
if (!symtable_add_def(st, &_Py_STR(format), DEF_PARAM, LOCATION(o))) {
return 0;
}
if (!symtable_add_def(st, &_Py_STR(format), USE, LOCATION(o))) {
return 0;
}
if (a->posonlyargs && !symtable_visit_argannotations(st, a->posonlyargs)) if (a->posonlyargs && !symtable_visit_argannotations(st, a->posonlyargs))
return 0; return 0;
if (a->args && !symtable_visit_argannotations(st, a->args)) if (a->args && !symtable_visit_argannotations(st, a->args))