summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniƫl van Noord <13665637+DanielNoord@users.noreply.github.com>2021-11-24 14:35:27 +0100
committerGitHub <noreply@github.com>2021-11-24 14:35:27 +0100
commit7c3533ca48e69394391945de1563ef7f639cd27d (patch)
treedb8d282b04ab7779ea28256330afa948c16e2550
parent5e9d20dc32768e873ab84bc4ed0b489fdda40672 (diff)
downloadpylint-git-7c3533ca48e69394391945de1563ef7f639cd27d.tar.gz
Update reporters to (allow) use of ``end_line`` and ``end_column`` (#5372)
* Update reporters to (allow) use end_line and end_column Co-authored-by: Marc Mueller <30130371+cdce8p@users.noreply.github.com> Co-authored-by: Pierre Sassoulas <pierre.sassoulas@gmail.com>
-rw-r--r--ChangeLog5
-rw-r--r--doc/user_guide/output.rst7
-rw-r--r--doc/whatsnew/2.12.rst5
-rw-r--r--pylint/reporters/text.py30
-rw-r--r--tests/unittest_reporting.py66
5 files changed, 111 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index b3c5fbcf7..9a20365af 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -15,6 +15,11 @@ Release date: TBA
Closes #4982
+* 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.
+
* Introduced primer tests and a configuration tests framework. The helper classes available in
``pylint/testutil/`` are still unstable and might be modified in the near future.
diff --git a/doc/user_guide/output.rst b/doc/user_guide/output.rst
index 52959d3c7..1aa18f3b3 100644
--- a/doc/user_guide/output.rst
+++ b/doc/user_guide/output.rst
@@ -58,6 +58,10 @@ line
line number
column
column number
+end_line
+ line number of the end of the node
+end_column
+ column number of the end of the node
module
module name
obj
@@ -94,6 +98,9 @@ A few other examples:
The ``--msg-template`` option can only be combined with text-based reporters (``--output-format`` either unspecified or one of: parseable, colorized or msvs).
If both ``--output-format`` and ``--msg-template`` are specified, the ``--msg-template`` option will take precedence over the default line format defined by the reporter class.
+If ``end_line`` or ``end_column`` are ``None``, they will be represented as an empty string
+by the default ``TextReporter``.
+
.. _Python new format syntax: https://docs.python.org/2/library/string.html#formatstrings
Source code analysis section
diff --git a/doc/whatsnew/2.12.rst b/doc/whatsnew/2.12.rst
index dae98d485..473a3ba02 100644
--- a/doc/whatsnew/2.12.rst
+++ b/doc/whatsnew/2.12.rst
@@ -205,6 +205,11 @@ Other Changes
Partially closes #5321
+* 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.
+
* Introduced primer tests and a configuration tests framework. The helper classes available in
``pylint/testutil/`` are still unstable and might be modified in the near future.
diff --git a/pylint/reporters/text.py b/pylint/reporters/text.py
index d4e7cf70c..b8de25dc0 100644
--- a/pylint/reporters/text.py
+++ b/pylint/reporters/text.py
@@ -24,6 +24,7 @@
:colorized: an ANSI colorized text reporter
"""
import os
+import re
import sys
import warnings
from typing import (
@@ -183,13 +184,38 @@ class TextReporter(BaseReporter):
super().__init__(output)
self._modules: Set[str] = set()
self._template = self.line_format
+ self._fixed_template = self.line_format
+ """The output format template with any unrecognized arguments removed"""
def on_set_current_module(self, module: str, filepath: Optional[str]) -> None:
- self._template = str(self.linter.config.msg_template or self._template)
+ """Set the format template to be used and check for unrecognized arguments."""
+ template = str(self.linter.config.msg_template or self._template)
+
+ # Return early if the template is the same as the previous one
+ if template == self._template:
+ return
+
+ # Set template to the currently selected template
+ self._template = template
+
+ # Check to see if all parameters in the template are attributes of the Message
+ arguments = re.findall(r"\{(.+?)(:.*)?\}", template)
+ for argument in arguments:
+ if argument[0] not in Message._fields:
+ warnings.warn(
+ f"Don't recognize the argument '{argument[0]}' in the --msg-template. "
+ "Are you sure it is supported on the current version of pylint?"
+ )
+ template = re.sub(r"\{" + argument[0] + r"(:.*?)?\}", "", template)
+ self._fixed_template = template
def write_message(self, msg: Message) -> None:
"""Convenience method to write a formatted message with class default template"""
- self.writeln(msg.format(self._template))
+ self_dict = msg._asdict()
+ for key in ("end_line", "end_column"):
+ self_dict[key] = self_dict[key] or ""
+
+ self.writeln(self._fixed_template.format(**self_dict))
def handle_message(self, msg: Message) -> None:
"""manage message of different type and in the context of path"""
diff --git a/tests/unittest_reporting.py b/tests/unittest_reporting.py
index 22fdc905c..3e6fdafd1 100644
--- a/tests/unittest_reporting.py
+++ b/tests/unittest_reporting.py
@@ -57,6 +57,72 @@ def test_template_option(linter):
assert output.getvalue() == "************* Module 0123\nC0301:001\nC0301:002\n"
+def test_template_option_default(linter) -> None:
+ """Test the default msg-template setting"""
+ output = StringIO()
+ linter.reporter.out = output
+ linter.open()
+ linter.set_current_module("my_module")
+ linter.add_message("C0301", line=1, args=(1, 2))
+ linter.add_message("line-too-long", line=2, args=(3, 4))
+
+ out_lines = output.getvalue().split("\n")
+ assert out_lines[1] == "my_module:1:0: C0301: Line too long (1/2) (line-too-long)"
+ assert out_lines[2] == "my_module:2:0: C0301: Line too long (3/4) (line-too-long)"
+
+
+def test_template_option_end_line(linter) -> None:
+ """Test the msg-template option with end_line and end_column"""
+ output = StringIO()
+ linter.reporter.out = output
+ linter.set_option(
+ "msg-template",
+ "{path}:{line}:{column}:{end_line}:{end_column}: {msg_id}: {msg} ({symbol})",
+ )
+ linter.open()
+ linter.set_current_module("my_mod")
+ linter.add_message("C0301", line=1, args=(1, 2))
+ linter.add_message(
+ "line-too-long", line=2, end_lineno=2, end_col_offset=4, args=(3, 4)
+ )
+
+ out_lines = output.getvalue().split("\n")
+ assert out_lines[1] == "my_mod:1:0::: C0301: Line too long (1/2) (line-too-long)"
+ assert out_lines[2] == "my_mod:2:0:2:4: C0301: Line too long (3/4) (line-too-long)"
+
+
+def test_template_option_non_exisiting(linter) -> None:
+ """Test the msg-template option with a non exisiting options.
+ This makes sure that this option remains backwards compatible as new
+ parameters do not break on previous versions"""
+ output = StringIO()
+ linter.reporter.out = output
+ linter.set_option(
+ "msg-template",
+ "{path}:{line}:{a_new_option}:({a_second_new_option:03d})",
+ )
+ linter.open()
+ with pytest.warns(UserWarning) as records:
+ linter.set_current_module("my_mod")
+ assert len(records) == 2
+ assert (
+ "Don't recognize the argument 'a_new_option'" in records[0].message.args[0]
+ )
+ assert (
+ "Don't recognize the argument 'a_second_new_option'"
+ in records[1].message.args[0]
+ )
+
+ linter.add_message("C0301", line=1, args=(1, 2))
+ linter.add_message(
+ "line-too-long", line=2, end_lineno=2, end_col_offset=4, args=(3, 4)
+ )
+
+ out_lines = output.getvalue().split("\n")
+ assert out_lines[1] == "my_mod:1::()"
+ assert out_lines[2] == "my_mod:2::()"
+
+
def test_deprecation_set_output(recwarn):
"""TODO remove in 3.0"""
reporter = BaseReporter()