Skip to content

Commit

Permalink
Avoid converting f-strings within Django gettext calls
Browse files Browse the repository at this point in the history
  • Loading branch information
charliermarsh committed Oct 10, 2023
1 parent ec7395b commit ee16edc
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from django.utils.translation import gettext

long = 'long'
split_to = 'split_to'
gettext(
'some super {} and complicated string so that the error code '
'E501 Triggers when this is not {} multi-line'.format(
long, split_to)
)
1 change: 1 addition & 0 deletions crates/ruff_linter/src/rules/pyupgrade/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ mod tests {
#[test_case(Rule::FString, Path::new("UP032_0.py"))]
#[test_case(Rule::FString, Path::new("UP032_1.py"))]
#[test_case(Rule::FString, Path::new("UP032_2.py"))]
#[test_case(Rule::FString, Path::new("UP032_3.py"))]
#[test_case(Rule::FormatLiterals, Path::new("UP030_0.py"))]
#[test_case(Rule::FormatLiterals, Path::new("UP030_1.py"))]
#[test_case(Rule::LRUCacheWithMaxsizeNone, Path::new("UP033_0.py"))]
Expand Down
20 changes: 20 additions & 0 deletions crates/ruff_linter/src/rules/pyupgrade/rules/f_strings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,7 @@ pub(crate) fn f_strings(
let Some(mut summary) = FormatSummaryValues::try_from_call(call, checker.locator()) else {
return;
};

let mut patches: Vec<(TextRange, String)> = vec![];
let mut lex = lexer::lex_starts_at(
checker.locator().slice(call.func.range()),
Expand Down Expand Up @@ -405,6 +406,25 @@ pub(crate) fn f_strings(
return;
}

// Finally, avoid refactors that would introduce a runtime error.
// For example, Django's `gettext` supports `format`-style arguments, but not f-strings.
// See: https://docs.djangoproject.com/en/4.2/topics/i18n/translation
if checker.semantic().current_expressions().any(|expr| {
expr.as_call_expr().is_some_and(|call| {
checker
.semantic()
.resolve_call_path(call.func.as_ref())
.map_or(false, |call_path| {
matches!(
call_path.as_slice(),
["django", "utils", "translation", "gettext" | "gettext_lazy"]
)
})
})
}) {
return;
}

let mut diagnostic = Diagnostic::new(FString, call.range());

// Avoid fix if there are comments within the call:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
source: crates/ruff_linter/src/rules/pyupgrade/mod.rs
---

0 comments on commit ee16edc

Please sign in to comment.