Skip to content
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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue #1081: non necessary raw strings #1178

Merged
merged 28 commits into from Oct 20, 2020
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
720b632
feat: added the new violation to be completed, closes #7
Feb 23, 2020
44f757e
refac: refactor for flake8 consistancy, issue #7
Feb 23, 2020
c02aa31
feat: implementing the new rule. Build yet to be debugged. Issue #9
Feb 23, 2020
358f852
test: added a test for violation WPS357. A raw string must contain th…
fwald Feb 23, 2020
4dea657
documentation: Added documentation for the violation RawStringNotNeed…
fwald Feb 23, 2020
b1bb063
fix: Removed an unnecessary single quotation mark in the documentation
fwald Feb 23, 2020
2ee8ce9
fix: repaired build a priori, issue #9
Feb 23, 2020
d3b8433
fix: adapted test suite to respect the new rule. Temporarily removed …
Feb 23, 2020
1af8ffc
fix: corrected the WPS warnings, issue #9
Feb 23, 2020
7b32af6
fix: enforce the new rule WPS357 in the project itself
Feb 23, 2020
e212e1a
refac: old tests to match the new rule or ignore it, issue #9
Feb 23, 2020
728ea0c
refac: last refactoring. Closes #9
Feb 23, 2020
933610c
doc: changelogs for new rule
Feb 23, 2020
36c5889
test: added a test for wrong case. PR #1178
Mema5 Feb 23, 2020
7be3416
fix: minor changes required for PR #1187
Mema5 Feb 23, 2020
c7a0d6f
Doc:
Mema5 Feb 24, 2020
a0303c3
test: new tests for rule WPS357. Not passing for escaped quote. PR #1178
Mema5 Feb 24, 2020
80fa236
fix: correct type and missing newline. PR #1178
Mema5 Feb 24, 2020
123f365
tests: refactored tests that now all pass. Closes #9. Related to PR #…
Mema5 Feb 24, 2020
4ad6970
doc: the previous usage was actually a wrong usage. PR #1178
Mema5 Feb 24, 2020
6d56f17
refac: remove useless encode().decode()
Mema5 Feb 24, 2020
14e8ce0
merged and solve the conflits. All tests pass
Mema5 Feb 25, 2020
eba9fef
fix: minor changes for PR #1178
Mema5 Feb 25, 2020
4092355
fix: error linter wrong indentation, related to PR #1178
Mema5 Feb 25, 2020
ef727bf
fix: wrong error_template in for RawStringNotNeededViolation
Mema5 Feb 26, 2020
708d92f
Merge
sobolevn Oct 20, 2020
d374b5e
Fixes Ci
sobolevn Oct 20, 2020
f9a38f7
Fixes Ci
sobolevn Oct 20, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Expand Up @@ -9,6 +9,14 @@ Semantic versioning in our case means:
- Major releases inidicate significant milestones or serious breaking changes.


## 0.15.0

### Features

- Forbids to use raw strings `r''` when not necessary

### Bug fixes

## 0.14.0 aka The Walrus fighter WIP

### Features
Expand Down
4 changes: 3 additions & 1 deletion tests/fixtures/noqa/noqa.py
Expand Up @@ -347,7 +347,7 @@ def function( # noqa: WPS320
} # noqa: WPS318


string_modifier = R'(s)' # noqa: WPS321
string_modifier = R'(\n)' # noqa: WPS321
multiline_string = """abc""" # noqa: WPS322


Expand Down Expand Up @@ -692,3 +692,5 @@ def consecutive_yields():
'wrong',
]
*numbers, = [4, 7] # noqa: WPS356

unnecessary_raw_string = r'this string does not contain any backslashes.' # noqa: WPS358
1 change: 1 addition & 0 deletions tests/test_checker/test_noqa.py
Expand Up @@ -164,6 +164,7 @@
'WPS355': 1,
'WPS356': 1,
'WPS357': 0, # logically unacceptable.
'WPS358': 1,

'WPS400': 0, # defined in ignored violations.
'WPS401': 0, # logically unacceptable.
Expand Down
Expand Up @@ -3,6 +3,7 @@
import pytest

