]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-104683: Make Argument Clinic template strings class level members (#107556)
authorErlend E. Aasland <erlend@python.org>
Wed, 2 Aug 2023 19:37:36 +0000 (21:37 +0200)
committerGitHub <noreply@github.com>
Wed, 2 Aug 2023 19:37:36 +0000 (21:37 +0200)
The motivation for this change is to clean up the output_templates()
method a little bit, as it accounts for ~10% of the lines of code in
clinic.py; removing some clutter helps readability.

Tools/clinic/clinic.py

index 1f461665003c8155007ac6effa66349b786cb739..ce8184753c72922aa7960a95a82b8841a551b5d8 100755 (executable)
@@ -760,6 +760,59 @@ class CLanguage(Language):
     stop_line     = "[{dsl_name} start generated code]*/"
     checksum_line = "/*[{dsl_name} end generated code: {arguments}]*/"
 
+    PARSER_PROTOTYPE_KEYWORD: Final[str] = normalize_snippet("""
+        static PyObject *
+        {c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs)
+    """)
+    PARSER_PROTOTYPE_KEYWORD___INIT__: Final[str] = normalize_snippet("""
+        static int
+        {c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs)
+    """)
+    PARSER_PROTOTYPE_VARARGS: Final[str] = normalize_snippet("""
+        static PyObject *
+        {c_basename}({self_type}{self_name}, PyObject *args)
+    """)
+    PARSER_PROTOTYPE_FASTCALL: Final[str] = normalize_snippet("""
+        static PyObject *
+        {c_basename}({self_type}{self_name}, PyObject *const *args, Py_ssize_t nargs)
+    """)
+    PARSER_PROTOTYPE_FASTCALL_KEYWORDS: Final[str] = normalize_snippet("""
+        static PyObject *
+        {c_basename}({self_type}{self_name}, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+    """)
+    PARSER_PROTOTYPE_DEF_CLASS: Final[str] = normalize_snippet("""
+        static PyObject *
+        {c_basename}({self_type}{self_name}, PyTypeObject *{defining_class_name}, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+    """)
+    PARSER_PROTOTYPE_NOARGS: Final[str] = normalize_snippet("""
+        static PyObject *
+        {c_basename}({self_type}{self_name}, PyObject *Py_UNUSED(ignored))
+    """)
+    METH_O_PROTOTYPE: Final[str] = normalize_snippet("""
+        static PyObject *
+        {c_basename}({impl_parameters})
+    """)
+    DOCSTRING_PROTOTYPE_VAR: Final[str] = normalize_snippet("""
+        PyDoc_VAR({c_basename}__doc__);
+    """)
+    DOCSTRING_PROTOTYPE_STRVAR: Final[str] = normalize_snippet("""
+        PyDoc_STRVAR({c_basename}__doc__,
+        {docstring});
+    """)
+    IMPL_DEFINITION_PROTOTYPE: Final[str] = normalize_snippet("""
+        static {impl_return_type}
+        {c_basename}_impl({impl_parameters})
+    """)
+    METHODDEF_PROTOTYPE_DEFINE: Final[str] = normalize_snippet(r"""
+        #define {methoddef_name}    \
+            {{"{name}", {methoddef_cast}{c_basename}{methoddef_cast_end}, {methoddef_flags}, {c_basename}__doc__}},
+    """)
+    METHODDEF_PROTOTYPE_IFNDEF: Final[str] = normalize_snippet("""
+        #ifndef {methoddef_name}
+            #define {methoddef_name}
+        #endif /* !defined({methoddef_name}) */
+    """)
+
     def __init__(self, filename: str) -> None:
         super().__init__(filename)
         self.cpp = cpp.Monitor(filename)
@@ -862,52 +915,15 @@ class CLanguage(Language):
         # methoddef_ifndef
 
         return_value_declaration = "PyObject *return_value = NULL;"
-
-        methoddef_define = normalize_snippet("""
-            #define {methoddef_name}    \\
-                {{"{name}", {methoddef_cast}{c_basename}{methoddef_cast_end}, {methoddef_flags}, {c_basename}__doc__}},
-            """)
+        methoddef_define = self.METHODDEF_PROTOTYPE_DEFINE
         if new_or_init and not f.docstring:
             docstring_prototype = docstring_definition = ''
         else:
-            docstring_prototype = normalize_snippet("""
-                PyDoc_VAR({c_basename}__doc__);
-                """)
-            docstring_definition = normalize_snippet("""
-                PyDoc_STRVAR({c_basename}__doc__,
-                {docstring});
-                """)
-        impl_definition = normalize_snippet("""
-            static {impl_return_type}
-            {c_basename}_impl({impl_parameters})
-            """)
+            docstring_prototype = self.DOCSTRING_PROTOTYPE_VAR
+            docstring_definition = self.DOCSTRING_PROTOTYPE_STRVAR
+        impl_definition = self.IMPL_DEFINITION_PROTOTYPE
         impl_prototype = parser_prototype = parser_definition = None
 
-        parser_prototype_keyword = normalize_snippet("""
-            static PyObject *
-            {c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs)
-            """)
-
-        parser_prototype_varargs = normalize_snippet("""
-            static PyObject *
-            {c_basename}({self_type}{self_name}, PyObject *args)
-            """)
-
-        parser_prototype_fastcall = normalize_snippet("""
-            static PyObject *
-            {c_basename}({self_type}{self_name}, PyObject *const *args, Py_ssize_t nargs)
-            """)
-
-        parser_prototype_fastcall_keywords = normalize_snippet("""
-            static PyObject *
-            {c_basename}({self_type}{self_name}, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
-            """)
-
-        parser_prototype_def_class = normalize_snippet("""
-            static PyObject *
-            {c_basename}({self_type}{self_name}, PyTypeObject *{defining_class_name}, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
-        """)
-
         # parser_body_fields remembers the fields passed in to the
         # previous call to parser_body. this is used for an awful hack.
         parser_body_fields: tuple[str, ...] = ()
@@ -950,19 +966,13 @@ class CLanguage(Language):
             if not requires_defining_class:
                 # no parameters, METH_NOARGS
                 flags = "METH_NOARGS"
-
-                parser_prototype = normalize_snippet("""
-                    static PyObject *
-                    {c_basename}({self_type}{self_name}, PyObject *Py_UNUSED(ignored))
-                    """)
+                parser_prototype = self.PARSER_PROTOTYPE_NOARGS
                 parser_code = []
-
             else:
                 assert not new_or_init
 
                 flags = "METH_METHOD|METH_FASTCALL|METH_KEYWORDS"
-
-                parser_prototype = parser_prototype_def_class
+                parser_prototype = self.PARSER_PROTOTYPE_DEF_CLASS
                 return_error = ('return NULL;' if default_return_converter
                                 else 'goto exit;')
                 parser_code = [normalize_snippet("""
@@ -987,10 +997,7 @@ class CLanguage(Language):
 
             if (isinstance(converters[0], object_converter) and
                 converters[0].format_unit == 'O'):
-                meth_o_prototype = normalize_snippet("""
-                    static PyObject *
-                    {c_basename}({impl_parameters})
-                    """)
+                meth_o_prototype = self.METH_O_PROTOTYPE
 
                 if default_return_converter:
                     # maps perfectly to METH_O, doesn't need a return converter.
@@ -1030,8 +1037,7 @@ class CLanguage(Language):
             #  in a big switch statement)
 
             flags = "METH_VARARGS"
-            parser_prototype = parser_prototype_varargs
-
+            parser_prototype = self.PARSER_PROTOTYPE_VARARGS
             parser_definition = parser_body(parser_prototype, '    {option_group_parsing}')
 
         elif not requires_defining_class and pos_only == len(parameters) - pseudo_args:
@@ -1040,7 +1046,7 @@ class CLanguage(Language):
                 # we only need one call to _PyArg_ParseStack
 
                 flags = "METH_FASTCALL"
-                parser_prototype = parser_prototype_fastcall
+                parser_prototype = self.PARSER_PROTOTYPE_FASTCALL
                 nargs = 'nargs'
                 argname_fmt = 'args[%d]'
             else:
@@ -1048,7 +1054,7 @@ class CLanguage(Language):
                 # we only need one call to PyArg_ParseTuple
 
                 flags = "METH_VARARGS"
-                parser_prototype = parser_prototype_varargs
+                parser_prototype = self.PARSER_PROTOTYPE_VARARGS
                 nargs = 'PyTuple_GET_SIZE(args)'
                 argname_fmt = 'PyTuple_GET_ITEM(args, %d)'
 
@@ -1145,7 +1151,7 @@ class CLanguage(Language):
                 nargs = f"Py_MIN(nargs, {max_pos})" if max_pos else "0"
             if not new_or_init:
                 flags = "METH_FASTCALL|METH_KEYWORDS"
-                parser_prototype = parser_prototype_fastcall_keywords
+                parser_prototype = self.PARSER_PROTOTYPE_FASTCALL_KEYWORDS
                 argname_fmt = 'args[%d]'
                 declarations = declare_parser(f)
                 declarations += "\nPyObject *argsbuf[%s];" % len(converters)
@@ -1160,7 +1166,7 @@ class CLanguage(Language):
             else:
                 # positional-or-keyword arguments
                 flags = "METH_VARARGS|METH_KEYWORDS"
-                parser_prototype = parser_prototype_keyword
+                parser_prototype = self.PARSER_PROTOTYPE_KEYWORD
                 argname_fmt = 'fastargs[%d]'
                 declarations = declare_parser(f)
                 declarations += "\nPyObject *argsbuf[%s];" % len(converters)
@@ -1177,7 +1183,7 @@ class CLanguage(Language):
 
             if requires_defining_class:
                 flags = 'METH_METHOD|' + flags
-                parser_prototype = parser_prototype_def_class
+                parser_prototype = self.PARSER_PROTOTYPE_DEF_CLASS
 
             add_label: str | None = None
             for i, p in enumerate(parameters):
@@ -1264,13 +1270,10 @@ class CLanguage(Language):
             methoddef_define = ''
 
             if f.kind is METHOD_NEW:
-                parser_prototype = parser_prototype_keyword
+                parser_prototype = self.PARSER_PROTOTYPE_KEYWORD
             else:
                 return_value_declaration = "int return_value = -1;"
-                parser_prototype = normalize_snippet("""
-                    static int
-                    {c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs)
-                    """)
+                parser_prototype = self.PARSER_PROTOTYPE_KEYWORD___INIT__
 
             fields = list(parser_body_fields)
             parses_positional = 'METH_NOARGS' not in flags
@@ -1323,12 +1326,7 @@ class CLanguage(Language):
 
             if methoddef_define and f.full_name not in clinic.ifndef_symbols:
                 clinic.ifndef_symbols.add(f.full_name)
-                methoddef_ifndef = normalize_snippet("""
-                    #ifndef {methoddef_name}
-                        #define {methoddef_name}
-                    #endif /* !defined({methoddef_name}) */
-                    """)
-
+                methoddef_ifndef = self.METHODDEF_PROTOTYPE_IFNDEF
 
         # add ';' to the end of parser_prototype and impl_prototype
         # (they mustn't be None, but they could be an empty string.)