Skip to content

Commit 744ba53

Browse files
Fix crash caused by invalid format strings in .format context (#10300) (#10302)
(cherry picked from commit e6cbd41) Co-authored-by: Zen Lee <[email protected]>
1 parent 7ac5a4d commit 744ba53

File tree

3 files changed

+29
-12
lines changed

3 files changed

+29
-12
lines changed

doc/whatsnew/fragments/10282.bugfix

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix a crash caused by malformed format strings when using `.format` with keyword arguments.
2+
3+
Closes #10282

pylint/checkers/refactoring/recommendation_checker.py

+18-12
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,14 @@ def _detect_replacable_format_call(self, node: nodes.Const) -> None:
382382
if not isinstance(node.parent.parent, nodes.Call):
383383
return
384384

385+
# Don't raise message on bad format string
386+
try:
387+
keyword_args = [
388+
i[0] for i in utils.parse_format_method_string(node.value)[0]
389+
]
390+
except utils.IncompleteFormatString:
391+
return
392+
385393
if node.parent.parent.args:
386394
for arg in node.parent.parent.args:
387395
# If star expressions with more than 1 element are being used
@@ -397,9 +405,6 @@ def _detect_replacable_format_call(self, node: nodes.Const) -> None:
397405
return
398406

399407
elif node.parent.parent.keywords:
400-
keyword_args = [
401-
i[0] for i in utils.parse_format_method_string(node.value)[0]
402-
]
403408
for keyword in node.parent.parent.keywords:
404409
# If keyword is used multiple times
405410
if keyword_args.count(keyword.arg) > 1:
@@ -408,9 +413,12 @@ def _detect_replacable_format_call(self, node: nodes.Const) -> None:
408413
keyword = utils.safe_infer(keyword.value)
409414

410415
# If lists of more than one element are being unpacked
411-
if isinstance(keyword, nodes.Dict):
412-
if len(keyword.items) > 1 and len(keyword_args) > 1:
413-
return
416+
if (
417+
isinstance(keyword, nodes.Dict)
418+
and len(keyword.items) > 1
419+
and len(keyword_args) > 1
420+
):
421+
return
414422

415423
# If all tests pass, then raise message
416424
self.add_message(
@@ -438,12 +446,10 @@ def _detect_replacable_format_call(self, node: nodes.Const) -> None:
438446
inferred_right = utils.safe_infer(node.parent.right)
439447

440448
# If dicts or lists of length > 1 are used
441-
if isinstance(inferred_right, nodes.Dict):
442-
if len(inferred_right.items) > 1:
443-
return
444-
elif isinstance(inferred_right, nodes.List):
445-
if len(inferred_right.elts) > 1:
446-
return
449+
if isinstance(inferred_right, nodes.Dict) and len(inferred_right.items) > 1:
450+
return
451+
if isinstance(inferred_right, nodes.List) and len(inferred_right.elts) > 1:
452+
return
447453

448454
# If all tests pass, then raise message
449455
self.add_message(

tests/functional/c/consider/consider_using_f_string.py

+8
Original file line numberDiff line numberDiff line change
@@ -128,3 +128,11 @@ def wrap_print(value):
128128
print(value)
129129

130130
wrap_print(value="{}".format)
131+
132+
133+
def invalid_format_string_good():
134+
"""Should not raise message when `.format` is called with an invalid format string."""
135+
# pylint: disable=bad-format-string
136+
print("{a[0] + a[1]}".format(a=[0, 1]))
137+
print("{".format(a=1))
138+
print("{".format(1))

0 commit comments

Comments
 (0)