]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-113317: Argument Clinic: Add libclinic.return_converters (#117451)
authorVictor Stinner <vstinner@python.org>
Tue, 2 Apr 2024 11:29:39 +0000 (13:29 +0200)
committerGitHub <noreply@github.com>
Tue, 2 Apr 2024 11:29:39 +0000 (11:29 +0000)
Move the following converter classes to libclinic.return_converters:

* CReturnConverter
* CReturnConverterAutoRegister
* Py_ssize_t_return_converter
* bool_return_converter
* double_return_converter
* float_return_converter
* int_return_converter
* long_return_converter
* size_t_return_converter
* unsigned_int_return_converter
* unsigned_long_return_converter

Move also the add_c_return_converter() function there.

Tools/clinic/clinic.py
Tools/clinic/libclinic/function.py
Tools/clinic/libclinic/return_converters.py [new file with mode: 0644]

index a4e004d5b124d104b57914e91f40851769558c71..97b1f46a13411beec8d1203d72da06ce14d65f3d 100755 (executable)
@@ -60,6 +60,9 @@ from libclinic.converter import (
 from libclinic.converters import (
     self_converter, defining_class_converter, object_converter, buffer,
     robuffer, rwbuffer, correct_name_for_self)
+from libclinic.return_converters import (
+    CReturnConverter, return_converters,
+    int_return_converter, ReturnConverterType)
 
 
 # TODO:
@@ -2088,186 +2091,6 @@ __xor__
 """.strip().split())
 
 
-ReturnConverterType = Callable[..., "CReturnConverter"]
-
-
-# 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 CReturnConverter object.
-# The callable should not call builtins.print.
-ReturnConverterDict = dict[str, ReturnConverterType]
-return_converters: ReturnConverterDict = {}
-
-
-def add_c_return_converter(
-        f: ReturnConverterType,
-        name: str | None = None
-) -> ReturnConverterType:
-    if not name:
-        name = f.__name__
-        if not name.endswith('_return_converter'):
-            return f
-        name = name.removesuffix('_return_converter')
-    return_converters[name] = f
-    return f
-
-
-class CReturnConverterAutoRegister(type):
-    def __init__(
-            cls: ReturnConverterType,
-            name: str,
-            bases: tuple[type[object], ...],
-            classdict: dict[str, Any]
-    ) -> None:
-        add_c_return_converter(cls)
-
-
-class CReturnConverter(metaclass=CReturnConverterAutoRegister):
-
-    # The C type to use for this variable.
-    # 'type' should be a Python string specifying the type, e.g. "int".
-    # If this is a pointer type, the type string should end with ' *'.
-    type = 'PyObject *'
-
-    # The Python default value for this parameter, as a Python value.
-    # Or the magic value "unspecified" if there is no default.
-    default: object = None
-
-    def __init__(
-            self,
-            *,
-            py_default: str | None = None,
-            **kwargs: Any
-    ) -> None:
-        self.py_default = py_default
-        try:
-            self.return_converter_init(**kwargs)
-        except TypeError as e:
-            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) -> None: ...
-
-    def declare(self, data: CRenderData) -> None:
-        line: list[str] = []
-        add = line.append
-        add(self.type)
-        if not self.type.endswith('*'):
-            add(' ')
-        add(data.converter_retval + ';')
-        data.declarations.append(''.join(line))
-        data.return_value = data.converter_retval
-
-    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: str,
-            data: CRenderData
-    ) -> None:
-        line = f'if ({variable} == NULL) {{\n    goto exit;\n}}\n'
-        data.return_conversion.append(line)
-
-    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: 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: 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 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'
-    unsigned_cast = '(size_t)'
-
-
-class double_return_converter(CReturnConverter):
-    type = 'double'
-    cast = ''
-
-    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)'
-
-
 def eval_ast_expr(
         node: ast.expr,
         *,
index b0dd08446e802d706ff0bf0738d9d25598c07869..1bfaad00cd0f08cbc5637567df601a42aeb52901 100644 (file)
@@ -6,9 +6,10 @@ import functools
 import inspect
 from typing import Final, Any, TYPE_CHECKING
 if TYPE_CHECKING:
-    from clinic import Clinic, CReturnConverter
+    from clinic import Clinic
     from libclinic.converter import CConverter
     from libclinic.converters import self_converter
+    from libclinic.return_converters import CReturnConverter
 
 from libclinic import VersionTuple, unspecified
 
diff --git a/Tools/clinic/libclinic/return_converters.py b/Tools/clinic/libclinic/return_converters.py
new file mode 100644 (file)
index 0000000..7bdd257
--- /dev/null
@@ -0,0 +1,173 @@
+import sys
+from collections.abc import Callable
+from libclinic.crenderdata import CRenderData
+from libclinic.function import Function
+from typing import Any
+
+
+ReturnConverterType = Callable[..., "CReturnConverter"]
+
+
+# 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 CReturnConverter object.
+# The callable should not call builtins.print.
+ReturnConverterDict = dict[str, ReturnConverterType]
+return_converters: ReturnConverterDict = {}
+
+
+def add_c_return_converter(
+    f: ReturnConverterType,
+    name: str | None = None
+) -> ReturnConverterType:
+    if not name:
+        name = f.__name__
+        if not name.endswith('_return_converter'):
+            return f
+        name = name.removesuffix('_return_converter')
+    return_converters[name] = f
+    return f
+
+
+class CReturnConverterAutoRegister(type):
+    def __init__(
+        cls: ReturnConverterType,
+        name: str,
+        bases: tuple[type[object], ...],
+        classdict: dict[str, Any]
+    ) -> None:
+        add_c_return_converter(cls)
+
+
+class CReturnConverter(metaclass=CReturnConverterAutoRegister):
+
+    # The C type to use for this variable.
+    # 'type' should be a Python string specifying the type, e.g. "int".
+    # If this is a pointer type, the type string should end with ' *'.
+    type = 'PyObject *'
+
+    # The Python default value for this parameter, as a Python value.
+    # Or the magic value "unspecified" if there is no default.
+    default: object = None
+
+    def __init__(
+        self,
+        *,
+        py_default: str | None = None,
+        **kwargs: Any
+    ) -> None:
+        self.py_default = py_default
+        try:
+            self.return_converter_init(**kwargs)
+        except TypeError as e:
+            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) -> None: ...
+
+    def declare(self, data: CRenderData) -> None:
+        line: list[str] = []
+        add = line.append
+        add(self.type)
+        if not self.type.endswith('*'):
+            add(' ')
+        add(data.converter_retval + ';')
+        data.declarations.append(''.join(line))
+        data.return_value = data.converter_retval
+
+    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: str,
+        data: CRenderData
+    ) -> None:
+        line = f'if ({variable} == NULL) {{\n    goto exit;\n}}\n'
+        data.return_conversion.append(line)
+
+    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: 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: 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 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'
+    unsigned_cast = '(size_t)'
+
+
+class double_return_converter(CReturnConverter):
+    type = 'double'
+    cast = ''
+
+    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)'