From 3c9e76eb6623c78bb12d4b1b7c7d319425ede0d4 Mon Sep 17 00:00:00 2001 From: InSync Date: Mon, 18 Nov 2024 09:24:35 +0700 Subject: [PATCH] [`flake8-datetimez`] Also exempt `.time()` (`DTZ901`) (#14394) ## Summary Resolves #14378. ## Test Plan `cargo nextest run` and `cargo insta test`. --------- Co-authored-by: Charlie Marsh --- .../test/fixtures/flake8_datetimez/DTZ901.py | 12 +++++++ .../rules/datetime_min_max.rs | 8 ++--- ...e8_datetimez__tests__DTZ901_DTZ901.py.snap | 36 +++++++++---------- 3 files changed, 34 insertions(+), 22 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_datetimez/DTZ901.py b/crates/ruff_linter/resources/test/fixtures/flake8_datetimez/DTZ901.py index 704ab974023bd..bd6fa399f56c2 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_datetimez/DTZ901.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_datetimez/DTZ901.py @@ -13,6 +13,12 @@ datetime.datetime.max.replace(tzinfo=...) datetime.datetime.min.replace(tzinfo=...) +datetime.datetime.max.time() +datetime.datetime.min.time() + +datetime.datetime.max.time(foo=...) +datetime.datetime.min.time(foo=...) + from datetime import datetime @@ -28,3 +34,9 @@ # No error datetime.max.replace(tzinfo=...) datetime.min.replace(tzinfo=...) + +datetime.max.time() +datetime.min.time() + +datetime.max.time(foo=...) +datetime.min.time(foo=...) diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/rules/datetime_min_max.rs b/crates/ruff_linter/src/rules/flake8_datetimez/rules/datetime_min_max.rs index a8227c27698d8..be39435d55586 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/rules/datetime_min_max.rs +++ b/crates/ruff_linter/src/rules/flake8_datetimez/rules/datetime_min_max.rs @@ -70,7 +70,7 @@ pub(crate) fn datetime_max_min(checker: &mut Checker, expr: &Expr) { _ => return, }; - if followed_by_replace_tzinfo(checker.semantic()) { + if usage_is_safe(checker.semantic()) { return; } @@ -79,8 +79,8 @@ pub(crate) fn datetime_max_min(checker: &mut Checker, expr: &Expr) { .push(Diagnostic::new(DatetimeMinMax { min_max }, expr.range())); } -/// Check if the current expression has the pattern `foo.replace(tzinfo=bar)`. -fn followed_by_replace_tzinfo(semantic: &SemanticModel) -> bool { +/// Check if the current expression has the pattern `foo.replace(tzinfo=bar)` or `foo.time()`. +fn usage_is_safe(semantic: &SemanticModel) -> bool { let Some(parent) = semantic.current_expression_parent() else { return false; }; @@ -90,7 +90,7 @@ fn followed_by_replace_tzinfo(semantic: &SemanticModel) -> bool { match (parent, grandparent) { (Expr::Attribute(ExprAttribute { attr, .. }), Expr::Call(ExprCall { arguments, .. })) => { - attr.as_str() == "replace" && arguments.find_keyword("tzinfo").is_some() + attr == "time" || (attr == "replace" && arguments.find_keyword("tzinfo").is_some()) } _ => false, } diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ901_DTZ901.py.snap b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ901_DTZ901.py.snap index 68ccb0f5e3e91..29636c3fca91d 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ901_DTZ901.py.snap +++ b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ901_DTZ901.py.snap @@ -40,40 +40,40 @@ DTZ901.py:9:1: DTZ901 Use of `datetime.datetime.min` without timezone informatio | = help: Replace with `datetime.datetime.min.replace(tzinfo=...)` -DTZ901.py:21:1: DTZ901 Use of `datetime.datetime.max` without timezone information +DTZ901.py:27:1: DTZ901 Use of `datetime.datetime.max` without timezone information | -20 | # Error -21 | datetime.max +26 | # Error +27 | datetime.max | ^^^^^^^^^^^^ DTZ901 -22 | datetime.min +28 | datetime.min | = help: Replace with `datetime.datetime.max.replace(tzinfo=...)` -DTZ901.py:22:1: DTZ901 Use of `datetime.datetime.min` without timezone information +DTZ901.py:28:1: DTZ901 Use of `datetime.datetime.min` without timezone information | -20 | # Error -21 | datetime.max -22 | datetime.min +26 | # Error +27 | datetime.max +28 | datetime.min | ^^^^^^^^^^^^ DTZ901 -23 | -24 | datetime.max.replace(year=...) +29 | +30 | datetime.max.replace(year=...) | = help: Replace with `datetime.datetime.min.replace(tzinfo=...)` -DTZ901.py:24:1: DTZ901 Use of `datetime.datetime.max` without timezone information +DTZ901.py:30:1: DTZ901 Use of `datetime.datetime.max` without timezone information | -22 | datetime.min -23 | -24 | datetime.max.replace(year=...) +28 | datetime.min +29 | +30 | datetime.max.replace(year=...) | ^^^^^^^^^^^^ DTZ901 -25 | datetime.min.replace(hour=...) +31 | datetime.min.replace(hour=...) | = help: Replace with `datetime.datetime.max.replace(tzinfo=...)` -DTZ901.py:25:1: DTZ901 Use of `datetime.datetime.min` without timezone information +DTZ901.py:31:1: DTZ901 Use of `datetime.datetime.min` without timezone information | -24 | datetime.max.replace(year=...) -25 | datetime.min.replace(hour=...) +30 | datetime.max.replace(year=...) +31 | datetime.min.replace(hour=...) | ^^^^^^^^^^^^ DTZ901 | = help: Replace with `datetime.datetime.min.replace(tzinfo=...)`