DTZ rules: Clarify error messages and docs (#10621)

- Clearly state in the documentation that passing `tz=None` is just as bad as not passing a `tz=` argument, from the perspective of these rules.
- Clearly state in the error messages exactly what the user is doing wrong, if the user is passing `tz=None` rather than failing to pass a `tz=` argument at all.
- Make error messages more concise, and separate out the suggested remedy from the thing that the user is identified as doing wrong.

Co-authored-by: Christian Clauss <cclauss@me.com>
This commit is contained in:
Alex Waygood 2024-03-27 19:42:13 +00:00 committed by GitHub
parent f9d0c6d9ae
commit abbefae6f1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 255 additions and 219 deletions

View file

@ -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
@ -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<String> {
Some("Use `datetime.datetime.fromtimestamp(ts, tz=...).date()` instead".to_string())
}
}

View file

@ -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
@ -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<String> {
Some("Use `datetime.datetime.now(tz=...).date()` instead".to_string())
}
}

View file

@ -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,9 +19,10 @@ 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
/// timezone-aware object.
/// `datetime.datetime.fromtimestamp(ts)` or
/// `datetime.datetime.fromtimestampe(ts, tz=None)` returns a naive datetime
/// object. Instead, use `datetime.datetime.fromtimestamp(ts, tz=<timezone>)`
/// to create a timezone-aware object.
///
/// ## Example
/// ```python
@ -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,24 @@ 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!("`datetime.datetime.fromtimestamp()` called without a `tz` argument")
}
DatetimeModuleAntipattern::NonePassedToTzArgument => {
format!("`tz=None` passed to `datetime.datetime.fromtimestamp()`")
}
}
}
fn fix_title(&self) -> Option<String> {
Some("Pass a `datetime.timezone` object to the `tz` parameter".to_string())
}
}
@ -82,26 +91,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;
}
let antipattern = match call.arguments.find_argument("tz", 1) {
Some(ast::Expr::NoneLiteral(_)) => DatetimeModuleAntipattern::NonePassedToTzArgument,
Some(_) => return,
None => DatetimeModuleAntipattern::NoTzArgumentPassed,
};
// 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;
}
// 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,
));
}

View file

@ -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 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 +18,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=<timezone>)` to create
/// a timezone-aware object.
///
/// ## Example
/// ```python
@ -47,12 +46,24 @@ 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!("The use of `datetime.datetime.now()` without `tz` argument is not allowed")
let CallDatetimeNowWithoutTzinfo(antipattern) = self;
match antipattern {
DatetimeModuleAntipattern::NoTzArgumentPassed => {
format!("`datetime.datetime.now()` called without a `tz` argument")
}
DatetimeModuleAntipattern::NonePassedToTzArgument => {
format!("`tz=None` passed to `datetime.datetime.now()`")
}
}
}
fn fix_title(&self) -> Option<String> {
Some("Pass a `datetime.timezone` object to the `tz` parameter".to_string())
}
}
@ -75,31 +86,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,
));
}

View file

@ -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
@ -19,7 +19,7 @@ use crate::rules::flake8_datetimez::rules::helpers::has_non_none_keyword;
/// 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=<timezone>)` or `.astimezone()`.
///
/// ## Example
/// ```python
@ -28,7 +28,7 @@ use crate::rules::flake8_datetimez::rules::helpers::has_non_none_keyword;
/// datetime.datetime.strptime("2022/01/31", "%Y/%m/%d")
/// ```
///
/// Instead, use `.replace(tzinfo=)`:
/// Instead, use `.replace(tzinfo=<timezone>)`:
/// ```python
/// import datetime
///
@ -51,15 +51,34 @@ 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!(
"Naive datetime constructed using `datetime.datetime.strptime()` without %z"
),
DatetimeModuleAntipattern::NonePassedToTzArgument => {
format!("`datetime.datetime.strptime(...).replace(tz=None)` used")
}
}
}
fn fix_title(&self) -> Option<String> {
let CallDatetimeStrptimeWithoutZone(antipattern) = self;
match antipattern {
DatetimeModuleAntipattern::NoTzArgumentPassed => Some(
"Call `.replace(tzinfo=<timezone>)` or `.astimezone()` \
to convert to an aware datetime"
.to_string(),
),
DatetimeModuleAntipattern::NonePassedToTzArgument => {
Some("Pass a `datetime.timezone` object to the `tzinfo` parameter".to_string())
}
}
}
}
@ -91,36 +110,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<DatetimeModuleAntipattern> {
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(tzinfo=None)`
Some(ast::Keyword {
value: Expr::NoneLiteral(_),
..
}) => Some(DatetimeModuleAntipattern::NonePassedToTzArgument),
// Ex) `datetime.strptime(...).replace(tzinfo=...)`
Some(_) => None,
// Ex) `datetime.strptime(...).replace(...)` with no `tzinfo` argument
None => Some(DatetimeModuleAntipattern::NoTzArgumentPassed),
}
}

View file

@ -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
@ -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<String> {
Some("Use `datetime.datetime.now(tz=...)` instead".to_string())
}
}

View file

@ -19,15 +19,15 @@ 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
/// 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
/// import datetime
///
/// datetime.datetime.utcfromtimestamp()
/// datetime.datetime.utcfromtimestamp(946684800)
/// ```
///
/// Use instead:
@ -37,7 +37,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
///
@ -52,10 +52,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<String> {
Some("Use `datetime.datetime.fromtimestamp(ts, tz=...)` instead".to_string())
}
}

