Skip to content

gh-107880: Argument Clinic: Fix regression in gh-107885 #107974

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 32 additions & 3 deletions Lib/test/test_clinic.py
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,35 @@ def test_directive_output_invalid_command(self):
"""
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(
Expand Down Expand Up @@ -1918,7 +1947,7 @@ class Foo "" ""
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 "" ""
Expand All @@ -1927,7 +1956,7 @@ class Foo "" ""
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 "" ""
Expand Down Expand Up @@ -2030,7 +2059,7 @@ def test_illegal_c_identifier(self):
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__
Expand Down
33 changes: 19 additions & 14 deletions Tools/clinic/clinic.py
Original file line number Diff line number Diff line change
Expand Up @@ -4840,6 +4840,21 @@ def state_dsl_start(self, line: str) -> None:

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
Expand Down Expand Up @@ -4888,6 +4903,7 @@ def state_modulename_name(self, line: str) -> None:
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,
Expand Down Expand Up @@ -4948,20 +4964,9 @@ def state_modulename_name(self, line: str) -> None:
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()
Expand Down