[refurb] Mark int and bool cases for Decimal.from_float as safe fixes in FURB164 tests (#19468)

## Summary

Fixes #19460

---------

Co-authored-by: Brent Westbrook <36778786+ntBre@users.noreply.github.com>
This commit is contained in:
Dan Parizher 2025-07-28 10:21:38 -04:00 committed by GitHub
parent 2680f2ed81
commit 201b079084
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 121 additions and 21 deletions

View file

@ -55,3 +55,12 @@ _ = Decimal(0.1)
_ = Decimal(-0.5) _ = Decimal(-0.5)
_ = Decimal(5.0) _ = Decimal(5.0)
_ = decimal.Decimal(4.2) _ = decimal.Decimal(4.2)
# Cases with int and bool - should produce safe fixes
_ = Decimal.from_float(1)
_ = Decimal.from_float(True)
# Cases with non-finite floats - should produce safe fixes
_ = Decimal.from_float(float("-nan"))
_ = Decimal.from_float(float("\x2dnan"))
_ = Decimal.from_float(float("\N{HYPHEN-MINUS}nan"))

View file

@ -180,18 +180,18 @@ fn is_valid_argument_type(
typing::is_float(binding, semantic), typing::is_float(binding, semantic),
) )
}) })
.unwrap_or_default() .unwrap_or((false, false))
} else { } else {
(false, false) (false, false)
}; };
match (method_name, constructor) { match (method_name, constructor) {
// Decimal.from_float accepts int, bool, float // Decimal.from_float: Only int or bool are safe (float is unsafe due to FloatOperation trap)
(MethodName::FromFloat, Constructor::Decimal) => match resolved_type { (MethodName::FromFloat, Constructor::Decimal) => match resolved_type {
ResolvedPythonType::Atom(PythonType::Number( ResolvedPythonType::Atom(PythonType::Number(
NumberLike::Integer | NumberLike::Bool | NumberLike::Float, NumberLike::Integer | NumberLike::Bool,
)) => true, )) => true,
ResolvedPythonType::Unknown => is_int || is_float, ResolvedPythonType::Unknown => is_int,
_ => false, _ => false,
}, },
// Fraction.from_float accepts int, bool, float // Fraction.from_float accepts int, bool, float
@ -286,10 +286,8 @@ fn handle_non_finite_float_special_case(
let [float_arg] = arguments.args.as_ref() else { let [float_arg] = arguments.args.as_ref() else {
return None; return None;
}; };
as_non_finite_float_string_literal(float_arg)?; let normalized = as_non_finite_float_string_literal(float_arg)?;
let replacement_text = format!(r#"{constructor_name}("{normalized}")"#);
let replacement_arg = checker.locator().slice(float_arg).to_string();
let replacement_text = format!("{constructor_name}({replacement_arg})");
Some(Edit::range_replacement(replacement_text, call.range())) Some(Edit::range_replacement(replacement_text, call.range()))
} }

View file

@ -158,7 +158,7 @@ FURB164.py:13:27: FURB164 [*] Verbose method `from_float` in `Decimal` construct
| |
= help: Replace with `Decimal` constructor = help: Replace with `Decimal` constructor
Safe fix Unsafe fix
10 10 | _ = fractions.Fraction.from_float(4.2) 10 10 | _ = fractions.Fraction.from_float(4.2)
11 11 | _ = Fraction.from_decimal(Decimal("4.2")) 11 11 | _ = Fraction.from_decimal(Decimal("4.2"))
12 12 | _ = Fraction.from_decimal(Decimal("-4.2")) 12 12 | _ = Fraction.from_decimal(Decimal("-4.2"))
@ -179,7 +179,7 @@ FURB164.py:14:5: FURB164 [*] Verbose method `from_float` in `Decimal` constructi
| |
= help: Replace with `Decimal` constructor = help: Replace with `Decimal` constructor
Safe fix Unsafe fix
11 11 | _ = Fraction.from_decimal(Decimal("4.2")) 11 11 | _ = Fraction.from_decimal(Decimal("4.2"))
12 12 | _ = Fraction.from_decimal(Decimal("-4.2")) 12 12 | _ = Fraction.from_decimal(Decimal("-4.2"))
13 13 | _ = Fraction.from_decimal(Decimal.from_float(4.2)) 13 13 | _ = Fraction.from_decimal(Decimal.from_float(4.2))
@ -200,7 +200,7 @@ FURB164.py:15:5: FURB164 [*] Verbose method `from_float` in `Decimal` constructi
| |
= help: Replace with `Decimal` constructor = help: Replace with `Decimal` constructor
Safe fix Unsafe fix
12 12 | _ = Fraction.from_decimal(Decimal("-4.2")) 12 12 | _ = Fraction.from_decimal(Decimal("-4.2"))
13 13 | _ = Fraction.from_decimal(Decimal.from_float(4.2)) 13 13 | _ = Fraction.from_decimal(Decimal.from_float(4.2))
14 14 | _ = Decimal.from_float(0.1) 14 14 | _ = Decimal.from_float(0.1)
@ -221,7 +221,7 @@ FURB164.py:16:5: FURB164 [*] Verbose method `from_float` in `Decimal` constructi
| |
= help: Replace with `Decimal` constructor = help: Replace with `Decimal` constructor
Safe fix Unsafe fix
13 13 | _ = Fraction.from_decimal(Decimal.from_float(4.2)) 13 13 | _ = Fraction.from_decimal(Decimal.from_float(4.2))
14 14 | _ = Decimal.from_float(0.1) 14 14 | _ = Decimal.from_float(0.1)
15 15 | _ = Decimal.from_float(-0.5) 15 15 | _ = Decimal.from_float(-0.5)
@ -242,7 +242,7 @@ FURB164.py:17:5: FURB164 [*] Verbose method `from_float` in `Decimal` constructi
| |
= help: Replace with `Decimal` constructor = help: Replace with `Decimal` constructor
Safe fix Unsafe fix
14 14 | _ = Decimal.from_float(0.1) 14 14 | _ = Decimal.from_float(0.1)
15 15 | _ = Decimal.from_float(-0.5) 15 15 | _ = Decimal.from_float(-0.5)
16 16 | _ = Decimal.from_float(5.0) 16 16 | _ = Decimal.from_float(5.0)
@ -310,7 +310,7 @@ FURB164.py:20:5: FURB164 [*] Verbose method `from_float` in `Decimal` constructi
18 18 | _ = Decimal.from_float(float("inf")) 18 18 | _ = Decimal.from_float(float("inf"))
19 19 | _ = Decimal.from_float(float("-inf")) 19 19 | _ = Decimal.from_float(float("-inf"))
20 |-_ = Decimal.from_float(float("Infinity")) 20 |-_ = Decimal.from_float(float("Infinity"))
20 |+_ = Decimal("Infinity") 20 |+_ = Decimal("infinity")
21 21 | _ = Decimal.from_float(float("-Infinity")) 21 21 | _ = Decimal.from_float(float("-Infinity"))
22 22 | _ = Decimal.from_float(float("nan")) 22 22 | _ = Decimal.from_float(float("nan"))
23 23 | _ = Decimal.from_float(float("-NaN")) 23 23 | _ = Decimal.from_float(float("-NaN"))
@ -331,7 +331,7 @@ FURB164.py:21:5: FURB164 [*] Verbose method `from_float` in `Decimal` constructi
19 19 | _ = Decimal.from_float(float("-inf")) 19 19 | _ = Decimal.from_float(float("-inf"))
20 20 | _ = Decimal.from_float(float("Infinity")) 20 20 | _ = Decimal.from_float(float("Infinity"))
21 |-_ = Decimal.from_float(float("-Infinity")) 21 |-_ = Decimal.from_float(float("-Infinity"))
21 |+_ = Decimal("-Infinity") 21 |+_ = Decimal("-infinity")
22 22 | _ = Decimal.from_float(float("nan")) 22 22 | _ = Decimal.from_float(float("nan"))
23 23 | _ = Decimal.from_float(float("-NaN")) 23 23 | _ = Decimal.from_float(float("-NaN"))
24 24 | _ = Decimal.from_float(float(" \n+nan \t")) 24 24 | _ = Decimal.from_float(float(" \n+nan \t"))
@ -373,7 +373,7 @@ FURB164.py:23:5: FURB164 [*] Verbose method `from_float` in `Decimal` constructi
21 21 | _ = Decimal.from_float(float("-Infinity")) 21 21 | _ = Decimal.from_float(float("-Infinity"))
22 22 | _ = Decimal.from_float(float("nan")) 22 22 | _ = Decimal.from_float(float("nan"))
23 |-_ = Decimal.from_float(float("-NaN")) 23 |-_ = Decimal.from_float(float("-NaN"))
23 |+_ = Decimal("-NaN") 23 |+_ = Decimal("-nan")
24 24 | _ = Decimal.from_float(float(" \n+nan \t")) 24 24 | _ = Decimal.from_float(float(" \n+nan \t"))
25 25 | _ = Decimal.from_float(float(" iNf\n\t ")) 25 25 | _ = Decimal.from_float(float(" iNf\n\t "))
26 26 | _ = Decimal.from_float(float(" -inF\n \t")) 26 26 | _ = Decimal.from_float(float(" -inF\n \t"))
@ -394,7 +394,7 @@ FURB164.py:24:5: FURB164 [*] Verbose method `from_float` in `Decimal` constructi
22 22 | _ = Decimal.from_float(float("nan")) 22 22 | _ = Decimal.from_float(float("nan"))
23 23 | _ = Decimal.from_float(float("-NaN")) 23 23 | _ = Decimal.from_float(float("-NaN"))
24 |-_ = Decimal.from_float(float(" \n+nan \t")) 24 |-_ = Decimal.from_float(float(" \n+nan \t"))
24 |+_ = Decimal(" \n+nan \t") 24 |+_ = Decimal("+nan")
25 25 | _ = Decimal.from_float(float(" iNf\n\t ")) 25 25 | _ = Decimal.from_float(float(" iNf\n\t "))
26 26 | _ = Decimal.from_float(float(" -inF\n \t")) 26 26 | _ = Decimal.from_float(float(" -inF\n \t"))
27 27 | _ = Decimal.from_float(float(" InfinIty\n\t ")) 27 27 | _ = Decimal.from_float(float(" InfinIty\n\t "))
@ -415,7 +415,7 @@ FURB164.py:25:5: FURB164 [*] Verbose method `from_float` in `Decimal` constructi
23 23 | _ = Decimal.from_float(float("-NaN")) 23 23 | _ = Decimal.from_float(float("-NaN"))
24 24 | _ = Decimal.from_float(float(" \n+nan \t")) 24 24 | _ = Decimal.from_float(float(" \n+nan \t"))
25 |-_ = Decimal.from_float(float(" iNf\n\t ")) 25 |-_ = Decimal.from_float(float(" iNf\n\t "))
25 |+_ = Decimal(" iNf\n\t ") 25 |+_ = Decimal("inf")
26 26 | _ = Decimal.from_float(float(" -inF\n \t")) 26 26 | _ = Decimal.from_float(float(" -inF\n \t"))
27 27 | _ = Decimal.from_float(float(" InfinIty\n\t ")) 27 27 | _ = Decimal.from_float(float(" InfinIty\n\t "))
28 28 | _ = Decimal.from_float(float(" -InfinIty\n \t")) 28 28 | _ = Decimal.from_float(float(" -InfinIty\n \t"))
@ -436,7 +436,7 @@ FURB164.py:26:5: FURB164 [*] Verbose method `from_float` in `Decimal` constructi
24 24 | _ = Decimal.from_float(float(" \n+nan \t")) 24 24 | _ = Decimal.from_float(float(" \n+nan \t"))
25 25 | _ = Decimal.from_float(float(" iNf\n\t ")) 25 25 | _ = Decimal.from_float(float(" iNf\n\t "))
26 |-_ = Decimal.from_float(float(" -inF\n \t")) 26 |-_ = Decimal.from_float(float(" -inF\n \t"))
26 |+_ = Decimal(" -inF\n \t") 26 |+_ = Decimal("-inf")
27 27 | _ = Decimal.from_float(float(" InfinIty\n\t ")) 27 27 | _ = Decimal.from_float(float(" InfinIty\n\t "))
28 28 | _ = Decimal.from_float(float(" -InfinIty\n \t")) 28 28 | _ = Decimal.from_float(float(" -InfinIty\n \t"))
29 29 | 29 29 |
@ -456,7 +456,7 @@ FURB164.py:27:5: FURB164 [*] Verbose method `from_float` in `Decimal` constructi
25 25 | _ = Decimal.from_float(float(" iNf\n\t ")) 25 25 | _ = Decimal.from_float(float(" iNf\n\t "))
26 26 | _ = Decimal.from_float(float(" -inF\n \t")) 26 26 | _ = Decimal.from_float(float(" -inF\n \t"))
27 |-_ = Decimal.from_float(float(" InfinIty\n\t ")) 27 |-_ = Decimal.from_float(float(" InfinIty\n\t "))
27 |+_ = Decimal(" InfinIty\n\t ") 27 |+_ = Decimal("infinity")
28 28 | _ = Decimal.from_float(float(" -InfinIty\n \t")) 28 28 | _ = Decimal.from_float(float(" -InfinIty\n \t"))
29 29 | 29 29 |
30 30 | # Cases with keyword arguments - should produce unsafe fixes 30 30 | # Cases with keyword arguments - should produce unsafe fixes
@ -477,7 +477,7 @@ FURB164.py:28:5: FURB164 [*] Verbose method `from_float` in `Decimal` constructi
26 26 | _ = Decimal.from_float(float(" -inF\n \t")) 26 26 | _ = Decimal.from_float(float(" -inF\n \t"))
27 27 | _ = Decimal.from_float(float(" InfinIty\n\t ")) 27 27 | _ = Decimal.from_float(float(" InfinIty\n\t "))
28 |-_ = Decimal.from_float(float(" -InfinIty\n \t")) 28 |-_ = Decimal.from_float(float(" -InfinIty\n \t"))
28 |+_ = Decimal(" -InfinIty\n \t") 28 |+_ = Decimal("-infinity")
29 29 | 29 29 |
30 30 | # Cases with keyword arguments - should produce unsafe fixes 30 30 | # Cases with keyword arguments - should produce unsafe fixes
31 31 | _ = Fraction.from_decimal(dec=Decimal("4.2")) 31 31 | _ = Fraction.from_decimal(dec=Decimal("4.2"))
@ -612,3 +612,96 @@ FURB164.py:45:5: FURB164 [*] Verbose method `from_float` in `Fraction` construct
46 46 | 46 46 |
47 47 | # OK - should not trigger the rule 47 47 | # OK - should not trigger the rule
48 48 | _ = Fraction(0.1) 48 48 | _ = Fraction(0.1)
FURB164.py:60:5: FURB164 [*] Verbose method `from_float` in `Decimal` construction
|
59 | # Cases with int and bool - should produce safe fixes
60 | _ = Decimal.from_float(1)
| ^^^^^^^^^^^^^^^^^^^^^ FURB164
61 | _ = Decimal.from_float(True)
|
= help: Replace with `Decimal` constructor
Safe fix
57 57 | _ = decimal.Decimal(4.2)
58 58 |
59 59 | # Cases with int and bool - should produce safe fixes
60 |-_ = Decimal.from_float(1)
60 |+_ = Decimal(1)
61 61 | _ = Decimal.from_float(True)
62 62 |
63 63 | # Cases with non-finite floats - should produce safe fixes
FURB164.py:61:5: FURB164 [*] Verbose method `from_float` in `Decimal` construction
|
59 | # Cases with int and bool - should produce safe fixes
60 | _ = Decimal.from_float(1)
61 | _ = Decimal.from_float(True)
| ^^^^^^^^^^^^^^^^^^^^^^^^ FURB164
62 |
63 | # Cases with non-finite floats - should produce safe fixes
|
= help: Replace with `Decimal` constructor
Safe fix
58 58 |
59 59 | # Cases with int and bool - should produce safe fixes
60 60 | _ = Decimal.from_float(1)
61 |-_ = Decimal.from_float(True)
61 |+_ = Decimal(True)
62 62 |
63 63 | # Cases with non-finite floats - should produce safe fixes
64 64 | _ = Decimal.from_float(float("-nan"))
FURB164.py:64:5: FURB164 [*] Verbose method `from_float` in `Decimal` construction
|
63 | # Cases with non-finite floats - should produce safe fixes
64 | _ = Decimal.from_float(float("-nan"))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FURB164
65 | _ = Decimal.from_float(float("\x2dnan"))
66 | _ = Decimal.from_float(float("\N{HYPHEN-MINUS}nan"))
|
= help: Replace with `Decimal` constructor
Safe fix
61 61 | _ = Decimal.from_float(True)
62 62 |
63 63 | # Cases with non-finite floats - should produce safe fixes
64 |-_ = Decimal.from_float(float("-nan"))
64 |+_ = Decimal("-nan")
65 65 | _ = Decimal.from_float(float("\x2dnan"))
66 66 | _ = Decimal.from_float(float("\N{HYPHEN-MINUS}nan"))
FURB164.py:65:5: FURB164 [*] Verbose method `from_float` in `Decimal` construction
|
63 | # Cases with non-finite floats - should produce safe fixes
64 | _ = Decimal.from_float(float("-nan"))
65 | _ = Decimal.from_float(float("\x2dnan"))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FURB164
66 | _ = Decimal.from_float(float("\N{HYPHEN-MINUS}nan"))
|
= help: Replace with `Decimal` constructor
Safe fix
62 62 |
63 63 | # Cases with non-finite floats - should produce safe fixes
64 64 | _ = Decimal.from_float(float("-nan"))
65 |-_ = Decimal.from_float(float("\x2dnan"))
65 |+_ = Decimal("-nan")
66 66 | _ = Decimal.from_float(float("\N{HYPHEN-MINUS}nan"))
FURB164.py:66:5: FURB164 [*] Verbose method `from_float` in `Decimal` construction
|
64 | _ = Decimal.from_float(float("-nan"))
65 | _ = Decimal.from_float(float("\x2dnan"))
66 | _ = Decimal.from_float(float("\N{HYPHEN-MINUS}nan"))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FURB164
|
= help: Replace with `Decimal` constructor
Safe fix
63 63 | # Cases with non-finite floats - should produce safe fixes
64 64 | _ = Decimal.from_float(float("-nan"))
65 65 | _ = Decimal.from_float(float("\x2dnan"))
66 |-_ = Decimal.from_float(float("\N{HYPHEN-MINUS}nan"))
66 |+_ = Decimal("-nan")