Skip to content

Commit

Permalink
[refurb] Further special cases added to `verbose-decimal-constructo…
Browse files Browse the repository at this point in the history
…r (FURB157)` (#14216)

This PR accounts for further subtleties in `Decimal` parsing:

- Strings which are empty modulo underscores and surrounding whitespace
are skipped
- `Decimal("-0")` is skipped
- `Decimal("{integer literal that is longer than 640 digits}")` are
skipped (see linked issue for explanation)

NB: The snapshot did not need to be updated since the new test cases are
"Ok" instances and added below the diff.

Closes #14204
  • Loading branch information
dylwil3 authored Nov 9, 2024
1 parent 93fdf7e commit b8dc780
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 24 deletions.
9 changes: 8 additions & 1 deletion crates/ruff_linter/resources/test/fixtures/refurb/FURB157.py
Original file line number Diff line number Diff line change
Expand Up @@ -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("١٢٣")
Decimal("١٢٣")

# Further subtleties
# https://github.com/astral-sh/ruff/issues/14204
Decimal("-0") # Ok
Decimal("_") # Ok
Decimal(" ") # Ok
Decimal("10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") # Ok
Original file line number Diff line number Diff line change
Expand Up @@ -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');

Expand All @@ -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(
Expand Down Expand Up @@ -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<Regex> = LazyLock::new(|| {
// Regex::new(
// r"(?x) # Verbose mode for comments
// ^ # Start of string
// (?P<sign>[-+])? # Optional sign
// (?:
// (?P<int>\d*) # Integer part (can be empty)
// (\.(?P<frac>\d+))? # Optional fractional part
// (E(?P<exp>[-+]?\d+))? # Optional exponent
// |
// Inf(inity)? # Infinity
// |
// (?P<signal>s)? # Optional signal
// NaN # NaN
// (?P<diag>\d*) # Optional diagnostic info
// )
// $ # End of string
// ",
// )
// .unwrap()
// });
// ```console
// $ python
// >>> import sys
// >>> sys.int_info.str_digits_check_threshold
// 640
// ```
const PYTHONINTMAXSTRDIGITS: usize = 640;

0 comments on commit b8dc780

Please sign in to comment.