Find replacement expression for every specifier in str.format() call. In case of an error use TempNode(AnyType).
(self, call: CallExpr, keys: list[str])
| 450 | ) |
| 451 | |
| 452 | def find_replacements_in_call(self, call: CallExpr, keys: list[str]) -> list[Expression]: |
| 453 | """Find replacement expression for every specifier in str.format() call. |
| 454 | |
| 455 | In case of an error use TempNode(AnyType). |
| 456 | """ |
| 457 | result: list[Expression] = [] |
| 458 | used: set[Expression] = set() |
| 459 | for key in keys: |
| 460 | if key.isdecimal(): |
| 461 | expr = self.get_expr_by_position(int(key), call) |
| 462 | if not expr: |
| 463 | self.msg.fail( |
| 464 | f"Cannot find replacement for positional format specifier {key}", |
| 465 | call, |
| 466 | code=codes.STRING_FORMATTING, |
| 467 | ) |
| 468 | expr = TempNode(AnyType(TypeOfAny.from_error)) |
| 469 | else: |
| 470 | expr = self.get_expr_by_name(key, call) |
| 471 | if not expr: |
| 472 | self.msg.fail( |
| 473 | f'Cannot find replacement for named format specifier "{key}"', |
| 474 | call, |
| 475 | code=codes.STRING_FORMATTING, |
| 476 | ) |
| 477 | expr = TempNode(AnyType(TypeOfAny.from_error)) |
| 478 | result.append(expr) |
| 479 | if not isinstance(expr, TempNode): |
| 480 | used.add(expr) |
| 481 | # Strictly speaking not using all replacements is not a type error, but most likely |
| 482 | # a typo in user code, so we show an error like we do for % formatting. |
| 483 | total_explicit = len([kind for kind in call.arg_kinds if kind in (ARG_POS, ARG_NAMED)]) |
| 484 | if len(used) < total_explicit: |
| 485 | self.msg.too_many_string_formatting_arguments(call) |
| 486 | return result |
| 487 | |
| 488 | def get_expr_by_position(self, pos: int, call: CallExpr) -> Expression | None: |
| 489 | """Get positional replacement expression from '{0}, {1}'.format(x, y, ...) call. |
no test coverage detected