Skip to content
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

Get rid of global state in fail and warn #35

11 changes: 5 additions & 6 deletions Lib/test/test_clinic.py
Original file line number Diff line number Diff line change
Expand Up @@ -1900,7 +1900,7 @@ def test_parameters_no_more_than_one_vararg(self):
*vararg1: object
*vararg2: object
"""
self.expect_failure(block, err, lineno=0)
self.expect_failure(block, err, lineno=3)

def test_function_not_at_column_0(self):
function = self.parse_function("""
Expand Down Expand Up @@ -2284,12 +2284,11 @@ def test_non_ascii_character_in_docstring(self):
"""
with support.captured_stdout() as stdout:
self.parse(block)
# The line numbers are off; this is a known limitation.
expected = dedent("""\
Warning in file 'clinic_tests' on line 0:
Warning in file 'clinic_tests':
Non-ascii characters are not allowed in docstrings: 'á'

Warning in file 'clinic_tests' on line 0:
Warning in file 'clinic_tests':
Non-ascii characters are not allowed in docstrings: 'ü', 'á', 'ß'

""")
Expand Down Expand Up @@ -2390,7 +2389,7 @@ def test_state_func_docstring_no_summary(self):
docstring1
docstring2
"""
self.expect_failure(block, err, lineno=0)
self.expect_failure(block, err)

def test_state_func_docstring_only_one_param_template(self):
err = "You may not specify {parameters} more than once in a docstring!"
Expand All @@ -2404,7 +2403,7 @@ def test_state_func_docstring_only_one_param_template(self):
these are the params again:
{parameters}
"""
self.expect_failure(block, err, lineno=0)
self.expect_failure(block, err)


class ClinicExternalTest(TestCase):
Expand Down
34 changes: 19 additions & 15 deletions Tools/clinic/clinic.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,6 @@ def warn_or_fail(
line_number: int | None = None,
) -> None:
joined = " ".join([str(a) for a in args])
if clinic:
if filename is None:
filename = clinic.filename
if getattr(clinic, 'block_parser', None) and (line_number is None):
line_number = clinic.block_parser.line_number
error = ClinicError(joined, filename=filename, lineno=line_number)
if fail:
raise error
Expand Down Expand Up @@ -277,7 +272,7 @@ class Language(metaclass=abc.ABCMeta):
checksum_line = ""

def __init__(self, filename: str) -> None:
...
self.filename = filename

@abc.abstractmethod
def render(
Expand Down Expand Up @@ -833,8 +828,6 @@ def output_templates(
if not p.is_optional():
min_kw_only = i - max_pos
elif p.is_vararg():
if vararg != self.NO_VARARG:
fail("Too many var args")
pseudo_args += 1
vararg = i - 1
else:
Expand Down Expand Up @@ -1937,12 +1930,16 @@ def is_stop_line(line: str) -> bool:
if line.startswith(stop_line):
remainder = line.removeprefix(stop_line)
if remainder and not remainder.isspace():
fail(f"Garbage after stop line: {remainder!r}")
fail(f"Garbage after stop line: {remainder!r}",
filename=self.language.filename,
line_number=self.line_number)
return True
else:
# gh-92256: don't allow incorrectly formatted stop lines
if line.lstrip().startswith(stop_line):
fail(f"Whitespace is not allowed before the stop line: {line!r}")
fail(f"Whitespace is not allowed before the stop line: {line!r}",
filename=self.language.filename,
line_number=self.line_number)
return False

# consume body of program
Expand Down Expand Up @@ -1987,7 +1984,9 @@ def is_stop_line(line: str) -> bool:
for field in shlex.split(arguments):
name, equals, value = field.partition('=')
if not equals:
fail(f"Mangled Argument Clinic marker line: {line!r}")
fail(f"Mangled Argument Clinic marker line: {line!r}",
line_number=self.line_number,
filename=self.language.filename)
d[name.strip()] = value.strip()

if self.verify:
Expand All @@ -2001,7 +2000,9 @@ def is_stop_line(line: str) -> bool:
fail("Checksum mismatch! "
f"Expected {checksum!r}, computed {computed!r}. "
"Suggested fix: remove all generated code including "
"the end marker, or use the '-f' option.")
"the end marker, or use the '-f' option.",
filename=self.language.filename,
line_number=self.line_number)
else:
# put back output
output_lines = output.splitlines(keepends=True)
Expand Down Expand Up @@ -5064,7 +5065,7 @@ def parse(self, block: Block) -> None:
for line_number, line in enumerate(lines, self.clinic.block_parser.block_start_line_number):
if '\t' in line:
fail(f'Tab characters are illegal in the Clinic DSL: {line!r}',
line_number=block_start)
line_number=line_number)
try:
self.state(line)
except ClinicError as exc:
Expand All @@ -5076,7 +5077,8 @@ def parse(self, block: Block) -> None:

if self.preserve_output:
if block.output:
fail("'preserve' only works for blocks that don't produce any output!")
fail("'preserve' only works for blocks that don't produce any output!",
line_number=block_start)
block.output = self.saved_output

def in_docstring(self) -> bool:
Expand Down Expand Up @@ -5484,6 +5486,8 @@ def parse_parameter(self, line: str) -> None:
f"invalid parameter declaration (**kwargs?): {line!r}")

if function_args.vararg:
if any(p.is_vararg() for p in self.function.parameters.values()):
fail("Too many var args")
is_vararg = True
parameter = function_args.vararg
else:
Expand Down Expand Up @@ -5853,7 +5857,7 @@ def docstring_append(self, obj: Function | Parameter, line: str) -> None:
matches = re.finditer(r'[^\x00-\x7F]', line)
if offending := ", ".join([repr(m[0]) for m in matches]):
warn("Non-ascii characters are not allowed in docstrings:",
offending)
offending, filename=self.clinic.filename)

docstring = obj.docstring
if docstring:
Expand Down
Loading