Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
uhbif19 authored and sobolevn committed Dec 13, 2021
1 parent 9faaef0 commit 227731b
Show file tree
Hide file tree
Showing 8 changed files with 54 additions and 31 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ Semantic versioning in our case means:
- Forbids getting first element of list by unpacking


## 0.16.0

### Features

- Now `WPS227` forbids returning tuples that are too long

## 0.15.2

### Bugfixes
Expand Down
3 changes: 3 additions & 0 deletions tests/fixtures/noqa/noqa.py
Original file line number Diff line number Diff line change
Expand Up @@ -813,3 +813,6 @@ class TestClass(object, **{}): # noqa: WPS470

secondary_slice = items[1:][:3] # noqa: WPS471
first, *_rest = some_collection # noqa: WPS472

def foo2_func():
return (1, 2, 3, 4, 5, 6) # noqa: WPS227
2 changes: 1 addition & 1 deletion tests/test_checker/test_noqa.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@
'WPS224': 0, # defined in version specific table.
'WPS225': 1,
'WPS226': 0, # defined in ignored violations.
'WPS227': 1,
'WPS227': 2,
'WPS228': 1,
'WPS229': 1,
'WPS230': 1,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import pytest

from wemake_python_styleguide.constants import MAX_LEN_YIELD_TUPLE
from wemake_python_styleguide.constants import MAX_LEN_TUPLE_OUTPUT
from wemake_python_styleguide.violations.complexity import (
TooLongYieldTupleViolation,
TooLongOutputTupleViolation,
)
from wemake_python_styleguide.visitors.ast.complexity.counts import (
YieldTupleVisitor,
ReturnLikeStatementTupleVisitor,
)

RETURN_LIKE_STATEMENTS = ('return', 'yield')


generator = """
def function_name():
i = 0
while True:
yield {0}
{0} {1}
i = i + 1
"""