from wemake_python_styleguide.violations.consistency import (
RawStringNotNeededViolation,
UppercaseStringModifierViolation,
)
from wemake_python_styleguide.visitors.tokenize.primitives import (
Expand All @@ -12,10 +13,10 @@

@pytest.mark.parametrize('modifier', [
'r',
'b',
'rb',
'f',
'fr',
'b',
'f',
'', # special case, no modifier is used
])
@pytest.mark.parametrize('primitive', [
Expand All @@ -40,7 +41,11 @@ def test_correct_prefix(
visitor = WrongStringTokenVisitor(default_options, file_tokens=file_tokens)
visitor.run()

assert_errors(visitor, [])
assert_errors(
visitor,
[],
ignored_types=(RawStringNotNeededViolation,),
)


@pytest.mark.parametrize('modifier', [
Expand Down Expand Up @@ -71,8 +76,12 @@ def test_uppercase_prefix(
visitor = WrongStringTokenVisitor(default_options, file_tokens=file_tokens)
visitor.run()

assert_errors(visitor, [UppercaseStringModifierViolation])
assert_error_text(visitor, modifier)
assert_errors(
visitor,
[UppercaseStringModifierViolation],
ignored_types=(RawStringNotNeededViolation,),
)
assert_error_text(visitor, modifier, multiple=True)


@pytest.mark.parametrize('modifier', [
Expand Down Expand Up @@ -106,4 +115,5 @@ def test_uppercase_prefix_multiple(
assert_errors(visitor, [
UppercaseStringModifierViolation,
UppercaseStringModifierViolation,
RawStringNotNeededViolation,
])
Expand Up @@ -3,6 +3,7 @@
import pytest

from wemake_python_styleguide.violations.consistency import (
RawStringNotNeededViolation,
WrongMultilineStringViolation,
)
from wemake_python_styleguide.visitors.tokenize.primitives import (
Expand Down Expand Up @@ -76,7 +77,11 @@ def test_incorrect_multiline_strings(
visitor = WrongStringTokenVisitor(default_options, file_tokens=file_tokens)
visitor.run()

assert_errors(visitor, [WrongMultilineStringViolation])
assert_errors(
visitor,
[WrongMultilineStringViolation],
ignored_types=(RawStringNotNeededViolation,),
)


@pytest.mark.parametrize('primitive', [
Expand Down
Expand Up @@ -38,7 +38,7 @@ def test_unicode_prefix(

@pytest.mark.parametrize('primitive', [
'"name"',
'r"text"',
'r"text with escape carac \n"',
"b'unicode'",
'"u"',
'"12"',
Expand Down
@@ -0,0 +1,57 @@
# -*- coding: utf-8 -*-

import pytest

from wemake_python_styleguide.violations.consistency import (
RawStringNotNeededViolation,
)
from wemake_python_styleguide.visitors.tokenize.primitives import (
WrongStringTokenVisitor,
)


@pytest.mark.parametrize('raw_strings', [
r"r'some text\\'",
r"r'some text\''",
r"r'some text\"'",
r'r"some text\'"',
r"r'some text\t'",
r"r'some text\a'",
r"r'some text\n'",
r"r'some text\u041b'",
r"r'some text\043'",
r"r'some text\x23'",
])
def test_necessary_raw_string(
parse_tokens,
assert_errors,
default_options,
raw_strings,
):
"""Ensures that correct usage of raw string works."""
file_tokens = parse_tokens(raw_strings)

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

assert_errors(visitor, [])


@pytest.mark.parametrize('raw_strings', [
"r'No escaped caracter'",
"r'Here neither'",
"r'''Not here as well'''",
])
def test_unnecessary_raw_string(
parse_tokens,
assert_errors,
default_options,
raw_strings,
):
"""Ensures that usage of raw string is forbidden if no backslash."""
file_tokens = parse_tokens(raw_strings)

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

assert_errors(visitor, [RawStringNotNeededViolation])
2 changes: 1 addition & 1 deletion wemake_python_styleguide/constants.py
Expand Up @@ -357,7 +357,7 @@
STDIN: Final = 'stdin'

# Used as a special name patterns for unused variables, like _, __:
UNUSED_VARIABLE_REGEX: Final = re.compile(r'^_+$')
UNUSED_VARIABLE_REGEX: Final = re.compile('^_+$')

# Used to specify as a placeholder for `__init__`:
INIT: Final = '__init__'
Expand Down
28 changes: 28 additions & 0 deletions wemake_python_styleguide/violations/consistency.py
Expand Up @@ -83,6 +83,7 @@
BracketBlankLineViolation
IterableUnpackingViolation
LineCompriseCarriageReturnViolation
RawStringNotNeededViolation

Consistency checks
------------------
Expand Down Expand Up @@ -145,6 +146,7 @@
.. autoclass:: BracketBlankLineViolation
.. autoclass:: IterableUnpackingViolation
.. autoclass:: LineCompriseCarriageReturnViolation
.. autoclass:: RawStringNotNeededViolation

"""

Expand Down Expand Up @@ -2143,3 +2145,29 @@ class LineCompriseCarriageReturnViolation(TokenizeViolation):

error_template = r'Found a ``\r`` (carriage return) line break'
code = 357


@final
class RawStringNotNeededViolation(TokenizeViolation):
r"""
Forbid the use of raw strings when there is no backslash in the string.

Reasoning:
Raw string are only needed when dealing with ``\`` in the string.

Solution:
Do not prefix the string with ``r``. Use a normal string instead.

Example::
# Correct:
r'This is a correct use \n'

# Wrong:
r'This string should not be prefixed with r.'

.. versionadded:: 0.15.0

"""

error_template = 'Error template here'
code = 358
10 changes: 10 additions & 0 deletions wemake_python_styleguide/visitors/tokenize/primitives.py
Expand Up @@ -165,12 +165,14 @@ def visit_string(self, token: tokenize.TokenInfo) -> None:
WrongMultilineStringViolation
ImplicitRawStringViolation
WrongUnicodeEscapeViolation
RawStringNotNeededViolation

"""
self._check_correct_multiline(token)
self._check_string_modifiers(token)
self._check_implicit_raw_string(token)
self._check_wrong_unicode_escape(token)
self._check_unnecessary_raw_string(token)

def _check_correct_multiline(self, token: tokenize.TokenInfo) -> None:
_, string_def = split_prefixes(token)
Expand Down Expand Up @@ -231,6 +233,14 @@ def _check_wrong_unicode_escape(self, token: tokenize.TokenInfo) -> None:
# character can never be the start of a new backslash escape.
index += 2

def _check_unnecessary_raw_string(self, token: tokenize.TokenInfo) -> None:
modifiers, string_def = split_prefixes(token)

if 'r' in modifiers.lower() and '\\' not in string_def:
self.add_violation(
consistency.RawStringNotNeededViolation(token),
)


@final
class WrongStringConcatenationVisitor(BaseTokenVisitor):
Expand Down