summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorErlend E. Aasland <erlend@python.org>2023-08-15 14:00:52 (GMT)
committerGitHub <noreply@github.com>2023-08-15 14:00:52 (GMT)
commite90036c9bdf25621c15207a9cabd119fb5366c27 (patch)
tree630b0a894d71d46a868e0b0c8f4fc452f9dbac67
parent6515ec3d3d5acd3d0b99c88794bdec09f0831e5b (diff)
downloadcpython-e90036c9bdf25621c15207a9cabd119fb5366c27.zip
cpython-e90036c9bdf25621c15207a9cabd119fb5366c27.tar.gz
cpython-e90036c9bdf25621c15207a9cabd119fb5366c27.tar.bz2
gh-107880: Argument Clinic: Fix regression in gh-107885 (#107974)
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
-rw-r--r--Lib/test/test_clinic.py35
-rwxr-xr-xTools/clinic/clinic.py33
2 files changed, 51 insertions, 17 deletions
diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py
index f067a26..a67cd30 100644
--- a/Lib/test/test_clinic.py
+++ b/Lib/test/test_clinic.py
@@ -609,6 +609,35 @@ class ClinicWholeFileTest(TestCase):
"""
self.expect_failure(block, err, lineno=2)
+ def test_validate_cloned_init(self):
+ block = """
+ /*[clinic input]
+ class C "void *" ""
+ C.meth
+ a: int
+ [clinic start generated code]*/
+ /*[clinic input]
+ @classmethod
+ C.__init__ = C.meth
+ [clinic start generated code]*/
+ """
+ err = "'__init__' must be a normal method, not a class or static method"
+ self.expect_failure(block, err, lineno=8)
+
+ def test_validate_cloned_new(self):
+ block = """
+ /*[clinic input]
+ class C "void *" ""
+ C.meth
+ a: int
+ [clinic start generated code]*/
+ /*[clinic input]
+ C.__new__ = C.meth
+ [clinic start generated code]*/
+ """
+ err = "'__new__' must be a class method"
+ self.expect_failure(block, err, lineno=7)
+
class ParseFileUnitTest(TestCase):
def expect_parsing_failure(
@@ -1918,7 +1947,7 @@ class ClinicParserTest(TestCase):
self.parse_function(block)
def test_new_must_be_a_class_method(self):
- err = "__new__ must be a class method!"
+ err = "'__new__' must be a class method!"
block = """
module foo
class Foo "" ""
@@ -1927,7 +1956,7 @@ class ClinicParserTest(TestCase):
self.expect_failure(block, err, lineno=2)
def test_init_must_be_a_normal_method(self):
- err = "__init__ must be a normal method, not a class or static method!"
+ err = "'__init__' must be a normal method, not a class or static method!"
block = """
module foo
class Foo "" ""
@@ -2030,7 +2059,7 @@ class ClinicParserTest(TestCase):
self.expect_failure(block, err, lineno=2)
def test_cannot_convert_special_method(self):
- err = "__len__ is a special method and cannot be converted"
+ err = "'__len__' is a special method and cannot be converted"
block = """
class T "" ""
T.__len__
diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py
index 1e0303c..11dbfb3 100755
--- a/Tools/clinic/clinic.py
+++ b/Tools/clinic/clinic.py
@@ -4840,6 +4840,21 @@ class DSLParser:
self.next(self.state_modulename_name, line)
+ def update_function_kind(self, fullname: str) -> None:
+ fields = fullname.split('.')
+ name = fields.pop()
+ _, cls = self.clinic._module_and_class(fields)
+ if name in unsupported_special_methods:
+ fail(f"{name!r} is a special method and cannot be converted to Argument Clinic!")
+ if name == '__new__':
+ if (self.kind is not CLASS_METHOD) or (not cls):
+ fail("'__new__' must be a class method!")
+ self.kind = METHOD_NEW
+ elif name == '__init__':
+ if (self.kind is not CALLABLE) or (not cls):
+ fail("'__init__' must be a normal method, not a class or static method!")
+ self.kind = METHOD_INIT
+
def state_modulename_name(self, line: str) -> None:
# looking for declaration, which establishes the leftmost column
# line should be
@@ -4888,6 +4903,7 @@ class DSLParser:
function_name = fields.pop()
module, cls = self.clinic._module_and_class(fields)
+ self.update_function_kind(full_name)
overrides: dict[str, Any] = {
"name": function_name,
"full_name": full_name,
@@ -4948,20 +4964,9 @@ class DSLParser:
function_name = fields.pop()
module, cls = self.clinic._module_and_class(fields)
- fields = full_name.split('.')
- if fields[-1] in unsupported_special_methods:
- fail(f"{fields[-1]} is a special method and cannot be converted to Argument Clinic! (Yet.)")
-
- if fields[-1] == '__new__':
- if (self.kind is not CLASS_METHOD) or (not cls):
- fail("__new__ must be a class method!")
- self.kind = METHOD_NEW
- elif fields[-1] == '__init__':
- if (self.kind is not CALLABLE) or (not cls):
- fail("__init__ must be a normal method, not a class or static method!")
- self.kind = METHOD_INIT
- if not return_converter:
- return_converter = init_return_converter()
+ self.update_function_kind(full_name)
+ if self.kind is METHOD_INIT and not return_converter:
+ return_converter = init_return_converter()
if not return_converter:
return_converter = CReturnConverter()