Mailing List Archive

gh-117431: Argument Clinic: copy forced text signature when cloning (#117591)
https://github.com/python/cpython/commit/0d42ac9474f857633d00b414c0715f4efa73f1ca
commit: 0d42ac9474f857633d00b414c0715f4efa73f1ca
branch: main
author: Erlend E. Aasland <erlend@python.org>
committer: erlend-aasland <erlend.aasland@protonmail.com>
date: 2024-04-10T10:12:05+02:00
summary:

gh-117431: Argument Clinic: copy forced text signature when cloning (#117591)

files:
M Lib/test/test_clinic.py
M Objects/clinic/unicodeobject.c.h
M Tools/clinic/libclinic/dsl_parser.py
M Tools/clinic/libclinic/function.py

diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py
index a5887cdb56e3ca..e3ba3d943216de 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 C "void *" ""
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 01c40b90d9b4b8..78e14b0021d006 100644
--- a/Objects/clinic/unicodeobject.c.h
+++ b/Objects/clinic/unicodeobject.c.h
@@ -357,7 +357,7 @@ unicode_expandtabs(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyOb
}

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 @@ unicode_find(PyObject *str, PyObject *const *args, Py_ssize_t nargs)
}

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 @@ unicode_removesuffix(PyObject *self, PyObject *arg)
}

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 @@ unicode_rfind(PyObject *str, PyObject *const *args, Py_ssize_t nargs)
}

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 @@ unicode_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
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 4c739efe1066e4..9e22d847c4dc90 100644
--- a/Tools/clinic/libclinic/dsl_parser.py
+++ b/Tools/clinic/libclinic/dsl_parser.py
@@ -666,6 +666,8 @@ def state_modulename_name(self, line: str) -> None:
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 @@ def state_modulename_name(self, line: str) -> None:
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 @@ def state_function_docstring(self, line: str) -> None:

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 572916bbe123b4..93901263e44c04 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)


_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-leave@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: list-python-checkins@lists.gossamer-threads.com