From f76867841e7bf6e53371bd1aaaf309a227c60367 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Tue, 24 Sep 2024 11:55:46 -0700 Subject: [PATCH 1/2] gh-119180: Rename parameter to __annotate__ functions Larry Hastings pointed out that using an illegal parameter name makes it impossible to use inspect.signature() on annotate functions. Cross-ref python/peps#3993. --- .../internal/pycore_global_objects_fini_generated.h | 1 - Include/internal/pycore_global_strings.h | 1 - Include/internal/pycore_runtime_init_generated.h | 1 - Include/internal/pycore_unicodeobject_generated.h | 4 ---- Lib/test/test_type_annotations.py | 12 ++++++++++++ Python/codegen.c | 3 +-- Python/symtable.c | 5 ++--- 7 files changed, 15 insertions(+), 12 deletions(-) diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index 6e948e16b7dbe8..b65fde3841c38b 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -557,7 +557,6 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(defaults)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(dot_locals)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(empty)); - _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(format)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(generic_base)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(json_decoder)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(kwdefaults)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 5c63a6e519b93d..5af986edd476c8 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -43,7 +43,6 @@ struct _Py_global_strings { STRUCT_FOR_STR(defaults, ".defaults") STRUCT_FOR_STR(dot_locals, ".") STRUCT_FOR_STR(empty, "") - STRUCT_FOR_STR(format, ".format") STRUCT_FOR_STR(generic_base, ".generic_base") STRUCT_FOR_STR(json_decoder, "json.decoder") STRUCT_FOR_STR(kwdefaults, ".kwdefaults") diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index bac6b5b8fcfd9d..06a9b4f72e4c03 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -552,7 +552,6 @@ extern "C" { INIT_STR(defaults, ".defaults"), \ INIT_STR(dot_locals, "."), \ INIT_STR(empty, ""), \ - INIT_STR(format, ".format"), \ INIT_STR(generic_base, ".generic_base"), \ INIT_STR(json_decoder, "json.decoder"), \ INIT_STR(kwdefaults, ".kwdefaults"), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index efdbde4c8ea3c6..5d7ed197f634de 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -2912,10 +2912,6 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); - string = &_Py_STR(format); - _PyUnicode_InternStatic(interp, &string); - assert(_PyUnicode_CheckConsistency(string, 1)); - assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_STR(generic_base); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); diff --git a/Lib/test/test_type_annotations.py b/Lib/test/test_type_annotations.py index 91082e6b23c04b..793152cd161c02 100644 --- a/Lib/test/test_type_annotations.py +++ b/Lib/test/test_type_annotations.py @@ -1,4 +1,5 @@ import annotationlib +import inspect import textwrap import types import unittest @@ -266,6 +267,17 @@ def check_annotations(self, f): f.__annotations__ = {"z": 43} self.assertIs(f.__annotate__, None) + def test_annotate_function_signature(self): + def f(x: int): pass + anno = f.__annotate__ + self.assertIsInstance(anno, types.FunctionType) + self.assertEqual(f.__name__, "__annotate__") + + expected_sig = inspect.Signature( + [inspect.Parameter("__format__", inspect.Parameter.POSITIONAL_ONLY)] + ) + self.assertEqual(inspect.signature(anno), expected_sig) + class DeferredEvaluationTests(unittest.TestCase): def test_function(self): diff --git a/Python/codegen.c b/Python/codegen.c index 0305f4299aec56..e40cdeaff6dada 100644 --- a/Python/codegen.c +++ b/Python/codegen.c @@ -655,8 +655,7 @@ codegen_setup_annotations_scope(compiler *c, location loc, codegen_enter_scope(c, name, COMPILE_SCOPE_ANNOTATIONS, key, loc.lineno, NULL, &umd)); - // if .format != 1: raise NotImplementedError - _Py_DECLARE_STR(format, ".format"); + // if __format__ != 1: raise NotImplementedError ADDOP_I(c, loc, LOAD_FAST, 0); ADDOP_LOAD_CONST(c, loc, _PyLong_GetOne()); ADDOP_I(c, loc, COMPARE_OP, (Py_NE << 5) | compare_masks[Py_NE]); diff --git a/Python/symtable.c b/Python/symtable.c index 8bc9db6d7d6811..6292e6dbbdba4b 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -1427,12 +1427,11 @@ symtable_enter_block(struct symtable *st, identifier name, _Py_block_ty block, int result = symtable_enter_existing_block(st, 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)) { + if (!symtable_add_def(st, &_Py_ID(__format__), DEF_PARAM, loc)) { return 0; } - if (!symtable_add_def(st, &_Py_STR(format), USE, loc)) { + if (!symtable_add_def(st, &_Py_ID(__format__), USE, loc)) { return 0; } } From 06a17dbcec6a13eac24f64337bef8ba4dd9aac63 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Tue, 24 Sep 2024 13:37:50 -0700 Subject: [PATCH 2/2] fix tests --- Lib/test/test_pydoc/test_pydoc.py | 4 ++-- Lib/test/test_type_annotations.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_pydoc/test_pydoc.py b/Lib/test/test_pydoc/test_pydoc.py index 2dba077cdea6a7..441bfcd1d0c756 100644 --- a/Lib/test/test_pydoc/test_pydoc.py +++ b/Lib/test/test_pydoc/test_pydoc.py @@ -79,7 +79,7 @@ class A(builtins.object) class B(builtins.object) | Methods defined here: | - | __annotate__(...) + | __annotate__(__format__, /) | | ---------------------------------------------------------------------- | Data descriptors defined here: @@ -180,7 +180,7 @@ class A(builtins.object) class B(builtins.object) Methods defined here: - __annotate__(...) + __annotate__(__format__, /) ---------------------------------------------------------------------- Data descriptors defined here: __dict__ diff --git a/Lib/test/test_type_annotations.py b/Lib/test/test_type_annotations.py index 793152cd161c02..a40a9fde67ebc1 100644 --- a/Lib/test/test_type_annotations.py +++ b/Lib/test/test_type_annotations.py @@ -271,7 +271,7 @@ def test_annotate_function_signature(self): def f(x: int): pass anno = f.__annotate__ self.assertIsInstance(anno, types.FunctionType) - self.assertEqual(f.__name__, "__annotate__") + self.assertEqual(anno.__name__, "__annotate__") expected_sig = inspect.Signature( [inspect.Parameter("__format__", inspect.Parameter.POSITIONAL_ONLY)]