summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPierre Sassoulas <pierre.sassoulas@gmail.com>2023-01-16 23:04:25 +0100
committerGitHub <noreply@github.com>2023-01-16 23:04:25 +0100
commit4a5b4e63c8177ec1b1c7d1ecb4eb2c448c7481a3 (patch)
tree33c7d491e2462d766aa0c3f360f9499e1cce809e
parenteae0eaff11239db4dc89d570d120ff0a6cbe1e61 (diff)
downloadpylint-git-4a5b4e63c8177ec1b1c7d1ecb4eb2c448c7481a3.tar.gz
[style] Limit line length and complexity using flake8 (#8064)
125 is a good start. The check was activated in pylint with value = 100, but flake8 is less lenient than pylint and does not make any exceptions (for docstrings, strings and comments in particular).
-rw-r--r--doc/exts/pylint_messages.py4
-rw-r--r--pylint/checkers/exceptions.py5
-rw-r--r--pylint/checkers/similar.py49
-rw-r--r--pylint/lint/pylinter.py3
-rw-r--r--pylint/pyreverse/inspector.py7
-rw-r--r--pylint/pyreverse/main.py9
-rw-r--r--pylint/pyreverse/plantuml_printer.py3
-rw-r--r--setup.cfg7
-rw-r--r--tests/checkers/unittest_spelling.py53
-rw-r--r--tests/test_func.py6
-rw-r--r--tests/test_self.py12
11 files changed, 86 insertions, 72 deletions
diff --git a/doc/exts/pylint_messages.py b/doc/exts/pylint_messages.py
index cef7c83a4..074e69387 100644
--- a/doc/exts/pylint_messages.py
+++ b/doc/exts/pylint_messages.py
@@ -290,8 +290,8 @@ def _generate_single_message_body(message: MessageData) -> str:
if message.checker_module_name.startswith("pylint.extensions."):
body += f"""
.. note::
- This message is emitted by the optional :ref:`'{message.checker}'<{message.checker_module_name}>` checker which requires the ``{message.checker_module_name}``
- plugin to be loaded.
+ This message is emitted by the optional :ref:`'{message.checker}'<{message.checker_module_name}>`
+ checker which requires the ``{message.checker_module_name}`` plugin to be loaded.
"""
return body
diff --git a/pylint/checkers/exceptions.py b/pylint/checkers/exceptions.py
index fbe71a598..0e30e5386 100644
--- a/pylint/checkers/exceptions.py
+++ b/pylint/checkers/exceptions.py
@@ -544,7 +544,10 @@ class ExceptionsChecker(checkers.BaseChecker):
def visit_compare(self, node: nodes.Compare) -> None:
if isinstance(node.parent, nodes.ExceptHandler):
# except (V < A)
- suggestion = f"Did you mean '({node.left.as_string()}, {', '.join(operand.as_string() for _, operand in node.ops)})' instead?"
+ suggestion = (
+ f"Did you mean '({node.left.as_string()}, "
+ f"{', '.join(o.as_string() for _, o in node.ops)})' instead?"
+ )
self.add_message("wrong-exception-operation", node=node, args=(suggestion,))
@utils.only_required_for_messages(
diff --git a/pylint/checkers/similar.py b/pylint/checkers/similar.py
index 3b18ddbfd..69b0677bd 100644
--- a/pylint/checkers/similar.py
+++ b/pylint/checkers/similar.py
@@ -5,16 +5,26 @@
"""A similarities / code duplication command line tool and pylint checker.
The algorithm is based on comparing the hash value of n successive lines of a file.
-First the files are read and any line that doesn't fulfill requirement are removed (comments, docstrings...)
+First the files are read and any line that doesn't fulfill requirement are removed
+(comments, docstrings...)
+
Those stripped lines are stored in the LineSet class which gives access to them.
-Then each index of the stripped lines collection is associated with the hash of n successive entries of the stripped lines starting at the current index
-(n is the minimum common lines option).
-The common hashes between both linesets are then looked for. If there are matches, then the match indices in both linesets are stored and associated
-with the corresponding couples (start line number/end line number) in both files.
-This association is then post-processed to handle the case of successive matches. For example if the minimum common lines setting is set to four, then
-the hashes are computed with four lines. If one of match indices couple (12, 34) is the successor of another one (11, 33) then it means that there are
-in fact five lines which are common.
-Once post-processed the values of association table are the result looked for, i.e start and end lines numbers of common lines in both files.
+Then each index of the stripped lines collection is associated with the hash of n
+successive entries of the stripped lines starting at the current index (n is the
+minimum common lines option).
+
+The common hashes between both linesets are then looked for. If there are matches, then
+the match indices in both linesets are stored and associated with the corresponding
+couples (start line number/end line number) in both files.
+
+This association is then post-processed to handle the case of successive matches. For
+example if the minimum common lines setting is set to four, then the hashes are
+computed with four lines. If one of match indices couple (12, 34) is the
+successor of another one (11, 33) then it means that there are in fact five lines which
+are common.
+
+Once post-processed the values of association table are the result looked for, i.e.
+start and end lines numbers of common lines in both files.
"""
from __future__ import annotations
@@ -457,7 +467,11 @@ class Similar:
report += f" {line.rstrip()}\n" if line.rstrip() else "\n"
duplicated_line_number += number * (len(couples_l) - 1)
total_line_number: int = sum(len(lineset) for lineset in self.linesets)
- report += f"TOTAL lines={total_line_number} duplicates={duplicated_line_number} percent={duplicated_line_number * 100.0 / total_line_number:.2f}\n"
+ report += (
+ f"TOTAL lines={total_line_number} "
+ f"duplicates={duplicated_line_number} "
+ f"percent={duplicated_line_number * 100.0 / total_line_number:.2f}\n"
+ )
return report
def _find_common(
@@ -465,12 +479,15 @@ class Similar:
) -> Generator[Commonality, None, None]:
"""Find similarities in the two given linesets.
- This the core of the algorithm.
- The idea is to compute the hashes of a minimal number of successive lines of each lineset and then compare the hashes.
- Every match of such comparison is stored in a dict that links the couple of starting indices in both linesets to
- the couple of corresponding starting and ending lines in both files.
- Last regroups all successive couples in a bigger one. It allows to take into account common chunk of lines that have more
- than the minimal number of successive lines required.
+ This the core of the algorithm. The idea is to compute the hashes of a
+ minimal number of successive lines of each lineset and then compare the
+ hashes. Every match of such comparison is stored in a dict that links the
+ couple of starting indices in both linesets to the couple of corresponding
+ starting and ending lines in both files.
+
+ Last regroups all successive couples in a bigger one. It allows to take into
+ account common chunk of lines that have more than the minimal number of
+ successive lines required.
"""
hash_to_index_1: HashToIndex_T
hash_to_index_2: HashToIndex_T
diff --git a/pylint/lint/pylinter.py b/pylint/lint/pylinter.py
index e773644ff..4d1bede9a 100644
--- a/pylint/lint/pylinter.py
+++ b/pylint/lint/pylinter.py
@@ -1252,8 +1252,9 @@ class PyLinter(
msg_cat = MSG_TYPES[message_definition.msgid[0]]
self.msg_status |= MSG_TYPES_STATUS[message_definition.msgid[0]]
self.stats.increase_single_message_count(msg_cat, 1)
+ # TODO: 3.0 Should be removable after https://github.com/PyCQA/pylint/pull/5580
self.stats.increase_single_module_message_count(
- self.current_name, # type: ignore[arg-type] # Should be removable after https://github.com/PyCQA/pylint/pull/5580
+ self.current_name, # type: ignore[arg-type]
msg_cat,
1,
)
diff --git a/pylint/pyreverse/inspector.py b/pylint/pyreverse/inspector.py
index af97cdb33..9150bbef3 100644
--- a/pylint/pyreverse/inspector.py
+++ b/pylint/pyreverse/inspector.py
@@ -202,9 +202,10 @@ class Linker(IdGeneratorMixIn, utils.LocalsVisitor):
if node.implements:
# TODO: 3.0: Remove support for __implements__
warnings.warn(
- "pyreverse will drop support for resolving and displaying implemented interfaces in pylint 3.0. "
- "The implementation relies on the '__implements__' attribute proposed in PEP 245, which was rejected "
- "in 2006.",
+ "pyreverse will drop support for resolving and displaying "
+ "implemented interfaces in pylint 3.0. The implementation "
+ "relies on the '__implements__' attribute proposed in PEP 245"
+ ", which was rejected in 2006.",
DeprecationWarning,
)
else:
diff --git a/pylint/pyreverse/main.py b/pylint/pyreverse/main.py
index 72429b41a..8a2055c41 100644
--- a/pylint/pyreverse/main.py
+++ b/pylint/pyreverse/main.py
@@ -145,8 +145,10 @@ OPTIONS: Options = (
"metavar": "<format>",
"type": "string",
"help": (
- f"create a *.<format> output file if format is available. Available formats are: {', '.join(DIRECTLY_SUPPORTED_FORMATS)}. "
- f"Any other format will be tried to create by means of the 'dot' command line tool, which requires a graphviz installation."
+ "create a *.<format> output file if format is available. Available "
+ f"formats are: {', '.join(DIRECTLY_SUPPORTED_FORMATS)}. Any other "
+ f"format will be tried to create by means of the 'dot' command line "
+ f"tool, which requires a graphviz installation."
),
},
),
@@ -221,7 +223,8 @@ class Run(_ArgumentsManager, _ArgumentsProvider):
if self.config.output_format not in DIRECTLY_SUPPORTED_FORMATS:
check_graphviz_availability()
print(
- f"Format {self.config.output_format} is not supported natively. Pyreverse will try to generate it using Graphviz..."
+ f"Format {self.config.output_format} is not supported natively."
+ " Pyreverse will try to generate it using Graphviz..."
)
check_if_graphviz_supports_format(self.config.output_format)
diff --git a/pylint/pyreverse/plantuml_printer.py b/pylint/pyreverse/plantuml_printer.py
index 56463165d..de3f983b7 100644
--- a/pylint/pyreverse/plantuml_printer.py
+++ b/pylint/pyreverse/plantuml_printer.py
@@ -40,7 +40,8 @@ class PlantUmlPrinter(Printer):
self.emit("top to bottom direction")
else:
raise ValueError(
- f"Unsupported layout {self.layout}. PlantUmlPrinter only supports left to right and top to bottom layout."
+ f"Unsupported layout {self.layout}. PlantUmlPrinter only "
+ "supports left to right and top to bottom layout."
)
def emit_node(
diff --git a/setup.cfg b/setup.cfg
index b6ebd2b77..e4c696c4c 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -12,15 +12,14 @@ license_files =
# Incompatible with black see https://github.com/ambv/black/issues/315
# E203: Whitespace before ':'
# W503: Line break occurred before a binary operator
-# E501: Line too long
# B028: consider using the `!r` conversion flag
ignore =
E203,
W503,
- E501,
B028,
-max-line-length=88
-max-complexity=39
+# Flake8 is less lenient than pylint and does not make any exceptions
+# (for docstrings, strings and comments in particular).
+max-line-length=125
# Required for flake8-typing-imports (v1.12.0)
# The plugin doesn't yet read the value from pyproject.toml
min_python_version = 3.7.2
diff --git a/tests/checkers/unittest_spelling.py b/tests/checkers/unittest_spelling.py
index abeb9dcf8..29783429b 100644
--- a/tests/checkers/unittest_spelling.py
+++ b/tests/checkers/unittest_spelling.py
@@ -286,44 +286,29 @@ class TestSpellingChecker(CheckerTestCase): # pylint:disable=too-many-public-me
@skip_on_missing_package_or_dict
@set_config(spelling_dict=spell_dict)
@pytest.mark.parametrize(
- ",".join(
- (
- "misspelled_portion_of_directive",
- "second_portion_of_directive",
- "description",
- )
- ),
+ "prefix,suffix",
(
- ("fmt", ": on", "black directive to turn on formatting"),
- ("fmt", ": off", "black directive to turn off formatting"),
- ("noqa", "", "pycharm directive"),
- ("noqa", ":", "flake8 / zimports directive"),
- ("nosec", "", "bandit directive"),
- ("isort", ":skip", "isort directive"),
- ("mypy", ":", "mypy top of file directive"),
+ pytest.param("fmt", ": on", id="black directive to turn on formatting"),
+ pytest.param("fmt", ": off", id="black directive to turn off formatting"),
+ pytest.param("noqa", "", id="pycharm directive"),
+ pytest.param("noqa", ":", id="flake8 / zimports directive"),
+ pytest.param("nosec", "", id="bandit directive"),
+ pytest.param("isort", ":skip", id="isort directive"),
+ pytest.param("mypy", ":", id="mypy top of file directive"),
),
)
- def test_skip_tool_directives_at_beginning_of_comments_but_still_raise_error_if_directive_appears_later_in_comment( # pylint:disable=unused-argument
- # Having the extra description parameter allows the description
- # to show up in the pytest output as part of the test name
- # when running parameterized tests.
- self,
- misspelled_portion_of_directive: str,
- second_portion_of_directive: str,
- description: str,
- ) -> None:
- full_comment = f"# {misspelled_portion_of_directive}{second_portion_of_directive} {misspelled_portion_of_directive}"
+ def test_tool_directives_handling(self, prefix: str, suffix: str) -> None:
+ """We're not raising when the directive is at the beginning of comments,
+ but we raise if a directive appears later in comment."""
+ full_comment = f"# {prefix}{suffix} {prefix}"
+ args = (
+ prefix,
+ full_comment,
+ f" {'^' * len(prefix)}",
+ self._get_msg_suggestions(prefix),
+ )
with self.assertAddsMessages(
- MessageTest(
- "wrong-spelling-in-comment",
- line=1,
- args=(
- misspelled_portion_of_directive,
- full_comment,
- f" {'^'*len(misspelled_portion_of_directive)}",
- self._get_msg_suggestions(misspelled_portion_of_directive),
- ),
- )
+ MessageTest("wrong-spelling-in-comment", line=1, args=args)
):
self.checker.process_tokens(_tokenize_str(full_comment))
diff --git a/tests/test_func.py b/tests/test_func.py
index 493489aee..a032baf5d 100644
--- a/tests/test_func.py
+++ b/tests/test_func.py
@@ -73,9 +73,11 @@ class LintTestUsingModule:
self.linter.check(tocheck)
except Exception as ex:
print(f"Exception: {ex} in {tocheck}:: {'‚ '.join(ex.args)}")
- ex.file = tocheck # type: ignore[attr-defined] # This is legacy code we're trying to remove, not worth it to type correctly
+ # This is legacy code we're trying to remove, not worth it to type correctly
+ ex.file = tocheck # type: ignore[attr-defined]
print(ex)
- ex.__str__ = exception_str # type: ignore[assignment] # This is legacy code we're trying to remove, impossible to type correctly
+ # This is legacy code we're trying to remove, not worth it to type correctly
+ ex.__str__ = exception_str # type: ignore[assignment]
raise
assert isinstance(self.linter.reporter, GenericTestReporter)
self._check_result(self.linter.reporter.finalize())
diff --git a/tests/test_self.py b/tests/test_self.py
index 9cec1b1c9..076f2a22f 100644
--- a/tests/test_self.py
+++ b/tests/test_self.py
@@ -1052,19 +1052,21 @@ a.py:1:4: E0001: Parsing failed: 'invalid syntax (<unknown>, line 1)' (syntax-er
[
(
"text",
- "tests/regrtest_data/unused_variable.py:4:4: W0612: Unused variable 'variable' (unused-variable)",
+ "{path}:4:4: W0612: Unused variable 'variable' (unused-variable)",
),
(
"parseable",
- "tests/regrtest_data/unused_variable.py:4: [W0612(unused-variable), test] Unused variable 'variable'",
+ "{path}:4: [W0612(unused-variable), test] Unused variable 'variable'",
),
(
"msvs",
- "tests/regrtest_data/unused_variable.py(4): [W0612(unused-variable)test] Unused variable 'variable'",
+ "{path}(4): [W0612(unused-variable)test] Unused variable 'variable'",
),
(
"colorized",
- "tests/regrtest_data/unused_variable.py:4:4: W0612: \x1B[35mUnused variable 'variable'\x1B[0m (\x1B[35munused-variable\x1B[0m)",
+ (
+ "{path}:4:4: W0612: \x1B[35mUnused variable 'variable'\x1B[0m (\x1B[35munused-variable\x1B[0m)"
+ ),
),
("json", '"message": "Unused variable \'variable\'",'),
],
@@ -1077,7 +1079,7 @@ a.py:1:4: E0001: Parsing failed: 'invalid syntax (<unknown>, line 1)' (syntax-er
self._test_output_file(
[path, f"--output={output_file}", f"--output-format={output_format}"],
output_file,
- expected_output,
+ expected_output.format(path="tests/regrtest_data/unused_variable.py"),
)
def test_output_file_can_be_combined_with_custom_reporter(