Skip to content

Commit

Permalink
Closes #956, closes #854
Browse files Browse the repository at this point in the history
  • Loading branch information
sobolevn committed Nov 17, 2019
1 parent e86a12c commit 85f5eda
Show file tree
Hide file tree
Showing 7 changed files with 290 additions and 33 deletions.
1 change: 1 addition & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ exclude =
.eggs
*.egg
# These folders contain code badly written for reasons:
# Project spefic, do not copy.
tests/fixtures/**
tests/**/snapshots/**

Expand Down
5 changes: 5 additions & 0 deletions tests/fixtures/noqa.py
Original file line number Diff line number Diff line change
Expand Up @@ -620,3 +620,8 @@ def consecutive_yields():
print(some_sized[len(some_sized) - 2]) # noqa: WPS530

deep_func(a)(b)(c)(d) # noqa: WPS233

extra_new_line = [ # noqa: WPS355

'wrong',
]
1 change: 1 addition & 0 deletions tests/test_checker/test_noqa.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@
'WPS352': 1,
'WPS353': 1,
'WPS354': 1,
'WPS355': 1,

'WPS400': 0,
'WPS401': 0,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
# -*- coding: utf-8 -*-

import pytest

from wemake_python_styleguide.violations.consistency import (
BracketBlankLineViolation,
)
from wemake_python_styleguide.visitors.tokenize.statements import (
BracketLocationVisitor,
)

# Correct:

correct_empty_module = ''
correct_single_line = 'arr = []'
correct_single_line_items = 'arr = [1, 2, 3]'
correct_single_line_call = 'some(1, 2, 3)'

correct_method = """
class Some(object):
'''
Dco.
Some [
Example,
]
'''
def __init__(self, node=None, text: Optional[str] = None) -> None:
...
"""

correct_blank_line_in_middle_list = """
arr = [
1,
2,
]
"""

correct_blank_line_in_middle_dict = """
arr = {
1:
2,
}
"""

correct_blank_line_in_middle_parens = """
arr = (
1,
2,
)
"""

correct_comment_start_of_list = """
arr = [
# comment
1,
2,
]
"""

correct_comment_in_middle_of_list = """
arr = [
1,
# comment
2,
]
"""

# Wrong:

wrong_blank_line_at_start_list = """
some = [
1,
2,
3,
]
"""

wrong_blank_line_at_end_list = """
some = [
1,
2,
3,
]
"""

wrong_blank_line_after_comment = """
extra_new_line = [ # some
'wrong',
]
"""

wrong_blank_line_at_start_dict = """
arr = {
1: 2,
}
"""

wrong_blank_line_at_end_dict = """
arr = {
1: 2,
}
"""

wrong_blank_line_at_start_parens = """
arr = (
1,
2,
)
"""

wrong_blank_line_at_end_parens = """
arr = (
1, 2,
)
"""


@pytest.mark.parametrize('code', [
correct_empty_module,
correct_single_line,
correct_single_line_call,
correct_single_line_items,
correct_method,
correct_blank_line_in_middle_list,
correct_blank_line_in_middle_dict,
correct_blank_line_in_middle_parens,
correct_comment_start_of_list,
correct_comment_in_middle_of_list,
])
def test_correct_blank_lines(
parse_tokens,
assert_errors,
default_options,
code,
):
"""Ensures that correct blank lines work."""
file_tokens = parse_tokens(code)

visitor = BracketLocationVisitor(default_options, file_tokens=file_tokens)
visitor.run()

assert_errors(visitor, [])


@pytest.mark.parametrize('code', [
wrong_blank_line_at_start_list,
wrong_blank_line_at_end_list,
wrong_blank_line_after_comment,
wrong_blank_line_at_start_dict,
wrong_blank_line_at_end_dict,
wrong_blank_line_at_start_parens,
wrong_blank_line_at_end_parens,
])
def test_wrong_blank_lines(
parse_tokens,
assert_errors,
default_options,
code,
):
"""Ensures that incorrect blank lines raise a warning."""
file_tokens = parse_tokens(code)

visitor = BracketLocationVisitor(default_options, file_tokens=file_tokens)
visitor.run()

assert_errors(visitor, [BracketBlankLineViolation])
42 changes: 41 additions & 1 deletion wemake_python_styleguide/logic/tokens.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,24 @@
# -*- coding: utf-8 -*-

import tokenize
from typing import Container, Iterable, Tuple
import types
from typing import Container, FrozenSet, Iterable, List, Mapping, Tuple

MATCHING: Mapping[int, int] = types.MappingProxyType({
tokenize.LBRACE: tokenize.RBRACE,
tokenize.LSQB: tokenize.RSQB,
tokenize.LPAR: tokenize.RPAR,
})

NEWLINES: FrozenSet[int] = frozenset((
tokenize.NL,
tokenize.NEWLINE,
))

ALLOWED_EMPTY_LINE_TOKENS: FrozenSet[int] = frozenset((
*NEWLINES,
*MATCHING.values(),
))


def split_prefixes(token: tokenize.TokenInfo) -> Tuple[str, str]:
Expand Down Expand Up @@ -44,3 +61,26 @@ def only_contains(
def get_comment_text(token: tokenize.TokenInfo) -> str:
"""Returns comment without `#` char from comment tokens."""
return token.string[1:].strip()


def get_reverse_bracket(bracket: tokenize.TokenInfo) -> int:
"""
Returns the reverse closing bracket for an openning token.
>>> import tokenize
>>> import token
>>> bracket = tokenize.TokenInfo(token.RPAR, ")", 6, 7, "(a, b)")
>>> get_reverse_bracket(bracket) == token.LPAR
True
"""
index = list(MATCHING.values()).index(bracket.exact_type)
return list(MATCHING.keys())[index]


def last_bracket(tokens: List[tokenize.TokenInfo], index: int) -> bool:
"""Tells whether the given index is the last bracket token in line."""
return only_contains(
tokens[index + 1:],
NEWLINES.union({tokenize.COMMENT}),
)
35 changes: 35 additions & 0 deletions wemake_python_styleguide/violations/consistency.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
MultilineLoopViolation
IncorrectYieldFromTargetViolation
ConsecutiveYieldsViolation
BracketBlankLineViolation
Consistency checks
------------------
Expand Down Expand Up @@ -139,6 +140,7 @@
.. autoclass:: MultilineLoopViolation
.. autoclass:: IncorrectYieldFromTargetViolation
.. autoclass:: ConsecutiveYieldsViolation
.. autoclass:: BracketBlankLineViolation
"""

Expand Down Expand Up @@ -2012,3 +2014,36 @@ class ConsecutiveYieldsViolation(ASTViolation):

error_template = 'Found consecutive `yield` expressions'
code = 354


@final
class BracketBlankLineViolation(TokenizeViolation):
"""
Forbids useless blank lines before and after brackets.
Reasoning:
We do this for consistency.
Solution:
Remove blank lines from the start and from the end of a collection.
Example::
# Correct:
arr = [
1,
2
]
# Wrong:
arr = [
1,
2
]
.. versionadded:: 0.13.0
"""

error_template = 'Found an unnecessary blank line before a bracket'
code = 355
Loading

0 comments on commit 85f5eda

Please sign in to comment.