diff options
author | Erlend E. Aasland <erlend@python.org> | 2024-04-10 08:12:05 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-04-10 08:12:05 (GMT) |
commit | 0d42ac9474f857633d00b414c0715f4efa73f1ca (patch) | |
tree | 96a3f6f4b4e7ed544d07b547ddf51b8cc5853acd | |
parent | 73906d5c908c1e0b73c5436faeff7d93698fc074 (diff) | |
download | cpython-0d42ac9474f857633d00b414c0715f4efa73f1ca.zip cpython-0d42ac9474f857633d00b414c0715f4efa73f1ca.tar.gz cpython-0d42ac9474f857633d00b414c0715f4efa73f1ca.tar.bz2 |
gh-117431: Argument Clinic: copy forced text signature when cloning (#117591)
-rw-r--r-- | Lib/test/test_clinic.py | 57 | ||||
-rw-r--r-- | Objects/clinic/unicodeobject.c.h | 10 | ||||
-rw-r--r-- | Tools/clinic/libclinic/dsl_parser.py | 12 | ||||
-rw-r--r-- | Tools/clinic/libclinic/function.py | 1 |
4 files changed, 70 insertions, 10 deletions
diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index a5887cd..e3ba3d9 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -5,7 +5,7 @@ from functools import partial from test import support, test_tools from test.support import os_helper -from test.support.os_helper import TESTFN, unlink +from test.support.os_helper import TESTFN, unlink, rmtree from textwrap import dedent from unittest import TestCase import inspect @@ -662,6 +662,61 @@ class ClinicWholeFileTest(TestCase): err = "Illegal C basename: '.illegal.'" self.expect_failure(block, err, lineno=7) + def test_cloned_forced_text_signature(self): + block = dedent(""" + /*[clinic input] + @text_signature "($module, a[, b])" + src + a: object + param a + b: object = NULL + / + + docstring + [clinic start generated code]*/ + + /*[clinic input] + dst = src + [clinic start generated code]*/ + """) + self.clinic.parse(block) + self.addCleanup(rmtree, "clinic") + funcs = self.clinic.functions + self.assertEqual(len(funcs), 2) + + src_docstring_lines = funcs[0].docstring.split("\n") + dst_docstring_lines = funcs[1].docstring.split("\n") + + # Signatures are copied. + self.assertEqual(src_docstring_lines[0], "src($module, a[, b])") + self.assertEqual(dst_docstring_lines[0], "dst($module, a[, b])") + + # Param docstrings are copied. + self.assertIn(" param a", src_docstring_lines) + self.assertIn(" param a", dst_docstring_lines) + + # Docstrings are not copied. + self.assertIn("docstring", src_docstring_lines) + self.assertNotIn("docstring", dst_docstring_lines) + + def test_cloned_forced_text_signature_illegal(self): + block = """ + /*[clinic input] + @text_signature "($module, a[, b])" + src + a: object + b: object = NULL + / + [clinic start generated code]*/ + + /*[clinic input] + @text_signature "($module, a_override[, b])" + dst = src + [clinic start generated code]*/ + """ + err = "Cannot use @text_signature when cloning a function" + self.expect_failure(block, err, lineno=11) + class ParseFileUnitTest(TestCase): def expect_parsing_failure( diff --git a/Objects/clinic/unicodeobject.c.h b/Objects/clinic/unicodeobject.c.h index 01c40b9..78e14b0 100644 --- a/Objects/clinic/unicodeobject.c.h +++ b/Objects/clinic/unicodeobject.c.h @@ -357,7 +357,7 @@ exit: } PyDoc_STRVAR(unicode_find__doc__, -"find($self, sub, start=None, end=None, /)\n" +"find($self, sub[, start[, end]], /)\n" "--\n" "\n" "Return the lowest index in S where substring sub is found, such that sub is contained within S[start:end].\n" @@ -413,7 +413,7 @@ exit: } PyDoc_STRVAR(unicode_index__doc__, -"index($self, sub, start=None, end=None, /)\n" +"index($self, sub[, start[, end]], /)\n" "--\n" "\n" "Return the lowest index in S where substring sub is found, such that sub is contained within S[start:end].\n" @@ -1060,7 +1060,7 @@ exit: } PyDoc_STRVAR(unicode_rfind__doc__, -"rfind($self, sub, start=None, end=None, /)\n" +"rfind($self, sub[, start[, end]], /)\n" "--\n" "\n" "Return the highest index in S where substring sub is found, such that sub is contained within S[start:end].\n" @@ -1116,7 +1116,7 @@ exit: } PyDoc_STRVAR(unicode_rindex__doc__, -"rindex($self, sub, start=None, end=None, /)\n" +"rindex($self, sub[, start[, end]], /)\n" "--\n" "\n" "Return the highest index in S where substring sub is found, such that sub is contained within S[start:end].\n" @@ -1888,4 +1888,4 @@ skip_optional_pos: exit: return return_value; } -/*[clinic end generated code: output=3aa49013ffa3fa93 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=9fee62bd337f809b input=a9049054013a1b77]*/ diff --git a/Tools/clinic/libclinic/dsl_parser.py b/Tools/clinic/libclinic/dsl_parser.py index 4c739ef..9e22d84 100644 --- a/Tools/clinic/libclinic/dsl_parser.py +++ b/Tools/clinic/libclinic/dsl_parser.py @@ -666,6 +666,8 @@ class DSLParser: if equals: existing = existing.strip() if libclinic.is_legal_py_identifier(existing): + if self.forced_text_signature: + fail("Cannot use @text_signature when cloning a function") # we're cloning! names = self.parse_function_names(before) return self.parse_cloned_function(names, existing) @@ -689,7 +691,8 @@ class DSLParser: kind=self.kind, coexist=self.coexist, critical_section=self.critical_section, - target_critical_section=self.target_critical_section + target_critical_section=self.target_critical_section, + forced_text_signature=self.forced_text_signature ) self.add_function(func) @@ -1324,13 +1327,14 @@ class DSLParser: self.docstring_append(self.function, line) + @staticmethod def format_docstring_signature( - self, f: Function, parameters: list[Parameter] + f: Function, parameters: list[Parameter] ) -> str: lines = [] lines.append(f.displayname) - if self.forced_text_signature: - lines.append(self.forced_text_signature) + if f.forced_text_signature: + lines.append(f.forced_text_signature) elif f.kind in {GETTER, SETTER}: # @getter and @setter do not need signatures like a method or a function. return '' diff --git a/Tools/clinic/libclinic/function.py b/Tools/clinic/libclinic/function.py index 572916b..9390126 100644 --- a/Tools/clinic/libclinic/function.py +++ b/Tools/clinic/libclinic/function.py @@ -107,6 +107,7 @@ class Function: # functions with optional groups because we can't represent # those accurately with inspect.Signature in 3.4. docstring_only: bool = False + forced_text_signature: str | None = None critical_section: bool = False target_critical_section: list[str] = dc.field(default_factory=list) |