Expand All @@ -30,17 +33,19 @@ def function_name():
tuple_empty,
tuple_fixed_short,
])
def test_yield_length_normal(
@pytest.mark.parametrize('return_like', RETURN_LIKE_STATEMENTS)
def test_output_length_normal(
assert_errors,
parse_ast_tree,
tuple_param,
mode,
default_options,
return_like,
):
"""Testing that classes and functions in a module work well."""
tree = parse_ast_tree(mode(generator.format(tuple_param)))
tree = parse_ast_tree(mode(generator.format(return_like, tuple_param)))

visitor = YieldTupleVisitor(default_options, tree=tree)
visitor = ReturnLikeStatementTupleVisitor(default_options, tree=tree)
visitor.run()

assert_errors(visitor, [])
Expand All @@ -50,19 +55,21 @@ def test_yield_length_normal(
tuple_long,
tuple_fixed_long,
])
def test_yield_length_violation(
@pytest.mark.parametrize('return_like', RETURN_LIKE_STATEMENTS)
def test_output_length_violation(
assert_errors,
assert_error_text,
parse_ast_tree,
tuple_param,
mode,
default_options,
return_like,
):
"""Testing that classes and functions in a module work well."""
tree = parse_ast_tree(mode(generator.format(tuple_param)))
tree = parse_ast_tree(mode(generator.format(return_like, tuple_param)))

visitor = YieldTupleVisitor(default_options, tree=tree)
visitor = ReturnLikeStatementTupleVisitor(default_options, tree=tree)
visitor.run()

assert_errors(visitor, [TooLongYieldTupleViolation])
assert_error_text(visitor, 6, MAX_LEN_YIELD_TUPLE)
assert_errors(visitor, [TooLongOutputTupleViolation])
assert_error_text(visitor, 6, MAX_LEN_TUPLE_OUTPUT)
4 changes: 2 additions & 2 deletions wemake_python_styleguide/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -406,8 +406,8 @@
#: Maximum amount of ``pragma`` no-cover comments per module.
MAX_NO_COVER_COMMENTS: Final = 5

#: Maximum length of ``yield`` ``tuple`` expressions.
MAX_LEN_YIELD_TUPLE: Final = 5
#: Maximum length of ``yield`` or ``return`` ``tuple`` expressions.
MAX_LEN_TUPLE_OUTPUT: Final = 5

#: Maximum number of compare nodes in a single expression.
MAX_COMPARES: Final = 2
Expand Down
2 changes: 1 addition & 1 deletion wemake_python_styleguide/presets/topics/complexity.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
counts.ConditionsVisitor,
counts.ElifVisitor,
counts.TryExceptVisitor,
counts.YieldTupleVisitor,
counts.ReturnLikeStatementTupleVisitor,
counts.TupleUnpackVisitor,

classes.ClassComplexityVisitor,
Expand Down
14 changes: 8 additions & 6 deletions wemake_python_styleguide/violations/complexity.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
TooManyForsInComprehensionViolation
TooManyExceptCasesViolation
OverusedStringViolation
TooLongYieldTupleViolation
TooLongOutputTupleViolation
TooLongCompareViolation
TooLongTryBodyViolation
TooManyPublicAttributesViolation
Expand Down Expand Up @@ -89,7 +89,7 @@
.. autoclass:: TooManyForsInComprehensionViolation
.. autoclass:: TooManyExceptCasesViolation
.. autoclass:: OverusedStringViolation
.. autoclass:: TooLongYieldTupleViolation
.. autoclass:: TooLongOutputTupleViolation
.. autoclass:: TooLongCompareViolation
.. autoclass:: TooLongTryBodyViolation
.. autoclass:: TooManyPublicAttributesViolation
Expand Down Expand Up @@ -884,22 +884,24 @@ class OverusedStringViolation(MaybeASTViolation):


@final
class TooLongYieldTupleViolation(ASTViolation):
class TooLongOutputTupleViolation(ASTViolation):
"""
Forbid yielding tuples that are too long.
Forbid returning or yielding tuples that are too long.
Reasoning:
Long yield tuples complicate generator usage.
Long output tuples complicate function or generator usage.
This rule helps to reduce complication.
Solution:
Use lists of similar type or wrapper objects.
.. versionadded:: 0.10.0
.. versionchanged:: 0.16.0
"""

error_template = 'Found too long yield tuple: {0}'
error_template = 'Found too long function output tuple: {0}'
code = 227


Expand Down
23 changes: 14 additions & 9 deletions wemake_python_styleguide/visitors/ast/complexity/counts.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
# Type aliases:
_ConditionNodes = Union[ast.If, ast.While, ast.IfExp]
_ModuleMembers = Union[AnyFunctionDef, ast.ClassDef]
_ReturnLikeStatement = Union[ast.Return, ast.Yield]


@final
Expand Down Expand Up @@ -205,22 +206,26 @@ def _check_try_body_length(self, node: ast.Try) -> None:


@final
class YieldTupleVisitor(BaseNodeVisitor):
"""Finds too long ``tuples`` in ``yield`` expressions."""
@alias('visit_return_like', (
'visit_Return',
'visit_Yield',
))
class ReturnLikeStatementTupleVisitor(BaseNodeVisitor):
"""Finds too long ``tuples`` in ``yield`` and ``return`` expressions."""

def visit_Yield(self, node: ast.Yield) -> None:
"""Helper to get all ``yield`` nodes in a function at once."""
self._check_yield_values(node)
def visit_return_like(self, node: _ReturnLikeStatement) -> None:
"""Helper to get all ``yield`` and ``return`` nodes in a function."""
self._check_return_like_values(node)
self.generic_visit(node)

def _check_yield_values(self, node: ast.Yield) -> None:
def _check_return_like_values(self, node: _ReturnLikeStatement) -> None:
if isinstance(node.value, ast.Tuple):
if len(node.value.elts) > constants.MAX_LEN_YIELD_TUPLE:
if len(node.value.elts) > constants.MAX_LEN_TUPLE_OUTPUT:
self.add_violation(
complexity.TooLongYieldTupleViolation(
complexity.TooLongOutputTupleViolation(
node,
text=str(len(node.value.elts)),
baseline=constants.MAX_LEN_YIELD_TUPLE,
baseline=constants.MAX_LEN_TUPLE_OUTPUT,
),
)

Expand Down

0 comments on commit 227731b

Please sign in to comment.