Skip to content

Commit 090c1a4

Browse files
Avoid converting f-strings within Django gettext calls (#7898)
## Summary Django's `gettext` doesn't support f-strings, so we should avoid translating `.format` calls in those cases. Closes #7891.
1 parent 2b95d38 commit 090c1a4

File tree

4 files changed

+34
-0
lines changed

4 files changed

+34
-0
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from django.utils.translation import gettext
2+
3+
long = 'long'
4+
split_to = 'split_to'
5+
gettext(
6+
'some super {} and complicated string so that the error code '
7+
'E501 Triggers when this is not {} multi-line'.format(
8+
long, split_to)
9+
)

crates/ruff_linter/src/rules/pyupgrade/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ mod tests {
2828
#[test_case(Rule::FString, Path::new("UP032_0.py"))]
2929
#[test_case(Rule::FString, Path::new("UP032_1.py"))]
3030
#[test_case(Rule::FString, Path::new("UP032_2.py"))]
31+
#[test_case(Rule::FString, Path::new("UP032_3.py"))]
3132
#[test_case(Rule::FormatLiterals, Path::new("UP030_0.py"))]
3233
#[test_case(Rule::FormatLiterals, Path::new("UP030_1.py"))]
3334
#[test_case(Rule::LRUCacheWithMaxsizeNone, Path::new("UP033_0.py"))]

crates/ruff_linter/src/rules/pyupgrade/rules/f_strings.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,7 @@ pub(crate) fn f_strings(
328328
let Some(mut summary) = FormatSummaryValues::try_from_call(call, checker.locator()) else {
329329
return;
330330
};
331+
331332
let mut patches: Vec<(TextRange, String)> = vec![];
332333
let mut lex = lexer::lex_starts_at(
333334
checker.locator().slice(call.func.range()),
@@ -405,6 +406,25 @@ pub(crate) fn f_strings(
405406
return;
406407
}
407408

409+
// Finally, avoid refactors that would introduce a runtime error.
410+
// For example, Django's `gettext` supports `format`-style arguments, but not f-strings.
411+
// See: https://docs.djangoproject.com/en/4.2/topics/i18n/translation
412+
if checker.semantic().current_expressions().any(|expr| {
413+
expr.as_call_expr().is_some_and(|call| {
414+
checker
415+
.semantic()
416+
.resolve_call_path(call.func.as_ref())
417+
.map_or(false, |call_path| {
418+
matches!(
419+
call_path.as_slice(),
420+
["django", "utils", "translation", "gettext" | "gettext_lazy"]
421+
)
422+
})
423+
})
424+
}) {
425+
return;
426+
}
427+
408428
let mut diagnostic = Diagnostic::new(FString, call.range());
409429

410430
// Avoid fix if there are comments within the call:
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
source: crates/ruff_linter/src/rules/pyupgrade/mod.rs
3+
---
4+

0 commit comments

Comments
 (0)