mirror of https://github.com/python/cpython
gh-117431: Argument Clinic: copy forced text signature when cloning (#117591)
This commit is contained in:
parent
73906d5c90
commit
0d42ac9474
|
@ -5,7 +5,7 @@
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from test import support, test_tools
|
from test import support, test_tools
|
||||||
from test.support import os_helper
|
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 textwrap import dedent
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
import inspect
|
import inspect
|
||||||
|
@ -662,6 +662,61 @@ class ClinicWholeFileTest(TestCase):
|
||||||
err = "Illegal C basename: '.illegal.'"
|
err = "Illegal C basename: '.illegal.'"
|
||||||
self.expect_failure(block, err, lineno=7)
|
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):
|
class ParseFileUnitTest(TestCase):
|
||||||
def expect_parsing_failure(
|
def expect_parsing_failure(
|
||||||
|
|
|
@ -357,7 +357,7 @@ exit:
|
||||||
}
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(unicode_find__doc__,
|
PyDoc_STRVAR(unicode_find__doc__,
|
||||||
"find($self, sub, start=None, end=None, /)\n"
|
"find($self, sub[, start[, end]], /)\n"
|
||||||
"--\n"
|
"--\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Return the lowest index in S where substring sub is found, such that sub is contained within S[start:end].\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__,
|
PyDoc_STRVAR(unicode_index__doc__,
|
||||||
"index($self, sub, start=None, end=None, /)\n"
|
"index($self, sub[, start[, end]], /)\n"
|
||||||
"--\n"
|
"--\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Return the lowest index in S where substring sub is found, such that sub is contained within S[start:end].\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__,
|
PyDoc_STRVAR(unicode_rfind__doc__,
|
||||||
"rfind($self, sub, start=None, end=None, /)\n"
|
"rfind($self, sub[, start[, end]], /)\n"
|
||||||
"--\n"
|
"--\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Return the highest index in S where substring sub is found, such that sub is contained within S[start:end].\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__,
|
PyDoc_STRVAR(unicode_rindex__doc__,
|
||||||
"rindex($self, sub, start=None, end=None, /)\n"
|
"rindex($self, sub[, start[, end]], /)\n"
|
||||||
"--\n"
|
"--\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Return the highest index in S where substring sub is found, such that sub is contained within S[start:end].\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:
|
exit:
|
||||||
return return_value;
|
return return_value;
|
||||||
}
|
}
|
||||||
/*[clinic end generated code: output=3aa49013ffa3fa93 input=a9049054013a1b77]*/
|
/*[clinic end generated code: output=9fee62bd337f809b input=a9049054013a1b77]*/
|
||||||
|
|
|
@ -666,6 +666,8 @@ class DSLParser:
|
||||||
if equals:
|
if equals:
|
||||||
existing = existing.strip()
|
existing = existing.strip()
|
||||||
if libclinic.is_legal_py_identifier(existing):
|
if libclinic.is_legal_py_identifier(existing):
|
||||||
|
if self.forced_text_signature:
|
||||||
|
fail("Cannot use @text_signature when cloning a function")
|
||||||
# we're cloning!
|
# we're cloning!
|
||||||
names = self.parse_function_names(before)
|
names = self.parse_function_names(before)
|
||||||
return self.parse_cloned_function(names, existing)
|
return self.parse_cloned_function(names, existing)
|
||||||
|
@ -689,7 +691,8 @@ class DSLParser:
|
||||||
kind=self.kind,
|
kind=self.kind,
|
||||||
coexist=self.coexist,
|
coexist=self.coexist,
|
||||||
critical_section=self.critical_section,
|
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)
|
self.add_function(func)
|
||||||
|
|
||||||
|
@ -1324,13 +1327,14 @@ class DSLParser:
|
||||||
|
|
||||||
self.docstring_append(self.function, line)
|
self.docstring_append(self.function, line)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
def format_docstring_signature(
|
def format_docstring_signature(
|
||||||
self, f: Function, parameters: list[Parameter]
|
f: Function, parameters: list[Parameter]
|
||||||
) -> str:
|
) -> str:
|
||||||
lines = []
|
lines = []
|
||||||
lines.append(f.displayname)
|
lines.append(f.displayname)
|
||||||
if self.forced_text_signature:
|
if f.forced_text_signature:
|
||||||
lines.append(self.forced_text_signature)
|
lines.append(f.forced_text_signature)
|
||||||
elif f.kind in {GETTER, SETTER}:
|
elif f.kind in {GETTER, SETTER}:
|
||||||
# @getter and @setter do not need signatures like a method or a function.
|
# @getter and @setter do not need signatures like a method or a function.
|
||||||
return ''
|
return ''
|
||||||
|
|
|
@ -107,6 +107,7 @@ class Function:
|
||||||
# functions with optional groups because we can't represent
|
# functions with optional groups because we can't represent
|
||||||
# those accurately with inspect.Signature in 3.4.
|
# those accurately with inspect.Signature in 3.4.
|
||||||
docstring_only: bool = False
|
docstring_only: bool = False
|
||||||
|
forced_text_signature: str | None = None
|
||||||
critical_section: bool = False
|
critical_section: bool = False
|
||||||
target_critical_section: list[str] = dc.field(default_factory=list)
|
target_critical_section: list[str] = dc.field(default_factory=list)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue