Skip to content

Commit

Permalink
pythongh-107972: Argument Clinic: Ensure a C basename is provided aft…
Browse files Browse the repository at this point in the history
…er 'as' (python#107973)

Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com>
  • Loading branch information
2 people authored and iritkatriel committed Aug 16, 2023
1 parent f336762 commit 60de9ea
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 7 deletions.
30 changes: 26 additions & 4 deletions Lib/test/test_clinic.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ def _make_clinic(*, filename='clinic_tests'):
return c


def _expect_failure(tc, parser, code, errmsg, *, filename=None, lineno=None):
def _expect_failure(tc, parser, code, errmsg, *, filename=None, lineno=None,
strip=True):
"""Helper for the parser tests.
tc: unittest.TestCase; passed self in the wrapper
Expand All @@ -38,7 +39,9 @@ def _expect_failure(tc, parser, code, errmsg, *, filename=None, lineno=None):
filename: str, optional filename
lineno: int, optional line number
"""
code = dedent(code).strip()
code = dedent(code)
if strip:
code = code.strip()
errmsg = re.escape(errmsg)
with tc.assertRaisesRegex(clinic.ClinicError, errmsg) as cm:
parser(code)
Expand Down Expand Up @@ -638,6 +641,19 @@ class C "void *" ""
err = "'__new__' must be a class method"
self.expect_failure(block, err, lineno=7)

def test_no_c_basename_cloned(self):
block = """
/*[clinic input]
foo2
[clinic start generated code]*/
/*[clinic input]
foo as = foo2
[clinic start generated code]*/
"""
err = "No C basename provided after 'as' keyword"
self.expect_failure(block, err, lineno=5)



class ParseFileUnitTest(TestCase):
def expect_parsing_failure(
Expand Down Expand Up @@ -857,9 +873,10 @@ def parse_function(self, text, signatures_in_block=2, function_index=1):
assert isinstance(s[function_index], clinic.Function)
return s[function_index]

def expect_failure(self, block, err, *, filename=None, lineno=None):
def expect_failure(self, block, err, *,
filename=None, lineno=None, strip=True):
return _expect_failure(self, self.parse_function, block, err,
filename=filename, lineno=lineno)
filename=filename, lineno=lineno, strip=strip)

def checkDocstring(self, fn, expected):
self.assertTrue(hasattr(fn, "docstring"))
Expand Down Expand Up @@ -1520,6 +1537,11 @@ def test_illegal_c_basename(self):
err = "Illegal C basename: '935'"
self.expect_failure(block, err)

def test_no_c_basename(self):
block = "foo as "
err = "No C basename provided after 'as' keyword"
self.expect_failure(block, err, strip=False)

def test_single_star(self):
block = """
module foo
Expand Down
9 changes: 6 additions & 3 deletions Tools/clinic/clinic.py
Original file line number Diff line number Diff line change
Expand Up @@ -4879,9 +4879,11 @@ def state_modulename_name(self, line: str) -> None:
before, equals, existing = line.rpartition('=')
c_basename: str | None
if equals:
full_name, _, c_basename = before.partition(' as ')
full_name, as_, c_basename = before.partition(' as ')
full_name = full_name.strip()
c_basename = c_basename.strip()
if as_ and not c_basename:
fail("No C basename provided after 'as' keyword")
existing = existing.strip()
if (is_legal_py_identifier(full_name) and
(not c_basename or is_legal_c_identifier(c_basename)) and
Expand Down Expand Up @@ -4932,10 +4934,11 @@ def state_modulename_name(self, line: str) -> None:
line, _, returns = line.partition('->')
returns = returns.strip()

full_name, _, c_basename = line.partition(' as ')
full_name, as_, c_basename = line.partition(' as ')
full_name = full_name.strip()
c_basename = c_basename.strip() or None

if as_ and not c_basename:
fail("No C basename provided after 'as' keyword")
if not is_legal_py_identifier(full_name):
fail(f"Illegal function name: {full_name!r}")
if c_basename and not is_legal_c_identifier(c_basename):
Expand Down

0 comments on commit 60de9ea

Please sign in to comment.