Skip to content

Commit

Permalink
Add redundant-u-string-prefix checker (#4804)
Browse files Browse the repository at this point in the history
* Add ``redundant-u-string-prefix`` checker
This adds a checker for u-prefixes for strings, as used in Python 2. It only work in python 3.8 and above.
Closes #4102
  • Loading branch information
DanielNoord committed Aug 6, 2021
1 parent 7d84a32 commit 865765c
Show file tree
Hide file tree
Showing 19 changed files with 85 additions and 28 deletions.
6 changes: 5 additions & 1 deletion ChangeLog
Expand Up @@ -89,10 +89,14 @@ Release date: TBA

Closes #626

* Add ``disable-next`` option: allows using `# pylint: disable-next=msgid` to disable a message for the following line
* Added ``disable-next`` option: allows using `# pylint: disable-next=msgid` to disable a message for the following line

Closes #1682

* Added ``redundant-u-string-prefix`` checker: Emitted when the u prefix is added to a string

Closes #4102


What's New in Pylint 2.9.6?
===========================
Expand Down
6 changes: 5 additions & 1 deletion doc/whatsnew/2.10.rst
Expand Up @@ -71,10 +71,14 @@ Other Changes

Closes #626

* Add ``disable-next`` option: allows using `# pylint: disable-next=msgid` to disable a message for the following line
* Added ``disable-next`` option: allows using `# pylint: disable-next=msgid` to disable a message for the following line

Closes #1682

* Added ``format-string-without-interpolation`` checker: Emitted when formatting is applied to a string without any variables to be replaced

Closes #4042

* Added ``redundant-u-string-prefix`` checker: Emitted when the u prefix is added to a string

Closes #4102
23 changes: 23 additions & 0 deletions pylint/checkers/strings.py
Expand Up @@ -669,6 +669,13 @@ class StringConstantChecker(BaseTokenChecker):
"Quote delimiters are not used consistently throughout a module "
"(with allowances made for avoiding unnecessary escaping).",
),
"W1406": (
"The u prefix for strings is no longer necessary in Python >=3.0",
"redundant-u-string-prefix",
"Used when we detect a string with a u prefix. These prefixes were necessary "
"in Python 2 to indicate a string was Unicode, but since Python 3.0 strings "
"are Unicode by default.",
),
}
options = (
(
Expand Down Expand Up @@ -905,6 +912,22 @@ def process_non_raw_string_token(
# character can never be the start of a new backslash escape.
index += 2

@check_messages("redundant-u-string-prefix")
def visit_const(self, node: astroid.Const):
if node.pytype() == "builtins.str" and not isinstance(
node.parent, astroid.JoinedStr
):
self._detect_u_string_prefix(node)

def _detect_u_string_prefix(self, node: astroid.Const):
"""Check whether strings include a 'u' prefix like u'String'"""
if node.kind == "u":
self.add_message(
"redundant-u-string-prefix",
line=node.lineno,
col_offset=node.col_offset,
)


def register(linter):
"""required method to auto register this checker"""
Expand Down
2 changes: 1 addition & 1 deletion tests/functional/a/anomalous_unicode_escape_py3.py
@@ -1,4 +1,4 @@
# pylint:disable=pointless-string-statement
# pylint:disable=pointless-string-statement, redundant-u-string-prefix
"""Test for backslash escapes in byte vs unicode strings"""

# Would be valid in Unicode, but probably not what you want otherwise
Expand Down
2 changes: 1 addition & 1 deletion tests/functional/a/assign/assigning_non_slot.py
@@ -1,7 +1,7 @@
""" Checks assigning attributes not found in class slots
will trigger assigning-non-slot warning.
"""
# pylint: disable=too-few-public-methods, no-init, missing-docstring, no-absolute-import, import-error, useless-object-inheritance
# pylint: disable=too-few-public-methods, no-init, missing-docstring, no-absolute-import, import-error, useless-object-inheritance, redundant-u-string-prefix
from collections import deque

from missing import Unknown
Expand Down
2 changes: 1 addition & 1 deletion tests/functional/d/duplicate_dict_literal_key.py
@@ -1,5 +1,5 @@
"""Check multiple key definition"""
# pylint: disable=pointless-statement
# pylint: disable=pointless-statement, redundant-u-string-prefix

correct_dict = {
'tea': 'for two',
Expand Down
1 change: 1 addition & 0 deletions tests/functional/e/excess_escapes.py
@@ -1,5 +1,6 @@
# pylint:disable=pointless-string-statement, fixme, misplaced-comparison-constant, comparison-with-itself
"""Stray backslash escapes may be missing a raw-string prefix."""
# pylint: disable=redundant-u-string-prefix

__revision__ = '$Id$'

Expand Down
18 changes: 9 additions & 9 deletions tests/functional/e/excess_escapes.txt
@@ -1,9 +1,9 @@
anomalous-backslash-in-string:7:5::"Anomalous backslash in string: '\['. String constant might be missing an r prefix."
anomalous-backslash-in-string:7:7::"Anomalous backslash in string: '\]'. String constant might be missing an r prefix."
anomalous-backslash-in-string:8:8::"Anomalous backslash in string: '\/'. String constant might be missing an r prefix."
anomalous-backslash-in-string:9:20::"Anomalous backslash in string: '\`'. String constant might be missing an r prefix."
anomalous-backslash-in-string:16:15::"Anomalous backslash in string: '\o'. String constant might be missing an r prefix."
anomalous-backslash-in-string:16:20::"Anomalous backslash in string: '\o'. String constant might be missing an r prefix."
anomalous-backslash-in-string:18:13::"Anomalous backslash in string: '\8'. String constant might be missing an r prefix."
anomalous-backslash-in-string:18:17::"Anomalous backslash in string: '\9'. String constant might be missing an r prefix."
anomalous-backslash-in-string:31:42::"Anomalous backslash in string: '\P'. String constant might be missing an r prefix."
anomalous-backslash-in-string:8:5::"Anomalous backslash in string: '\['. String constant might be missing an r prefix."
anomalous-backslash-in-string:8:7::"Anomalous backslash in string: '\]'. String constant might be missing an r prefix."
anomalous-backslash-in-string:9:8::"Anomalous backslash in string: '\/'. String constant might be missing an r prefix."
anomalous-backslash-in-string:10:20::"Anomalous backslash in string: '\`'. String constant might be missing an r prefix."
anomalous-backslash-in-string:17:15::"Anomalous backslash in string: '\o'. String constant might be missing an r prefix."
anomalous-backslash-in-string:17:20::"Anomalous backslash in string: '\o'. String constant might be missing an r prefix."
anomalous-backslash-in-string:19:13::"Anomalous backslash in string: '\8'. String constant might be missing an r prefix."
anomalous-backslash-in-string:19:17::"Anomalous backslash in string: '\9'. String constant might be missing an r prefix."
anomalous-backslash-in-string:32:42::"Anomalous backslash in string: '\P'. String constant might be missing an r prefix."
2 changes: 1 addition & 1 deletion tests/functional/i/implicit/implicit_str_concat.py
@@ -1,4 +1,4 @@
#pylint: disable=invalid-name,missing-docstring
#pylint: disable=invalid-name,missing-docstring,redundant-u-string-prefix

# Basic test with a list
TEST_LIST1 = ['a' 'b'] # [implicit-str-concat]
Expand Down
2 changes: 1 addition & 1 deletion tests/functional/i/iterable_context.py
Expand Up @@ -2,7 +2,7 @@
Checks that primitive values are not used in an
iterating/mapping context.
"""
# pylint: disable=missing-docstring,invalid-name,too-few-public-methods,no-init,no-self-use,import-error,unused-argument,bad-mcs-method-argument,wrong-import-position,no-else-return, useless-object-inheritance, unnecessary-comprehension
# pylint: disable=missing-docstring,invalid-name,too-few-public-methods,no-init,no-self-use,import-error,unused-argument,bad-mcs-method-argument,wrong-import-position,no-else-return, useless-object-inheritance, unnecessary-comprehension,redundant-u-string-prefix
from __future__ import print_function

# primitives
Expand Down
2 changes: 1 addition & 1 deletion tests/functional/m/member/membership_protocol.py
@@ -1,4 +1,4 @@
# pylint: disable=missing-docstring,pointless-statement,expression-not-assigned,too-few-public-methods,import-error,no-init,wrong-import-position,no-else-return, comparison-with-itself, useless-object-inheritance
# pylint: disable=missing-docstring,pointless-statement,expression-not-assigned,too-few-public-methods,import-error,no-init,wrong-import-position,no-else-return, comparison-with-itself, useless-object-inheritance, redundant-u-string-prefix

# standard types
1 in [1, 2, 3]
Expand Down
1 change: 1 addition & 0 deletions tests/functional/r/raise/raising_format_tuple.py
Expand Up @@ -4,6 +4,7 @@
instead. The same holds for a string containing {...} suggesting str.format()
was intended.
'''
# pylint: disable=redundant-u-string-prefix

def bad_percent(arg):
'''Raising a percent-formatted string and an argument'''
Expand Down
14 changes: 7 additions & 7 deletions tests/functional/r/raise/raising_format_tuple.txt
@@ -1,7 +1,7 @@
raising-format-tuple:10:4:bad_percent:Exception arguments suggest string formatting might be intended
raising-format-tuple:18:4:bad_multiarg:Exception arguments suggest string formatting might be intended
raising-format-tuple:26:4:bad_braces:Exception arguments suggest string formatting might be intended
raising-format-tuple:34:4:bad_multistring:Exception arguments suggest string formatting might be intended
raising-format-tuple:40:4:bad_triplequote:Exception arguments suggest string formatting might be intended
raising-format-tuple:46:4:bad_unicode:Exception arguments suggest string formatting might be intended
raising-format-tuple:51:4:raise_something_without_name:Exception arguments suggest string formatting might be intended
raising-format-tuple:11:4:bad_percent:Exception arguments suggest string formatting might be intended
raising-format-tuple:19:4:bad_multiarg:Exception arguments suggest string formatting might be intended
raising-format-tuple:27:4:bad_braces:Exception arguments suggest string formatting might be intended
raising-format-tuple:35:4:bad_multistring:Exception arguments suggest string formatting might be intended
raising-format-tuple:41:4:bad_triplequote:Exception arguments suggest string formatting might be intended
raising-format-tuple:47:4:bad_unicode:Exception arguments suggest string formatting might be intended
raising-format-tuple:52:4:raise_something_without_name:Exception arguments suggest string formatting might be intended
14 changes: 14 additions & 0 deletions tests/functional/r/redundant_u_string_prefix.py
@@ -0,0 +1,14 @@
""""Checks for redundant u-prefixes for strings"""
# pylint: disable=missing-function-docstring

def print_good():
print("String")
print(f"String{1 + 1}")


def print_bad():
print(u"String") # [redundant-u-string-prefix]
print(u'String') # [redundant-u-string-prefix]
print([u"String", u"String2"]) # [redundant-u-string-prefix, redundant-u-string-prefix]
print((u"String", u"String2")) # [redundant-u-string-prefix, redundant-u-string-prefix]
print({1: u"String"}) # [redundant-u-string-prefix]
2 changes: 2 additions & 0 deletions tests/functional/r/redundant_u_string_prefix.rc
@@ -0,0 +1,2 @@
[testoptions]
min_pyver=3.8
7 changes: 7 additions & 0 deletions tests/functional/r/redundant_u_string_prefix.txt
@@ -0,0 +1,7 @@
redundant-u-string-prefix:10:10::The u prefix for strings is no longer necessary in Python >=3.0:HIGH
redundant-u-string-prefix:11:10::The u prefix for strings is no longer necessary in Python >=3.0:HIGH
redundant-u-string-prefix:12:11::The u prefix for strings is no longer necessary in Python >=3.0:HIGH
redundant-u-string-prefix:12:22::The u prefix for strings is no longer necessary in Python >=3.0:HIGH
redundant-u-string-prefix:13:11::The u prefix for strings is no longer necessary in Python >=3.0:HIGH
redundant-u-string-prefix:13:22::The u prefix for strings is no longer necessary in Python >=3.0:HIGH
redundant-u-string-prefix:14:14::The u prefix for strings is no longer necessary in Python >=3.0:HIGH
1 change: 1 addition & 0 deletions tests/functional/s/suspicious_str_strip_call_py3.py
@@ -1,4 +1,5 @@
"""Suspicious str.strip calls."""
# pylint: disable=redundant-u-string-prefix
__revision__ = 1

''.strip('yo')
Expand Down
6 changes: 3 additions & 3 deletions tests/functional/s/suspicious_str_strip_call_py3.txt
@@ -1,3 +1,3 @@
bad-str-strip-call:7:0::Suspicious argument in str.strip call
bad-str-strip-call:8:0::Suspicious argument in str.lstrip call
bad-str-strip-call:9:0::Suspicious argument in bytes.rstrip call
bad-str-strip-call:8:0::Suspicious argument in str.strip call
bad-str-strip-call:9:0::Suspicious argument in str.lstrip call
bad-str-strip-call:10:0::Suspicious argument in bytes.rstrip call
2 changes: 1 addition & 1 deletion tests/functional/u/unsubscriptable_value.py
Expand Up @@ -3,7 +3,7 @@
(i.e. defines __getitem__ method).
"""
# pylint: disable=missing-docstring,pointless-statement,expression-not-assigned,wrong-import-position, unnecessary-comprehension
# pylint: disable=too-few-public-methods,import-error,invalid-name,wrong-import-order, useless-object-inheritance
# pylint: disable=too-few-public-methods,import-error,invalid-name,wrong-import-order, useless-object-inheritance, redundant-u-string-prefix
import six

# primitives
Expand Down

0 comments on commit 865765c

Please sign in to comment.