Skip to content

Normalise Argument Clinic error messages #107614

Description

@erlend-aasland

Argument Clinic is pretty good at disallowing weird corner cases and producing error messages (there are 130 fail(..)s sprinkled around clinic.py!). Unfortunately, many of the error messages do not wrap the line or token in question, nor the function/module/class name in question in quotes. Also, some error messages contain line breaks in unexpected places.

Some examples:

Error message with unexpected line break

Clinic input:

/*[clinic input]
function
    a: int = 0
    b: int
[clinic start generated code]*/
$ python3.12 Tools/clinic/clinic.py test.c
Error in file 'test.c' on line 4:
Can't have a parameter without a default ('b')
after a parameter with a default!
Details

Clinic input:

/*[clinic input]
function
    b: int
    *
[clinic start generated code]*/

Error message:

$ python3.12 Tools/clinic/clinic.py test.c
Error in file 'test.c' on line 5:
Function function specifies '*' without any parameters afterwards.

Suggesting to normalise Argument Clinic error messages, using the following guidelines:

  • always wrap the offending line, token, or name in quotes
  • no line break; the entire error message should be on one line

Linked PRs

Activity

  1. added a commit that references this issue on Aug 4, 2023
  2. erlend-aasland commented on Aug 4, 2023

    @erlend-aasland
    ContributorAuthor

    In addition to normalising the error message format, I'd like to do an audit on the error message content. We've got some messages that are hard to comprehend; I think we can do better. Example:

    "Function 'bar' has an unsupported group configuration. (Unexpected state 0.d)"

    There are four variants on the error message above; none of them are any better.

    There are also a lot of error messages where the offending line/token/name is not included, which leads to the programmer having to guess what's wrong. Example:

    "Annotations must be either a name, a function call, or a string."

  3. erlend-aasland commented on Aug 4, 2023

    @erlend-aasland
    ContributorAuthor

    There is a place where line break really could help, though:

    Details
    diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py
    index 979e07f13c..2fa75133da 100644
    --- a/Lib/test/test_clinic.py
    +++ b/Lib/test/test_clinic.py
    @@ -634,13 +634,24 @@ def test_directive_preserve_output(self):
             self.assertEqual(generated, block)
     
         def test_directive_output_invalid_command(self):
    -        err = (
    -            "Invalid command / destination name 'cmd', must be one of:\n"
    -            "preset push pop print everything cpp_if docstring_prototype "
    -            "docstring_definition methoddef_define impl_prototype "
    -            "parser_prototype parser_definition cpp_endif methoddef_ifndef "
    -            "impl_definition"
    -        )
    +        err = dedent("""
    +            Invalid command or destination name 'cmd'. Must be one of:
    +             - preset
    +             - push
    +             - pop
    +             - print
    +             - everything
    +             - cpp_if
    +             - docstring_prototype
    +             - docstring_definition
    +             - methoddef_define
    +             - impl_prototype
    +             - parser_prototype
    +             - parser_definition
    +             - cpp_endif
    +             - methoddef_ifndef
    +             - impl_definition
    +        """).strip()
             block = """
                 /*[clinic input]
                 output cmd buffer
    diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py
    index a50f574327..d2a96ecfa4 100755
    --- a/Tools/clinic/clinic.py
    +++ b/Tools/clinic/clinic.py
    @@ -4567,8 +4567,10 @@ def directive_output(
                 return
     
             if command_or_name not in fd:
    -            fail(f"Invalid command / destination name {command_or_name!r}, must be one of:\n"
    -                 "preset push pop print everything", " ".join(fd))
    +            allowed = ["preset", "push", "pop", "print", "everything"]
    +            allowed.extend(fd)
    +            fail(f"Invalid command or destination name {command_or_name!r}. "
    +                 "Must be one of:\n -", "\n - ".join(allowed))
             fd[command_or_name] = d
     
         def directive_dump(self, name: str) -> None:
  4. AlexWaygood commented on Aug 4, 2023

    @AlexWaygood
    Member

    There is a place where line break really could help, though:

    +1, I think that would be an improvement

  5. erlend-aasland commented on Aug 4, 2023

    @erlend-aasland
    ContributorAuthor

    There is a place where line break really could help, though:

    +1, I think that would be an improvement

    Added on the PR with feb6aec

  6. added a commit that references this issue on Aug 4, 2023
  7. erlend-aasland commented on Aug 4, 2023

    @erlend-aasland
    ContributorAuthor

    The error messages are now normalised with regard to formatting. Suggesting to address issues with the content of the messages in separate issues.

  8. erlend-aasland commented on Aug 4, 2023

    @erlend-aasland
    ContributorAuthor
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions