[pyupgrade] Fix UP030 to avoid modifying double curly braces in format strings#19378
[pyupgrade] Fix UP030 to avoid modifying double curly braces in format strings#19378ntBre merged 5 commits intoastral-sh:mainfrom
pyupgrade] Fix UP030 to avoid modifying double curly braces in format strings#19378Conversation
|
ntBre
left a comment
There was a problem hiding this comment.
Thanks! I think we can just extend the current regex and also handle an additional edge case at the same time.
| fn replace_single_brace(text: &str) -> String { | ||
| let mut result = String::with_capacity(text.len()); | ||
| let mut last = 0; | ||
| for mat in FORMAT_SPECIFIER.find_iter(text) { |
There was a problem hiding this comment.
At the risk of going too wild with regular expressions, I think we can just handle this directly in FORMAT_SPECIFIER:
static FORMAT_SPECIFIER: LazyLock<Regex> = LazyLock::new(|| {
Regex::new(
r"(?x)
(?P<prefix>
^|[^{]|(?:\{{2})+ # preceded by nothing, a non-brace, or an even number of braces
)
\{ # opening curly brace
(?P<int>\d+) # followed by any integer
(?P<fmt>.*?) # followed by any text
} # followed by a closing brace
",
)
.unwrap()
});While I was here, I went ahead and set verbose mode on the regex (initial (?x)) and moved the comments on FORMAT_SPECIFIER into the regex itself.
With this change, we also have to pass along the $prefix in the calls below. For example:
string.value = arena.alloc(
FORMAT_SPECIFIER
.replace_all(string.value, "$prefix{$fmt}")
.to_string(),
);I almost neglected the "even number of braces" check, but cases like this are valid:
"{{{0}}}".format(123)I think this is verging on needing us to parse the whole format string manually, but if we can't come up with any other edge cases, I think the regex is fine. I'd recommend adding this as a fixable test case too.
pyupgrade] Fix UP030 to avoid modifying double curly braces in format stringspyupgrade] Fix UP030 to avoid modifying double curly braces in format strings
* main: (24 commits) Add `Checker::context` method, deduplicate Unicode checks (#19609) [`flake8-pyi`] Preserve inline comment in ellipsis removal (`PYI013`) (#19399) [ty] Add flow diagram for import resolution [ty] Add comments to some core resolver functions [ty] Add missing ticks and use consistent quoting [ty] Reflow some long lines [ty] Unexport helper function [ty] Remove offset from `CompletionTargetTokens::Unknown` [`pyupgrade`] Fix `UP030` to avoid modifying double curly braces in format strings (#19378) [ty] fix a typo (#19621) [ty] synthesize `__replace__` for dataclasses (>=3.13) (#19545) [ty] Discard `Definition`s when normalizing `Signature`s (#19615) [ty] Fix empty spans following a line terminator and unprintable character spans in diagnostics (#19535) Add `LinterContext::settings` to avoid passing separate settings (#19608) Support `.pyi` files in ruff analyze graph (#19611) [ty] Sync vendored typeshed stubs (#19607) [ty] Bump docstring-adder pin (#19606) [`perflint`] Ignore rule if target is `global` or `nonlocal` (`PERF401`) (#19539) Add license classifier back to pyproject.toml (#19599) [ty] Add stub mapping support to signature help (#19570) ...
Summary
Fixes #19348