Update reporters to (allow) use of end_line and end_column#5372
Update reporters to (allow) use of end_line and end_column#5372Pierre-Sassoulas merged 17 commits intopylint-dev:mainfrom
end_line and end_column#5372Conversation
Pull Request Test Coverage Report for Build 1499421022
💛 - Coveralls |
pylint/reporters/text.py
Outdated
| for key, value in self_dict.items(): | ||
| # pylint: disable=fixme | ||
| # TODO: Add column to list of attributes to be printed as an empty string | ||
| if value is None and key in PRINT_AS_EMPTY_STRING: | ||
| self_dict[key] = "" |
There was a problem hiding this comment.
Is a for - loop really necessary here? Maybe iterate only over PRINT_AS_EMPTY_STRING and do
self_dict[key] = self_dict[key] or ""There was a problem hiding this comment.
Or even better, what about this?
Initialize end_lineno and end_col_offset with an empty string instead "". You still would be able to differentiate between a null value and a number. I.e. int | Literal[""] as type.
There was a problem hiding this comment.
Or even better, what about this?
Initialize
end_linenoandend_col_offsetwith an empty string instead"". You still would be able to differentiate between a null value and a number. I.e.int | Literal[""]as type.
I don't really like that as then we we're changing the type of end_lineno and end_col_offset while still "internal" to fit a specific type of reporter. For example, for the JSONReporter it makes no sense to have it be "". I'm not sure if other developer have written other Reporter but I think keeping both attributes None until a specific reporter starts handling them is the better option here.
I'll add your first suggestion!
pylint/reporters/text.py
Outdated
| # TODO: Add column to list of attributes to be printed as an empty string | ||
| if value is None and key in PRINT_AS_EMPTY_STRING: | ||
| self_dict[key] = "" | ||
| self.writeln(self._template.format(**self_dict)) |
There was a problem hiding this comment.
self.writeln(msg.format(self._template)) has been quite elegant, but there is one drawback. Calling it with an unknown key raises a KeyError. Ideally we could check a template and replace invalid values with "" beforehand. I'm currently having the issue to implement some kind of version check in vscode-python as calling pylint with the new msg-template would raise this error.
Traceback (most recent call last):
File "/.../venv-310/bin/pylint", line 33, in <module>
sys.exit(load_entry_point('pylint', 'console_scripts', 'pylint')())
File "/.../pylint/__init__.py", line 24, in run_pylint
PylintRun(sys.argv[1:])
File "/.../pylint/lint/run.py", line 398, in __init__
linter.check(args)
File "/.../pylint/lint/pylinter.py", line 992, in check
self._check_files(
File "/.../pylint/lint/pylinter.py", line 1041, in _check_files
self.add_message(symbol, args=msg)
File "/.../pylint/lint/pylinter.py", line 1513, in add_message
self._add_one_message(
File "/.../pylint/lint/pylinter.py", line 1471, in _add_one_message
self.reporter.handle_message(
File "/.../pylint/reporters/text.py", line 202, in handle_message
self.write_message(msg)
File "/.../pylint/reporters/text.py", line 192, in write_message
self.writeln(msg.format(self._template))
File "/.../pylint/message/message.py", line 94, in format
return template.format(**self._asdict())
KeyError: 'msg1'There was a problem hiding this comment.
Shouldn't that just raise a new warning? Something like config-parse-error as introduced in #5365. We could emit it on an except for the KeyError.
There was a problem hiding this comment.
That doesn't really solve the issue. At the core of it its backwards incompatibility.
We should be able to use a new template, i.e. with end_lineno, in old pylint versions and still get a usable result. The way it's now, I need to make sure only to add end_lineno if we are using the new pylint version.
If at some point we add another key, this will only repeat. Every time incompatible with old versions.
There was a problem hiding this comment.
Came up with something. A little hacky, but let me know what you think. I added if not self._checked_template: because I thought the additional if statement would be better than doing the regex statement each line.
Co-authored-by: Marc Mueller <30130371+cdce8p@users.noreply.github.com>
pylint/reporters/text.py
Outdated
| # TODO: Add column to list of attributes to be printed as an empty string | ||
| if value is None and key in PRINT_AS_EMPTY_STRING: | ||
| self_dict[key] = "" | ||
| self.writeln(self._template.format(**self_dict)) |
There was a problem hiding this comment.
That doesn't really solve the issue. At the core of it its backwards incompatibility.
We should be able to use a new template, i.e. with end_lineno, in old pylint versions and still get a usable result. The way it's now, I need to make sure only to add end_lineno if we are using the new pylint version.
If at some point we add another key, this will only repeat. Every time incompatible with old versions.
pylint/reporters/text.py
Outdated
| # Check to see if all parameters in the template are attributes of the Message | ||
| if not self._checked_template: | ||
| template = self._template | ||
| parameters = re.findall(r"\{(.+?)\}", template) | ||
| for parameter in parameters: | ||
| if parameter not in self_dict: | ||
| template = template.replace(f"{{{parameter}}}", "") | ||
| self._template = template | ||
| self._checked_template = True |
There was a problem hiding this comment.
Can this be moved to on_set_current_module or even __init__? Don't now if the config settings are defined at the point already.
There was a problem hiding this comment.
Moved to on_set_current_module
pylint/reporters/text.py
Outdated
| # Check to see if all parameters in the template are attributes of the Message | ||
| if not self._checked_template: | ||
| template = self._template | ||
| parameters = re.findall(r"\{(.+?)\}", template) |
There was a problem hiding this comment.
The regex doesn't quiet work with formatting strings. Maybe something like this?
{([^:]+?)(?::([^:]+))?}
for
"{line:03d}"
There was a problem hiding this comment.
Used a new pattern. I think my new one works as well although the replacing is quite ugly.
pylint/reporters/text.py
Outdated
| parameters = re.findall(r"\{(.+?)\}", template) | ||
| for parameter in parameters: | ||
| if parameter not in self_dict: | ||
| template = template.replace(f"{{{parameter}}}", "") |
There was a problem hiding this comment.
Is it save to overwrite self._template directly?
There was a problem hiding this comment.
It should be in its new place
pylint/reporters/text.py
Outdated
| # Check to see if all parameters in the template are attributes of the Message | ||
| template = self._template | ||
| parameters = re.findall(r"\{(.+?)(:.*)?\}", template) | ||
| for parameter in parameters: | ||
| if parameter[0] not in Message._fields: | ||
| template = re.sub(r"\{" + parameter[0] + r"(:.*?)?\}", "", template) | ||
| self._template = template |
There was a problem hiding this comment.
Just an idea, currently this is down for every module. Can we store the original template and the new one. Then for every subsequent call, compare the "new" self._template with the stored template and if they match use the fixed one.
There was a problem hiding this comment.
It might also be a good idea to at least emit a short warning: Hey, we don't know this option are you sure?. Otherwise we fail silently.
There was a problem hiding this comment.
Done and done!
Co-authored-by: Pierre Sassoulas <pierre.sassoulas@gmail.com>
for more information, see https://pre-commit.ci
doc/whatsnew/2.12.rst
Outdated
| end of a node to the output of Pylint. If these numbers are unknown, they are represented | ||
| by an empty string. | ||
|
|
||
| * Add ``end_line`` and ``end_column`` fields to the output of the ``JSONReporter``. |
Did not see change to JsonReporter
|
@DanielNoord I fixed the merged conflict but is this ready to review ? I'm a little lost about the order to follow between #5349 #5372 and #5336 |
|
#5376 was not in the 2.12.0 milestone I added it. |
Pierre-Sassoulas
left a comment
There was a problem hiding this comment.
LGTM ! I only have a small question.
| * Add ability to add ``end_line`` and ``end_column`` to the ``--msg-template`` option. | ||
| With the standard ``TextReporter`` this will add the line and column number of the | ||
| end of a node to the output of Pylint. If these numbers are unknown, they are represented | ||
| by an empty string. |
There was a problem hiding this comment.
I think we could also change the default for msg-template in 3.0. Do we want the default to have end line and end column ? This seems like something that is useful in an IDE but not a lot for a text output read by humans.
There was a problem hiding this comment.
@cdce8p Argued that we might leave the default output as is because of the potential to break many tools. I think this is a discussion which (if we want to have it anyway) we could leave until we are closer to the release of 3.0. With this merge everybody that wants to can use this new feature!
doc/whatsnew/<current release.rst>.Type of Changes
Description
Blocked by #5343
Ref #5336
This updates the reporters of
pylintto start usingend_lineandend_column. It is the first PR as mentioned in #5343 (comment)