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.
|
/// always use timezone-aware objects.
|
||||||
///
|
///
|
||||||
/// `datetime.date.fromtimestamp(ts)` returns a naive datetime object.
|
/// `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.
|
/// timezone-aware object.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
|
@ -50,10 +50,11 @@ pub struct CallDateFromtimestamp;
|
||||||
impl Violation for CallDateFromtimestamp {
|
impl Violation for CallDateFromtimestamp {
|
||||||
#[derive_message_formats]
|
#[derive_message_formats]
|
||||||
fn message(&self) -> String {
|
fn message(&self) -> String {
|
||||||
format!(
|
format!("`datetime.date.fromtimestamp()` used")
|
||||||
"The use of `datetime.date.fromtimestamp()` is not allowed, use \
|
}
|
||||||
`datetime.datetime.fromtimestamp(ts, tz=).date()` instead"
|
|
||||||
)
|
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.
|
/// always use timezone-aware objects.
|
||||||
///
|
///
|
||||||
/// `datetime.date.today` returns a naive datetime object. Instead, use
|
/// `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
|
/// ## Example
|
||||||
/// ```python
|
/// ```python
|
||||||
|
@ -49,10 +49,11 @@ pub struct CallDateToday;
|
||||||
impl Violation for CallDateToday {
|
impl Violation for CallDateToday {
|
||||||
#[derive_message_formats]
|
#[derive_message_formats]
|
||||||
fn message(&self) -> String {
|
fn message(&self) -> String {
|
||||||
format!(
|
format!("`datetime.date.today()` used")
|
||||||
"The use of `datetime.date.today()` is not allowed, use \
|
}
|
||||||
`datetime.datetime.now(tz=).date()` instead"
|
|
||||||
)
|
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_ast::{self as ast};
|
||||||
use ruff_python_semantic::Modules;
|
use ruff_python_semantic::Modules;
|
||||||
use ruff_text_size::Ranged;
|
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
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
|
/// ## What it does
|
||||||
/// Checks for usage of `datetime.datetime.fromtimestamp()` without a `tz`
|
/// Checks for usage of `datetime.datetime.fromtimestamp()` that do not specify
|
||||||
/// argument.
|
/// a timezone.
|
||||||
///
|
///
|
||||||
/// ## Why is this bad?
|
/// ## Why is this bad?
|
||||||
/// Python datetime objects can be naive or timezone-aware. While an aware
|
/// 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
|
/// datetime objects. Since this can lead to errors, it is recommended to
|
||||||
/// always use timezone-aware objects.
|
/// always use timezone-aware objects.
|
||||||
///
|
///
|
||||||
/// `datetime.datetime.fromtimestamp(ts)` returns a naive datetime object.
|
/// `datetime.datetime.fromtimestamp(ts)` or
|
||||||
/// Instead, use `datetime.datetime.fromtimestamp(ts, tz=)` to return a
|
/// `datetime.datetime.fromtimestampe(ts, tz=None)` returns a naive datetime
|
||||||
/// timezone-aware object.
|
/// object. Instead, use `datetime.datetime.fromtimestamp(ts, tz=<timezone>)`
|
||||||
|
/// to create a timezone-aware object.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
/// ```python
|
/// ```python
|
||||||
|
@ -39,7 +38,7 @@ use super::helpers;
|
||||||
/// datetime.datetime.fromtimestamp(946684800, tz=datetime.timezone.utc)
|
/// datetime.datetime.fromtimestamp(946684800, tz=datetime.timezone.utc)
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// Or, for Python 3.11 and later:
|
/// Or, on Python 3.11 and later:
|
||||||
/// ```python
|
/// ```python
|
||||||
/// import datetime
|
/// import datetime
|
||||||
///
|
///
|
||||||
|
@ -49,14 +48,24 @@ use super::helpers;
|
||||||
/// ## References
|
/// ## References
|
||||||
/// - [Python documentation: Aware and Naive Objects](https://docs.python.org/3/library/datetime.html#aware-and-naive-objects)
|
/// - [Python documentation: Aware and Naive Objects](https://docs.python.org/3/library/datetime.html#aware-and-naive-objects)
|
||||||
#[violation]
|
#[violation]
|
||||||
pub struct CallDatetimeFromtimestamp;
|
pub struct CallDatetimeFromtimestamp(DatetimeModuleAntipattern);
|
||||||
|
|
||||||
impl Violation for CallDatetimeFromtimestamp {
|
impl Violation for CallDatetimeFromtimestamp {
|
||||||
#[derive_message_formats]
|
#[derive_message_formats]
|
||||||
fn message(&self) -> String {
|
fn message(&self) -> String {
|
||||||
format!(
|
let CallDatetimeFromtimestamp(antipattern) = self;
|
||||||
"The use of `datetime.datetime.fromtimestamp()` without `tz` argument is not allowed"
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// no args / no args unqualified
|
let antipattern = match call.arguments.find_argument("tz", 1) {
|
||||||
if call.arguments.args.len() < 2 && call.arguments.keywords.is_empty() {
|
Some(ast::Expr::NoneLiteral(_)) => DatetimeModuleAntipattern::NonePassedToTzArgument,
|
||||||
checker
|
Some(_) => return,
|
||||||
.diagnostics
|
None => DatetimeModuleAntipattern::NoTzArgumentPassed,
|
||||||
.push(Diagnostic::new(CallDatetimeFromtimestamp, call.range()));
|
};
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// none args
|
checker.diagnostics.push(Diagnostic::new(
|
||||||
if call.arguments.args.len() > 1 && call.arguments.args[1].is_none_literal_expr() {
|
CallDatetimeFromtimestamp(antipattern),
|
||||||
checker
|
call.range,
|
||||||
.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()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,15 @@
|
||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, 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_python_semantic::Modules;
|
||||||
use ruff_text_size::Ranged;
|
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
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
|
/// ## 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?
|
/// ## Why is this bad?
|
||||||
/// Python datetime objects can be naive or timezone-aware. While an aware
|
/// 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
|
/// datetime objects. Since this can lead to errors, it is recommended to
|
||||||
/// always use timezone-aware objects.
|
/// always use timezone-aware objects.
|
||||||
///
|
///
|
||||||
/// `datetime.datetime.now()` returns a naive datetime object. Instead, use
|
/// `datetime.datetime.now()` or `datetime.datetime.now(tz=None)` returns a naive
|
||||||
/// `datetime.datetime.now(tz=)` to return a timezone-aware object.
|
/// datetime object. Instead, use `datetime.datetime.now(tz=<timezone>)` to create
|
||||||
|
/// a timezone-aware object.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
/// ```python
|
/// ```python
|
||||||
|
@ -47,12 +46,24 @@ use super::helpers;
|
||||||
/// ## References
|
/// ## References
|
||||||
/// - [Python documentation: Aware and Naive Objects](https://docs.python.org/3/library/datetime.html#aware-and-naive-objects)
|
/// - [Python documentation: Aware and Naive Objects](https://docs.python.org/3/library/datetime.html#aware-and-naive-objects)
|
||||||
#[violation]
|
#[violation]
|
||||||
pub struct CallDatetimeNowWithoutTzinfo;
|
pub struct CallDatetimeNowWithoutTzinfo(DatetimeModuleAntipattern);
|
||||||
|
|
||||||
impl Violation for CallDatetimeNowWithoutTzinfo {
|
impl Violation for CallDatetimeNowWithoutTzinfo {
|
||||||
#[derive_message_formats]
|
#[derive_message_formats]
|
||||||
fn message(&self) -> String {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// no args / no args unqualified
|
let antipattern = match call.arguments.find_argument("tz", 0) {
|
||||||
if call.arguments.args.is_empty() && call.arguments.keywords.is_empty() {
|
Some(ast::Expr::NoneLiteral(_)) => DatetimeModuleAntipattern::NonePassedToTzArgument,
|
||||||
checker
|
Some(_) => return,
|
||||||
.diagnostics
|
None => DatetimeModuleAntipattern::NoTzArgumentPassed,
|
||||||
.push(Diagnostic::new(CallDatetimeNowWithoutTzinfo, call.range()));
|
};
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// none args
|
checker.diagnostics.push(Diagnostic::new(
|
||||||
if call
|
CallDatetimeNowWithoutTzinfo(antipattern),
|
||||||
.arguments
|
call.range,
|
||||||
.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()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,10 @@ use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
use ruff_python_ast::{self as ast, Expr};
|
use ruff_python_ast::{self as ast, Expr};
|
||||||
use ruff_python_semantic::Modules;
|
use ruff_python_semantic::Modules;
|
||||||
use ruff_text_size::Ranged;
|
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::rules::flake8_datetimez::rules::helpers::has_non_none_keyword;
|
|
||||||
|
use super::helpers::DatetimeModuleAntipattern;
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for uses of `datetime.datetime.strptime()` that lead to naive
|
/// 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.
|
/// always use timezone-aware objects.
|
||||||
///
|
///
|
||||||
/// `datetime.datetime.strptime()` without `%z` returns a naive datetime
|
/// `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
|
/// ## Example
|
||||||
/// ```python
|
/// ```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")
|
/// datetime.datetime.strptime("2022/01/31", "%Y/%m/%d")
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// Instead, use `.replace(tzinfo=)`:
|
/// Instead, use `.replace(tzinfo=<timezone>)`:
|
||||||
/// ```python
|
/// ```python
|
||||||
/// import datetime
|
/// 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: 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)
|
/// - [Python documentation: `strftime()` and `strptime()` Behavior](https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior)
|
||||||
#[violation]
|
#[violation]
|
||||||
pub struct CallDatetimeStrptimeWithoutZone;
|
pub struct CallDatetimeStrptimeWithoutZone(DatetimeModuleAntipattern);
|
||||||
|
|
||||||
impl Violation for CallDatetimeStrptimeWithoutZone {
|
impl Violation for CallDatetimeStrptimeWithoutZone {
|
||||||
#[derive_message_formats]
|
#[derive_message_formats]
|
||||||
fn message(&self) -> String {
|
fn message(&self) -> String {
|
||||||
format!(
|
let CallDatetimeStrptimeWithoutZone(antipattern) = self;
|
||||||
"The use of `datetime.datetime.strptime()` without %z must be followed by \
|
match antipattern {
|
||||||
`.replace(tzinfo=)` or `.astimezone()`"
|
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)) = (
|
let semantic = checker.semantic();
|
||||||
checker.semantic().current_expression_grandparent(),
|
if let Some(antipattern) = find_antipattern(
|
||||||
checker.semantic().current_expression_parent(),
|
semantic.current_expression_grandparent(),
|
||||||
) else {
|
semantic.current_expression_parent(),
|
||||||
|
) {
|
||||||
checker.diagnostics.push(Diagnostic::new(
|
checker.diagnostics.push(Diagnostic::new(
|
||||||
CallDatetimeStrptimeWithoutZone,
|
CallDatetimeStrptimeWithoutZone(antipattern),
|
||||||
call.range(),
|
call.range,
|
||||||
));
|
));
|
||||||
return;
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
if let Expr::Call(ast::ExprCall { arguments, .. }) = grandparent {
|
fn find_antipattern(
|
||||||
if let Expr::Attribute(ast::ExprAttribute { attr, .. }) = parent {
|
grandparent: Option<&Expr>,
|
||||||
let attr = attr.as_str();
|
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()`
|
// Ex) `datetime.strptime(...).astimezone()`
|
||||||
if attr == "astimezone" {
|
if attr == "astimezone" {
|
||||||
return;
|
return None;
|
||||||
}
|
}
|
||||||
|
if attr != "replace" {
|
||||||
// Ex) `datetime.strptime(...).replace(tzinfo=UTC)`
|
return Some(DatetimeModuleAntipattern::NoTzArgumentPassed);
|
||||||
if attr == "replace" {
|
|
||||||
if has_non_none_keyword(arguments, "tzinfo") {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
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),
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
checker.diagnostics.push(Diagnostic::new(
|
|
||||||
CallDatetimeStrptimeWithoutZone,
|
|
||||||
call.range(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ use super::helpers;
|
||||||
/// time, unlike "naive" objects.
|
/// time, unlike "naive" objects.
|
||||||
///
|
///
|
||||||
/// `datetime.datetime.today()` creates a "naive" object; instead, use
|
/// `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
|
/// ## Example
|
||||||
/// ```python
|
/// ```python
|
||||||
|
@ -48,10 +48,11 @@ pub struct CallDatetimeToday;
|
||||||
impl Violation for CallDatetimeToday {
|
impl Violation for CallDatetimeToday {
|
||||||
#[derive_message_formats]
|
#[derive_message_formats]
|
||||||
fn message(&self) -> String {
|
fn message(&self) -> String {
|
||||||
format!(
|
format!("`datetime.datetime.today()` used")
|
||||||
"The use of `datetime.datetime.today()` is not allowed, use \
|
}
|
||||||
`datetime.datetime.now(tz=)` instead"
|
|
||||||
)
|
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
|
/// datetime objects. Since this can lead to errors, it is recommended to
|
||||||
/// always use timezone-aware objects.
|
/// always use timezone-aware objects.
|
||||||
///
|
///
|
||||||
/// `datetime.datetime.utcfromtimestamp()` returns a naive datetime object;
|
/// `datetime.datetime.utcfromtimestamp()` returns a naive datetime
|
||||||
/// instead, use `datetime.datetime.fromtimestamp(ts, tz=)` to return a
|
/// object; instead, use `datetime.datetime.fromtimestamp(ts, tz=...)`
|
||||||
/// timezone-aware object.
|
/// to create a timezone-aware object.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
/// ```python
|
/// ```python
|
||||||
/// import datetime
|
/// import datetime
|
||||||
///
|
///
|
||||||
/// datetime.datetime.utcfromtimestamp()
|
/// datetime.datetime.utcfromtimestamp(946684800)
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// Use instead:
|
/// Use instead:
|
||||||
|
@ -37,7 +37,7 @@ use super::helpers;
|
||||||
/// datetime.datetime.fromtimestamp(946684800, tz=datetime.timezone.utc)
|
/// datetime.datetime.fromtimestamp(946684800, tz=datetime.timezone.utc)
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// Or, for Python 3.11 and later:
|
/// Or, on Python 3.11 and later:
|
||||||
/// ```python
|
/// ```python
|
||||||
/// import datetime
|
/// import datetime
|
||||||
///
|
///
|
||||||
|
@ -52,10 +52,11 @@ pub struct CallDatetimeUtcfromtimestamp;
|
||||||
impl Violation for CallDatetimeUtcfromtimestamp {
|
impl Violation for CallDatetimeUtcfromtimestamp {
|
||||||
#[derive_message_formats]
|
#[derive_message_formats]
|
||||||
fn message(&self) -> String {
|
fn message(&self) -> String {
|
||||||
format!(
|
format!("`datetime.datetime.utcfromtimestamp()` used")
|
||||||
"The use of `datetime.datetime.utcfromtimestamp()` is not allowed, use \
|
}
|
||||||
`datetime.datetime.fromtimestamp(ts, tz=)` instead"
|
|
||||||
)
|
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.
|
/// always use timezone-aware objects.
|
||||||
///
|
///
|
||||||
/// `datetime.datetime.utcnow()` returns a naive datetime object; instead, use
|
/// `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
|
/// ## Example
|
||||||
/// ```python
|
/// ```python
|
||||||
|
@ -51,10 +51,11 @@ pub struct CallDatetimeUtcnow;
|
||||||
impl Violation for CallDatetimeUtcnow {
|
impl Violation for CallDatetimeUtcnow {
|
||||||
#[derive_message_formats]
|
#[derive_message_formats]
|
||||||
fn message(&self) -> String {
|
fn message(&self) -> String {
|
||||||
format!(
|
format!("`datetime.datetime.utcnow()` used")
|
||||||
"The use of `datetime.datetime.utcnow()` is not allowed, use \
|
}
|
||||||
`datetime.datetime.now(tz=)` instead"
|
|
||||||
)
|
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_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, 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_python_semantic::Modules;
|
||||||
use ruff_text_size::Ranged;
|
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
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
|
/// ## 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?
|
/// ## Why is this bad?
|
||||||
/// `datetime` objects are "naive" by default, in that they do not include
|
/// `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
|
/// `datetime` objects are preferred, as they represent a specific moment in
|
||||||
/// time, unlike "naive" objects.
|
/// 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
|
/// ## Example
|
||||||
/// ```python
|
/// ```python
|
||||||
|
@ -36,19 +35,31 @@ use super::helpers;
|
||||||
/// datetime.datetime(2000, 1, 1, 0, 0, 0, tzinfo=datetime.timezone.utc)
|
/// 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
|
/// ```python
|
||||||
/// import datetime
|
/// import datetime
|
||||||
///
|
///
|
||||||
/// datetime.datetime(2000, 1, 1, 0, 0, 0, tzinfo=datetime.UTC)
|
/// datetime.datetime(2000, 1, 1, 0, 0, 0, tzinfo=datetime.UTC)
|
||||||
/// ```
|
/// ```
|
||||||
#[violation]
|
#[violation]
|
||||||
pub struct CallDatetimeWithoutTzinfo;
|
pub struct CallDatetimeWithoutTzinfo(DatetimeModuleAntipattern);
|
||||||
|
|
||||||
impl Violation for CallDatetimeWithoutTzinfo {
|
impl Violation for CallDatetimeWithoutTzinfo {
|
||||||
#[derive_message_formats]
|
#[derive_message_formats]
|
||||||
fn message(&self) -> String {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No positional arg: keyword is missing or constant None.
|
let antipattern = match call.arguments.find_argument("tzinfo", 7) {
|
||||||
if call.arguments.args.len() < 8 && !has_non_none_keyword(&call.arguments, "tzinfo") {
|
Some(ast::Expr::NoneLiteral(_)) => DatetimeModuleAntipattern::NonePassedToTzArgument,
|
||||||
checker
|
Some(_) => return,
|
||||||
.diagnostics
|
None => DatetimeModuleAntipattern::NoTzArgumentPassed,
|
||||||
.push(Diagnostic::new(CallDatetimeWithoutTzinfo, call.range()));
|
};
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Positional arg: is constant None.
|
checker.diagnostics.push(Diagnostic::new(
|
||||||
if call
|
CallDatetimeWithoutTzinfo(antipattern),
|
||||||
.arguments
|
call.range,
|
||||||
.args
|
));
|
||||||
.get(7)
|
|
||||||
.is_some_and(Expr::is_none_literal_expr)
|
|
||||||
{
|
|
||||||
checker
|
|
||||||
.diagnostics
|
|
||||||
.push(Diagnostic::new(CallDatetimeWithoutTzinfo, call.range()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,13 @@
|
||||||
use ruff_python_ast::{Arguments, Expr, ExprAttribute};
|
use ruff_python_ast::{Expr, ExprAttribute};
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
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
|
/// Check if the parent expression is a call to `astimezone`. This assumes that
|
||||||
/// the current expression is a `datetime.datetime` object.
|
/// the current expression is a `datetime.datetime` object.
|
||||||
pub(super) fn parent_expr_is_astimezone(checker: &Checker) -> bool {
|
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")
|
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
|
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
|
3 | # no args
|
||||||
4 | datetime.datetime(2000, 1, 1, 0, 0, 0)
|
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 |
|
5 |
|
||||||
6 | # none args
|
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
|
6 | # none args
|
||||||
7 | datetime.datetime(2000, 1, 1, 0, 0, 0, 0, None)
|
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 |
|
8 |
|
||||||
9 | # not none arg
|
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
|
12 | # no kwargs
|
||||||
13 | datetime.datetime(2000, 1, 1, fold=1)
|
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 |
|
14 |
|
||||||
15 | # none kwargs
|
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
|
15 | # none kwargs
|
||||||
16 | datetime.datetime(2000, 1, 1, tzinfo=None)
|
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 |
|
17 |
|
||||||
18 | from datetime import datetime
|
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
|
20 | # no args unqualified
|
||||||
21 | datetime(2000, 1, 1, 0, 0, 0)
|
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 |
|
22 |
|
||||||
23 | # uses `astimezone` method
|
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
|
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
|
3 | # qualified
|
||||||
4 | datetime.datetime.today()
|
4 | datetime.datetime.today()
|
||||||
|
@ -9,8 +9,9 @@ DTZ002.py:4:1: DTZ002 The use of `datetime.datetime.today()` is not allowed, use
|
||||||
5 |
|
5 |
|
||||||
6 | from datetime import datetime
|
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
|
8 | # unqualified
|
||||||
9 | datetime.today()
|
9 | datetime.today()
|
||||||
|
@ -18,5 +19,4 @@ DTZ002.py:9:1: DTZ002 The use of `datetime.datetime.today()` is not allowed, use
|
||||||
10 |
|
10 |
|
||||||
11 | # uses `astimezone` method
|
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
|
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
|
3 | # qualified
|
||||||
4 | datetime.datetime.utcnow()
|
4 | datetime.datetime.utcnow()
|
||||||
|
@ -9,8 +9,9 @@ DTZ003.py:4:1: DTZ003 The use of `datetime.datetime.utcnow()` is not allowed, us
|
||||||
5 |
|
5 |
|
||||||
6 | from datetime import datetime
|
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
|
8 | # unqualified
|
||||||
9 | datetime.utcnow()
|
9 | datetime.utcnow()
|
||||||
|
@ -18,5 +19,4 @@ DTZ003.py:9:1: DTZ003 The use of `datetime.datetime.utcnow()` is not allowed, us
|
||||||
10 |
|
10 |
|
||||||
11 | # uses `astimezone` method
|
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
|
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
|
3 | # qualified
|
||||||
4 | datetime.datetime.utcfromtimestamp(1234)
|
4 | datetime.datetime.utcfromtimestamp(1234)
|
||||||
|
@ -9,8 +9,9 @@ DTZ004.py:4:1: DTZ004 The use of `datetime.datetime.utcfromtimestamp()` is not a
|
||||||
5 |
|
5 |
|
||||||
6 | from datetime import datetime
|
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
|
8 | # unqualified
|
||||||
9 | datetime.utcfromtimestamp(1234)
|
9 | datetime.utcfromtimestamp(1234)
|
||||||
|
@ -18,5 +19,4 @@ DTZ004.py:9:1: DTZ004 The use of `datetime.datetime.utcfromtimestamp()` is not a
|
||||||
10 |
|
10 |
|
||||||
11 | # uses `astimezone` method
|
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
|
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
|
3 | # no args
|
||||||
4 | datetime.datetime.now()
|
4 | datetime.datetime.now()
|
||||||
|
@ -9,8 +9,9 @@ DTZ005.py:4:1: DTZ005 The use of `datetime.datetime.now()` without `tz` argument
|
||||||
5 |
|
5 |
|
||||||
6 | # wrong keywords
|
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
|
6 | # wrong keywords
|
||||||
7 | datetime.datetime.now(bad=datetime.timezone.utc)
|
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 |
|
8 |
|
||||||
9 | # none args
|
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
|
9 | # none args
|
||||||
10 | datetime.datetime.now(None)
|
10 | datetime.datetime.now(None)
|
||||||
|
@ -27,8 +29,9 @@ DTZ005.py:10:1: DTZ005 The use of `datetime.datetime.now()` without `tz` argumen
|
||||||
11 |
|
11 |
|
||||||
12 | # none keywords
|
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
|
12 | # none keywords
|
||||||
13 | datetime.datetime.now(tz=None)
|
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 |
|
14 |
|
||||||
15 | from datetime import datetime
|
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
|
17 | # no args unqualified
|
||||||
18 | datetime.now()
|
18 | datetime.now()
|
||||||
|
@ -45,5 +49,4 @@ DTZ005.py:18:1: DTZ005 The use of `datetime.datetime.now()` without `tz` argumen
|
||||||
19 |
|
19 |
|
||||||
20 | # uses `astimezone` method
|
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
|
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
|
3 | # no args
|
||||||
4 | datetime.datetime.fromtimestamp(1234)
|
4 | datetime.datetime.fromtimestamp(1234)
|
||||||
|
@ -9,8 +9,9 @@ DTZ006.py:4:1: DTZ006 The use of `datetime.datetime.fromtimestamp()` without `tz
|
||||||
5 |
|
5 |
|
||||||
6 | # wrong keywords
|
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
|
6 | # wrong keywords
|
||||||
7 | datetime.datetime.fromtimestamp(1234, bad=datetime.timezone.utc)
|
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 |
|
8 |
|
||||||
9 | # none args
|
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
|
9 | # none args
|
||||||
10 | datetime.datetime.fromtimestamp(1234, None)
|
10 | datetime.datetime.fromtimestamp(1234, None)
|
||||||
|
@ -27,8 +29,9 @@ DTZ006.py:10:1: DTZ006 The use of `datetime.datetime.fromtimestamp()` without `t
|
||||||
11 |
|
11 |
|
||||||
12 | # none keywords
|
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
|
12 | # none keywords
|
||||||
13 | datetime.datetime.fromtimestamp(1234, tz=None)
|
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 |
|
14 |
|
||||||
15 | from datetime import datetime
|
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
|
17 | # no args unqualified
|
||||||
18 | datetime.fromtimestamp(1234)
|
18 | datetime.fromtimestamp(1234)
|
||||||
|
@ -45,5 +49,4 @@ DTZ006.py:18:1: DTZ006 The use of `datetime.datetime.fromtimestamp()` without `t
|
||||||
19 |
|
19 |
|
||||||
20 | # uses `astimezone` method
|
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
|
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
|
3 | # bad format
|
||||||
4 | datetime.datetime.strptime("something", "%H:%M:%S%Z")
|
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 |
|
5 |
|
||||||
6 | # no replace or astimezone
|
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
|
6 | # no replace or astimezone
|
||||||
7 | datetime.datetime.strptime("something", "something")
|
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 |
|
8 |
|
||||||
9 | # wrong replace
|
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
|
9 | # wrong replace
|
||||||
10 | datetime.datetime.strptime("something", "something").replace(hour=1)
|
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 |
|
11 |
|
||||||
12 | # none replace
|
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
|
12 | # none replace
|
||||||
13 | datetime.datetime.strptime("something", "something").replace(tzinfo=None)
|
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 |
|
14 |
|
||||||
15 | # OK
|
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
|
34 | # no replace orastimezone unqualified
|
||||||
35 | datetime.strptime("something", "something")
|
35 | datetime.strptime("something", "something")
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ DTZ007
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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
|
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
|
3 | # qualified
|
||||||
4 | datetime.date.today()
|
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 |
|
5 |
|
||||||
6 | from datetime import date
|
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
|
8 | # unqualified
|
||||||
9 | date.today()
|
9 | date.today()
|
||||||
| ^^^^^^^^^^^^ DTZ011
|
| ^^^^^^^^^^^^ DTZ011
|
||||||
|
|
|
|
||||||
|
= help: Use `datetime.datetime.now(tz=...).date()` instead
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_linter/src/rules/flake8_datetimez/mod.rs
|
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
|
3 | # qualified
|
||||||
4 | datetime.date.fromtimestamp(1234)
|
4 | datetime.date.fromtimestamp(1234)
|
||||||
|
@ -9,12 +9,12 @@ DTZ012.py:4:1: DTZ012 The use of `datetime.date.fromtimestamp()` is not allowed,
|
||||||
5 |
|
5 |
|
||||||
6 | from datetime import date
|
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
|
8 | # unqualified
|
||||||
9 | date.fromtimestamp(1234)
|
9 | date.fromtimestamp(1234)
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ DTZ012
|
| ^^^^^^^^^^^^^^^^^^^^^^^^ DTZ012
|
||||||
|
|
|
|
||||||
|
= help: Use `datetime.datetime.fromtimestamp(ts, tz=...).date()` instead
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue