diff --git a/crates/ruff_linter/resources/test/fixtures/refurb/FURB157.py b/crates/ruff_linter/resources/test/fixtures/refurb/FURB157.py index 56c1f00aba20d..facb2a373568f 100644 --- a/crates/ruff_linter/resources/test/fixtures/refurb/FURB157.py +++ b/crates/ruff_linter/resources/test/fixtures/refurb/FURB157.py @@ -34,4 +34,11 @@ # Ok: even though this is equal to `Decimal(123)`, # we assume that a developer would # only write it this way if they meant to. -Decimal("١٢٣") \ No newline at end of file +Decimal("١٢٣") + +# Further subtleties +# https://github.com/astral-sh/ruff/issues/14204 +Decimal("-0") # Ok +Decimal("_") # Ok +Decimal(" ") # Ok +Decimal("10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") # Ok diff --git a/crates/ruff_linter/src/rules/refurb/rules/verbose_decimal_constructor.rs b/crates/ruff_linter/src/rules/refurb/rules/verbose_decimal_constructor.rs index 6aecfadbd4499..559458cc57ef8 100644 --- a/crates/ruff_linter/src/rules/refurb/rules/verbose_decimal_constructor.rs +++ b/crates/ruff_linter/src/rules/refurb/rules/verbose_decimal_constructor.rs @@ -94,6 +94,12 @@ pub(crate) fn verbose_decimal_constructor(checker: &mut Checker, call: &ast::Exp ("", trimmed) }; + // Early return if we now have an empty string + // or a very long string: + if (rest.len() > PYTHONINTMAXSTRDIGITS) || (rest.len() == 0) { + return; + } + // Skip leading zeros. let rest = rest.trim_start_matches('0'); @@ -103,7 +109,15 @@ pub(crate) fn verbose_decimal_constructor(checker: &mut Checker, call: &ast::Exp }; // If all the characters are zeros, then the value is zero. - let rest = if rest.is_empty() { "0" } else { rest }; + let rest = match (unary, rest.is_empty()) { + // `Decimal("-0")` is not the same as `Decimal("0")` + // so we return early. + ("-", true) => { + return; + } + (_, true) => "0", + _ => rest, + }; let replacement = format!("{unary}{rest}"); let mut diagnostic = Diagnostic::new( @@ -168,25 +182,10 @@ pub(crate) fn verbose_decimal_constructor(checker: &mut Checker, call: &ast::Exp checker.diagnostics.push(diagnostic); } -// // Slightly modified from [CPython regex] to ignore https://github.com/python/cpython/blob/ac556a2ad1213b8bb81372fe6fb762f5fcb076de/Lib/_pydecimal.py#L6060-L6077 -// static DECIMAL_PARSER_REGEX: LazyLock = LazyLock::new(|| { -// Regex::new( -// r"(?x) # Verbose mode for comments -// ^ # Start of string -// (?P[-+])? # Optional sign -// (?: -// (?P\d*) # Integer part (can be empty) -// (\.(?P\d+))? # Optional fractional part -// (E(?P[-+]?\d+))? # Optional exponent -// | -// Inf(inity)? # Infinity -// | -// (?Ps)? # Optional signal -// NaN # NaN -// (?P\d*) # Optional diagnostic info -// ) -// $ # End of string -// ", -// ) -// .unwrap() -// }); +// ```console +// $ python +// >>> import sys +// >>> sys.int_info.str_digits_check_threshold +// 640 +// ``` +const PYTHONINTMAXSTRDIGITS: usize = 640;