From 878feadcc867a817abca15b23c83c85b800ea8ba Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sat, 20 May 2023 23:49:40 +0200 Subject: [PATCH 1/3] gh-104050: Annotate Argument Clinic return converters --- Tools/clinic/clinic.py | 103 +++++++++++++++++++++++++++++------------ 1 file changed, 73 insertions(+), 30 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 41e08d15436b11..f9fac95b9cbe6d 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -1966,15 +1966,6 @@ def dump(self): extensions['py'] = PythonLanguage -# maps strings to callables. -# these callables must be of the form: -# def foo(*, ...) -# The callable may have any number of keyword-only parameters. -# The callable must return a CConverter object. -# The callable should not call builtins.print. -return_converters = {} - - def file_changed(filename: str, new_contents: str) -> bool: """Return true if file contents changed (meaning we must update it)""" try: @@ -3005,6 +2996,14 @@ def parser_name(self): # note however that they will never be called with keyword-only parameters. legacy_converters: ConverterDict = {} +# maps strings to callables. +# these callables must be of the form: +# def foo(*, ...) +# The callable may have any number of keyword-only parameters. +# The callable must return a CConverter object. +# The callable should not call builtins.print. +return_converters: ConverterDict = {} + TypeSet = set[bltns.type[Any]] @@ -3966,8 +3965,10 @@ def set_template_dict(self, template_dict): template_dict['base_type_ptr'] = type_ptr - -def add_c_return_converter(f, name=None): +def add_c_return_converter( + f: type, + name: str | None = None +) -> ConverterType: if not name: name = f.__name__ if not name.endswith('_return_converter'): @@ -3978,9 +3979,15 @@ def add_c_return_converter(f, name=None): class CReturnConverterAutoRegister(type): - def __init__(cls, name, bases, classdict): + def __init__( + cls, + name: str, + bases: tuple[type, ...], + classdict: dict[Any, Any] + ) -> None: add_c_return_converter(cls) + class CReturnConverter(metaclass=CReturnConverterAutoRegister): # The C type to use for this variable. @@ -3992,7 +3999,12 @@ class CReturnConverter(metaclass=CReturnConverterAutoRegister): # Or the magic value "unspecified" if there is no default. default: object = None - def __init__(self, *, py_default=None, **kwargs): + def __init__( + self, + *, + py_default: str | None = None, + **kwargs + ) -> None: self.py_default = py_default try: self.return_converter_init(**kwargs) @@ -4000,11 +4012,10 @@ def __init__(self, *, py_default=None, **kwargs): s = ', '.join(name + '=' + repr(value) for name, value in kwargs.items()) sys.exit(self.__class__.__name__ + '(' + s + ')\n' + str(e)) - def return_converter_init(self): - pass + def return_converter_init(self) -> None: ... - def declare(self, data): - line = [] + def declare(self, data: CRenderData) -> None: + line: list[str] = [] add = line.append add(self.type) if not self.type.endswith('*'): @@ -4013,50 +4024,70 @@ def declare(self, data): data.declarations.append(''.join(line)) data.return_value = data.converter_retval - def err_occurred_if(self, expr, data): + def err_occurred_if( + self, + expr: str, + data: CRenderData + ) -> None: line = f'if (({expr}) && PyErr_Occurred()) {{\n goto exit;\n}}\n' data.return_conversion.append(line) - def err_occurred_if_null_pointer(self, variable, data): + def err_occurred_if_null_pointer( + self, + variable: str, + data: CRenderData + ) -> None: line = f'if ({variable} == NULL) {{\n goto exit;\n}}\n' data.return_conversion.append(line) - def render(self, function, data): - """ - function is a clinic.Function instance. - data is a CRenderData instance. - """ - pass + def render( + self, + function: Function, + data: CRenderData + ) -> None: ... + add_c_return_converter(CReturnConverter, 'object') + class bool_return_converter(CReturnConverter): type = 'int' - def render(self, function, data): + def render( + self, + function: Function, + data: CRenderData + ) -> None: self.declare(data) self.err_occurred_if(f"{data.converter_retval} == -1", data) data.return_conversion.append( f'return_value = PyBool_FromLong((long){data.converter_retval});\n' ) + class long_return_converter(CReturnConverter): type = 'long' conversion_fn = 'PyLong_FromLong' cast = '' unsigned_cast = '' - def render(self, function, data): + def render( + self, + function: Function, + data: CRenderData + ) -> None: self.declare(data) self.err_occurred_if(f"{data.converter_retval} == {self.unsigned_cast}-1", data) data.return_conversion.append( f'return_value = {self.conversion_fn}({self.cast}{data.converter_retval});\n' ) + class int_return_converter(long_return_converter): type = 'int' cast = '(long)' + class init_return_converter(long_return_converter): """ Special return converter for __init__ functions. @@ -4064,23 +4095,30 @@ class init_return_converter(long_return_converter): type = 'int' cast = '(long)' - def render(self, function, data): - pass + def render( + self, + function: Function, + data: CRenderData + ) -> None: ... + class unsigned_long_return_converter(long_return_converter): type = 'unsigned long' conversion_fn = 'PyLong_FromUnsignedLong' unsigned_cast = '(unsigned long)' + class unsigned_int_return_converter(unsigned_long_return_converter): type = 'unsigned int' cast = '(unsigned long)' unsigned_cast = '(unsigned int)' + class Py_ssize_t_return_converter(long_return_converter): type = 'Py_ssize_t' conversion_fn = 'PyLong_FromSsize_t' + class size_t_return_converter(long_return_converter): type = 'size_t' conversion_fn = 'PyLong_FromSize_t' @@ -4091,13 +4129,18 @@ class double_return_converter(CReturnConverter): type = 'double' cast = '' - def render(self, function, data): + def render( + self, + function: Function, + data: CRenderData + ) -> None: self.declare(data) self.err_occurred_if(f"{data.converter_retval} == -1.0", data) data.return_conversion.append( f'return_value = PyFloat_FromDouble({self.cast}{data.converter_retval});\n' ) + class float_return_converter(double_return_converter): type = 'float' cast = '(double)' From 4400586b38fe598dc61363a4a489429b7cacbfde Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sun, 21 May 2023 20:53:54 +0200 Subject: [PATCH 2/3] Address review --- Tools/clinic/clinic.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 50d8c1f2e2bb62..1addf29d163d51 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -3000,9 +3000,11 @@ def parser_name(self): # these callables must be of the form: # def foo(*, ...) # The callable may have any number of keyword-only parameters. -# The callable must return a CConverter object. +# The callable must return a CReturnConverter object. # The callable should not call builtins.print. -return_converters: ConverterDict = {} +ReturnConverterType = Callable[..., "CReturnConverter"] +ReturnConverterDict = dict[str, ReturnConverterType] +return_converters: ReturnConverterDict = {} TypeSet = set[bltns.type[Any]] @@ -3966,9 +3968,9 @@ def set_template_dict(self, template_dict): def add_c_return_converter( - f: type, + f: ReturnConverterType, name: str | None = None -) -> ConverterType: +) -> ReturnConverterType: if not name: name = f.__name__ if not name.endswith('_return_converter'): @@ -3980,7 +3982,7 @@ def add_c_return_converter( class CReturnConverterAutoRegister(type): def __init__( - cls, + cls: ReturnConverterType, name: str, bases: tuple[type, ...], classdict: dict[Any, Any] From 61d6bb0cc091b4aff9227eb027c4aa4acf6558e9 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sun, 21 May 2023 21:56:12 +0200 Subject: [PATCH 3/3] Update Tools/clinic/clinic.py Co-authored-by: Alex Waygood --- Tools/clinic/clinic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 1addf29d163d51..a1e8947529a0d4 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -3985,7 +3985,7 @@ def __init__( cls: ReturnConverterType, name: str, bases: tuple[type, ...], - classdict: dict[Any, Any] + classdict: dict[str, Any] ) -> None: add_c_return_converter(cls)