Fixes #18869: Ensure to_meters() always returns a clean decimal value (#18883)

* Fixes #18869: Ensure to_meters() always returns a clean decimal value

* Handle float values
This commit is contained in:
Jeremy Stretch 2025-03-12 14:42:38 -04:00 committed by GitHub
parent 749a83d742
commit 092f7549ca
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 66 additions and 12 deletions

View File

@ -1,4 +1,4 @@
from decimal import Decimal from decimal import Decimal, InvalidOperation
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
@ -37,28 +37,29 @@ def to_grams(weight, unit) -> int:
) )
def to_meters(length, unit): def to_meters(length, unit) -> Decimal:
""" """
Convert the given length to meters. Convert the given length to meters, returning a Decimal value.
""" """
try: try:
if length < 0: length = Decimal(length)
raise ValueError(_("Length must be a positive number")) except InvalidOperation:
except TypeError:
raise TypeError(_("Invalid value '{length}' for length (must be a number)").format(length=length)) raise TypeError(_("Invalid value '{length}' for length (must be a number)").format(length=length))
if length < 0:
raise ValueError(_("Length must be a positive number"))
if unit == CableLengthUnitChoices.UNIT_KILOMETER: if unit == CableLengthUnitChoices.UNIT_KILOMETER:
return length * 1000 return round(Decimal(length * 1000), 4)
if unit == CableLengthUnitChoices.UNIT_METER: if unit == CableLengthUnitChoices.UNIT_METER:
return length return round(Decimal(length), 4)
if unit == CableLengthUnitChoices.UNIT_CENTIMETER: if unit == CableLengthUnitChoices.UNIT_CENTIMETER:
return length / 100 return round(Decimal(length / 100), 4)
if unit == CableLengthUnitChoices.UNIT_MILE: if unit == CableLengthUnitChoices.UNIT_MILE:
return length * Decimal(1609.344) return round(length * Decimal(1609.344), 4)
if unit == CableLengthUnitChoices.UNIT_FOOT: if unit == CableLengthUnitChoices.UNIT_FOOT:
return length * Decimal(0.3048) return round(length * Decimal(0.3048), 4)
if unit == CableLengthUnitChoices.UNIT_INCH: if unit == CableLengthUnitChoices.UNIT_INCH:
return length * Decimal(0.0254) return round(length * Decimal(0.0254), 4)
raise ValueError( raise ValueError(
_("Unknown unit {unit}. Must be one of the following: {valid_units}").format( _("Unknown unit {unit}. Must be one of the following: {valid_units}").format(
unit=unit, unit=unit,

View File

@ -0,0 +1,53 @@
from decimal import Decimal
from dcim.choices import CableLengthUnitChoices
from netbox.choices import WeightUnitChoices
from utilities.conversion import to_grams, to_meters
from utilities.testing.base import TestCase
class ConversionsTest(TestCase):
def test_to_grams(self):
self.assertEqual(
to_grams(1, WeightUnitChoices.UNIT_KILOGRAM),
1000
)
self.assertEqual(
to_grams(1, WeightUnitChoices.UNIT_GRAM),
1
)
self.assertEqual(
to_grams(1, WeightUnitChoices.UNIT_POUND),
453
)
self.assertEqual(
to_grams(1, WeightUnitChoices.UNIT_OUNCE),
28
)
def test_to_meters(self):
self.assertEqual(
to_meters(1.5, CableLengthUnitChoices.UNIT_KILOMETER),
Decimal('1500')
)
self.assertEqual(
to_meters(1, CableLengthUnitChoices.UNIT_METER),
Decimal('1')
)
self.assertEqual(
to_meters(1, CableLengthUnitChoices.UNIT_CENTIMETER),
Decimal('0.01')
)
self.assertEqual(
to_meters(1, CableLengthUnitChoices.UNIT_MILE),
Decimal('1609.344')
)
self.assertEqual(
to_meters(1, CableLengthUnitChoices.UNIT_FOOT),
Decimal('0.3048')
)
self.assertEqual(
to_meters(1, CableLengthUnitChoices.UNIT_INCH),
Decimal('0.0254')
)