mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-01 14:21:24 +00:00
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:
parent
f9d0c6d9ae
commit
abbefae6f1
19 changed files with 255 additions and 219 deletions
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
));
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
));
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
));
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue