-
-
Notifications
You must be signed in to change notification settings - Fork 429
add TooManyComments (#3689) #3695
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| from collections.abc import Sequence | ||
| from tokenize import COMMENT, TokenInfo | ||
|
|
||
|
|
||
| def count_comments_in_range( | ||
| file_tokens: Sequence[TokenInfo], | ||
| start_line: int, | ||
| end_line: int, | ||
| ) -> int: | ||
| """Counts comment tokens within a given line range.""" | ||
| return sum( | ||
| 1 | ||
| for token in file_tokens | ||
| if token.type == COMMENT and start_line <= token.start[0] <= end_line | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -166,6 +166,9 @@ class of violations that are forbidden to ignore inline, defaults to | |
| expression. | ||
| defaults to | ||
| :str:`wemake_python_styleguide.options.defaults.MAX_CONDITIONS` | ||
| - ``max-comments-in-function`` - maximum number of comments in a single | ||
| function, defaults to | ||
| :str:`wemake_python_styleguide.options.defaults.MAX_COMMENTS_IN_FUNCTION` | ||
|
|
||
| .. rubric:: Formatter options | ||
|
|
||
|
|
@@ -239,6 +242,11 @@ class Configuration: | |
| defaults.MAX_NOQA_COMMENTS, | ||
| 'Maximum amount of `noqa` comments per module.', | ||
| ), | ||
| _Option( | ||
| '--max-comments-in-function', | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think that it should be this simple. We should count the code / comments rate. There might be several important cases:
These cases are valid. def some():
x = 1 # define x
y = 2 # define y
z = 3 # define z
return x + y # return their sumWe should also ignore So, basically we need to find a lot of slop code, analyze its comments and patterns, try to formalize it, ban it. This is a very complex task :)
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the details! |
||
| defaults.MAX_COMMENTS_IN_FUNCTION, | ||
| 'Maximum number of comments in a single function.', | ||
| ), | ||
| _Option( | ||
| '--nested-classes-whitelist', | ||
| defaults.NESTED_CLASSES_WHITELIST, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| import ast | ||
| from typing import cast, final | ||
|
|
||
| from wemake_python_styleguide.logic.tokens.comments import ( | ||
| count_comments_in_range, | ||
| ) | ||
| from wemake_python_styleguide.types import AnyFunctionDef | ||
| from wemake_python_styleguide.violations.best_practices import ( | ||
| TooManyCommentsViolation, | ||
| ) | ||
| from wemake_python_styleguide.visitors.base import BaseNodeTokenVisitor | ||
| from wemake_python_styleguide.visitors.decorators import alias | ||
|
|
||
|
|
||
| @final | ||
| @alias( | ||
| 'visit_any_function', | ||
| ( | ||
| 'visit_FunctionDef', | ||
| 'visit_AsyncFunctionDef', | ||
| ), | ||
| ) | ||
| class FunctionCommentsVisitor(BaseNodeTokenVisitor): | ||
| """Checks comment count limits inside functions.""" | ||
|
|
||
| def visit_any_function( | ||
| self, | ||
| node: AnyFunctionDef, | ||
| ) -> None: | ||
| """Checks comment count for each function.""" | ||
| self._check_comments_count(node) | ||
| self.generic_visit(node) | ||
|
|
||
| def _check_comments_count( | ||
| self, | ||
| node: AnyFunctionDef, | ||
| ) -> None: | ||
| """Checks whether the function exceeds the max allowed comment count.""" | ||
| nested_ranges: list[tuple[int, int]] = [ | ||
| (child.lineno, cast(int, child.end_lineno)) | ||
| for child in ast.walk(node) | ||
| if isinstance(child, AnyFunctionDef) and child is not node | ||
| ] | ||
|
|
||
| nested_ranges.sort() | ||
|
|
||
| comments_count = 0 | ||
| cursor = node.lineno | ||
|
|
||
| for n_start, n_end in nested_ranges: | ||
| if cursor < n_start: | ||
| comments_count += count_comments_in_range( | ||
| self.file_tokens, | ||
| cursor, | ||
| n_start - 1, | ||
| ) | ||
| cursor = n_end + 1 | ||
|
|
||
| if cursor <= cast(int, node.end_lineno): | ||
| comments_count += count_comments_in_range( | ||
| self.file_tokens, | ||
| cursor, | ||
| cast(int, node.end_lineno), | ||
| ) | ||
|
|
||
| if comments_count > self.options.max_comments_in_function: | ||
| self.add_violation( | ||
| TooManyCommentsViolation( | ||
| node, | ||
| text=str(comments_count), | ||
| baseline=self.options.max_comments_in_function, | ||
| ), | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In
test_noqaonly one example is needed, here we test: