Skip to content

Commit

Permalink
Moved consider-using-f-string to RecommendationChecker (#4957)
Browse files Browse the repository at this point in the history
Based on discussion in #4787

Co-authored-by: Pierre Sassoulas <pierre.sassoulas@gmail.com>
  • Loading branch information
DanielNoord and Pierre-Sassoulas committed Sep 3, 2021
1 parent baaa81a commit 6c81831
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 101 deletions.
78 changes: 78 additions & 0 deletions pylint/checkers/refactoring/recommendation_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ class RecommendationChecker(checkers.BaseChecker):
"When iterating over values, sequence types (e.g., ``lists``, ``tuples``, ``ranges``) "
"are more efficient than ``sets``.",
),
"C0209": (
"Formatting a regular string which could be a f-string",
"consider-using-f-string",
"Used when we detect a string that is being formatted with format() or % "
"which could potentially be a f-string. The use of f-strings is preferred.",
),
}

@staticmethod
Expand Down Expand Up @@ -313,3 +319,75 @@ def _check_use_sequence_for_iteration(
"""Check if code iterates over an in-place defined set."""
if isinstance(node.iter, nodes.Set):
self.add_message("use-sequence-for-iteration", node=node.iter)

@utils.check_messages("consider-using-f-string")
def visit_const(self, node: nodes.Const) -> None:
if node.pytype() == "builtins.str" and not isinstance(
node.parent, nodes.JoinedStr
):
self._detect_replacable_format_call(node)

def _detect_replacable_format_call(self, node: nodes.Const) -> None:
"""Check whether a string is used in a call to format() or '%' and whether it
can be replaced by a f-string"""
if (
isinstance(node.parent, nodes.Attribute)
and node.parent.attrname == "format"
):
# Allow assigning .format to a variable
if isinstance(node.parent.parent, nodes.Assign):
return

if node.parent.parent.args:
for arg in node.parent.parent.args:
# If star expressions with more than 1 element are being used
if isinstance(arg, nodes.Starred):
inferred = utils.safe_infer(arg.value)
if (
isinstance(inferred, astroid.List)
and len(inferred.elts) > 1
):
return

elif node.parent.parent.keywords:
keyword_args = [
i[0] for i in utils.parse_format_method_string(node.value)[0]
]
for keyword in node.parent.parent.keywords:
# If keyword is used multiple times
if keyword_args.count(keyword.arg) > 1:
return

keyword = utils.safe_infer(keyword.value)

# If lists of more than one element are being unpacked
if isinstance(keyword, nodes.Dict):
if len(keyword.items) > 1 and len(keyword_args) > 1:
return

# If all tests pass, then raise message
self.add_message(
"consider-using-f-string",
node=node,
line=node.lineno,
col_offset=node.col_offset,
)

elif isinstance(node.parent, nodes.BinOp) and node.parent.op == "%":
inferred_right = utils.safe_infer(node.parent.right)

# If dicts or lists of length > 1 are used
if isinstance(inferred_right, nodes.Dict):
if len(inferred_right.items) > 1:
return
elif isinstance(inferred_right, nodes.List):
if len(inferred_right.elts) > 1:
return

# If all tests pass, then raise message
self.add_message(
"consider-using-f-string",
node=node,
line=node.lineno,
col_offset=node.col_offset,
)
71 changes: 0 additions & 71 deletions pylint/checkers/strings.py
Original file line number Diff line number Diff line change
Expand Up @@ -671,12 +671,6 @@ class StringConstantChecker(BaseTokenChecker):
"in Python 2 to indicate a string was Unicode, but since Python 3.0 strings "
"are Unicode by default.",
),
"C1407": (
"Formatting a regular string which could be a f-string",
"consider-using-f-string",
"Used when we detect a string that is being formatted with format() or % "
"which could potentially be a f-string. The use of f-strings is preferred.",
),
}
options = (
(
Expand Down Expand Up @@ -914,13 +908,11 @@ def process_non_raw_string_token(
index += 2

@check_messages("redundant-u-string-prefix")
@check_messages("consider-using-f-string")
def visit_const(self, node: nodes.Const) -> None:
if node.pytype() == "builtins.str" and not isinstance(
node.parent, nodes.JoinedStr
):
self._detect_u_string_prefix(node)
self._detect_replacable_format_call(node)

def _detect_u_string_prefix(self, node: nodes.Const):
"""Check whether strings include a 'u' prefix like u'String'"""
Expand All @@ -931,69 +923,6 @@ def _detect_u_string_prefix(self, node: nodes.Const):
col_offset=node.col_offset,
)

def _detect_replacable_format_call(self, node: nodes.Const) -> None:
"""Check whether a string is used in a call to format() or '%' and whether it
can be replaced by a f-string"""
if (
isinstance(node.parent, nodes.Attribute)
and node.parent.attrname == "format"
):
# Allow assigning .format to a variable
if isinstance(node.parent.parent, nodes.Assign):
return

if node.parent.parent.args:
for arg in node.parent.parent.args:
# If star expressions with more than 1 element are being used
if isinstance(arg, nodes.Starred):
inferred = utils.safe_infer(arg.value)
if (
isinstance(inferred, astroid.List)
and len(inferred.elts) > 1
):
return

elif node.parent.parent.keywords:
keyword_args = [
i[0] for i in utils.parse_format_method_string(node.value)[0]
]
for keyword in node.parent.parent.keywords:
# If keyword is used multiple times
if keyword_args.count(keyword.arg) > 1:
return

keyword = utils.safe_infer(keyword.value)

# If lists of more than one element are being unpacked
if isinstance(keyword, nodes.Dict):
if len(keyword.items) > 1 and len(keyword_args) > 1:
return

# If all tests pass, then raise message
self.add_message(
"consider-using-f-string",
line=node.lineno,
col_offset=node.col_offset,
)

elif isinstance(node.parent, nodes.BinOp) and node.parent.op == "%":
inferred_right = utils.safe_infer(node.parent.right)

# If dicts or lists of length > 1 are used
if isinstance(inferred_right, nodes.Dict):
if len(inferred_right.items) > 1:
return
elif isinstance(inferred_right, nodes.List):
if len(inferred_right.elts) > 1:
return

# If all tests pass, then raise message
self.add_message(
"consider-using-f-string",
line=node.lineno,
col_offset=node.col_offset,
)


def register(linter):
"""required method to auto register this checker"""
Expand Down
60 changes: 30 additions & 30 deletions tests/functional/c/consider/consider_using_f_string.txt
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
consider-using-f-string:40:10::"Formatting a regular string which could be a f-string":HIGH
consider-using-f-string:41:10::"Formatting a regular string which could be a f-string":HIGH
consider-using-f-string:42:10::"Formatting a regular string which could be a f-string":HIGH
consider-using-f-string:43:10::"Formatting a regular string which could be a f-string":HIGH
consider-using-f-string:44:10::"Formatting a regular string which could be a f-string":HIGH
consider-using-f-string:45:10::"Formatting a regular string which could be a f-string":HIGH
consider-using-f-string:46:10::"Formatting a regular string which could be a f-string":HIGH
consider-using-f-string:47:10::"Formatting a regular string which could be a f-string":HIGH
consider-using-f-string:48:10::"Formatting a regular string which could be a f-string":HIGH
consider-using-f-string:49:10::"Formatting a regular string which could be a f-string":HIGH
consider-using-f-string:68:4::"Formatting a regular string which could be a f-string":HIGH
consider-using-f-string:69:4::"Formatting a regular string which could be a f-string":HIGH
consider-using-f-string:70:4::"Formatting a regular string which could be a f-string":HIGH
consider-using-f-string:71:4::"Formatting a regular string which could be a f-string":HIGH
consider-using-f-string:72:4::"Formatting a regular string which could be a f-string":HIGH
consider-using-f-string:73:4::"Formatting a regular string which could be a f-string":HIGH
consider-using-f-string:74:4::"Formatting a regular string which could be a f-string":HIGH
consider-using-f-string:75:4::"Formatting a regular string which could be a f-string":HIGH
consider-using-f-string:76:4::"Formatting a regular string which could be a f-string":HIGH
consider-using-f-string:77:4::"Formatting a regular string which could be a f-string":HIGH
consider-using-f-string:98:8::"Formatting a regular string which could be a f-string":HIGH
consider-using-f-string:99:8::"Formatting a regular string which could be a f-string":HIGH
consider-using-f-string:100:8::"Formatting a regular string which could be a f-string":HIGH
consider-using-f-string:101:8::"Formatting a regular string which could be a f-string":HIGH
consider-using-f-string:102:8::"Formatting a regular string which could be a f-string":HIGH
consider-using-f-string:103:8::"Formatting a regular string which could be a f-string":HIGH
consider-using-f-string:104:8::"Formatting a regular string which could be a f-string":HIGH
consider-using-f-string:105:8::"Formatting a regular string which could be a f-string":HIGH
consider-using-f-string:106:8::"Formatting a regular string which could be a f-string":HIGH
consider-using-f-string:107:8::"Formatting a regular string which could be a f-string":HIGH
consider-using-f-string:40:10:print_bad:Formatting a regular string which could be a f-string:HIGH
consider-using-f-string:41:10:print_bad:Formatting a regular string which could be a f-string:HIGH
consider-using-f-string:42:10:print_bad:Formatting a regular string which could be a f-string:HIGH
consider-using-f-string:43:10:print_bad:Formatting a regular string which could be a f-string:HIGH
consider-using-f-string:44:10:print_bad:Formatting a regular string which could be a f-string:HIGH
consider-using-f-string:45:10:print_bad:Formatting a regular string which could be a f-string:HIGH
consider-using-f-string:46:10:print_bad:Formatting a regular string which could be a f-string:HIGH
consider-using-f-string:47:10:print_bad:Formatting a regular string which could be a f-string:HIGH
consider-using-f-string:48:10:print_bad:Formatting a regular string which could be a f-string:HIGH
consider-using-f-string:49:10:print_bad:Formatting a regular string which could be a f-string:HIGH
consider-using-f-string:68:4:statement_bad:Formatting a regular string which could be a f-string:HIGH
consider-using-f-string:69:4:statement_bad:Formatting a regular string which could be a f-string:HIGH
consider-using-f-string:70:4:statement_bad:Formatting a regular string which could be a f-string:HIGH
consider-using-f-string:71:4:statement_bad:Formatting a regular string which could be a f-string:HIGH
consider-using-f-string:72:4:statement_bad:Formatting a regular string which could be a f-string:HIGH
consider-using-f-string:73:4:statement_bad:Formatting a regular string which could be a f-string:HIGH
consider-using-f-string:74:4:statement_bad:Formatting a regular string which could be a f-string:HIGH
consider-using-f-string:75:4:statement_bad:Formatting a regular string which could be a f-string:HIGH
consider-using-f-string:76:4:statement_bad:Formatting a regular string which could be a f-string:HIGH
consider-using-f-string:77:4:statement_bad:Formatting a regular string which could be a f-string:HIGH
consider-using-f-string:98:8:assignment_bad:Formatting a regular string which could be a f-string:HIGH
consider-using-f-string:99:8:assignment_bad:Formatting a regular string which could be a f-string:HIGH
consider-using-f-string:100:8:assignment_bad:Formatting a regular string which could be a f-string:HIGH
consider-using-f-string:101:8:assignment_bad:Formatting a regular string which could be a f-string:HIGH
consider-using-f-string:102:8:assignment_bad:Formatting a regular string which could be a f-string:HIGH
consider-using-f-string:103:8:assignment_bad:Formatting a regular string which could be a f-string:HIGH
consider-using-f-string:104:8:assignment_bad:Formatting a regular string which could be a f-string:HIGH
consider-using-f-string:105:8:assignment_bad:Formatting a regular string which could be a f-string:HIGH
consider-using-f-string:106:8:assignment_bad:Formatting a regular string which could be a f-string:HIGH
consider-using-f-string:107:8:assignment_bad:Formatting a regular string which could be a f-string:HIGH

0 comments on commit 6c81831

Please sign in to comment.