Skip to content

Commit 02a4109

Browse files
authored
Fix acknowledge comments (#126)
* debugging: give test name based on input folder * change LintError to typing.NamedTuple for type info * add some more test ids * update format * handle new way of dealing with multiple violations on a line * handle that comments can trigger W505. * format * update tests * handle lint errors * these aren't valid code files that can pass black * update tests * this doesn't get used like we thought it did * make spacing consistent * bump patch version * cleanup leading spaces * add test that old comment stile is removed on --aggressive
1 parent 875c8c7 commit 02a4109

File tree

26 files changed

+262
-205
lines changed

26 files changed

+262
-205
lines changed

ni_python_styleguide/_acknowledge_existing_errors/__init__.py

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@
33
import re
44
from collections import defaultdict
55

6-
from ni_python_styleguide import _format
7-
from ni_python_styleguide import _utils
6+
from ni_python_styleguide import _format, _utils
87

98
_module_logger = logging.getLogger(__name__)
109

@@ -18,16 +17,25 @@ def _add_noqa_to_line(lineno, code_lines, error_code, explanation):
1817
old_line_ending = "\n" if line.endswith("\n") else ""
1918
line = line.rstrip("\n")
2019

21-
if f"noqa {error_code}" not in line:
20+
if f"noqa: {error_code}" not in line:
2221
prefix = " " if line.strip() else ""
23-
line += f"{prefix}# noqa {error_code}: {explanation} (auto-generated noqa)"
22+
code, _, existing = line.partition("# noqa:")
23+
24+
existing_codes, _, existing_explanations = existing.partition(" - ")
25+
if existing_codes:
26+
error_code = existing_codes + ", " + error_code
27+
explanation = f"{existing_explanations}, {explanation} (auto-generated noqa)"
28+
else:
29+
explanation = explanation + " (auto-generated noqa)"
30+
31+
line = f"{code.rstrip()}{prefix}# noqa: {error_code.lstrip()} - {explanation}"
2432

2533
code_lines[lineno] = line + old_line_ending
2634

2735

2836
def _filter_suppresion_from_line(line: str):
2937
if "(auto-generated noqa)" in line:
30-
return re.sub(r"# noqa .+\(auto-generated noqa\)", "", line).rstrip()
38+
return re.sub(r"# noqa:? .+\(auto-generated noqa\)$", "", line).rstrip()
3139
else:
3240
return line
3341

@@ -56,6 +64,8 @@ def acknowledge_lint_errors(
5664
for bad_file, errors_in_file in lint_errors_by_file.items():
5765
_suppress_errors_in_file(bad_file, errors_in_file, encoding=_utils.DEFAULT_ENCODING)
5866

67+
_handle_emergent_violations(exclude, app_import_names, extend_ignore, file_or_dir, bad_file)
68+
5969
if aggressive:
6070
# some cases are expected to take up to 4 passes, making this 2x rounded
6171
per_file_format_iteration_limit = 10
@@ -81,8 +91,16 @@ def acknowledge_lint_errors(
8191
bad_file, current_lint_errors, encoding=_utils.DEFAULT_ENCODING
8292
)
8393

94+
remaining_errors = _handle_emergent_violations(
95+
exclude=exclude,
96+
app_import_names=app_import_names,
97+
extend_ignore=extend_ignore,
98+
file_or_dir=file_or_dir,
99+
bad_file=bad_file,
100+
)
101+
84102
changed = _format.format_check(bad_file)
85-
if not changed: # are we done?
103+
if not changed and not remaining_errors: # are we done?
86104
break
87105
else:
88106
failed_files.append(
@@ -93,6 +111,27 @@ def acknowledge_lint_errors(
93111
raise RuntimeError("Could not handle some files:\n" + "\n\n".join(failed_files) + "\n\n\n")
94112

95113

114+
def _handle_emergent_violations(exclude, app_import_names, extend_ignore, file_or_dir, bad_file):
115+
"""Some errors can be created by adding the acknowledge comments handle those now.
116+
117+
Example emergent violations:
118+
W505 -> due to adding comment to docstring
119+
"""
120+
current_lint_errors = set(
121+
_utils.lint.get_errors_to_process(
122+
exclude=exclude,
123+
app_import_names=app_import_names,
124+
extend_ignore=extend_ignore,
125+
file_or_dir=file_or_dir,
126+
excluded_errors=EXCLUDED_ERRORS,
127+
)
128+
)
129+
errors_to_process_now = set(filter(lambda o: o.code in {"W505"}, current_lint_errors))
130+
_suppress_errors_in_file(bad_file, errors_to_process_now, encoding=_utils.DEFAULT_ENCODING)
131+
remaining_errors = current_lint_errors - errors_to_process_now
132+
return remaining_errors
133+
134+
96135
def remove_auto_suppressions_from_file(file: pathlib.Path):
97136
"""Removes auto-suppressions from file."""
98137
lines = file.read_text(encoding=_utils.DEFAULT_ENCODING).splitlines()

ni_python_styleguide/_utils/lint.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import logging
22
import re
3-
from collections import namedtuple
3+
import typing
44

55
from ni_python_styleguide import _lint
66

@@ -23,7 +23,14 @@ def get_errors_to_process(exclude, app_import_names, extend_ignore, file_or_dir,
2323
return lint_errors_to_process
2424

2525

26-
LintError = namedtuple("LintError", ["file", "line", "column", "code", "explanation"])
26+
class LintError(typing.NamedTuple):
27+
"""Class defining a lint error."""
28+
29+
file: str
30+
line: int
31+
column: int
32+
code: str
33+
explanation: str
2734

2835

2936
def parse(line):

pyproject.toml

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@ name = "ni-python-styleguide"
33
# The -alpha.0 here denotes a source based version
44
# This is removed when released through the Publish-Package.yml GitHub action
55
# Official PyPI releases follow Major.Minor.Patch
6-
version = "0.4.0-alpha.0"
6+
version = "0.4.1-alpha.0"
77
description = "NI's internal and external Python linter rules and plugins"
88
authors = ["NI <[email protected]>"]
99
readme = "README.md" # apply the repo readme to the package as well
1010
repository = "https://github.com/ni/python-styleguide"
1111
license = "MIT"
1212
include = ["ni_python_styleguide/config.toml"]
1313

14+
1415
[tool.poetry.dependencies]
1516
python = "^3.7"
1617

@@ -24,7 +25,6 @@ click = ">=7.1.2"
2425
toml = ">=0.10.1"
2526
isort = ">=5.10"
2627

27-
2828
# flake8 plugins should be listed here (in alphabetical order)
2929
flake8-black = ">=0.2.1"
3030
flake8-docstrings = ">=1.5.0"
@@ -40,29 +40,30 @@ pep8-naming = ">=0.11.1"
4040
# Tooling that we're locking so our tool can run
4141
importlib-metadata = {version= "<5.0", python="<3.8"}
4242

43+
4344
[tool.poetry.dev-dependencies]
4445
pytest = ">=6.0.1"
4546
pytest_click = ">=1.0.2"
4647
pytest-snapshot = ">=0.6.3"
4748

49+
4850
[tool.poetry.scripts]
4951
ni-python-styleguide = 'ni_python_styleguide._cli:main'
5052

53+
5154
[tool.black]
5255
line-length = 100
53-
extend-exclude = '''
54-
(
55-
/.*__snapshots/.*output\.py # exclude the simple snapshot outputs
56-
)
57-
'''
56+
5857

5958
[tool.pytest.ini_options]
6059
addopts = "--doctest-modules"
6160
norecursedirs = "*__snapshots"
6261

62+
6363
[tool.ni-python-styleguide]
6464
extend_exclude = "*__snapshots/*/*input.py"
6565

66+
6667
[build-system]
6768
requires = ["poetry>=0.12"]
6869
build-backend = "poetry.masonry.api"

tests/test_cli/acknowledge_existing_errors_test_cases__snapshots/blank_file_tests/output.py

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# noqa: D100 - Missing docstring in public module (auto-generated noqa)
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
# noqa D100: Missing docstring in public module (auto-generated noqa)
1+
# noqa: D100 - Missing docstring in public module (auto-generated noqa)

tests/test_cli/acknowledge_existing_errors_test_cases__snapshots/doc_line_tests/output.py renamed to tests/test_cli/acknowledge_existing_errors_test_cases__snapshots/doc_line_tests/output.py.txt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
1-
def method1(): # noqa D100: Missing docstring in public module (auto-generated noqa) # noqa D103: Missing docstring in public function (auto-generated noqa)
1+
def method1(): # noqa: D100, D103 - Missing docstring in public module (auto-generated noqa), Missing docstring in public function (auto-generated noqa)
22
return 7
33

44

55
def method2():
66
"""Provide an examples of doc strings that are too long.
77

88
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
9-
""" # noqa W505: doc line too long (127 > 100 characters) (auto-generated noqa)
9+
""" # noqa: W505 - doc line too long (127 > 100 characters) (auto-generated noqa)
1010
return 7 # Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
1111

1212

13-
class Foo: # noqa D101: Missing docstring in public class (auto-generated noqa)
14-
def __init__(self): # noqa D107: Missing docstring in __init__ (auto-generated noqa)
13+
class Foo: # noqa: D101 - Missing docstring in public class (auto-generated noqa)
14+
def __init__(self): # noqa: D107 - Missing docstring in __init__ (auto-generated noqa)
1515
pass
1616

1717
def add(self, o):
1818
"""Provide an examples of doc strings that are too long.
1919

2020
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
21-
""" # noqa W505: doc line too long (131 > 100 characters) (auto-generated noqa)
21+
""" # noqa: W505 - doc line too long (131 > 100 characters) (auto-generated noqa)
2222
return 7 # Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
2323

2424

@@ -30,5 +30,5 @@ def add(self, o):
3030
"""Provide an examples of doc strings that are too long.
3131

3232
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
33-
""" # noqa W505: doc line too long (131 > 100 characters) (auto-generated noqa)
33+
""" # noqa: W505 - doc line too long (131 > 100 characters) (auto-generated noqa)
3434
return 7 # Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
1-
def method1(): # noqa D100: Missing docstring in public module (auto-generated noqa) # noqa D103: Missing docstring in public function (auto-generated noqa)
1+
def method1(): # noqa: D100, D103 - Missing docstring in public module (auto-generated noqa), Missing docstring in public function (auto-generated noqa)
22
return 7
33

44

55
def method2():
66
"""Provide an examples of doc strings that are too long.
77
88
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
9-
""" # noqa W505: doc line too long (127 > 100 characters) (auto-generated noqa)
9+
""" # noqa: W505 - doc line too long (127 > 100 characters) (auto-generated noqa)
1010
return 7 # Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
1111

1212

13-
class Foo: # noqa D101: Missing docstring in public class (auto-generated noqa)
14-
def __init__(self): # noqa D107: Missing docstring in __init__ (auto-generated noqa)
13+
class Foo: # noqa: D101 - Missing docstring in public class (auto-generated noqa)
14+
def __init__(self): # noqa: D107 - Missing docstring in __init__ (auto-generated noqa)
1515
pass
1616

1717
def add(self, o):
1818
"""Provide an examples of doc strings that are too long.
1919
2020
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
21-
""" # noqa W505: doc line too long (131 > 100 characters) (auto-generated noqa)
21+
""" # noqa: W505 - doc line too long (131 > 100 characters) (auto-generated noqa)
2222
return 7 # Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
2323

2424

@@ -30,5 +30,5 @@ def add(self, o):
3030
"""Provide an examples of doc strings that are too long.
3131
3232
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
33-
""" # noqa W505: doc line too long (131 > 100 characters) (auto-generated noqa)
33+
""" # noqa: W505 - doc line too long (131 > 100 characters) (auto-generated noqa)
3434
return 7 # Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

tests/test_cli/acknowledge_existing_errors_test_cases__snapshots/function_signature_tests/output.py renamed to tests/test_cli/acknowledge_existing_errors_test_cases__snapshots/function_signature_tests/output.py.txt

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -35,68 +35,68 @@ def method_with_parameters_on_multiple_lines(x, y):
3535
return x + y
3636

3737

38-
def method_with_bad_names_on_single_line(myBadlyNamedParam, my_other_Bad_name): # noqa N803: argument name 'myBadlyNamedParam' should be lowercase (auto-generated noqa)
38+
def method_with_bad_names_on_single_line(myBadlyNamedParam, my_other_Bad_name): # noqa: N803 - argument name 'myBadlyNamedParam' should be lowercase (auto-generated noqa)
3939
"""Provide parameters with bad names on single line."""
4040
return myBadlyNamedParam + my_other_Bad_name
4141

4242

4343
def method_with_bad_names_on_multiple_lines_1(
44-
myBadlyNamedParam, # noqa N803: argument name 'myBadlyNamedParam' should be lowercase (auto-generated noqa)
44+
myBadlyNamedParam, # noqa: N803 - argument name 'myBadlyNamedParam' should be lowercase (auto-generated noqa)
4545
):
4646
"""Provide parameters with bad names on multiple lines."""
4747
return myBadlyNamedParam + 5
4848

4949

5050
def method_with_bad_names_on_multiple_lines_2(
51-
myBadlyNamedParam, # noqa N803: argument name 'myBadlyNamedParam' should be lowercase (auto-generated noqa)
51+
myBadlyNamedParam, # noqa: N803 - argument name 'myBadlyNamedParam' should be lowercase (auto-generated noqa)
5252
my_other_Bad_name,
5353
):
5454
"""Provide parameters with bad names on multiple lines."""
5555
return myBadlyNamedParam + my_other_Bad_name
5656

5757

58-
def method_withBadName_with_shadow(input): # noqa N802: function name 'method_withBadName_with_shadow' should be lowercase (auto-generated noqa)
58+
def method_withBadName_with_shadow(input): # noqa: N802 - function name 'method_withBadName_with_shadow' should be lowercase (auto-generated noqa)
5959
"""Shadow a builtin."""
6060
return input
6161

6262

63-
def method_withBadName_with_unused_param(unused_input): # noqa N802: function name 'method_withBadName_with_unused_param' should be lowercase (auto-generated noqa)
63+
def method_withBadName_with_unused_param(unused_input): # noqa: N802 - function name 'method_withBadName_with_unused_param' should be lowercase (auto-generated noqa)
6464
"""Provide and unused param."""
6565
return 5
6666

6767

68-
def method_withBadName_with_parameters_on_multiple_lines(x, y): # noqa N802: function name 'method_withBadName_with_parameters_on_multiple_lines' should be lowercase (auto-generated noqa)
68+
def method_withBadName_with_parameters_on_multiple_lines(x, y): # noqa: N802 - function name 'method_withBadName_with_parameters_on_multiple_lines' should be lowercase (auto-generated noqa)
6969
"""Provide parameters on multiple lines test case."""
7070
return x + y
7171

7272

73-
def method_withBadName_with_bad_params_on_single_line(myBadlyNamedParam, my_other_Bad_name): # noqa N803: argument name 'myBadlyNamedParam' should be lowercase (auto-generated noqa) # noqa N802: function name 'method_withBadName_with_bad_params_on_single_line' should be lowercase (auto-generated noqa)
73+
def method_withBadName_with_bad_params_on_single_line(myBadlyNamedParam, my_other_Bad_name): # noqa: N803, N802 - argument name 'myBadlyNamedParam' should be lowercase (auto-generated noqa), function name 'method_withBadName_with_bad_params_on_single_line' should be lowercase (auto-generated noqa)
7474
"""Provide parameters with bad names on single line."""
7575
return myBadlyNamedParam + my_other_Bad_name
7676

7777

78-
def method_withBadName_with_bad_params_on_multiple_lines_1( # noqa N802: function name 'method_withBadName_with_bad_params_on_multiple_lines_1' should be lowercase (auto-generated noqa)
79-
myBadlyNamedParam, # noqa N803: argument name 'myBadlyNamedParam' should be lowercase (auto-generated noqa)
78+
def method_withBadName_with_bad_params_on_multiple_lines_1( # noqa: N802 - function name 'method_withBadName_with_bad_params_on_multiple_lines_1' should be lowercase (auto-generated noqa)
79+
myBadlyNamedParam, # noqa: N803 - argument name 'myBadlyNamedParam' should be lowercase (auto-generated noqa)
8080
):
8181
"""Provide parameters with bad names on multiple lines."""
8282
return myBadlyNamedParam + 5
8383

8484

85-
def method_withBadName_with_bad_params_on_multiple_lines_2( # noqa N802: function name 'method_withBadName_with_bad_params_on_multiple_lines_2' should be lowercase (auto-generated noqa)
86-
myBadlyNamedParam, # noqa N803: argument name 'myBadlyNamedParam' should be lowercase (auto-generated noqa)
85+
def method_withBadName_with_bad_params_on_multiple_lines_2( # noqa: N802 - function name 'method_withBadName_with_bad_params_on_multiple_lines_2' should be lowercase (auto-generated noqa)
86+
myBadlyNamedParam, # noqa: N803 - argument name 'myBadlyNamedParam' should be lowercase (auto-generated noqa)
8787
my_other_Bad_name,
8888
):
8989
"""Provide parameters with bad names on multiple lines."""
9090
return myBadlyNamedParam + my_other_Bad_name
9191

9292

93-
def method_withBadName_andParams(my_normal_param, myBadlyNamedParam, my_other_Bad_param): # noqa N803: argument name 'myBadlyNamedParam' should be lowercase (auto-generated noqa) # noqa N802: function name 'method_withBadName_andParams' should be lowercase (auto-generated noqa)
93+
def method_withBadName_andParams(my_normal_param, myBadlyNamedParam, my_other_Bad_param): # noqa: N803, N802 - argument name 'myBadlyNamedParam' should be lowercase (auto-generated noqa), function name 'method_withBadName_andParams' should be lowercase (auto-generated noqa)
9494
"""Provide example where black will want to split out result."""
9595
return 5 + 7
9696

9797

98-
def method_withBadName_and_bad_param_with_long_name( # noqa N802: function name 'method_withBadName_and_bad_param_with_long_name' should be lowercase (auto-generated noqa)
99-
my_normal_param, myBadlyNamedParam, my_other_Bad_param # noqa N803: argument name 'myBadlyNamedParam' should be lowercase (auto-generated noqa)
98+
def method_withBadName_and_bad_param_with_long_name( # noqa: N802 - function name 'method_withBadName_and_bad_param_with_long_name' should be lowercase (auto-generated noqa)
99+
my_normal_param, myBadlyNamedParam, my_other_Bad_param # noqa: N803 - argument name 'myBadlyNamedParam' should be lowercase (auto-generated noqa)
100100
):
101-
"""Provide example where black will want to split out result even more""" # noqa D415: First line should end with a period, question mark, or exclamation point (auto-generated noqa)
101+
"""Provide example where black will want to split out result even more""" # noqa: D415, W505 - First line should end with a period, question mark, or exclamation point (auto-generated noqa), doc line too long (188 > 100 characters) (auto-generated noqa)
102102
return 5 + 7

0 commit comments

Comments
 (0)