[DTZ] Improve docs for call-datetime-without-tzinfo (DTZ005)#10590
[DTZ] Improve docs for call-datetime-without-tzinfo (DTZ005)#10590cclauss wants to merge 4 commits intoastral-sh:mainfrom
DTZ] Improve docs for call-datetime-without-tzinfo (DTZ005)#10590Conversation
|
| code | total | + violation | - violation | + fix | - fix |
|---|---|---|---|---|---|
| DTZ005 | 218 | 109 | 109 | 0 | 0 |
Linter (preview)
ℹ️ ecosystem check detected linter changes. (+109 -109 violations, +0 -0 fixes in 2 projects; 42 projects unchanged)
apache/airflow (+100 -100 violations, +0 -0 fixes)
ruff check --no-cache --exit-zero --ignore RUF9 --output-format concise --preview --select ALL
- airflow/providers/amazon/aws/hooks/s3.py:699:34: DTZ005 The use of `datetime.datetime.now()` without `tz` argument is not allowed + airflow/providers/amazon/aws/hooks/s3.py:699:34: DTZ005 Using `datetime.datetime.now()` without specifying a timezone is not allowed - airflow/providers/amazon/aws/hooks/s3.py:714:38: DTZ005 The use of `datetime.datetime.now()` without `tz` argument is not allowed + airflow/providers/amazon/aws/hooks/s3.py:714:38: DTZ005 Using `datetime.datetime.now()` without specifying a timezone is not allowed - airflow/providers/amazon/aws/hooks/s3.py:738:34: DTZ005 The use of `datetime.datetime.now()` without `tz` argument is not allowed + airflow/providers/amazon/aws/hooks/s3.py:738:34: DTZ005 Using `datetime.datetime.now()` without specifying a timezone is not allowed - airflow/providers/amazon/aws/sensors/s3.py:291:39: DTZ005 The use of `datetime.datetime.now()` without `tz` argument is not allowed + airflow/providers/amazon/aws/sensors/s3.py:291:39: DTZ005 Using `datetime.datetime.now()` without specifying a timezone is not allowed - airflow/providers/amazon/aws/sensors/s3.py:301:43: DTZ005 The use of `datetime.datetime.now()` without `tz` argument is not allowed + airflow/providers/amazon/aws/sensors/s3.py:301:43: DTZ005 Using `datetime.datetime.now()` without specifying a timezone is not allowed - airflow/providers/amazon/aws/sensors/s3.py:319:44: DTZ005 The use of `datetime.datetime.now()` without `tz` argument is not allowed + airflow/providers/amazon/aws/sensors/s3.py:319:44: DTZ005 Using `datetime.datetime.now()` without specifying a timezone is not allowed - airflow/providers/amazon/aws/sensors/s3.py:322:39: DTZ005 The use of `datetime.datetime.now()` without `tz` argument is not allowed + airflow/providers/amazon/aws/sensors/s3.py:322:39: DTZ005 Using `datetime.datetime.now()` without specifying a timezone is not allowed - airflow/providers/cncf/kubernetes/operators/custom_object_launcher.py:300:25: DTZ005 The use of `datetime.datetime.now()` without `tz` argument is not allowed + airflow/providers/cncf/kubernetes/operators/custom_object_launcher.py:300:25: DTZ005 Using `datetime.datetime.now()` without specifying a timezone is not allowed - airflow/providers/cncf/kubernetes/operators/custom_object_launcher.py:307:25: DTZ005 The use of `datetime.datetime.now()` without `tz` argument is not allowed + airflow/providers/cncf/kubernetes/operators/custom_object_launcher.py:307:25: DTZ005 Using `datetime.datetime.now()` without specifying a timezone is not allowed - airflow/providers/fab/auth_manager/security_manager/override.py:1641:31: DTZ005 The use of `datetime.datetime.now()` without `tz` argument is not allowed + airflow/providers/fab/auth_manager/security_manager/override.py:1641:31: DTZ005 Using `datetime.datetime.now()` without specifying a timezone is not allowed - airflow/providers/google/cloud/hooks/bigquery.py:1554:14: DTZ005 The use of `datetime.datetime.now()` without `tz` argument is not allowed + airflow/providers/google/cloud/hooks/bigquery.py:1554:14: DTZ005 Using `datetime.datetime.now()` without specifying a timezone is not allowed - airflow/providers/google/cloud/sensors/gcs.py:383:12: DTZ005 The use of `datetime.datetime.now()` without `tz` argument is not allowed + airflow/providers/google/cloud/sensors/gcs.py:383:12: DTZ005 Using `datetime.datetime.now()` without specifying a timezone is not allowed - airflow/providers/google/cloud/triggers/gcs.py:385:16: DTZ005 The use of `datetime.datetime.now()` without `tz` argument is not allowed + airflow/providers/google/cloud/triggers/gcs.py:385:16: DTZ005 Using `datetime.datetime.now()` without specifying a timezone is not allowed - airflow/providers/openlineage/plugins/listener.py:110:84: DTZ005 The use of `datetime.datetime.now()` without `tz` argument is not allowed + airflow/providers/openlineage/plugins/listener.py:110:84: DTZ005 Using `datetime.datetime.now()` without specifying a timezone is not allowed - airflow/providers/openlineage/plugins/listener.py:178:78: DTZ005 The use of `datetime.datetime.now()` without `tz` argument is not allowed + airflow/providers/openlineage/plugins/listener.py:178:78: DTZ005 Using `datetime.datetime.now()` without specifying a timezone is not allowed - airflow/providers/openlineage/plugins/listener.py:233:78: DTZ005 The use of `datetime.datetime.now()` without `tz` argument is not allowed + airflow/providers/openlineage/plugins/listener.py:233:78: DTZ005 Using `datetime.datetime.now()` without specifying a timezone is not allowed - airflow/timetables/interval.py:215:15: DTZ005 The use of `datetime.datetime.now()` without `tz` argument is not allowed + airflow/timetables/interval.py:215:15: DTZ005 Using `datetime.datetime.now()` without specifying a timezone is not allowed - dev/breeze/src/airflow_breeze/commands/release_management_commands.py:2036:96: DTZ005 The use of `datetime.datetime.now()` without `tz` argument is not allowed + dev/breeze/src/airflow_breeze/commands/release_management_commands.py:2036:96: DTZ005 Using `datetime.datetime.now()` without specifying a timezone is not allowed - dev/breeze/src/airflow_breeze/commands/release_management_commands.py:2046:28: DTZ005 The use of `datetime.datetime.now()` without `tz` argument is not allowed + dev/breeze/src/airflow_breeze/commands/release_management_commands.py:2046:28: DTZ005 Using `datetime.datetime.now()` without specifying a timezone is not allowed - dev/breeze/src/airflow_breeze/commands/release_management_commands.py:2058:72: DTZ005 The use of `datetime.datetime.now()` without `tz` argument is not allowed + dev/breeze/src/airflow_breeze/commands/release_management_commands.py:2058:72: DTZ005 Using `datetime.datetime.now()` without specifying a timezone is not allowed - dev/breeze/src/airflow_breeze/commands/testing_commands.py:223:24: DTZ005 The use of `datetime.datetime.now()` without `tz` argument is not allowed + dev/breeze/src/airflow_breeze/commands/testing_commands.py:223:24: DTZ005 Using `datetime.datetime.now()` without specifying a timezone is not allowed - dev/breeze/src/airflow_breeze/params/common_build_params.py:131:15: DTZ005 The use of `datetime.datetime.now()` without `tz` argument is not allowed + dev/breeze/src/airflow_breeze/params/common_build_params.py:131:15: DTZ005 Using `datetime.datetime.now()` without specifying a timezone is not allowed - dev/perf/dags/elastic_dag.py:155:14: DTZ005 The use of `datetime.datetime.now()` without `tz` argument is not allowed ... 155 additional changes omitted for project
bokeh/bokeh (+9 -9 violations, +0 -0 fixes)
ruff check --no-cache --exit-zero --ignore RUF9 --output-format concise --preview --select ALL
- docs/bokeh/source/docs/first_steps/examples/first_steps_4_datetime_axis.py:8:11: DTZ005 The use of `datetime.datetime.now()` without `tz` argument is not allowed + docs/bokeh/source/docs/first_steps/examples/first_steps_4_datetime_axis.py:8:11: DTZ005 Using `datetime.datetime.now()` without specifying a timezone is not allowed - examples/basic/data/server_sent_events_source.py:55:17: DTZ005 The use of `datetime.datetime.now()` without `tz` argument is not allowed + examples/basic/data/server_sent_events_source.py:55:17: DTZ005 Using `datetime.datetime.now()` without specifying a timezone is not allowed - examples/server/app/faces/main.py:53:6: DTZ005 The use of `datetime.datetime.now()` without `tz` argument is not allowed + examples/server/app/faces/main.py:53:6: DTZ005 Using `datetime.datetime.now()` without specifying a timezone is not allowed - examples/server/app/faces/main.py:82:16: DTZ005 The use of `datetime.datetime.now()` without `tz` argument is not allowed + examples/server/app/faces/main.py:82:16: DTZ005 Using `datetime.datetime.now()` without specifying a timezone is not allowed - src/bokeh/events.py:242:26: DTZ005 The use of `datetime.datetime.now()` without `tz` argument is not allowed + src/bokeh/events.py:242:26: DTZ005 Using `datetime.datetime.now()` without specifying a timezone is not allowed ... 8 additional changes omitted for project
Changes by rule (1 rules affected)
| code | total | + violation | - violation | + fix | - fix |
|---|---|---|---|---|---|
| DTZ005 | 218 | 109 | 109 | 0 | 0 |
DTZ] Update call_datetime_now_without_tzinfo.rs DTZ005
|
Hmm, I'm not sure about just adding a paragraph at the bottom. Possibly you could argue that the first sentence of the documentation for this rule is wrong:
In reality, it does more than that, since it also emits an error if you explicitly pass
Then we could explain in the body of the rule's documentation why |
AlexWaygood
left a comment
There was a problem hiding this comment.
Looks good! Could you also change the error message? It's currently
"The use of
datetime.datetime.now()withouttzargument is not allowed"
It should be
"Using
datetime.datetime.now()without specifying a timezone is not allowed"
DTZ] Update call_datetime_now_without_tzinfo.rs DTZ005DTZ] Improve docs for call-datetime-without-tzinfo (DTZ005)
|
We have lost this helpful hint from the original commit...
|
Right. I think that could be worked into the docs somewhere; I agree that it's useful. I'm also wondering if we could tailor the error message to the specific thing that the user is doing wrong. Something like this? --- 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,3 +1,5 @@
+use std::fmt;
+
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
@@ -6,7 +8,6 @@ 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;
@@ -48,12 +49,28 @@ 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(DatetimeNowAntipattern);
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;
+ format!("{antipattern} is not allowed")
+ }
+}
+
+#[derive(Debug, Clone, Copy, Eq, PartialEq)]
+enum DatetimeNowAntipattern {
+ NoTzArgumentPassed,
+ NonePassedToTzArgument,
+}
+
+impl fmt::Display for DatetimeNowAntipattern {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str(match self {
+ Self::NoTzArgumentPassed => "Using `datetime.datetime.now()` without a `tz=` argument",
+ Self::NonePassedToTzArgument => "Passing `tz=None` to `datetime.datetime.now()`",
+ })
}
}
@@ -78,9 +95,10 @@ pub(crate) fn call_datetime_now_without_tzinfo(checker: &mut Checker, call: &ast
// no args / no args unqualified
if call.arguments.args.is_empty() && call.arguments.keywords.is_empty() {
- checker
- .diagnostics
- .push(Diagnostic::new(CallDatetimeNowWithoutTzinfo, call.range()));
+ checker.diagnostics.push(Diagnostic::new(
+ CallDatetimeNowWithoutTzinfo(DatetimeNowAntipattern::NoTzArgumentPassed),
+ call.range(),
+ ));
return;
}
@@ -91,16 +109,24 @@ pub(crate) fn call_datetime_now_without_tzinfo(checker: &mut Checker, call: &ast
.first()
.is_some_and(Expr::is_none_literal_expr)
{
- checker
- .diagnostics
- .push(Diagnostic::new(CallDatetimeNowWithoutTzinfo, call.range()));
+ checker.diagnostics.push(Diagnostic::new(
+ CallDatetimeNowWithoutTzinfo(DatetimeNowAntipattern::NonePassedToTzArgument),
+ 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()));
+ if let Some(keyword_argument) = call.arguments.find_keyword("tz") {
+ if keyword_argument.value.is_none_literal_expr() {
+ checker.diagnostics.push(Diagnostic::new(
+ CallDatetimeNowWithoutTzinfo(DatetimeNowAntipattern::NonePassedToTzArgument),
+ call.range(),
+ ));
+ }
+ } else {
+ checker.diagnostics.push(Diagnostic::new(
+ CallDatetimeNowWithoutTzinfo(DatetimeNowAntipattern::NoTzArgumentPassed),
+ call.range(),
+ ));
}
}
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 2f24cc4dc..d79264aad 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()(I'm happy to push that straight to your branch if you like it, since I've already tried it out locally!) |
|
I'm gonna defer to Alex on the actual copy, but I'll note that similar changes may need to be applied to the other DTZ rules which enforce the ~same thing. |
Fixes #10251
tz=None#10251Summary
Test Plan