[ruff] Handle empty t-strings in unnecessary-empty-iterable-within-deque-call (RUF037) (#20045)

Adds a method to `TStringValue` to detect whether the t-string is empty
_as an iterable_. Note the subtlety here that, unlike f-strings, an
empty t-string is still truthy (i.e. `bool(t"")==True`).

Closes #19951
This commit is contained in:
Dylan 2025-08-22 10:23:49 -05:00 committed by GitHub
parent 0e9d77e43a
commit 0b6ce1c788
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 66 additions and 1 deletions

View file

@ -515,7 +515,7 @@ impl FStringValue {
/// Returns `true` if the node represents an empty f-string literal.
///
/// Noteh that a [`FStringValue`] node will always have >= 1 [`FStringPart`]s inside it.
/// Note that a [`FStringValue`] node will always have >= 1 [`FStringPart`]s inside it.
/// This method checks whether the value of the concatenated parts is equal to the empty
/// f-string, not whether the f-string has 0 parts inside it.
pub fn is_empty_literal(&self) -> bool {
@ -681,6 +681,22 @@ impl TStringValue {
pub fn elements(&self) -> impl Iterator<Item = &InterpolatedStringElement> {
self.iter().flat_map(|tstring| tstring.elements.iter())
}
/// Returns `true` if the node represents an empty t-string in the
/// sense that `__iter__` returns an empty iterable.
///
/// Beware that empty t-strings are still truthy, i.e. `bool(t"") == True`.
///
/// Note that a [`TStringValue`] node will always contain at least one
/// [`TString`] node. This method checks whether each of the constituent
/// t-strings (in an implicitly concatenated t-string) are empty
/// in the above sense.
pub fn is_empty_iterable(&self) -> bool {
match &self.inner {
TStringValueInner::Single(tstring) => tstring.is_empty(),
TStringValueInner::Concatenated(tstrings) => tstrings.iter().all(TString::is_empty),
}
}
}
impl<'a> IntoIterator for &'a TStringValue {
@ -1182,6 +1198,10 @@ impl TString {
pub fn quote_style(&self) -> Quote {
self.flags.quote_style()
}
pub fn is_empty(&self) -> bool {
self.elements.is_empty()
}
}
impl From<TString> for Expr {