Skip to content

Commit

Permalink
gh-107880: Argument Clinic: Fix regression in gh-107885 (#107974)
Browse files Browse the repository at this point in the history
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
  • Loading branch information
erlend-aasland and AlexWaygood authored Aug 15, 2023
1 parent 6515ec3 commit e90036c
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 17 deletions.
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

0 comments on commit e90036c

Please sign in to comment.