Skip to content

Commit e6cbd41

Browse files
authored
Fix crash caused by invalid format strings in .format context (#10300)
1 parent a5f6765 commit e6cbd41

File tree

3 files changed

+29
-12
lines changed

3 files changed

+29
-12
lines changed

doc/whatsnew/fragments/10282.bugfix

Lines changed: 3 additions & 0 deletions
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

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,14 @@ def _detect_replacable_format_call(self, node: nodes.Const) -> None:
386386
if not isinstance(node.parent.parent, nodes.Call):
387387
return
388388

389+
# Don't raise message on bad format string
390+
try:
391+
keyword_args = [
392+
i[0] for i in utils.parse_format_method_string(node.value)[0]
393+
]
394+
except utils.IncompleteFormatString:
395+
return
396+
389397
if node.parent.parent.args:
390398
for arg in node.parent.parent.args:
391399
# If star expressions with more than 1 element are being used
@@ -401,9 +409,6 @@ def _detect_replacable_format_call(self, node: nodes.Const) -> None:
401409
return
402410

403411
elif node.parent.parent.keywords:
404-
keyword_args = [
405-
i[0] for i in utils.parse_format_method_string(node.value)[0]
406-
]
407412
for keyword in node.parent.parent.keywords:
408413
# If keyword is used multiple times
409414
if keyword_args.count(keyword.arg) > 1:
@@ -412,9 +417,12 @@ def _detect_replacable_format_call(self, node: nodes.Const) -> None:
412417
keyword = utils.safe_infer(keyword.value)
413418

414419
# If lists of more than one element are being unpacked
415-
if isinstance(keyword, nodes.Dict):
416-
if len(keyword.items) > 1 and len(keyword_args) > 1:
417-
return
420+
if (
421+
isinstance(keyword, nodes.Dict)
422+
and len(keyword.items) > 1
423+
and len(keyword_args) > 1
424+
):
425+
return
418426

419427
# If all tests pass, then raise message
420428
self.add_message(
@@ -442,12 +450,10 @@ def _detect_replacable_format_call(self, node: nodes.Const) -> None:
442450
inferred_right = utils.safe_infer(node.parent.right)
443451

444452
# If dicts or lists of length > 1 are used
445-
if isinstance(inferred_right, nodes.Dict):
446-
if len(inferred_right.items) > 1:
447-
return
448-
elif isinstance(inferred_right, nodes.List):
449-
if len(inferred_right.elts) > 1:
450-
return
453+
if isinstance(inferred_right, nodes.Dict) and len(inferred_right.items) > 1:
454+
return
455+
if isinstance(inferred_right, nodes.List) and len(inferred_right.elts) > 1:
456+
return
451457

452458
# If all tests pass, then raise message
453459
self.add_message(

tests/functional/c/consider/consider_using_f_string.py

Lines changed: 8 additions & 0 deletions
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)