From 9ad9cea95233448fd191bba0669f45141102bb6e Mon Sep 17 00:00:00 2001 From: hikaru-kajita <61526956+boolean-light@users.noreply.github.com> Date: Sat, 30 Mar 2024 20:04:01 +0900 Subject: [PATCH] [`refurb`] Implement `unnecessary-from-float` (`FURB164`) (#10647) ## Summary Implement FURB164 in the issue #1348. Relevant Refurb docs is here: /~https://github.com/dosisod/refurb/blob/v2.0.0/docs/checks.md#furb164-no-from-float I've changed the name from `no-from-float` to `verbose-decimal-fraction-construction`. ## Test Plan I've written it in the `FURB164.py`. --------- Co-authored-by: Charlie Marsh --- .../resources/test/fixtures/refurb/FURB164.py | 34 ++ .../src/checkers/ast/analyze/expression.rs | 3 + crates/ruff_linter/src/codes.rs | 1 + crates/ruff_linter/src/rules/refurb/mod.rs | 1 + .../ruff_linter/src/rules/refurb/rules/mod.rs | 2 + .../refurb/rules/unnecessary_from_float.rs | 205 ++++++++++ .../rules/verbose_decimal_constructor.rs | 4 +- ...es__refurb__tests__FURB164_FURB164.py.snap | 357 ++++++++++++++++++ ruff.schema.json | 1 + 9 files changed, 606 insertions(+), 2 deletions(-) create mode 100644 crates/ruff_linter/resources/test/fixtures/refurb/FURB164.py create mode 100644 crates/ruff_linter/src/rules/refurb/rules/unnecessary_from_float.rs create mode 100644 crates/ruff_linter/src/rules/refurb/snapshots/ruff_linter__rules__refurb__tests__FURB164_FURB164.py.snap diff --git a/crates/ruff_linter/resources/test/fixtures/refurb/FURB164.py b/crates/ruff_linter/resources/test/fixtures/refurb/FURB164.py new file mode 100644 index 0000000000000..2adbc446331c4 --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/refurb/FURB164.py @@ -0,0 +1,34 @@ +from decimal import Decimal +from fractions import Fraction +import decimal +import fractions + +# Errors +_ = Fraction.from_float(0.1) +_ = Fraction.from_float(-0.5) +_ = Fraction.from_float(5.0) +_ = fractions.Fraction.from_float(4.2) +_ = Fraction.from_decimal(Decimal("4.2")) +_ = Fraction.from_decimal(Decimal("-4.2")) +_ = Fraction.from_decimal(Decimal.from_float(4.2)) +_ = Decimal.from_float(0.1) +_ = Decimal.from_float(-0.5) +_ = Decimal.from_float(5.0) +_ = decimal.Decimal.from_float(4.2) +_ = Decimal.from_float(float("inf")) +_ = Decimal.from_float(float("-inf")) +_ = Decimal.from_float(float("Infinity")) +_ = Decimal.from_float(float("-Infinity")) +_ = Decimal.from_float(float("nan")) + +# OK +_ = Fraction(0.1) +_ = Fraction(-0.5) +_ = Fraction(5.0) +_ = fractions.Fraction(4.2) +_ = Fraction(Decimal("4.2")) +_ = Fraction(Decimal("-4.2")) +_ = Decimal(0.1) +_ = Decimal(-0.5) +_ = Decimal(5.0) +_ = decimal.Decimal(4.2) diff --git a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs index e2d9f94a63a6b..9e85625e87eba 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs @@ -929,6 +929,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { if checker.enabled(Rule::VerboseDecimalConstructor) { refurb::rules::verbose_decimal_constructor(checker, call); } + if checker.enabled(Rule::UnnecessaryFromFloat) { + refurb::rules::unnecessary_from_float(checker, call); + } if checker.enabled(Rule::QuadraticListSummation) { ruff::rules::quadratic_list_summation(checker, call); } diff --git a/crates/ruff_linter/src/codes.rs b/crates/ruff_linter/src/codes.rs index 7b5dbd8a24502..ce8b7c4661977 100644 --- a/crates/ruff_linter/src/codes.rs +++ b/crates/ruff_linter/src/codes.rs @@ -1051,6 +1051,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> { (Refurb, "157") => (RuleGroup::Preview, rules::refurb::rules::VerboseDecimalConstructor), (Refurb, "161") => (RuleGroup::Preview, rules::refurb::rules::BitCount), (Refurb, "163") => (RuleGroup::Preview, rules::refurb::rules::RedundantLogBase), + (Refurb, "164") => (RuleGroup::Preview, rules::refurb::rules::UnnecessaryFromFloat), (Refurb, "167") => (RuleGroup::Preview, rules::refurb::rules::RegexFlagAlias), (Refurb, "168") => (RuleGroup::Preview, rules::refurb::rules::IsinstanceTypeNone), (Refurb, "169") => (RuleGroup::Preview, rules::refurb::rules::TypeNoneComparison), diff --git a/crates/ruff_linter/src/rules/refurb/mod.rs b/crates/ruff_linter/src/rules/refurb/mod.rs index 1408109b2c6e6..67e1022600426 100644 --- a/crates/ruff_linter/src/rules/refurb/mod.rs +++ b/crates/ruff_linter/src/rules/refurb/mod.rs @@ -27,6 +27,7 @@ mod tests { #[test_case(Rule::UnnecessaryEnumerate, Path::new("FURB148.py"))] #[test_case(Rule::MathConstant, Path::new("FURB152.py"))] #[test_case(Rule::VerboseDecimalConstructor, Path::new("FURB157.py"))] + #[test_case(Rule::UnnecessaryFromFloat, Path::new("FURB164.py"))] #[test_case(Rule::PrintEmptyString, Path::new("FURB105.py"))] #[test_case(Rule::ImplicitCwd, Path::new("FURB177.py"))] #[test_case(Rule::SingleItemMembershipTest, Path::new("FURB171.py"))] diff --git a/crates/ruff_linter/src/rules/refurb/rules/mod.rs b/crates/ruff_linter/src/rules/refurb/rules/mod.rs index 832342c509e13..cbb8d1fc7f0bb 100644 --- a/crates/ruff_linter/src/rules/refurb/rules/mod.rs +++ b/crates/ruff_linter/src/rules/refurb/rules/mod.rs @@ -21,6 +21,7 @@ pub(crate) use single_item_membership_test::*; pub(crate) use slice_copy::*; pub(crate) use type_none_comparison::*; pub(crate) use unnecessary_enumerate::*; +pub(crate) use unnecessary_from_float::*; pub(crate) use verbose_decimal_constructor::*; mod bit_count; @@ -46,4 +47,5 @@ mod single_item_membership_test; mod slice_copy; mod type_none_comparison; mod unnecessary_enumerate; +mod unnecessary_from_float; mod verbose_decimal_constructor; diff --git a/crates/ruff_linter/src/rules/refurb/rules/unnecessary_from_float.rs b/crates/ruff_linter/src/rules/refurb/rules/unnecessary_from_float.rs new file mode 100644 index 0000000000000..8994ce81ac3a4 --- /dev/null +++ b/crates/ruff_linter/src/rules/refurb/rules/unnecessary_from_float.rs @@ -0,0 +1,205 @@ +use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation}; +use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::{self as ast, Expr, ExprCall}; +use ruff_text_size::Ranged; + +use crate::checkers::ast::Checker; + +/// ## What it does +/// Checks for unnecessary `from_float` and `from_decimal` usages to construct +/// `Decimal` and `Fraction` instances. +/// +/// ## Why is this bad? +/// Since Python 3.2, the `Fraction` and `Decimal` classes can be constructed +/// by passing float or decimal instances to the constructor directly. As such, +/// the use of `from_float` and `from_decimal` methods is unnecessary, and +/// should be avoided in favor of the more concise constructor syntax. +/// +/// ## Examples +/// ```python +/// Decimal.from_float(4.2) +/// Decimal.from_float(float("inf")) +/// Fraction.from_float(4.2) +/// Fraction.from_decimal(Decimal("4.2")) +/// ``` +/// +/// Use instead: +/// ```python +/// Decimal(4.2) +/// Decimal("inf") +/// Fraction(4.2) +/// Fraction(Decimal(4.2)) +/// ``` +/// +/// ## References +/// - [Python documentation: `decimal`](https://docs.python.org/3/library/decimal.html) +/// - [Python documentation: `fractions`](https://docs.python.org/3/library/fractions.html) +#[violation] +pub struct UnnecessaryFromFloat { + method_name: MethodName, + constructor: Constructor, +} + +impl Violation for UnnecessaryFromFloat { + const FIX_AVAILABILITY: FixAvailability = FixAvailability::Sometimes; + + #[derive_message_formats] + fn message(&self) -> String { + let UnnecessaryFromFloat { + method_name, + constructor, + } = self; + format!("Verbose method `{method_name}` in `{constructor}` construction",) + } + + fn fix_title(&self) -> Option { + let UnnecessaryFromFloat { constructor, .. } = self; + Some(format!("Replace with `{constructor}` constructor")) + } +} + +/// FURB164 +pub(crate) fn unnecessary_from_float(checker: &mut Checker, call: &ExprCall) { + let Expr::Attribute(ast::ExprAttribute { value, attr, .. }) = &*call.func else { + return; + }; + + // The method name must be either `from_float` or `from_decimal`. + let method_name = match attr.as_str() { + "from_float" => MethodName::FromFloat, + "from_decimal" => MethodName::FromDecimal, + _ => return, + }; + + // The value must be either `decimal.Decimal` or `fractions.Fraction`. + let Some(constructor) = + checker + .semantic() + .resolve_qualified_name(value) + .and_then(|qualified_name| match qualified_name.segments() { + ["decimal", "Decimal"] => Some(Constructor::Decimal), + ["fractions", "Fraction"] => Some(Constructor::Fraction), + _ => None, + }) + else { + return; + }; + + // `Decimal.from_decimal` doesn't exist. + if matches!( + (method_name, constructor), + (MethodName::FromDecimal, Constructor::Decimal) + ) { + return; + } + + let mut diagnostic = Diagnostic::new( + UnnecessaryFromFloat { + method_name, + constructor, + }, + call.range(), + ); + + let edit = Edit::range_replacement( + checker.locator().slice(&**value).to_string(), + call.func.range(), + ); + + // Short-circuit case for special values, such as: `Decimal.from_float(float("inf"))` to `Decimal("inf")`. + 'short_circuit: { + if !matches!(constructor, Constructor::Decimal) { + break 'short_circuit; + }; + if !(method_name == MethodName::FromFloat) { + break 'short_circuit; + }; + + let Some(value) = (match method_name { + MethodName::FromFloat => call.arguments.find_argument("f", 0), + MethodName::FromDecimal => call.arguments.find_argument("dec", 0), + }) else { + return; + }; + + let Expr::Call( + call @ ast::ExprCall { + func, arguments, .. + }, + ) = value + else { + break 'short_circuit; + }; + + // Must be a call to the `float` builtin. + let Some(func_name) = func.as_name_expr() else { + break 'short_circuit; + }; + if func_name.id != "float" { + break 'short_circuit; + }; + + // Must have exactly one argument, which is a string literal. + if arguments.keywords.len() != 0 { + break 'short_circuit; + }; + let [float] = arguments.args.as_ref() else { + break 'short_circuit; + }; + let Some(float) = float.as_string_literal_expr() else { + break 'short_circuit; + }; + if !matches!( + float.value.to_str().to_lowercase().as_str(), + "inf" | "-inf" | "infinity" | "-infinity" | "nan" + ) { + break 'short_circuit; + } + + if !checker.semantic().is_builtin("float") { + break 'short_circuit; + }; + + let replacement = checker.locator().slice(float).to_string(); + diagnostic.set_fix(Fix::safe_edits( + edit, + [Edit::range_replacement(replacement, call.range())], + )); + checker.diagnostics.push(diagnostic); + + return; + } + + diagnostic.set_fix(Fix::safe_edit(edit)); + checker.diagnostics.push(diagnostic); +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +enum MethodName { + FromFloat, + FromDecimal, +} + +impl std::fmt::Display for MethodName { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + MethodName::FromFloat => fmt.write_str("from_float"), + MethodName::FromDecimal => fmt.write_str("from_decimal"), + } + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +enum Constructor { + Decimal, + Fraction, +} + +impl std::fmt::Display for Constructor { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Constructor::Decimal => fmt.write_str("Decimal"), + Constructor::Fraction => fmt.write_str("Fraction"), + } + } +} 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 154c0405c41fb..831b07f86df83 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 @@ -1,6 +1,6 @@ use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::{self as ast, Expr, ExprCall}; +use ruff_python_ast::{self as ast, Expr}; use ruff_python_trivia::PythonWhitespace; use ruff_text_size::Ranged; @@ -56,7 +56,7 @@ impl Violation for VerboseDecimalConstructor { } /// FURB157 -pub(crate) fn verbose_decimal_constructor(checker: &mut Checker, call: &ExprCall) { +pub(crate) fn verbose_decimal_constructor(checker: &mut Checker, call: &ast::ExprCall) { if !checker .semantic() .resolve_qualified_name(&call.func) diff --git a/crates/ruff_linter/src/rules/refurb/snapshots/ruff_linter__rules__refurb__tests__FURB164_FURB164.py.snap b/crates/ruff_linter/src/rules/refurb/snapshots/ruff_linter__rules__refurb__tests__FURB164_FURB164.py.snap new file mode 100644 index 0000000000000..04340e219c219 --- /dev/null +++ b/crates/ruff_linter/src/rules/refurb/snapshots/ruff_linter__rules__refurb__tests__FURB164_FURB164.py.snap @@ -0,0 +1,357 @@ +--- +source: crates/ruff_linter/src/rules/refurb/mod.rs +--- +FURB164.py:7:5: FURB164 [*] Verbose method `from_float` in `Fraction` construction + | +6 | # Errors +7 | _ = Fraction.from_float(0.1) + | ^^^^^^^^^^^^^^^^^^^^^^^^ FURB164 +8 | _ = Fraction.from_float(-0.5) +9 | _ = Fraction.from_float(5.0) + | + = help: Replace with `Fraction` constructor + +ℹ Safe fix +4 4 | import fractions +5 5 | +6 6 | # Errors +7 |-_ = Fraction.from_float(0.1) + 7 |+_ = Fraction(0.1) +8 8 | _ = Fraction.from_float(-0.5) +9 9 | _ = Fraction.from_float(5.0) +10 10 | _ = fractions.Fraction.from_float(4.2) + +FURB164.py:8:5: FURB164 [*] Verbose method `from_float` in `Fraction` construction + | + 6 | # Errors + 7 | _ = Fraction.from_float(0.1) + 8 | _ = Fraction.from_float(-0.5) + | ^^^^^^^^^^^^^^^^^^^^^^^^^ FURB164 + 9 | _ = Fraction.from_float(5.0) +10 | _ = fractions.Fraction.from_float(4.2) + | + = help: Replace with `Fraction` constructor + +ℹ Safe fix +5 5 | +6 6 | # Errors +7 7 | _ = Fraction.from_float(0.1) +8 |-_ = Fraction.from_float(-0.5) + 8 |+_ = Fraction(-0.5) +9 9 | _ = Fraction.from_float(5.0) +10 10 | _ = fractions.Fraction.from_float(4.2) +11 11 | _ = Fraction.from_decimal(Decimal("4.2")) + +FURB164.py:9:5: FURB164 [*] Verbose method `from_float` in `Fraction` construction + | + 7 | _ = Fraction.from_float(0.1) + 8 | _ = Fraction.from_float(-0.5) + 9 | _ = Fraction.from_float(5.0) + | ^^^^^^^^^^^^^^^^^^^^^^^^ FURB164 +10 | _ = fractions.Fraction.from_float(4.2) +11 | _ = Fraction.from_decimal(Decimal("4.2")) + | + = help: Replace with `Fraction` constructor + +ℹ Safe fix +6 6 | # Errors +7 7 | _ = Fraction.from_float(0.1) +8 8 | _ = Fraction.from_float(-0.5) +9 |-_ = Fraction.from_float(5.0) + 9 |+_ = Fraction(5.0) +10 10 | _ = fractions.Fraction.from_float(4.2) +11 11 | _ = Fraction.from_decimal(Decimal("4.2")) +12 12 | _ = Fraction.from_decimal(Decimal("-4.2")) + +FURB164.py:10:5: FURB164 [*] Verbose method `from_float` in `Fraction` construction + | + 8 | _ = Fraction.from_float(-0.5) + 9 | _ = Fraction.from_float(5.0) +10 | _ = fractions.Fraction.from_float(4.2) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FURB164 +11 | _ = Fraction.from_decimal(Decimal("4.2")) +12 | _ = Fraction.from_decimal(Decimal("-4.2")) + | + = help: Replace with `Fraction` constructor + +ℹ Safe fix +7 7 | _ = Fraction.from_float(0.1) +8 8 | _ = Fraction.from_float(-0.5) +9 9 | _ = Fraction.from_float(5.0) +10 |-_ = fractions.Fraction.from_float(4.2) + 10 |+_ = fractions.Fraction(4.2) +11 11 | _ = Fraction.from_decimal(Decimal("4.2")) +12 12 | _ = Fraction.from_decimal(Decimal("-4.2")) +13 13 | _ = Fraction.from_decimal(Decimal.from_float(4.2)) + +FURB164.py:11:5: FURB164 [*] Verbose method `from_decimal` in `Fraction` construction + | + 9 | _ = Fraction.from_float(5.0) +10 | _ = fractions.Fraction.from_float(4.2) +11 | _ = Fraction.from_decimal(Decimal("4.2")) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FURB164 +12 | _ = Fraction.from_decimal(Decimal("-4.2")) +13 | _ = Fraction.from_decimal(Decimal.from_float(4.2)) + | + = help: Replace with `Fraction` constructor + +ℹ Safe fix +8 8 | _ = Fraction.from_float(-0.5) +9 9 | _ = Fraction.from_float(5.0) +10 10 | _ = fractions.Fraction.from_float(4.2) +11 |-_ = Fraction.from_decimal(Decimal("4.2")) + 11 |+_ = Fraction(Decimal("4.2")) +12 12 | _ = Fraction.from_decimal(Decimal("-4.2")) +13 13 | _ = Fraction.from_decimal(Decimal.from_float(4.2)) +14 14 | _ = Decimal.from_float(0.1) + +FURB164.py:12:5: FURB164 [*] Verbose method `from_decimal` in `Fraction` construction + | +10 | _ = fractions.Fraction.from_float(4.2) +11 | _ = Fraction.from_decimal(Decimal("4.2")) +12 | _ = Fraction.from_decimal(Decimal("-4.2")) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FURB164 +13 | _ = Fraction.from_decimal(Decimal.from_float(4.2)) +14 | _ = Decimal.from_float(0.1) + | + = help: Replace with `Fraction` constructor + +ℹ Safe fix +9 9 | _ = Fraction.from_float(5.0) +10 10 | _ = fractions.Fraction.from_float(4.2) +11 11 | _ = Fraction.from_decimal(Decimal("4.2")) +12 |-_ = Fraction.from_decimal(Decimal("-4.2")) + 12 |+_ = Fraction(Decimal("-4.2")) +13 13 | _ = Fraction.from_decimal(Decimal.from_float(4.2)) +14 14 | _ = Decimal.from_float(0.1) +15 15 | _ = Decimal.from_float(-0.5) + +FURB164.py:13:5: FURB164 [*] Verbose method `from_decimal` in `Fraction` construction + | +11 | _ = Fraction.from_decimal(Decimal("4.2")) +12 | _ = Fraction.from_decimal(Decimal("-4.2")) +13 | _ = Fraction.from_decimal(Decimal.from_float(4.2)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FURB164 +14 | _ = Decimal.from_float(0.1) +15 | _ = Decimal.from_float(-0.5) + | + = help: Replace with `Fraction` constructor + +ℹ Safe fix +10 10 | _ = fractions.Fraction.from_float(4.2) +11 11 | _ = Fraction.from_decimal(Decimal("4.2")) +12 12 | _ = Fraction.from_decimal(Decimal("-4.2")) +13 |-_ = Fraction.from_decimal(Decimal.from_float(4.2)) + 13 |+_ = Fraction(Decimal.from_float(4.2)) +14 14 | _ = Decimal.from_float(0.1) +15 15 | _ = Decimal.from_float(-0.5) +16 16 | _ = Decimal.from_float(5.0) + +FURB164.py:13:27: FURB164 [*] Verbose method `from_float` in `Decimal` construction + | +11 | _ = Fraction.from_decimal(Decimal("4.2")) +12 | _ = Fraction.from_decimal(Decimal("-4.2")) +13 | _ = Fraction.from_decimal(Decimal.from_float(4.2)) + | ^^^^^^^^^^^^^^^^^^^^^^^ FURB164 +14 | _ = Decimal.from_float(0.1) +15 | _ = Decimal.from_float(-0.5) + | + = help: Replace with `Decimal` constructor + +ℹ Safe fix +10 10 | _ = fractions.Fraction.from_float(4.2) +11 11 | _ = Fraction.from_decimal(Decimal("4.2")) +12 12 | _ = Fraction.from_decimal(Decimal("-4.2")) +13 |-_ = Fraction.from_decimal(Decimal.from_float(4.2)) + 13 |+_ = Fraction.from_decimal(Decimal(4.2)) +14 14 | _ = Decimal.from_float(0.1) +15 15 | _ = Decimal.from_float(-0.5) +16 16 | _ = Decimal.from_float(5.0) + +FURB164.py:14:5: FURB164 [*] Verbose method `from_float` in `Decimal` construction + | +12 | _ = Fraction.from_decimal(Decimal("-4.2")) +13 | _ = Fraction.from_decimal(Decimal.from_float(4.2)) +14 | _ = Decimal.from_float(0.1) + | ^^^^^^^^^^^^^^^^^^^^^^^ FURB164 +15 | _ = Decimal.from_float(-0.5) +16 | _ = Decimal.from_float(5.0) + | + = help: Replace with `Decimal` constructor + +ℹ Safe fix +11 11 | _ = Fraction.from_decimal(Decimal("4.2")) +12 12 | _ = Fraction.from_decimal(Decimal("-4.2")) +13 13 | _ = Fraction.from_decimal(Decimal.from_float(4.2)) +14 |-_ = Decimal.from_float(0.1) + 14 |+_ = Decimal(0.1) +15 15 | _ = Decimal.from_float(-0.5) +16 16 | _ = Decimal.from_float(5.0) +17 17 | _ = decimal.Decimal.from_float(4.2) + +FURB164.py:15:5: FURB164 [*] Verbose method `from_float` in `Decimal` construction + | +13 | _ = Fraction.from_decimal(Decimal.from_float(4.2)) +14 | _ = Decimal.from_float(0.1) +15 | _ = Decimal.from_float(-0.5) + | ^^^^^^^^^^^^^^^^^^^^^^^^ FURB164 +16 | _ = Decimal.from_float(5.0) +17 | _ = decimal.Decimal.from_float(4.2) + | + = help: Replace with `Decimal` constructor + +ℹ Safe fix +12 12 | _ = Fraction.from_decimal(Decimal("-4.2")) +13 13 | _ = Fraction.from_decimal(Decimal.from_float(4.2)) +14 14 | _ = Decimal.from_float(0.1) +15 |-_ = Decimal.from_float(-0.5) + 15 |+_ = Decimal(-0.5) +16 16 | _ = Decimal.from_float(5.0) +17 17 | _ = decimal.Decimal.from_float(4.2) +18 18 | _ = Decimal.from_float(float("inf")) + +FURB164.py:16:5: FURB164 [*] Verbose method `from_float` in `Decimal` construction + | +14 | _ = Decimal.from_float(0.1) +15 | _ = Decimal.from_float(-0.5) +16 | _ = Decimal.from_float(5.0) + | ^^^^^^^^^^^^^^^^^^^^^^^ FURB164 +17 | _ = decimal.Decimal.from_float(4.2) +18 | _ = Decimal.from_float(float("inf")) + | + = help: Replace with `Decimal` constructor + +ℹ Safe fix +13 13 | _ = Fraction.from_decimal(Decimal.from_float(4.2)) +14 14 | _ = Decimal.from_float(0.1) +15 15 | _ = Decimal.from_float(-0.5) +16 |-_ = Decimal.from_float(5.0) + 16 |+_ = Decimal(5.0) +17 17 | _ = decimal.Decimal.from_float(4.2) +18 18 | _ = Decimal.from_float(float("inf")) +19 19 | _ = Decimal.from_float(float("-inf")) + +FURB164.py:17:5: FURB164 [*] Verbose method `from_float` in `Decimal` construction + | +15 | _ = Decimal.from_float(-0.5) +16 | _ = Decimal.from_float(5.0) +17 | _ = decimal.Decimal.from_float(4.2) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FURB164 +18 | _ = Decimal.from_float(float("inf")) +19 | _ = Decimal.from_float(float("-inf")) + | + = help: Replace with `Decimal` constructor + +ℹ Safe fix +14 14 | _ = Decimal.from_float(0.1) +15 15 | _ = Decimal.from_float(-0.5) +16 16 | _ = Decimal.from_float(5.0) +17 |-_ = decimal.Decimal.from_float(4.2) + 17 |+_ = decimal.Decimal(4.2) +18 18 | _ = Decimal.from_float(float("inf")) +19 19 | _ = Decimal.from_float(float("-inf")) +20 20 | _ = Decimal.from_float(float("Infinity")) + +FURB164.py:18:5: FURB164 [*] Verbose method `from_float` in `Decimal` construction + | +16 | _ = Decimal.from_float(5.0) +17 | _ = decimal.Decimal.from_float(4.2) +18 | _ = Decimal.from_float(float("inf")) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FURB164 +19 | _ = Decimal.from_float(float("-inf")) +20 | _ = Decimal.from_float(float("Infinity")) + | + = help: Replace with `Decimal` constructor + +ℹ Safe fix +15 15 | _ = Decimal.from_float(-0.5) +16 16 | _ = Decimal.from_float(5.0) +17 17 | _ = decimal.Decimal.from_float(4.2) +18 |-_ = Decimal.from_float(float("inf")) + 18 |+_ = Decimal("inf") +19 19 | _ = Decimal.from_float(float("-inf")) +20 20 | _ = Decimal.from_float(float("Infinity")) +21 21 | _ = Decimal.from_float(float("-Infinity")) + +FURB164.py:19:5: FURB164 [*] Verbose method `from_float` in `Decimal` construction + | +17 | _ = decimal.Decimal.from_float(4.2) +18 | _ = Decimal.from_float(float("inf")) +19 | _ = Decimal.from_float(float("-inf")) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FURB164 +20 | _ = Decimal.from_float(float("Infinity")) +21 | _ = Decimal.from_float(float("-Infinity")) + | + = help: Replace with `Decimal` constructor + +ℹ Safe fix +16 16 | _ = Decimal.from_float(5.0) +17 17 | _ = decimal.Decimal.from_float(4.2) +18 18 | _ = Decimal.from_float(float("inf")) +19 |-_ = Decimal.from_float(float("-inf")) + 19 |+_ = Decimal("-inf") +20 20 | _ = Decimal.from_float(float("Infinity")) +21 21 | _ = Decimal.from_float(float("-Infinity")) +22 22 | _ = Decimal.from_float(float("nan")) + +FURB164.py:20:5: FURB164 [*] Verbose method `from_float` in `Decimal` construction + | +18 | _ = Decimal.from_float(float("inf")) +19 | _ = Decimal.from_float(float("-inf")) +20 | _ = Decimal.from_float(float("Infinity")) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FURB164 +21 | _ = Decimal.from_float(float("-Infinity")) +22 | _ = Decimal.from_float(float("nan")) + | + = help: Replace with `Decimal` constructor + +ℹ Safe fix +17 17 | _ = decimal.Decimal.from_float(4.2) +18 18 | _ = Decimal.from_float(float("inf")) +19 19 | _ = Decimal.from_float(float("-inf")) +20 |-_ = Decimal.from_float(float("Infinity")) + 20 |+_ = Decimal("Infinity") +21 21 | _ = Decimal.from_float(float("-Infinity")) +22 22 | _ = Decimal.from_float(float("nan")) +23 23 | + +FURB164.py:21:5: FURB164 [*] Verbose method `from_float` in `Decimal` construction + | +19 | _ = Decimal.from_float(float("-inf")) +20 | _ = Decimal.from_float(float("Infinity")) +21 | _ = Decimal.from_float(float("-Infinity")) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FURB164 +22 | _ = Decimal.from_float(float("nan")) + | + = help: Replace with `Decimal` constructor + +ℹ Safe fix +18 18 | _ = Decimal.from_float(float("inf")) +19 19 | _ = Decimal.from_float(float("-inf")) +20 20 | _ = Decimal.from_float(float("Infinity")) +21 |-_ = Decimal.from_float(float("-Infinity")) + 21 |+_ = Decimal("-Infinity") +22 22 | _ = Decimal.from_float(float("nan")) +23 23 | +24 24 | # OK + +FURB164.py:22:5: FURB164 [*] Verbose method `from_float` in `Decimal` construction + | +20 | _ = Decimal.from_float(float("Infinity")) +21 | _ = Decimal.from_float(float("-Infinity")) +22 | _ = Decimal.from_float(float("nan")) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FURB164 +23 | +24 | # OK + | + = help: Replace with `Decimal` constructor + +ℹ Safe fix +19 19 | _ = Decimal.from_float(float("-inf")) +20 20 | _ = Decimal.from_float(float("Infinity")) +21 21 | _ = Decimal.from_float(float("-Infinity")) +22 |-_ = Decimal.from_float(float("nan")) + 22 |+_ = Decimal("nan") +23 23 | +24 24 | # OK +25 25 | _ = Fraction(0.1) diff --git a/ruff.schema.json b/ruff.schema.json index e335f7b5567f1..2858f60029dd4 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -3062,6 +3062,7 @@ "FURB16", "FURB161", "FURB163", + "FURB164", "FURB167", "FURB168", "FURB169",