From 647e131f1e615e31d96a461e50a90a52eb592c77 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Mon, 25 Mar 2024 22:21:28 +0100 Subject: [PATCH 1/7] Update call_datetime_now_without_tzinfo.rs Fixes #10251 * #10251 --- .../rules/call_datetime_now_without_tzinfo.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_now_without_tzinfo.rs b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_now_without_tzinfo.rs index 6a40aa2734b40..144b3558fe9f1 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_now_without_tzinfo.rs +++ b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_now_without_tzinfo.rs @@ -44,6 +44,13 @@ use super::helpers; /// datetime.datetime.now(tz=datetime.UTC) /// ``` /// +/// ## Why can't I use `datetime.datetime.now(tz=None)`? +/// ```python +/// datetime.datetime.now(tz=None) # Returns a naive datetime for the machine's timezone. +/// # So, for a timezone-aware datetime for the machine's timezone, use: +/// datetime.datetime.now(tz=datetime.timezone.utc).astimezone() +/// ``` +/// /// ## References /// - [Python documentation: Aware and Naive Objects](https://docs.python.org/3/library/datetime.html#aware-and-naive-objects) #[violation] From 4f600366dbd2762308089420438e9d44646329a7 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Tue, 26 Mar 2024 13:06:15 +0100 Subject: [PATCH 2/7] Checks for usages of `datetime.datetime.now()` that do not specify a timezone --- .../rules/call_datetime_now_without_tzinfo.rs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_now_without_tzinfo.rs b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_now_without_tzinfo.rs index 144b3558fe9f1..8a32a4587220f 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_now_without_tzinfo.rs +++ b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_now_without_tzinfo.rs @@ -11,7 +11,7 @@ use crate::rules::flake8_datetimez::rules::helpers::has_non_none_keyword; use super::helpers; /// ## What it does -/// Checks for usage of `datetime.datetime.now()` without a `tz` argument. +/// Checks for usages of `datetime.datetime.now()` that do not specify a timezone. /// /// ## Why is this bad? /// Python datetime objects can be naive or timezone-aware. While an aware @@ -20,8 +20,9 @@ use super::helpers; /// datetime objects. Since this can lead to errors, it is recommended to /// always use timezone-aware objects. /// -/// `datetime.datetime.now()` returns a naive datetime object. Instead, use -/// `datetime.datetime.now(tz=)` to return a timezone-aware object. +/// `datetime.datetime.now()` or `datetime.datetime.now(tz=None)` returns a naive +/// datetime object. Instead, use `datetime.datetime.now(tz=)` to return a +/// timezone-aware object. /// /// ## Example /// ```python @@ -44,13 +45,6 @@ use super::helpers; /// datetime.datetime.now(tz=datetime.UTC) /// ``` /// -/// ## Why can't I use `datetime.datetime.now(tz=None)`? -/// ```python -/// datetime.datetime.now(tz=None) # Returns a naive datetime for the machine's timezone. -/// # So, for a timezone-aware datetime for the machine's timezone, use: -/// datetime.datetime.now(tz=datetime.timezone.utc).astimezone() -/// ``` -/// /// ## References /// - [Python documentation: Aware and Naive Objects](https://docs.python.org/3/library/datetime.html#aware-and-naive-objects) #[violation] From 60dd46f4a4ddf8865534217421d8083f21796132 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Tue, 26 Mar 2024 13:31:04 +0100 Subject: [PATCH 3/7] Using `datetime.datetime.now()` without specifying a timezone is not allowed --- .../flake8_datetimez/rules/call_datetime_now_without_tzinfo.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_now_without_tzinfo.rs b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_now_without_tzinfo.rs index 8a32a4587220f..1260585969ecf 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_now_without_tzinfo.rs +++ b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_now_without_tzinfo.rs @@ -53,7 +53,7 @@ pub struct CallDatetimeNowWithoutTzinfo; impl Violation for CallDatetimeNowWithoutTzinfo { #[derive_message_formats] fn message(&self) -> String { - format!("The use of `datetime.datetime.now()` without `tz` argument is not allowed") + format!("The use of `datetime.datetime.now()` without specifying a timezone is not allowed"") } } From c7761aad49716f7767d471d0dad1645c9a1678ac Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Tue, 26 Mar 2024 12:35:45 +0000 Subject: [PATCH 4/7] fixes --- .../rules/call_datetime_now_without_tzinfo.rs | 2 +- ...s__flake8_datetimez__tests__DTZ005_DTZ005.py.snap | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_now_without_tzinfo.rs b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_now_without_tzinfo.rs index 1260585969ecf..b06db813c085e 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_now_without_tzinfo.rs +++ b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_now_without_tzinfo.rs @@ -53,7 +53,7 @@ pub struct CallDatetimeNowWithoutTzinfo; impl Violation for CallDatetimeNowWithoutTzinfo { #[derive_message_formats] fn message(&self) -> String { - format!("The use of `datetime.datetime.now()` without specifying a timezone is not allowed"") + format!("Using `datetime.datetime.now()` without specifying a timezone is not allowed") } } diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ005_DTZ005.py.snap b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ005_DTZ005.py.snap index a20ccd8a4606c..2f24cc4dce1e8 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ005_DTZ005.py.snap +++ b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ005_DTZ005.py.snap @@ -1,7 +1,7 @@ --- source: crates/ruff_linter/src/rules/flake8_datetimez/mod.rs --- -DTZ005.py:4:1: DTZ005 The use of `datetime.datetime.now()` without `tz` argument is not allowed +DTZ005.py:4:1: DTZ005 Using `datetime.datetime.now()` without specifying a timezone is not allowed | 3 | # no args 4 | datetime.datetime.now() @@ -10,7 +10,7 @@ DTZ005.py:4:1: DTZ005 The use of `datetime.datetime.now()` without `tz` argument 6 | # wrong keywords | -DTZ005.py:7:1: DTZ005 The use of `datetime.datetime.now()` without `tz` argument is not allowed +DTZ005.py:7:1: DTZ005 Using `datetime.datetime.now()` without specifying a timezone is not allowed | 6 | # wrong keywords 7 | datetime.datetime.now(bad=datetime.timezone.utc) @@ -19,7 +19,7 @@ DTZ005.py:7:1: DTZ005 The use of `datetime.datetime.now()` without `tz` argument 9 | # none args | -DTZ005.py:10:1: DTZ005 The use of `datetime.datetime.now()` without `tz` argument is not allowed +DTZ005.py:10:1: DTZ005 Using `datetime.datetime.now()` without specifying a timezone is not allowed | 9 | # none args 10 | datetime.datetime.now(None) @@ -28,7 +28,7 @@ DTZ005.py:10:1: DTZ005 The use of `datetime.datetime.now()` without `tz` argumen 12 | # none keywords | -DTZ005.py:13:1: DTZ005 The use of `datetime.datetime.now()` without `tz` argument is not allowed +DTZ005.py:13:1: DTZ005 Using `datetime.datetime.now()` without specifying a timezone is not allowed | 12 | # none keywords 13 | datetime.datetime.now(tz=None) @@ -37,7 +37,7 @@ DTZ005.py:13:1: DTZ005 The use of `datetime.datetime.now()` without `tz` argumen 15 | from datetime import datetime | -DTZ005.py:18:1: DTZ005 The use of `datetime.datetime.now()` without `tz` argument is not allowed +DTZ005.py:18:1: DTZ005 Using `datetime.datetime.now()` without specifying a timezone is not allowed | 17 | # no args unqualified 18 | datetime.now() @@ -45,5 +45,3 @@ DTZ005.py:18:1: DTZ005 The use of `datetime.datetime.now()` without `tz` argumen 19 | 20 | # uses `astimezone` method | - - From d3fe8bb92ae7cdfabd810781a9bc6304f527a213 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Tue, 26 Mar 2024 18:32:35 +0000 Subject: [PATCH 5/7] Rework `DTZ` rules to clarify error messages --- .../rules/call_datetime_fromtimestamp.rs | 59 ++++++------- .../rules/call_datetime_now_without_tzinfo.rs | 53 +++++------- .../call_datetime_strptime_without_zone.rs | 85 +++++++++++-------- .../rules/call_datetime_utcfromtimestamp.rs | 9 +- .../rules/call_datetime_without_tzinfo.rs | 52 ++++++------ .../rules/flake8_datetimez/rules/helpers.rs | 15 ++-- ...e8_datetimez__tests__DTZ001_DTZ001.py.snap | 6 +- ...e8_datetimez__tests__DTZ005_DTZ005.py.snap | 10 +-- ...e8_datetimez__tests__DTZ006_DTZ006.py.snap | 6 +- ...e8_datetimez__tests__DTZ007_DTZ007.py.snap | 4 +- 10 files changed, 144 insertions(+), 155 deletions(-) diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_fromtimestamp.rs b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_fromtimestamp.rs index 30e67d827e06e..eb4a8db5cb77c 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_fromtimestamp.rs +++ b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_fromtimestamp.rs @@ -3,16 +3,14 @@ use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::{self as ast}; use ruff_python_semantic::Modules; -use ruff_text_size::Ranged; use crate::checkers::ast::Checker; -use crate::rules::flake8_datetimez::rules::helpers::has_non_none_keyword; -use super::helpers; +use super::helpers::{self, DatetimeModuleAntipattern}; /// ## What it does -/// Checks for usage of `datetime.datetime.fromtimestamp()` without a `tz` -/// argument. +/// Checks for usage of `datetime.datetime.fromtimestamp()` that do not specify +/// a timezone. /// /// ## Why is this bad? /// Python datetime objects can be naive or timezone-aware. While an aware @@ -21,8 +19,9 @@ use super::helpers; /// datetime objects. Since this can lead to errors, it is recommended to /// always use timezone-aware objects. /// -/// `datetime.datetime.fromtimestamp(ts)` returns a naive datetime object. -/// Instead, use `datetime.datetime.fromtimestamp(ts, tz=)` to return a +/// `datetime.datetime.fromtimestamp(ts)` or +/// `datetime.datetime.fromtimestampe(ts, tz=None)` returns a naive datetime +/// object. Instead, use `datetime.datetime.fromtimestamp(ts, tz=)` to return a /// timezone-aware object. /// /// ## Example @@ -39,7 +38,7 @@ use super::helpers; /// datetime.datetime.fromtimestamp(946684800, tz=datetime.timezone.utc) /// ``` /// -/// Or, for Python 3.11 and later: +/// Or, on Python 3.11 and later: /// ```python /// import datetime /// @@ -49,14 +48,20 @@ use super::helpers; /// ## References /// - [Python documentation: Aware and Naive Objects](https://docs.python.org/3/library/datetime.html#aware-and-naive-objects) #[violation] -pub struct CallDatetimeFromtimestamp; +pub struct CallDatetimeFromtimestamp(DatetimeModuleAntipattern); impl Violation for CallDatetimeFromtimestamp { #[derive_message_formats] fn message(&self) -> String { - format!( - "The use of `datetime.datetime.fromtimestamp()` without `tz` argument is not allowed" - ) + let CallDatetimeFromtimestamp(antipattern) = self; + match antipattern { + DatetimeModuleAntipattern::NoTzArgumentPassed => format!( + "The use of `datetime.datetime.fromtimestamp()` without `tz` argument is not allowed" + ), + DatetimeModuleAntipattern::NonePassedToTzArgument => format!( + "Passing `tz=None` is forbidden, as it creates a naive datetime object" + ), + } } } @@ -82,26 +87,14 @@ pub(crate) fn call_datetime_fromtimestamp(checker: &mut Checker, call: &ast::Exp return; } - // no args / no args unqualified - if call.arguments.args.len() < 2 && call.arguments.keywords.is_empty() { - checker - .diagnostics - .push(Diagnostic::new(CallDatetimeFromtimestamp, call.range())); - return; - } - - // none args - if call.arguments.args.len() > 1 && call.arguments.args[1].is_none_literal_expr() { - checker - .diagnostics - .push(Diagnostic::new(CallDatetimeFromtimestamp, call.range())); - return; - } + let antipattern = match call.arguments.find_argument("tz", 1) { + Some(ast::Expr::NoneLiteral(_)) => DatetimeModuleAntipattern::NonePassedToTzArgument, + Some(_) => return, + None => DatetimeModuleAntipattern::NoTzArgumentPassed, + }; - // wrong keywords / none keyword - if !call.arguments.keywords.is_empty() && !has_non_none_keyword(&call.arguments, "tz") { - checker - .diagnostics - .push(Diagnostic::new(CallDatetimeFromtimestamp, call.range())); - } + checker.diagnostics.push(Diagnostic::new( + CallDatetimeFromtimestamp(antipattern), + call.range, + )); } diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_now_without_tzinfo.rs b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_now_without_tzinfo.rs index b06db813c085e..a51d83801fd2c 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_now_without_tzinfo.rs +++ b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_now_without_tzinfo.rs @@ -1,14 +1,12 @@ use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::{self as ast, Expr}; +use ruff_python_ast as ast; use ruff_python_semantic::Modules; -use ruff_text_size::Ranged; use crate::checkers::ast::Checker; -use crate::rules::flake8_datetimez::rules::helpers::has_non_none_keyword; -use super::helpers; +use super::helpers::{self, DatetimeModuleAntipattern}; /// ## What it does /// Checks for usages of `datetime.datetime.now()` that do not specify a timezone. @@ -48,12 +46,20 @@ use super::helpers; /// ## References /// - [Python documentation: Aware and Naive Objects](https://docs.python.org/3/library/datetime.html#aware-and-naive-objects) #[violation] -pub struct CallDatetimeNowWithoutTzinfo; +pub struct CallDatetimeNowWithoutTzinfo(DatetimeModuleAntipattern); impl Violation for CallDatetimeNowWithoutTzinfo { #[derive_message_formats] fn message(&self) -> String { - format!("Using `datetime.datetime.now()` without specifying a timezone is not allowed") + let CallDatetimeNowWithoutTzinfo(antipattern) = self; + match antipattern { + DatetimeModuleAntipattern::NoTzArgumentPassed => { + format!("Using `datetime.datetime.now()` without a `tz=` argument is not allowed") + } + DatetimeModuleAntipattern::NonePassedToTzArgument => { + format!("Passing `tz=None` to `datetime.datetime.now()` is not allowed") + } + } } } @@ -76,31 +82,14 @@ pub(crate) fn call_datetime_now_without_tzinfo(checker: &mut Checker, call: &ast return; } - // no args / no args unqualified - if call.arguments.args.is_empty() && call.arguments.keywords.is_empty() { - checker - .diagnostics - .push(Diagnostic::new(CallDatetimeNowWithoutTzinfo, call.range())); - return; - } + let antipattern = match call.arguments.find_argument("tz", 0) { + Some(ast::Expr::NoneLiteral(_)) => DatetimeModuleAntipattern::NonePassedToTzArgument, + Some(_) => return, + None => DatetimeModuleAntipattern::NoTzArgumentPassed, + }; - // none args - if call - .arguments - .args - .first() - .is_some_and(Expr::is_none_literal_expr) - { - checker - .diagnostics - .push(Diagnostic::new(CallDatetimeNowWithoutTzinfo, call.range())); - return; - } - - // wrong keywords / none keyword - if !call.arguments.keywords.is_empty() && !has_non_none_keyword(&call.arguments, "tz") { - checker - .diagnostics - .push(Diagnostic::new(CallDatetimeNowWithoutTzinfo, call.range())); - } + checker.diagnostics.push(Diagnostic::new( + CallDatetimeNowWithoutTzinfo(antipattern), + call.range, + )); } diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_strptime_without_zone.rs b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_strptime_without_zone.rs index 9fdce6ee34829..320a14157c9ad 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_strptime_without_zone.rs +++ b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_strptime_without_zone.rs @@ -2,10 +2,10 @@ use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::{self as ast, Expr}; use ruff_python_semantic::Modules; -use ruff_text_size::Ranged; use crate::checkers::ast::Checker; -use crate::rules::flake8_datetimez::rules::helpers::has_non_none_keyword; + +use super::helpers::DatetimeModuleAntipattern; /// ## What it does /// Checks for uses of `datetime.datetime.strptime()` that lead to naive @@ -51,15 +51,22 @@ use crate::rules::flake8_datetimez::rules::helpers::has_non_none_keyword; /// - [Python documentation: Aware and Naive Objects](https://docs.python.org/3/library/datetime.html#aware-and-naive-objects) /// - [Python documentation: `strftime()` and `strptime()` Behavior](https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior) #[violation] -pub struct CallDatetimeStrptimeWithoutZone; +pub struct CallDatetimeStrptimeWithoutZone(DatetimeModuleAntipattern); impl Violation for CallDatetimeStrptimeWithoutZone { #[derive_message_formats] fn message(&self) -> String { - format!( - "The use of `datetime.datetime.strptime()` without %z must be followed by \ - `.replace(tzinfo=)` or `.astimezone()`" - ) + let CallDatetimeStrptimeWithoutZone(antipattern) = self; + match antipattern { + DatetimeModuleAntipattern::NoTzArgumentPassed => format!( + "The use of `datetime.datetime.strptime()` without %z must be followed by \ + `.replace(tzinfo=)` or `.astimezone()`" + ), + DatetimeModuleAntipattern::NonePassedToTzArgument => format!( + "Passing `tzinfo=None` to `datetime.datetime.replace()` is forbidden, \ + as it creates a naive datetime object" + ), + } } } @@ -91,36 +98,44 @@ pub(crate) fn call_datetime_strptime_without_zone(checker: &mut Checker, call: & } }; - let (Some(grandparent), Some(parent)) = ( - checker.semantic().current_expression_grandparent(), - checker.semantic().current_expression_parent(), - ) else { + let semantic = checker.semantic(); + if let Some(antipattern) = find_antipattern( + semantic.current_expression_grandparent(), + semantic.current_expression_parent(), + ) { checker.diagnostics.push(Diagnostic::new( - CallDatetimeStrptimeWithoutZone, - call.range(), + CallDatetimeStrptimeWithoutZone(antipattern), + call.range, )); - return; - }; - - if let Expr::Call(ast::ExprCall { arguments, .. }) = grandparent { - if let Expr::Attribute(ast::ExprAttribute { attr, .. }) = parent { - let attr = attr.as_str(); - // Ex) `datetime.strptime(...).astimezone()` - if attr == "astimezone" { - return; - } - - // Ex) `datetime.strptime(...).replace(tzinfo=UTC)` - if attr == "replace" { - if has_non_none_keyword(arguments, "tzinfo") { - return; - } - } - } } +} - checker.diagnostics.push(Diagnostic::new( - CallDatetimeStrptimeWithoutZone, - call.range(), - )); +fn find_antipattern( + grandparent: Option<&Expr>, + parent: Option<&Expr>, +) -> Option { + let Some(Expr::Call(ast::ExprCall { arguments, .. })) = grandparent else { + return Some(DatetimeModuleAntipattern::NoTzArgumentPassed); + }; + let Some(Expr::Attribute(ast::ExprAttribute { attr, .. })) = parent else { + return Some(DatetimeModuleAntipattern::NoTzArgumentPassed); + }; + // Ex) `datetime.strptime(...).astimezone()` + if attr == "astimezone" { + return None; + } + if attr != "replace" { + return Some(DatetimeModuleAntipattern::NoTzArgumentPassed); + } + match arguments.find_keyword("tzinfo") { + // Ex) `datetime.strptime(...).replace(tz=None)` + Some(ast::Keyword { + value: Expr::NoneLiteral(_), + .. + }) => Some(DatetimeModuleAntipattern::NonePassedToTzArgument), + // Ex) `datetime.strptime(...).replace(tz=...)` + Some(_) => None, + // Ex) `datetime.strptime(...).replace(...)` with no tz= argument + None => Some(DatetimeModuleAntipattern::NoTzArgumentPassed), + } } diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_utcfromtimestamp.rs b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_utcfromtimestamp.rs index 2db2649e73793..7661ab602fdb6 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_utcfromtimestamp.rs +++ b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_utcfromtimestamp.rs @@ -19,15 +19,16 @@ use super::helpers; /// datetime objects. Since this can lead to errors, it is recommended to /// always use timezone-aware objects. /// -/// `datetime.datetime.utcfromtimestamp()` returns a naive datetime object; -/// instead, use `datetime.datetime.fromtimestamp(ts, tz=)` to return a +/// `datetime.datetime.utcfromtimestamp()` or +/// `datetime.datetime.utcfromtimestamp(tz=None)` returns a naive datetime +/// object; instead, use `datetime.datetime.fromtimestamp(ts, tz=)` to return a /// timezone-aware object. /// /// ## Example /// ```python /// import datetime /// -/// datetime.datetime.utcfromtimestamp() +/// datetime.datetime.utcfromtimestamp(946684800) /// ``` /// /// Use instead: @@ -37,7 +38,7 @@ use super::helpers; /// datetime.datetime.fromtimestamp(946684800, tz=datetime.timezone.utc) /// ``` /// -/// Or, for Python 3.11 and later: +/// Or, on Python 3.11 and later: /// ```python /// import datetime /// diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_without_tzinfo.rs b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_without_tzinfo.rs index 5c3bc9cec39a4..192ab094c72bd 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_without_tzinfo.rs +++ b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_without_tzinfo.rs @@ -1,17 +1,15 @@ use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::{self as ast, Expr}; +use ruff_python_ast as ast; use ruff_python_semantic::Modules; -use ruff_text_size::Ranged; use crate::checkers::ast::Checker; -use crate::rules::flake8_datetimez::rules::helpers::has_non_none_keyword; -use super::helpers; +use super::helpers::{self, DatetimeModuleAntipattern}; /// ## What it does -/// Checks for `datetime` instantiations that lack a `tzinfo` argument. +/// Checks for `datetime` instantiations that do not specify a timezone. /// /// ## Why is this bad? /// `datetime` objects are "naive" by default, in that they do not include @@ -20,7 +18,8 @@ use super::helpers; /// `datetime` objects are preferred, as they represent a specific moment in /// time, unlike "naive" objects. /// -/// By providing a `tzinfo` value, a `datetime` can be made timezone-aware. +/// By providing a non-`None` value for `tzinfo`, a `datetime` can be made +/// timezone-aware. /// /// ## Example /// ```python @@ -36,19 +35,27 @@ use super::helpers; /// datetime.datetime(2000, 1, 1, 0, 0, 0, tzinfo=datetime.timezone.utc) /// ``` /// -/// Or, for Python 3.11 and later: +/// Or, on Python 3.11 and later: /// ```python /// import datetime /// /// datetime.datetime(2000, 1, 1, 0, 0, 0, tzinfo=datetime.UTC) /// ``` #[violation] -pub struct CallDatetimeWithoutTzinfo; +pub struct CallDatetimeWithoutTzinfo(DatetimeModuleAntipattern); impl Violation for CallDatetimeWithoutTzinfo { #[derive_message_formats] fn message(&self) -> String { - format!("The use of `datetime.datetime()` without `tzinfo` argument is not allowed") + let CallDatetimeWithoutTzinfo(antipattern) = self; + match antipattern { + DatetimeModuleAntipattern::NoTzArgumentPassed => { + format!("The use of `datetime.datetime()` without `tzinfo` argument is not allowed") + } + DatetimeModuleAntipattern::NonePassedToTzArgument => { + format!("Passing `tzinfo=None` if forbidden, as it creates a naive datetime object") + } + } } } @@ -69,23 +76,14 @@ pub(crate) fn call_datetime_without_tzinfo(checker: &mut Checker, call: &ast::Ex return; } - // No positional arg: keyword is missing or constant None. - if call.arguments.args.len() < 8 && !has_non_none_keyword(&call.arguments, "tzinfo") { - checker - .diagnostics - .push(Diagnostic::new(CallDatetimeWithoutTzinfo, call.range())); - return; - } + let antipattern = match call.arguments.find_argument("tzinfo", 7) { + Some(ast::Expr::NoneLiteral(_)) => DatetimeModuleAntipattern::NonePassedToTzArgument, + Some(_) => return, + None => DatetimeModuleAntipattern::NoTzArgumentPassed, + }; - // Positional arg: is constant None. - if call - .arguments - .args - .get(7) - .is_some_and(Expr::is_none_literal_expr) - { - checker - .diagnostics - .push(Diagnostic::new(CallDatetimeWithoutTzinfo, call.range())); - } + checker.diagnostics.push(Diagnostic::new( + CallDatetimeWithoutTzinfo(antipattern), + call.range, + )); } diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/rules/helpers.rs b/crates/ruff_linter/src/rules/flake8_datetimez/rules/helpers.rs index 21912044d13bb..a580c9bc95e76 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/rules/helpers.rs +++ b/crates/ruff_linter/src/rules/flake8_datetimez/rules/helpers.rs @@ -1,7 +1,13 @@ -use ruff_python_ast::{Arguments, Expr, ExprAttribute}; +use ruff_python_ast::{Expr, ExprAttribute}; use crate::checkers::ast::Checker; +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +pub(super) enum DatetimeModuleAntipattern { + NoTzArgumentPassed, + NonePassedToTzArgument, +} + /// Check if the parent expression is a call to `astimezone`. This assumes that /// the current expression is a `datetime.datetime` object. pub(super) fn parent_expr_is_astimezone(checker: &Checker) -> bool { @@ -9,10 +15,3 @@ pub(super) fn parent_expr_is_astimezone(checker: &Checker) -> bool { matches!(parent, Expr::Attribute(ExprAttribute { attr, .. }) if attr.as_str() == "astimezone") }) } - -/// Return `true` if a keyword argument is present with a non-`None` value. -pub(super) fn has_non_none_keyword(arguments: &Arguments, keyword: &str) -> bool { - arguments - .find_keyword(keyword) - .is_some_and(|keyword| !keyword.value.is_none_literal_expr()) -} diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ001_DTZ001.py.snap b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ001_DTZ001.py.snap index 45f6dc665784a..d7e029d27ba7e 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ001_DTZ001.py.snap +++ b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ001_DTZ001.py.snap @@ -10,7 +10,7 @@ DTZ001.py:4:1: DTZ001 The use of `datetime.datetime()` without `tzinfo` argument 6 | # none args | -DTZ001.py:7:1: DTZ001 The use of `datetime.datetime()` without `tzinfo` argument is not allowed +DTZ001.py:7:1: DTZ001 Passing `tzinfo=None` if forbidden, as it creates a naive datetime object | 6 | # none args 7 | datetime.datetime(2000, 1, 1, 0, 0, 0, 0, None) @@ -28,7 +28,7 @@ DTZ001.py:13:1: DTZ001 The use of `datetime.datetime()` without `tzinfo` argumen 15 | # none kwargs | -DTZ001.py:16:1: DTZ001 The use of `datetime.datetime()` without `tzinfo` argument is not allowed +DTZ001.py:16:1: DTZ001 Passing `tzinfo=None` if forbidden, as it creates a naive datetime object | 15 | # none kwargs 16 | datetime.datetime(2000, 1, 1, tzinfo=None) @@ -45,5 +45,3 @@ DTZ001.py:21:1: DTZ001 The use of `datetime.datetime()` without `tzinfo` argumen 22 | 23 | # uses `astimezone` method | - - diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ005_DTZ005.py.snap b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ005_DTZ005.py.snap index 2f24cc4dce1e8..d79264aadba33 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ005_DTZ005.py.snap +++ b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ005_DTZ005.py.snap @@ -1,7 +1,7 @@ --- source: crates/ruff_linter/src/rules/flake8_datetimez/mod.rs --- -DTZ005.py:4:1: DTZ005 Using `datetime.datetime.now()` without specifying a timezone is not allowed +DTZ005.py:4:1: DTZ005 Using `datetime.datetime.now()` without a `tz=` argument is not allowed | 3 | # no args 4 | datetime.datetime.now() @@ -10,7 +10,7 @@ DTZ005.py:4:1: DTZ005 Using `datetime.datetime.now()` without specifying a timez 6 | # wrong keywords | -DTZ005.py:7:1: DTZ005 Using `datetime.datetime.now()` without specifying a timezone is not allowed +DTZ005.py:7:1: DTZ005 Using `datetime.datetime.now()` without a `tz=` argument is not allowed | 6 | # wrong keywords 7 | datetime.datetime.now(bad=datetime.timezone.utc) @@ -19,7 +19,7 @@ DTZ005.py:7:1: DTZ005 Using `datetime.datetime.now()` without specifying a timez 9 | # none args | -DTZ005.py:10:1: DTZ005 Using `datetime.datetime.now()` without specifying a timezone is not allowed +DTZ005.py:10:1: DTZ005 Passing `tz=None` to `datetime.datetime.now()` is not allowed | 9 | # none args 10 | datetime.datetime.now(None) @@ -28,7 +28,7 @@ DTZ005.py:10:1: DTZ005 Using `datetime.datetime.now()` without specifying a time 12 | # none keywords | -DTZ005.py:13:1: DTZ005 Using `datetime.datetime.now()` without specifying a timezone is not allowed +DTZ005.py:13:1: DTZ005 Passing `tz=None` to `datetime.datetime.now()` is not allowed | 12 | # none keywords 13 | datetime.datetime.now(tz=None) @@ -37,7 +37,7 @@ DTZ005.py:13:1: DTZ005 Using `datetime.datetime.now()` without specifying a time 15 | from datetime import datetime | -DTZ005.py:18:1: DTZ005 Using `datetime.datetime.now()` without specifying a timezone is not allowed +DTZ005.py:18:1: DTZ005 Using `datetime.datetime.now()` without a `tz=` argument is not allowed | 17 | # no args unqualified 18 | datetime.now() diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ006_DTZ006.py.snap b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ006_DTZ006.py.snap index 671c428306698..61b4c87ed41c8 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ006_DTZ006.py.snap +++ b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ006_DTZ006.py.snap @@ -19,7 +19,7 @@ DTZ006.py:7:1: DTZ006 The use of `datetime.datetime.fromtimestamp()` without `tz 9 | # none args | -DTZ006.py:10:1: DTZ006 The use of `datetime.datetime.fromtimestamp()` without `tz` argument is not allowed +DTZ006.py:10:1: DTZ006 Passing `tz=None` is forbidden, as it creates a naive datetime object | 9 | # none args 10 | datetime.datetime.fromtimestamp(1234, None) @@ -28,7 +28,7 @@ DTZ006.py:10:1: DTZ006 The use of `datetime.datetime.fromtimestamp()` without `t 12 | # none keywords | -DTZ006.py:13:1: DTZ006 The use of `datetime.datetime.fromtimestamp()` without `tz` argument is not allowed +DTZ006.py:13:1: DTZ006 Passing `tz=None` is forbidden, as it creates a naive datetime object | 12 | # none keywords 13 | datetime.datetime.fromtimestamp(1234, tz=None) @@ -45,5 +45,3 @@ DTZ006.py:18:1: DTZ006 The use of `datetime.datetime.fromtimestamp()` without `t 19 | 20 | # uses `astimezone` method | - - diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ007_DTZ007.py.snap b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ007_DTZ007.py.snap index d47324ece6d1d..41ea289c70df6 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ007_DTZ007.py.snap +++ b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ007_DTZ007.py.snap @@ -28,7 +28,7 @@ DTZ007.py:10:1: DTZ007 The use of `datetime.datetime.strptime()` without %z must 12 | # none replace | -DTZ007.py:13:1: DTZ007 The use of `datetime.datetime.strptime()` without %z must be followed by `.replace(tzinfo=)` or `.astimezone()` +DTZ007.py:13:1: DTZ007 Passing `tzinfo=None` to `datetime.datetime.replace()` is forbidden, as it creates a naive datetime object | 12 | # none replace 13 | datetime.datetime.strptime("something", "something").replace(tzinfo=None) @@ -43,5 +43,3 @@ DTZ007.py:35:1: DTZ007 The use of `datetime.datetime.strptime()` without %z must 35 | datetime.strptime("something", "something") | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ DTZ007 | - - From 7beb878e274ee091ed2bd7c138906565253c7951 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Tue, 26 Mar 2024 21:09:36 +0000 Subject: [PATCH 6/7] Address review --- .../rules/call_date_fromtimestamp.rs | 9 ++++---- .../flake8_datetimez/rules/call_date_today.rs | 9 ++++---- .../rules/call_datetime_fromtimestamp.rs | 16 ++++++++------ .../rules/call_datetime_now_without_tzinfo.rs | 8 +++++-- .../call_datetime_strptime_without_zone.rs | 21 ++++++++++++++----- .../rules/call_datetime_today.rs | 9 ++++---- .../rules/call_datetime_utcfromtimestamp.rs | 9 ++++---- .../rules/call_datetime_utcnow.rs | 9 ++++---- .../rules/call_datetime_without_tzinfo.rs | 8 +++++-- ...e8_datetimez__tests__DTZ001_DTZ001.py.snap | 15 ++++++++----- ...e8_datetimez__tests__DTZ002_DTZ002.py.snap | 8 +++---- ...e8_datetimez__tests__DTZ003_DTZ003.py.snap | 8 +++---- ...e8_datetimez__tests__DTZ004_DTZ004.py.snap | 8 +++---- ...e8_datetimez__tests__DTZ005_DTZ005.py.snap | 15 ++++++++----- ...e8_datetimez__tests__DTZ006_DTZ006.py.snap | 15 ++++++++----- ...e8_datetimez__tests__DTZ007_DTZ007.py.snap | 15 ++++++++----- ...e8_datetimez__tests__DTZ011_DTZ011.py.snap | 8 +++---- ...e8_datetimez__tests__DTZ012_DTZ012.py.snap | 8 +++---- 18 files changed, 123 insertions(+), 75 deletions(-) diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_date_fromtimestamp.rs b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_date_fromtimestamp.rs index 1a022a3010fb0..b5c0469b9a00c 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_date_fromtimestamp.rs +++ b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_date_fromtimestamp.rs @@ -50,10 +50,11 @@ pub struct CallDateFromtimestamp; impl Violation for CallDateFromtimestamp { #[derive_message_formats] fn message(&self) -> String { - format!( - "The use of `datetime.date.fromtimestamp()` is not allowed, use \ - `datetime.datetime.fromtimestamp(ts, tz=).date()` instead" - ) + format!("`datetime.date.fromtimestamp()` used") + } + + fn fix_title(&self) -> Option { + Some("Use `datetime.datetime.fromtimestamp(ts, tz=).date()` instead".to_string()) } } diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_date_today.rs b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_date_today.rs index 9e0bacbff8921..46abe43ccecd1 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_date_today.rs +++ b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_date_today.rs @@ -49,10 +49,11 @@ pub struct CallDateToday; impl Violation for CallDateToday { #[derive_message_formats] fn message(&self) -> String { - format!( - "The use of `datetime.date.today()` is not allowed, use \ - `datetime.datetime.now(tz=).date()` instead" - ) + format!("`datetime.date.today()` used") + } + + fn fix_title(&self) -> Option { + Some("Use `datetime.datetime.now(tz=).date()` instead".to_string()) } } diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_fromtimestamp.rs b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_fromtimestamp.rs index eb4a8db5cb77c..58dec4d8310b8 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_fromtimestamp.rs +++ b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_fromtimestamp.rs @@ -55,14 +55,18 @@ impl Violation for CallDatetimeFromtimestamp { fn message(&self) -> String { let CallDatetimeFromtimestamp(antipattern) = self; match antipattern { - DatetimeModuleAntipattern::NoTzArgumentPassed => format!( - "The use of `datetime.datetime.fromtimestamp()` without `tz` argument is not allowed" - ), - DatetimeModuleAntipattern::NonePassedToTzArgument => format!( - "Passing `tz=None` is forbidden, as it creates a naive datetime object" - ), + DatetimeModuleAntipattern::NoTzArgumentPassed => { + format!("`datetime.datetime.fromtimestamp()` called without a `tz` argument") + } + DatetimeModuleAntipattern::NonePassedToTzArgument => { + format!("`tz=None` passed to `datetime.datetime.fromtimestamp()`") + } } } + + fn fix_title(&self) -> Option { + Some("Pass a `datetime.timezone` object to the `tz` parameter".to_string()) + } } pub(crate) fn call_datetime_fromtimestamp(checker: &mut Checker, call: &ast::ExprCall) { diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_now_without_tzinfo.rs b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_now_without_tzinfo.rs index a51d83801fd2c..e472daee04100 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_now_without_tzinfo.rs +++ b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_now_without_tzinfo.rs @@ -54,13 +54,17 @@ impl Violation for CallDatetimeNowWithoutTzinfo { let CallDatetimeNowWithoutTzinfo(antipattern) = self; match antipattern { DatetimeModuleAntipattern::NoTzArgumentPassed => { - format!("Using `datetime.datetime.now()` without a `tz=` argument is not allowed") + format!("`datetime.datetime.now()` called without a `tz=` argument") } DatetimeModuleAntipattern::NonePassedToTzArgument => { - format!("Passing `tz=None` to `datetime.datetime.now()` is not allowed") + format!("`tz=None` passed to `datetime.datetime.now()`") } } } + + fn fix_title(&self) -> Option { + Some("Pass a `datetime.timezone` object to the `tz` parameter".to_string()) + } } pub(crate) fn call_datetime_now_without_tzinfo(checker: &mut Checker, call: &ast::ExprCall) { diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_strptime_without_zone.rs b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_strptime_without_zone.rs index 320a14157c9ad..1b6f1401c4924 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_strptime_without_zone.rs +++ b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_strptime_without_zone.rs @@ -59,13 +59,24 @@ impl Violation for CallDatetimeStrptimeWithoutZone { let CallDatetimeStrptimeWithoutZone(antipattern) = self; match antipattern { DatetimeModuleAntipattern::NoTzArgumentPassed => format!( - "The use of `datetime.datetime.strptime()` without %z must be followed by \ - `.replace(tzinfo=)` or `.astimezone()`" + "Naive datetime constructed using `datetime.datetime.strptime()` without %z" ), - DatetimeModuleAntipattern::NonePassedToTzArgument => format!( - "Passing `tzinfo=None` to `datetime.datetime.replace()` is forbidden, \ - as it creates a naive datetime object" + DatetimeModuleAntipattern::NonePassedToTzArgument => { + format!("`datetime.datetime.strptime(...).replace(tz=None)` used") + } + } + } + + fn fix_title(&self) -> Option { + let CallDatetimeStrptimeWithoutZone(antipattern) = self; + match antipattern { + DatetimeModuleAntipattern::NoTzArgumentPassed => Some( + "Call `.replace(tzinfo=)` or `.astimezone()` to convert to an aware datetime" + .to_string(), ), + DatetimeModuleAntipattern::NonePassedToTzArgument => { + Some("Pass a `datetime.timezone` object to `tzinfo=`".to_string()) + } } } } diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_today.rs b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_today.rs index d712f604ec1d7..5d99dab69b4ae 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_today.rs +++ b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_today.rs @@ -48,10 +48,11 @@ pub struct CallDatetimeToday; impl Violation for CallDatetimeToday { #[derive_message_formats] fn message(&self) -> String { - format!( - "The use of `datetime.datetime.today()` is not allowed, use \ - `datetime.datetime.now(tz=)` instead" - ) + format!("`datetime.datetime.today()` used") + } + + fn fix_title(&self) -> Option { + Some("Use `datetime.datetime.now(tz=)` instead".to_string()) } } diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_utcfromtimestamp.rs b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_utcfromtimestamp.rs index 7661ab602fdb6..3848295fc0862 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_utcfromtimestamp.rs +++ b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_utcfromtimestamp.rs @@ -53,10 +53,11 @@ pub struct CallDatetimeUtcfromtimestamp; impl Violation for CallDatetimeUtcfromtimestamp { #[derive_message_formats] fn message(&self) -> String { - format!( - "The use of `datetime.datetime.utcfromtimestamp()` is not allowed, use \ - `datetime.datetime.fromtimestamp(ts, tz=)` instead" - ) + format!("`datetime.datetime.utcfromtimestamp()` used") + } + + fn fix_title(&self) -> Option { + Some("Use `datetime.datetime.fromtimestamp(ts, tz=)` instead".to_string()) } } diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_utcnow.rs b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_utcnow.rs index 9ff0de0549cb3..503fdb656c5b3 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_utcnow.rs +++ b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_utcnow.rs @@ -51,10 +51,11 @@ pub struct CallDatetimeUtcnow; impl Violation for CallDatetimeUtcnow { #[derive_message_formats] fn message(&self) -> String { - format!( - "The use of `datetime.datetime.utcnow()` is not allowed, use \ - `datetime.datetime.now(tz=)` instead" - ) + format!("`datetime.datetime.utcnow()` used") + } + + fn fix_title(&self) -> Option { + Some("Use `datetime.datetime.now(tz=)` instead".to_string()) } } diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_without_tzinfo.rs b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_without_tzinfo.rs index 192ab094c72bd..264950d937eff 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_without_tzinfo.rs +++ b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_without_tzinfo.rs @@ -50,13 +50,17 @@ impl Violation for CallDatetimeWithoutTzinfo { let CallDatetimeWithoutTzinfo(antipattern) = self; match antipattern { DatetimeModuleAntipattern::NoTzArgumentPassed => { - format!("The use of `datetime.datetime()` without `tzinfo` argument is not allowed") + format!("`datetime.datetime()` called without a `tzinfo` argument") } DatetimeModuleAntipattern::NonePassedToTzArgument => { - format!("Passing `tzinfo=None` if forbidden, as it creates a naive datetime object") + format!("`tzinfo=None` passed to `datetime.datetime()`") } } } + + fn fix_title(&self) -> Option { + Some("Pass a `datetime.timezone` object to the `tzinfo` parameter".to_string()) + } } pub(crate) fn call_datetime_without_tzinfo(checker: &mut Checker, call: &ast::ExprCall) { diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ001_DTZ001.py.snap b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ001_DTZ001.py.snap index d7e029d27ba7e..e4e8e1f901ef0 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ001_DTZ001.py.snap +++ b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ001_DTZ001.py.snap @@ -1,7 +1,7 @@ --- source: crates/ruff_linter/src/rules/flake8_datetimez/mod.rs --- -DTZ001.py:4:1: DTZ001 The use of `datetime.datetime()` without `tzinfo` argument is not allowed +DTZ001.py:4:1: DTZ001 `datetime.datetime()` called without a `tzinfo` argument | 3 | # no args 4 | datetime.datetime(2000, 1, 1, 0, 0, 0) @@ -9,8 +9,9 @@ DTZ001.py:4:1: DTZ001 The use of `datetime.datetime()` without `tzinfo` argument 5 | 6 | # none args | + = help: Pass a `datetime.timezone` object to the `tzinfo` parameter -DTZ001.py:7:1: DTZ001 Passing `tzinfo=None` if forbidden, as it creates a naive datetime object +DTZ001.py:7:1: DTZ001 `tzinfo=None` passed to `datetime.datetime()` | 6 | # none args 7 | datetime.datetime(2000, 1, 1, 0, 0, 0, 0, None) @@ -18,8 +19,9 @@ DTZ001.py:7:1: DTZ001 Passing `tzinfo=None` if forbidden, as it creates a naive 8 | 9 | # not none arg | + = help: Pass a `datetime.timezone` object to the `tzinfo` parameter -DTZ001.py:13:1: DTZ001 The use of `datetime.datetime()` without `tzinfo` argument is not allowed +DTZ001.py:13:1: DTZ001 `datetime.datetime()` called without a `tzinfo` argument | 12 | # no kwargs 13 | datetime.datetime(2000, 1, 1, fold=1) @@ -27,8 +29,9 @@ DTZ001.py:13:1: DTZ001 The use of `datetime.datetime()` without `tzinfo` argumen 14 | 15 | # none kwargs | + = help: Pass a `datetime.timezone` object to the `tzinfo` parameter -DTZ001.py:16:1: DTZ001 Passing `tzinfo=None` if forbidden, as it creates a naive datetime object +DTZ001.py:16:1: DTZ001 `tzinfo=None` passed to `datetime.datetime()` | 15 | # none kwargs 16 | datetime.datetime(2000, 1, 1, tzinfo=None) @@ -36,8 +39,9 @@ DTZ001.py:16:1: DTZ001 Passing `tzinfo=None` if forbidden, as it creates a naive 17 | 18 | from datetime import datetime | + = help: Pass a `datetime.timezone` object to the `tzinfo` parameter -DTZ001.py:21:1: DTZ001 The use of `datetime.datetime()` without `tzinfo` argument is not allowed +DTZ001.py:21:1: DTZ001 `datetime.datetime()` called without a `tzinfo` argument | 20 | # no args unqualified 21 | datetime(2000, 1, 1, 0, 0, 0) @@ -45,3 +49,4 @@ DTZ001.py:21:1: DTZ001 The use of `datetime.datetime()` without `tzinfo` argumen 22 | 23 | # uses `astimezone` method | + = help: Pass a `datetime.timezone` object to the `tzinfo` parameter diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ002_DTZ002.py.snap b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ002_DTZ002.py.snap index d7ff15f3f5898..9042ed756be1c 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ002_DTZ002.py.snap +++ b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ002_DTZ002.py.snap @@ -1,7 +1,7 @@ --- source: crates/ruff_linter/src/rules/flake8_datetimez/mod.rs --- -DTZ002.py:4:1: DTZ002 The use of `datetime.datetime.today()` is not allowed, use `datetime.datetime.now(tz=)` instead +DTZ002.py:4:1: DTZ002 `datetime.datetime.today()` used | 3 | # qualified 4 | datetime.datetime.today() @@ -9,8 +9,9 @@ DTZ002.py:4:1: DTZ002 The use of `datetime.datetime.today()` is not allowed, use 5 | 6 | from datetime import datetime | + = help: Use `datetime.datetime.now(tz=)` instead -DTZ002.py:9:1: DTZ002 The use of `datetime.datetime.today()` is not allowed, use `datetime.datetime.now(tz=)` instead +DTZ002.py:9:1: DTZ002 `datetime.datetime.today()` used | 8 | # unqualified 9 | datetime.today() @@ -18,5 +19,4 @@ DTZ002.py:9:1: DTZ002 The use of `datetime.datetime.today()` is not allowed, use 10 | 11 | # uses `astimezone` method | - - + = help: Use `datetime.datetime.now(tz=)` instead diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ003_DTZ003.py.snap b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ003_DTZ003.py.snap index 0c1da8d49b8e6..bb802f886237f 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ003_DTZ003.py.snap +++ b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ003_DTZ003.py.snap @@ -1,7 +1,7 @@ --- source: crates/ruff_linter/src/rules/flake8_datetimez/mod.rs --- -DTZ003.py:4:1: DTZ003 The use of `datetime.datetime.utcnow()` is not allowed, use `datetime.datetime.now(tz=)` instead +DTZ003.py:4:1: DTZ003 `datetime.datetime.utcnow()` used | 3 | # qualified 4 | datetime.datetime.utcnow() @@ -9,8 +9,9 @@ DTZ003.py:4:1: DTZ003 The use of `datetime.datetime.utcnow()` is not allowed, us 5 | 6 | from datetime import datetime | + = help: Use `datetime.datetime.now(tz=)` instead -DTZ003.py:9:1: DTZ003 The use of `datetime.datetime.utcnow()` is not allowed, use `datetime.datetime.now(tz=)` instead +DTZ003.py:9:1: DTZ003 `datetime.datetime.utcnow()` used | 8 | # unqualified 9 | datetime.utcnow() @@ -18,5 +19,4 @@ DTZ003.py:9:1: DTZ003 The use of `datetime.datetime.utcnow()` is not allowed, us 10 | 11 | # uses `astimezone` method | - - + = help: Use `datetime.datetime.now(tz=)` instead diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ004_DTZ004.py.snap b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ004_DTZ004.py.snap index d0a0184fe3eda..7bb55cba92c8c 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ004_DTZ004.py.snap +++ b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ004_DTZ004.py.snap @@ -1,7 +1,7 @@ --- source: crates/ruff_linter/src/rules/flake8_datetimez/mod.rs --- -DTZ004.py:4:1: DTZ004 The use of `datetime.datetime.utcfromtimestamp()` is not allowed, use `datetime.datetime.fromtimestamp(ts, tz=)` instead +DTZ004.py:4:1: DTZ004 `datetime.datetime.utcfromtimestamp()` used | 3 | # qualified 4 | datetime.datetime.utcfromtimestamp(1234) @@ -9,8 +9,9 @@ DTZ004.py:4:1: DTZ004 The use of `datetime.datetime.utcfromtimestamp()` is not a 5 | 6 | from datetime import datetime | + = help: Use `datetime.datetime.fromtimestamp(ts, tz=)` instead -DTZ004.py:9:1: DTZ004 The use of `datetime.datetime.utcfromtimestamp()` is not allowed, use `datetime.datetime.fromtimestamp(ts, tz=)` instead +DTZ004.py:9:1: DTZ004 `datetime.datetime.utcfromtimestamp()` used | 8 | # unqualified 9 | datetime.utcfromtimestamp(1234) @@ -18,5 +19,4 @@ DTZ004.py:9:1: DTZ004 The use of `datetime.datetime.utcfromtimestamp()` is not a 10 | 11 | # uses `astimezone` method | - - + = help: Use `datetime.datetime.fromtimestamp(ts, tz=)` instead diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ005_DTZ005.py.snap b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ005_DTZ005.py.snap index d79264aadba33..d06fd3358d3d1 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ005_DTZ005.py.snap +++ b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ005_DTZ005.py.snap @@ -1,7 +1,7 @@ --- source: crates/ruff_linter/src/rules/flake8_datetimez/mod.rs --- -DTZ005.py:4:1: DTZ005 Using `datetime.datetime.now()` without a `tz=` argument is not allowed +DTZ005.py:4:1: DTZ005 `datetime.datetime.now()` called without a `tz=` argument | 3 | # no args 4 | datetime.datetime.now() @@ -9,8 +9,9 @@ DTZ005.py:4:1: DTZ005 Using `datetime.datetime.now()` without a `tz=` argument i 5 | 6 | # wrong keywords | + = help: Pass a `datetime.timezone` object to the `tz` parameter -DTZ005.py:7:1: DTZ005 Using `datetime.datetime.now()` without a `tz=` argument is not allowed +DTZ005.py:7:1: DTZ005 `datetime.datetime.now()` called without a `tz=` argument | 6 | # wrong keywords 7 | datetime.datetime.now(bad=datetime.timezone.utc) @@ -18,8 +19,9 @@ DTZ005.py:7:1: DTZ005 Using `datetime.datetime.now()` without a `tz=` argument i 8 | 9 | # none args | + = help: Pass a `datetime.timezone` object to the `tz` parameter -DTZ005.py:10:1: DTZ005 Passing `tz=None` to `datetime.datetime.now()` is not allowed +DTZ005.py:10:1: DTZ005 `tz=None` passed to `datetime.datetime.now()` | 9 | # none args 10 | datetime.datetime.now(None) @@ -27,8 +29,9 @@ DTZ005.py:10:1: DTZ005 Passing `tz=None` to `datetime.datetime.now()` is not all 11 | 12 | # none keywords | + = help: Pass a `datetime.timezone` object to the `tz` parameter -DTZ005.py:13:1: DTZ005 Passing `tz=None` to `datetime.datetime.now()` is not allowed +DTZ005.py:13:1: DTZ005 `tz=None` passed to `datetime.datetime.now()` | 12 | # none keywords 13 | datetime.datetime.now(tz=None) @@ -36,8 +39,9 @@ DTZ005.py:13:1: DTZ005 Passing `tz=None` to `datetime.datetime.now()` is not all 14 | 15 | from datetime import datetime | + = help: Pass a `datetime.timezone` object to the `tz` parameter -DTZ005.py:18:1: DTZ005 Using `datetime.datetime.now()` without a `tz=` argument is not allowed +DTZ005.py:18:1: DTZ005 `datetime.datetime.now()` called without a `tz=` argument | 17 | # no args unqualified 18 | datetime.now() @@ -45,3 +49,4 @@ DTZ005.py:18:1: DTZ005 Using `datetime.datetime.now()` without a `tz=` argument 19 | 20 | # uses `astimezone` method | + = help: Pass a `datetime.timezone` object to the `tz` parameter diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ006_DTZ006.py.snap b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ006_DTZ006.py.snap index 61b4c87ed41c8..e708ed9d52404 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ006_DTZ006.py.snap +++ b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ006_DTZ006.py.snap @@ -1,7 +1,7 @@ --- source: crates/ruff_linter/src/rules/flake8_datetimez/mod.rs --- -DTZ006.py:4:1: DTZ006 The use of `datetime.datetime.fromtimestamp()` without `tz` argument is not allowed +DTZ006.py:4:1: DTZ006 `datetime.datetime.fromtimestamp()` called without a `tz` argument | 3 | # no args 4 | datetime.datetime.fromtimestamp(1234) @@ -9,8 +9,9 @@ DTZ006.py:4:1: DTZ006 The use of `datetime.datetime.fromtimestamp()` without `tz 5 | 6 | # wrong keywords | + = help: Pass a `datetime.timezone` object to the `tz` parameter -DTZ006.py:7:1: DTZ006 The use of `datetime.datetime.fromtimestamp()` without `tz` argument is not allowed +DTZ006.py:7:1: DTZ006 `datetime.datetime.fromtimestamp()` called without a `tz` argument | 6 | # wrong keywords 7 | datetime.datetime.fromtimestamp(1234, bad=datetime.timezone.utc) @@ -18,8 +19,9 @@ DTZ006.py:7:1: DTZ006 The use of `datetime.datetime.fromtimestamp()` without `tz 8 | 9 | # none args | + = help: Pass a `datetime.timezone` object to the `tz` parameter -DTZ006.py:10:1: DTZ006 Passing `tz=None` is forbidden, as it creates a naive datetime object +DTZ006.py:10:1: DTZ006 `tz=None` passed to `datetime.datetime.fromtimestamp()` | 9 | # none args 10 | datetime.datetime.fromtimestamp(1234, None) @@ -27,8 +29,9 @@ DTZ006.py:10:1: DTZ006 Passing `tz=None` is forbidden, as it creates a naive dat 11 | 12 | # none keywords | + = help: Pass a `datetime.timezone` object to the `tz` parameter -DTZ006.py:13:1: DTZ006 Passing `tz=None` is forbidden, as it creates a naive datetime object +DTZ006.py:13:1: DTZ006 `tz=None` passed to `datetime.datetime.fromtimestamp()` | 12 | # none keywords 13 | datetime.datetime.fromtimestamp(1234, tz=None) @@ -36,8 +39,9 @@ DTZ006.py:13:1: DTZ006 Passing `tz=None` is forbidden, as it creates a naive dat 14 | 15 | from datetime import datetime | + = help: Pass a `datetime.timezone` object to the `tz` parameter -DTZ006.py:18:1: DTZ006 The use of `datetime.datetime.fromtimestamp()` without `tz` argument is not allowed +DTZ006.py:18:1: DTZ006 `datetime.datetime.fromtimestamp()` called without a `tz` argument | 17 | # no args unqualified 18 | datetime.fromtimestamp(1234) @@ -45,3 +49,4 @@ DTZ006.py:18:1: DTZ006 The use of `datetime.datetime.fromtimestamp()` without `t 19 | 20 | # uses `astimezone` method | + = help: Pass a `datetime.timezone` object to the `tz` parameter diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ007_DTZ007.py.snap b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ007_DTZ007.py.snap index 41ea289c70df6..9f9bb3fdbd18a 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ007_DTZ007.py.snap +++ b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ007_DTZ007.py.snap @@ -1,7 +1,7 @@ --- source: crates/ruff_linter/src/rules/flake8_datetimez/mod.rs --- -DTZ007.py:4:1: DTZ007 The use of `datetime.datetime.strptime()` without %z must be followed by `.replace(tzinfo=)` or `.astimezone()` +DTZ007.py:4:1: DTZ007 Naive datetime constructed using `datetime.datetime.strptime()` without %z | 3 | # bad format 4 | datetime.datetime.strptime("something", "%H:%M:%S%Z") @@ -9,8 +9,9 @@ DTZ007.py:4:1: DTZ007 The use of `datetime.datetime.strptime()` without %z must 5 | 6 | # no replace or astimezone | + = help: Call `.replace(tzinfo=)` or `.astimezone()` to convert to an aware datetime -DTZ007.py:7:1: DTZ007 The use of `datetime.datetime.strptime()` without %z must be followed by `.replace(tzinfo=)` or `.astimezone()` +DTZ007.py:7:1: DTZ007 Naive datetime constructed using `datetime.datetime.strptime()` without %z | 6 | # no replace or astimezone 7 | datetime.datetime.strptime("something", "something") @@ -18,8 +19,9 @@ DTZ007.py:7:1: DTZ007 The use of `datetime.datetime.strptime()` without %z must 8 | 9 | # wrong replace | + = help: Call `.replace(tzinfo=)` or `.astimezone()` to convert to an aware datetime -DTZ007.py:10:1: DTZ007 The use of `datetime.datetime.strptime()` without %z must be followed by `.replace(tzinfo=)` or `.astimezone()` +DTZ007.py:10:1: DTZ007 Naive datetime constructed using `datetime.datetime.strptime()` without %z | 9 | # wrong replace 10 | datetime.datetime.strptime("something", "something").replace(hour=1) @@ -27,8 +29,9 @@ DTZ007.py:10:1: DTZ007 The use of `datetime.datetime.strptime()` without %z must 11 | 12 | # none replace | + = help: Call `.replace(tzinfo=)` or `.astimezone()` to convert to an aware datetime -DTZ007.py:13:1: DTZ007 Passing `tzinfo=None` to `datetime.datetime.replace()` is forbidden, as it creates a naive datetime object +DTZ007.py:13:1: DTZ007 `datetime.datetime.strptime(...).replace(tz=None)` used | 12 | # none replace 13 | datetime.datetime.strptime("something", "something").replace(tzinfo=None) @@ -36,10 +39,12 @@ DTZ007.py:13:1: DTZ007 Passing `tzinfo=None` to `datetime.datetime.replace()` is 14 | 15 | # OK | + = help: Pass a `datetime.timezone` object to `tzinfo=` -DTZ007.py:35:1: DTZ007 The use of `datetime.datetime.strptime()` without %z must be followed by `.replace(tzinfo=)` or `.astimezone()` +DTZ007.py:35:1: DTZ007 Naive datetime constructed using `datetime.datetime.strptime()` without %z | 34 | # no replace orastimezone unqualified 35 | datetime.strptime("something", "something") | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ DTZ007 | + = help: Call `.replace(tzinfo=)` or `.astimezone()` to convert to an aware datetime diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ011_DTZ011.py.snap b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ011_DTZ011.py.snap index 546f8e9bbfc3b..dee4d02ab4c1c 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ011_DTZ011.py.snap +++ b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ011_DTZ011.py.snap @@ -1,7 +1,7 @@ --- source: crates/ruff_linter/src/rules/flake8_datetimez/mod.rs --- -DTZ011.py:4:1: DTZ011 The use of `datetime.date.today()` is not allowed, use `datetime.datetime.now(tz=).date()` instead +DTZ011.py:4:1: DTZ011 `datetime.date.today()` used | 3 | # qualified 4 | datetime.date.today() @@ -9,12 +9,12 @@ DTZ011.py:4:1: DTZ011 The use of `datetime.date.today()` is not allowed, use `da 5 | 6 | from datetime import date | + = help: Use `datetime.datetime.now(tz=).date()` instead -DTZ011.py:9:1: DTZ011 The use of `datetime.date.today()` is not allowed, use `datetime.datetime.now(tz=).date()` instead +DTZ011.py:9:1: DTZ011 `datetime.date.today()` used | 8 | # unqualified 9 | date.today() | ^^^^^^^^^^^^ DTZ011 | - - + = help: Use `datetime.datetime.now(tz=).date()` instead diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ012_DTZ012.py.snap b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ012_DTZ012.py.snap index cce6418b93b0c..e7784fcc66631 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ012_DTZ012.py.snap +++ b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ012_DTZ012.py.snap @@ -1,7 +1,7 @@ --- source: crates/ruff_linter/src/rules/flake8_datetimez/mod.rs --- -DTZ012.py:4:1: DTZ012 The use of `datetime.date.fromtimestamp()` is not allowed, use `datetime.datetime.fromtimestamp(ts, tz=).date()` instead +DTZ012.py:4:1: DTZ012 `datetime.date.fromtimestamp()` used | 3 | # qualified 4 | datetime.date.fromtimestamp(1234) @@ -9,12 +9,12 @@ DTZ012.py:4:1: DTZ012 The use of `datetime.date.fromtimestamp()` is not allowed, 5 | 6 | from datetime import date | + = help: Use `datetime.datetime.fromtimestamp(ts, tz=).date()` instead -DTZ012.py:9:1: DTZ012 The use of `datetime.date.fromtimestamp()` is not allowed, use `datetime.datetime.fromtimestamp(ts, tz=).date()` instead +DTZ012.py:9:1: DTZ012 `datetime.date.fromtimestamp()` used | 8 | # unqualified 9 | date.fromtimestamp(1234) | ^^^^^^^^^^^^^^^^^^^^^^^^ DTZ012 | - - + = help: Use `datetime.datetime.fromtimestamp(ts, tz=).date()` instead From 300ac2fb276c783b1c12bb8f704df1329e44d7c2 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Wed, 27 Mar 2024 16:42:58 +0000 Subject: [PATCH 7/7] Don't suggest invalid syntax --- .../rules/call_date_fromtimestamp.rs | 4 ++-- .../flake8_datetimez/rules/call_date_today.rs | 4 ++-- .../rules/call_datetime_fromtimestamp.rs | 4 ++-- .../rules/call_datetime_now_without_tzinfo.rs | 6 +++--- .../rules/call_datetime_strptime_without_zone.rs | 15 ++++++++------- .../flake8_datetimez/rules/call_datetime_today.rs | 4 ++-- .../rules/call_datetime_utcfromtimestamp.rs | 9 ++++----- .../rules/call_datetime_utcnow.rs | 4 ++-- ...flake8_datetimez__tests__DTZ002_DTZ002.py.snap | 4 ++-- ...flake8_datetimez__tests__DTZ003_DTZ003.py.snap | 4 ++-- ...flake8_datetimez__tests__DTZ004_DTZ004.py.snap | 4 ++-- ...flake8_datetimez__tests__DTZ005_DTZ005.py.snap | 6 +++--- ...flake8_datetimez__tests__DTZ007_DTZ007.py.snap | 10 +++++----- ...flake8_datetimez__tests__DTZ011_DTZ011.py.snap | 4 ++-- ...flake8_datetimez__tests__DTZ012_DTZ012.py.snap | 4 ++-- 15 files changed, 43 insertions(+), 43 deletions(-) diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_date_fromtimestamp.rs b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_date_fromtimestamp.rs index b5c0469b9a00c..cf3397a4771ac 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_date_fromtimestamp.rs +++ b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_date_fromtimestamp.rs @@ -18,7 +18,7 @@ use crate::checkers::ast::Checker; /// always use timezone-aware objects. /// /// `datetime.date.fromtimestamp(ts)` returns a naive datetime object. -/// Instead, use `datetime.datetime.fromtimestamp(ts, tz=)` to return a +/// Instead, use `datetime.datetime.fromtimestamp(ts, tz=...)` to create a /// timezone-aware object. /// /// ## Example @@ -54,7 +54,7 @@ impl Violation for CallDateFromtimestamp { } fn fix_title(&self) -> Option { - Some("Use `datetime.datetime.fromtimestamp(ts, tz=).date()` instead".to_string()) + Some("Use `datetime.datetime.fromtimestamp(ts, tz=...).date()` instead".to_string()) } } diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_date_today.rs b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_date_today.rs index 46abe43ccecd1..3dd1d967b2f92 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_date_today.rs +++ b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_date_today.rs @@ -18,7 +18,7 @@ use crate::checkers::ast::Checker; /// always use timezone-aware objects. /// /// `datetime.date.today` returns a naive datetime object. Instead, use -/// `datetime.datetime.now(tz=).date()` to return a timezone-aware object. +/// `datetime.datetime.now(tz=...).date()` to create a timezone-aware object. /// /// ## Example /// ```python @@ -53,7 +53,7 @@ impl Violation for CallDateToday { } fn fix_title(&self) -> Option { - Some("Use `datetime.datetime.now(tz=).date()` instead".to_string()) + Some("Use `datetime.datetime.now(tz=...).date()` instead".to_string()) } } diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_fromtimestamp.rs b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_fromtimestamp.rs index 58dec4d8310b8..26b5682f91e0e 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_fromtimestamp.rs +++ b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_fromtimestamp.rs @@ -21,8 +21,8 @@ use super::helpers::{self, DatetimeModuleAntipattern}; /// /// `datetime.datetime.fromtimestamp(ts)` or /// `datetime.datetime.fromtimestampe(ts, tz=None)` returns a naive datetime -/// object. Instead, use `datetime.datetime.fromtimestamp(ts, tz=)` to return a -/// timezone-aware object. +/// object. Instead, use `datetime.datetime.fromtimestamp(ts, tz=)` +/// to create a timezone-aware object. /// /// ## Example /// ```python diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_now_without_tzinfo.rs b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_now_without_tzinfo.rs index e472daee04100..603f9ac018576 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_now_without_tzinfo.rs +++ b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_now_without_tzinfo.rs @@ -19,8 +19,8 @@ use super::helpers::{self, DatetimeModuleAntipattern}; /// always use timezone-aware objects. /// /// `datetime.datetime.now()` or `datetime.datetime.now(tz=None)` returns a naive -/// datetime object. Instead, use `datetime.datetime.now(tz=)` to return a -/// timezone-aware object. +/// datetime object. Instead, use `datetime.datetime.now(tz=)` to create +/// a timezone-aware object. /// /// ## Example /// ```python @@ -54,7 +54,7 @@ impl Violation for CallDatetimeNowWithoutTzinfo { let CallDatetimeNowWithoutTzinfo(antipattern) = self; match antipattern { DatetimeModuleAntipattern::NoTzArgumentPassed => { - format!("`datetime.datetime.now()` called without a `tz=` argument") + format!("`datetime.datetime.now()` called without a `tz` argument") } DatetimeModuleAntipattern::NonePassedToTzArgument => { format!("`tz=None` passed to `datetime.datetime.now()`") diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_strptime_without_zone.rs b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_strptime_without_zone.rs index 1b6f1401c4924..8f9acc166e2e2 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_strptime_without_zone.rs +++ b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_strptime_without_zone.rs @@ -19,7 +19,7 @@ use super::helpers::DatetimeModuleAntipattern; /// always use timezone-aware objects. /// /// `datetime.datetime.strptime()` without `%z` returns a naive datetime -/// object. Follow it with `.replace(tzinfo=)` or `.astimezone()`. +/// object. Follow it with `.replace(tzinfo=)` or `.astimezone()`. /// /// ## Example /// ```python @@ -28,7 +28,7 @@ use super::helpers::DatetimeModuleAntipattern; /// datetime.datetime.strptime("2022/01/31", "%Y/%m/%d") /// ``` /// -/// Instead, use `.replace(tzinfo=)`: +/// Instead, use `.replace(tzinfo=)`: /// ```python /// import datetime /// @@ -71,11 +71,12 @@ impl Violation for CallDatetimeStrptimeWithoutZone { let CallDatetimeStrptimeWithoutZone(antipattern) = self; match antipattern { DatetimeModuleAntipattern::NoTzArgumentPassed => Some( - "Call `.replace(tzinfo=)` or `.astimezone()` to convert to an aware datetime" + "Call `.replace(tzinfo=)` or `.astimezone()` \ + to convert to an aware datetime" .to_string(), ), DatetimeModuleAntipattern::NonePassedToTzArgument => { - Some("Pass a `datetime.timezone` object to `tzinfo=`".to_string()) + Some("Pass a `datetime.timezone` object to the `tzinfo` parameter".to_string()) } } } @@ -139,14 +140,14 @@ fn find_antipattern( return Some(DatetimeModuleAntipattern::NoTzArgumentPassed); } match arguments.find_keyword("tzinfo") { - // Ex) `datetime.strptime(...).replace(tz=None)` + // Ex) `datetime.strptime(...).replace(tzinfo=None)` Some(ast::Keyword { value: Expr::NoneLiteral(_), .. }) => Some(DatetimeModuleAntipattern::NonePassedToTzArgument), - // Ex) `datetime.strptime(...).replace(tz=...)` + // Ex) `datetime.strptime(...).replace(tzinfo=...)` Some(_) => None, - // Ex) `datetime.strptime(...).replace(...)` with no tz= argument + // Ex) `datetime.strptime(...).replace(...)` with no `tzinfo` argument None => Some(DatetimeModuleAntipattern::NoTzArgumentPassed), } } diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_today.rs b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_today.rs index 5d99dab69b4ae..b22a7e84c2ddb 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_today.rs +++ b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_today.rs @@ -20,7 +20,7 @@ use super::helpers; /// time, unlike "naive" objects. /// /// `datetime.datetime.today()` creates a "naive" object; instead, use -/// `datetime.datetime.now(tz=)` to create a timezone-aware object. +/// `datetime.datetime.now(tz=...)` to create a timezone-aware object. /// /// ## Example /// ```python @@ -52,7 +52,7 @@ impl Violation for CallDatetimeToday { } fn fix_title(&self) -> Option { - Some("Use `datetime.datetime.now(tz=)` instead".to_string()) + Some("Use `datetime.datetime.now(tz=...)` instead".to_string()) } } diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_utcfromtimestamp.rs b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_utcfromtimestamp.rs index 3848295fc0862..f24b54158d845 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_utcfromtimestamp.rs +++ b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_utcfromtimestamp.rs @@ -19,10 +19,9 @@ use super::helpers; /// datetime objects. Since this can lead to errors, it is recommended to /// always use timezone-aware objects. /// -/// `datetime.datetime.utcfromtimestamp()` or -/// `datetime.datetime.utcfromtimestamp(tz=None)` returns a naive datetime -/// object; instead, use `datetime.datetime.fromtimestamp(ts, tz=)` to return a -/// timezone-aware object. +/// `datetime.datetime.utcfromtimestamp()` returns a naive datetime +/// object; instead, use `datetime.datetime.fromtimestamp(ts, tz=...)` +/// to create a timezone-aware object. /// /// ## Example /// ```python @@ -57,7 +56,7 @@ impl Violation for CallDatetimeUtcfromtimestamp { } fn fix_title(&self) -> Option { - Some("Use `datetime.datetime.fromtimestamp(ts, tz=)` instead".to_string()) + Some("Use `datetime.datetime.fromtimestamp(ts, tz=...)` instead".to_string()) } } diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_utcnow.rs b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_utcnow.rs index 503fdb656c5b3..059f9b80df572 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_utcnow.rs +++ b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_utcnow.rs @@ -20,7 +20,7 @@ use super::helpers; /// always use timezone-aware objects. /// /// `datetime.datetime.utcnow()` returns a naive datetime object; instead, use -/// `datetime.datetime.now(tz=)` to return a timezone-aware object. +/// `datetime.datetime.now(tz=...)` to create a timezone-aware object. /// /// ## Example /// ```python @@ -55,7 +55,7 @@ impl Violation for CallDatetimeUtcnow { } fn fix_title(&self) -> Option { - Some("Use `datetime.datetime.now(tz=)` instead".to_string()) + Some("Use `datetime.datetime.now(tz=...)` instead".to_string()) } } diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ002_DTZ002.py.snap b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ002_DTZ002.py.snap index 9042ed756be1c..0f29ecf110394 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ002_DTZ002.py.snap +++ b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ002_DTZ002.py.snap @@ -9,7 +9,7 @@ DTZ002.py:4:1: DTZ002 `datetime.datetime.today()` used 5 | 6 | from datetime import datetime | - = help: Use `datetime.datetime.now(tz=)` instead + = help: Use `datetime.datetime.now(tz=...)` instead DTZ002.py:9:1: DTZ002 `datetime.datetime.today()` used | @@ -19,4 +19,4 @@ DTZ002.py:9:1: DTZ002 `datetime.datetime.today()` used 10 | 11 | # uses `astimezone` method | - = help: Use `datetime.datetime.now(tz=)` instead + = help: Use `datetime.datetime.now(tz=...)` instead diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ003_DTZ003.py.snap b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ003_DTZ003.py.snap index bb802f886237f..2b7953a7148aa 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ003_DTZ003.py.snap +++ b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ003_DTZ003.py.snap @@ -9,7 +9,7 @@ DTZ003.py:4:1: DTZ003 `datetime.datetime.utcnow()` used 5 | 6 | from datetime import datetime | - = help: Use `datetime.datetime.now(tz=)` instead + = help: Use `datetime.datetime.now(tz=...)` instead DTZ003.py:9:1: DTZ003 `datetime.datetime.utcnow()` used | @@ -19,4 +19,4 @@ DTZ003.py:9:1: DTZ003 `datetime.datetime.utcnow()` used 10 | 11 | # uses `astimezone` method | - = help: Use `datetime.datetime.now(tz=)` instead + = help: Use `datetime.datetime.now(tz=...)` instead diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ004_DTZ004.py.snap b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ004_DTZ004.py.snap index 7bb55cba92c8c..0efe06454de4b 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ004_DTZ004.py.snap +++ b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ004_DTZ004.py.snap @@ -9,7 +9,7 @@ DTZ004.py:4:1: DTZ004 `datetime.datetime.utcfromtimestamp()` used 5 | 6 | from datetime import datetime | - = help: Use `datetime.datetime.fromtimestamp(ts, tz=)` instead + = help: Use `datetime.datetime.fromtimestamp(ts, tz=...)` instead DTZ004.py:9:1: DTZ004 `datetime.datetime.utcfromtimestamp()` used | @@ -19,4 +19,4 @@ DTZ004.py:9:1: DTZ004 `datetime.datetime.utcfromtimestamp()` used 10 | 11 | # uses `astimezone` method | - = help: Use `datetime.datetime.fromtimestamp(ts, tz=)` instead + = help: Use `datetime.datetime.fromtimestamp(ts, tz=...)` instead diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ005_DTZ005.py.snap b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ005_DTZ005.py.snap index d06fd3358d3d1..ee6f711e0bfc3 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ005_DTZ005.py.snap +++ b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ005_DTZ005.py.snap @@ -1,7 +1,7 @@ --- source: crates/ruff_linter/src/rules/flake8_datetimez/mod.rs --- -DTZ005.py:4:1: DTZ005 `datetime.datetime.now()` called without a `tz=` argument +DTZ005.py:4:1: DTZ005 `datetime.datetime.now()` called without a `tz` argument | 3 | # no args 4 | datetime.datetime.now() @@ -11,7 +11,7 @@ DTZ005.py:4:1: DTZ005 `datetime.datetime.now()` called without a `tz=` argument | = help: Pass a `datetime.timezone` object to the `tz` parameter -DTZ005.py:7:1: DTZ005 `datetime.datetime.now()` called without a `tz=` argument +DTZ005.py:7:1: DTZ005 `datetime.datetime.now()` called without a `tz` argument | 6 | # wrong keywords 7 | datetime.datetime.now(bad=datetime.timezone.utc) @@ -41,7 +41,7 @@ DTZ005.py:13:1: DTZ005 `tz=None` passed to `datetime.datetime.now()` | = help: Pass a `datetime.timezone` object to the `tz` parameter -DTZ005.py:18:1: DTZ005 `datetime.datetime.now()` called without a `tz=` argument +DTZ005.py:18:1: DTZ005 `datetime.datetime.now()` called without a `tz` argument | 17 | # no args unqualified 18 | datetime.now() diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ007_DTZ007.py.snap b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ007_DTZ007.py.snap index 9f9bb3fdbd18a..21184a68e755c 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ007_DTZ007.py.snap +++ b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ007_DTZ007.py.snap @@ -9,7 +9,7 @@ DTZ007.py:4:1: DTZ007 Naive datetime constructed using `datetime.datetime.strpti 5 | 6 | # no replace or astimezone | - = help: Call `.replace(tzinfo=)` or `.astimezone()` to convert to an aware datetime + = help: Call `.replace(tzinfo=)` or `.astimezone()` to convert to an aware datetime DTZ007.py:7:1: DTZ007 Naive datetime constructed using `datetime.datetime.strptime()` without %z | @@ -19,7 +19,7 @@ DTZ007.py:7:1: DTZ007 Naive datetime constructed using `datetime.datetime.strpti 8 | 9 | # wrong replace | - = help: Call `.replace(tzinfo=)` or `.astimezone()` to convert to an aware datetime + = help: Call `.replace(tzinfo=)` or `.astimezone()` to convert to an aware datetime DTZ007.py:10:1: DTZ007 Naive datetime constructed using `datetime.datetime.strptime()` without %z | @@ -29,7 +29,7 @@ DTZ007.py:10:1: DTZ007 Naive datetime constructed using `datetime.datetime.strpt 11 | 12 | # none replace | - = help: Call `.replace(tzinfo=)` or `.astimezone()` to convert to an aware datetime + = help: Call `.replace(tzinfo=)` or `.astimezone()` to convert to an aware datetime DTZ007.py:13:1: DTZ007 `datetime.datetime.strptime(...).replace(tz=None)` used | @@ -39,7 +39,7 @@ DTZ007.py:13:1: DTZ007 `datetime.datetime.strptime(...).replace(tz=None)` used 14 | 15 | # OK | - = help: Pass a `datetime.timezone` object to `tzinfo=` + = help: Pass a `datetime.timezone` object to the `tzinfo` parameter DTZ007.py:35:1: DTZ007 Naive datetime constructed using `datetime.datetime.strptime()` without %z | @@ -47,4 +47,4 @@ DTZ007.py:35:1: DTZ007 Naive datetime constructed using `datetime.datetime.strpt 35 | datetime.strptime("something", "something") | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ DTZ007 | - = help: Call `.replace(tzinfo=)` or `.astimezone()` to convert to an aware datetime + = help: Call `.replace(tzinfo=)` or `.astimezone()` to convert to an aware datetime diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ011_DTZ011.py.snap b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ011_DTZ011.py.snap index dee4d02ab4c1c..2a19a7162f01b 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ011_DTZ011.py.snap +++ b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ011_DTZ011.py.snap @@ -9,7 +9,7 @@ DTZ011.py:4:1: DTZ011 `datetime.date.today()` used 5 | 6 | from datetime import date | - = help: Use `datetime.datetime.now(tz=).date()` instead + = help: Use `datetime.datetime.now(tz=...).date()` instead DTZ011.py:9:1: DTZ011 `datetime.date.today()` used | @@ -17,4 +17,4 @@ DTZ011.py:9:1: DTZ011 `datetime.date.today()` used 9 | date.today() | ^^^^^^^^^^^^ DTZ011 | - = help: Use `datetime.datetime.now(tz=).date()` instead + = help: Use `datetime.datetime.now(tz=...).date()` instead diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ012_DTZ012.py.snap b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ012_DTZ012.py.snap index e7784fcc66631..fe0bffe0f4d3c 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ012_DTZ012.py.snap +++ b/crates/ruff_linter/src/rules/flake8_datetimez/snapshots/ruff_linter__rules__flake8_datetimez__tests__DTZ012_DTZ012.py.snap @@ -9,7 +9,7 @@ DTZ012.py:4:1: DTZ012 `datetime.date.fromtimestamp()` used 5 | 6 | from datetime import date | - = help: Use `datetime.datetime.fromtimestamp(ts, tz=).date()` instead + = help: Use `datetime.datetime.fromtimestamp(ts, tz=...).date()` instead DTZ012.py:9:1: DTZ012 `datetime.date.fromtimestamp()` used | @@ -17,4 +17,4 @@ DTZ012.py:9:1: DTZ012 `datetime.date.fromtimestamp()` used 9 | date.fromtimestamp(1234) | ^^^^^^^^^^^^^^^^^^^^^^^^ DTZ012 | - = help: Use `datetime.datetime.fromtimestamp(ts, tz=).date()` instead + = help: Use `datetime.datetime.fromtimestamp(ts, tz=...).date()` instead