-
Notifications
You must be signed in to change notification settings - Fork 1.6k
[pyupgrade] Fix UP030 to avoid modifying double curly braces in format strings
#19378
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
ntBre
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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