View file

@ -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
@ -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<String> {
Some("Use `datetime.datetime.now(tz=...)` instead".to_string())
}
}

View file

@ -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,31 @@ 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!("`datetime.datetime()` called without a `tzinfo` argument")
}
DatetimeModuleAntipattern::NonePassedToTzArgument => {
format!("`tzinfo=None` passed to `datetime.datetime()`")
}
}
}
fn fix_title(&self) -> Option<String> {
Some("Pass a `datetime.timezone` object to the `tzinfo` parameter".to_string())
}
}
@ -69,23 +80,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,
));
}

View file

@ -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())
}

View file

@ -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 The use of `datetime.datetime()` without `tzinfo` argument is not allowed
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 The use of `datetime.datetime()` without `tzinfo` argument
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 The use of `datetime.datetime()` without `tzinfo` argument is not allowed
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 The use of `datetime.datetime()` without `tzinfo` argumen
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,5 +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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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 `datetime.datetime.now()` called without a `tz` argument
|
3 | # no args
4 | datetime.datetime.now()
@ -9,8 +9,9 @@ DTZ005.py:4:1: DTZ005 The use of `datetime.datetime.now()` without `tz` argument
5 |
6 | # wrong keywords
|
= help: Pass a `datetime.timezone` object to the `tz` parameter
DTZ005.py:7:1: DTZ005 The use of `datetime.datetime.now()` without `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 The use of `datetime.datetime.now()` without `tz` argument
8 |
9 | # none args
|
= help: Pass a `datetime.timezone` object to the `tz` parameter
DTZ005.py:10:1: DTZ005 The use of `datetime.datetime.now()` without `tz` argument 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 The use of `datetime.datetime.now()` without `tz` argumen
11 |
12 | # none keywords
|
= help: Pass a `datetime.timezone` object to the `tz` parameter
DTZ005.py:13:1: DTZ005 The use of `datetime.datetime.now()` without `tz` argument 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 The use of `datetime.datetime.now()` without `tz` argumen
14 |
15 | from datetime import datetime
|
= help: Pass a `datetime.timezone` object to the `tz` parameter
DTZ005.py:18:1: DTZ005 The use of `datetime.datetime.now()` without `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,5 +49,4 @@ DTZ005.py:18:1: DTZ005 The use of `datetime.datetime.now()` without `tz` argumen
19 |
20 | # uses `astimezone` method
|
= help: Pass a `datetime.timezone` object to the `tz` parameter

View file

@ -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 The use of `datetime.datetime.fromtimestamp()` without `tz` argument is not allowed
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 The use of `datetime.datetime.fromtimestamp()` without `t
11 |
12 | # none keywords
|
= help: Pass a `datetime.timezone` object to the `tz` parameter
DTZ006.py:13:1: DTZ006 The use of `datetime.datetime.fromtimestamp()` without `tz` argument is not allowed
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 The use of `datetime.datetime.fromtimestamp()` without `t
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,5 +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

View file

@ -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=<timezone>)` 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=<timezone>)` 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=<timezone>)` or `.astimezone()` to convert to an aware datetime
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 `datetime.datetime.strptime(...).replace(tz=None)` used
|
12 | # none replace
13 | datetime.datetime.strptime("something", "something").replace(tzinfo=None)
@ -36,12 +39,12 @@ DTZ007.py:13:1: DTZ007 The use of `datetime.datetime.strptime()` without %z must
14 |
15 | # OK
|
= help: Pass a `datetime.timezone` object to the `tzinfo` parameter
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=<timezone>)` or `.astimezone()` to convert to an aware datetime

View file

@ -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

View file

@ -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