Skip to content

Use, misuse and confusion of @check_messages decorator #6060

@DudeNr33

Description

@DudeNr33

Current problem

The work on #5953 showed that specifically enabling just a single message is sometimes not working as expected.
This is due to either missing message declaration in a checkers msgs attribute or the incorrect usage of the @check_messages decorator.
Ideally I would like to implement a new, optional checker aimed at Pylint core development and custom checker development.
This checker would focus on correct message declaration and handling.
I already started working on it, but noticed that there is especially quite some problems with the @check_messages decorator. I totally understand that, because while being extensively used across all checker classes, there is not a single word on its purpose and effect in the documentation. Its docstring is also not really helpful, you have to dig deeper into the codebase to understand what it does.

Desired solution

Before continuing my work on the new checker, I want to address and clarify some questions about the intended use of @check_messages.
After that this issue can be closed with a PR that extends the documentation, and if necessary some code changes.

A brief explanation on what @check_messages does:
It helps the ASTWalker decide whether a callback for the current node type should be called or not.
This is done by adding the list of messages passed in as a checks_messages attribute on method object.
When a checker is added to the ASTWalker instance, it loops over all of its methods. Every method starting with visit_ or leave_ is now checked for the checks_messages attribute:

  • if the attribute does not exist, this method will be added to the list of callbacks
  • if it exists and at least one message of the checks_messages list is enabled, this method will be added to the list of callbacks
  • otherwise, it will not be added to the list of callbacks and will therefore not be executed

Essentially this means:

  1. The main (and only) intent of the @check_messages decorator is to improve performance
  2. Placing the @check_messages decorator on any method which is not a "top level callback" (methods starting with visit_ or leave_ does not have any effect
  3. Forgetting to apply the @check_messages decorator has no negative functional consequences, it only affects performance (which, of course, is always an issue)
  4. Applying the decorator but forgetting to add messages that are emitted from this callback can lead to false negatives: if none of the messages actually included in the decorator are enabled, it will not be called
  5. Applying the decorator to a callback that not only emits messages but also does other things can have nasty side effects (false positives, false negatives, crashes)

What I want to gain a consensus on:

  1. Do we want to keep the name check_messages? I don't think it really conveys the effect it has on the decorated method.
  2. What shall we regard as best practice for this decorator? Should every callback be decorated and the list of messages must always be correct and consistent, or should we rather advise to use it only in cases where we expect a significant speedup when this callback is omitted?
  3. Do we want to keep the restriction that this decorator only has an effect on the "top level callbacks"? Seeing that a lot of those callbacks can emit quite a lot of messages and the logic for the checks is often split up into several subfunctions, it would be more flexible and also more robust (as it is easier to keep track of the messages that need to be included in the decorator) if one could apply it on the subfunctions rather than on the top level callback.

Looking over the code base there are quite a lot of places where the decorator is not used correctly:

  • used with simply passing in all messages (which has the same effect as just omitting it): @check_messages(*MSGS)
  • used on methods that are not a callback (which has no effect)
  • Used, but not including all messages possibly emitted by the callback

Additional context

No response

Metadata

Metadata

Assignees

Labels

Discussion 🤔MaintenanceDiscussion or action around maintaining pylint or the dev workflow

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions