(
self,
spec: ConversionSpecifier,
call: CallExpr,
repl: Expression,
actual_type: Type,
expected_type: Type,
)
| 404 | self.perform_special_format_checks(spec, call, repl, a_type, expected_type) |
| 405 | |
| 406 | def perform_special_format_checks( |
| 407 | self, |
| 408 | spec: ConversionSpecifier, |
| 409 | call: CallExpr, |
| 410 | repl: Expression, |
| 411 | actual_type: Type, |
| 412 | expected_type: Type, |
| 413 | ) -> None: |
| 414 | # TODO: try refactoring to combine this logic with % formatting. |
| 415 | if spec.conv_type == "c": |
| 416 | if isinstance(repl, (StrExpr, BytesExpr)) and len(repl.value) != 1: |
| 417 | self.msg.requires_int_or_char(call, format_call=True) |
| 418 | c_typ = get_proper_type(self.chk.lookup_type(repl)) |
| 419 | if isinstance(c_typ, Instance) and c_typ.last_known_value: |
| 420 | c_typ = c_typ.last_known_value |
| 421 | if isinstance(c_typ, LiteralType) and isinstance(c_typ.value, str): |
| 422 | if len(c_typ.value) != 1: |
| 423 | self.msg.requires_int_or_char(call, format_call=True) |
| 424 | if (not spec.conv_type or spec.conv_type == "s") and not spec.conversion: |
| 425 | if has_type_component(actual_type, "builtins.bytes") and not custom_special_method( |
| 426 | actual_type, "__str__" |
| 427 | ): |
| 428 | self.msg.fail( |
| 429 | 'If x = b\'abc\' then f"{x}" or "{}".format(x) produces "b\'abc\'", ' |
| 430 | 'not "abc". If this is desired behavior, use f"{x!r}" or "{!r}".format(x). ' |
| 431 | "Otherwise, decode the bytes", |
| 432 | call, |
| 433 | code=codes.STR_BYTES_PY3, |
| 434 | ) |
| 435 | if spec.flags: |
| 436 | numeric_types = UnionType( |
| 437 | [self.named_type("builtins.int"), self.named_type("builtins.float")] |
| 438 | ) |
| 439 | if ( |
| 440 | spec.conv_type |
| 441 | and spec.conv_type not in NUMERIC_TYPES_NEW |
| 442 | or not spec.conv_type |
| 443 | and not is_subtype(actual_type, numeric_types) |
| 444 | and not custom_special_method(actual_type, "__format__") |
| 445 | ): |
| 446 | self.msg.fail( |
| 447 | "Numeric flags are only allowed for numeric types", |
| 448 | call, |
| 449 | code=codes.STRING_FORMATTING, |
| 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. |
no test coverage detected