Skip to content

Commit ace9abd

Browse files
committed
Merge branch '28-empty-composite-dimension'
2 parents be68cd1 + 579836c commit ace9abd

File tree

4 files changed

+78
-3
lines changed

4 files changed

+78
-3
lines changed

src/property_utils/properties/property.py

+15-3
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ def __mul__(self, other) -> "Property":
217217
if isinstance(other, Property):
218218
_other = self._unit_preconversion(other)
219219
return Property(
220-
self.value * _other.value, (self.unit * _other.unit).simplified()
220+
self.value * _other.value, self._simplify_units(self.unit * _other.unit)
221221
)
222222
raise PropertyBinaryOperationError(
223223
f"cannot multiply {self} with {other}; "
@@ -268,7 +268,7 @@ def __truediv__(self, other) -> "Property":
268268
raise PropertyBinaryOperationError(
269269
f"cannot divide {self} with {other}; denominator's value is zero. "
270270
) from None
271-
return Property(value, (self.unit / _other.unit).simplified())
271+
return Property(value, self._simplify_units(self.unit / _other.unit))
272272
raise PropertyBinaryOperationError(
273273
f"cannot divide {self} with {other}; "
274274
"denominator must be numeric or Property. "
@@ -299,7 +299,7 @@ def __rtruediv__(self, other) -> "Property":
299299
raise PropertyBinaryOperationError(
300300
f"cannot divide {self} with {other}; denominator's value is zero. "
301301
) from None
302-
return Property(value, (other.unit / self.unit).simplified())
302+
return Property(value, self._simplify_units(other.unit / self.unit))
303303
raise PropertyBinaryOperationError(
304304
f"cannot divide {self} with {other}; "
305305
"numerator must be numeric or Property. "
@@ -727,3 +727,15 @@ def _simple_unit_preconversion(self, unit: MeasurementUnit) -> MeasurementUnit:
727727
multiplication or division with this property.
728728
"""
729729
return self._dimension_unit_preconversion(unit**1).unit
730+
731+
def _simplify_units(self, unit: CompositeDimension) -> UnitDescriptor:
732+
"""
733+
Simplifies the composite dimension and returns NON_DIMENSIONAL if the simplified
734+
composite does not have units.
735+
"""
736+
unit = unit.simplified()
737+
738+
if unit.has_no_units():
739+
return NonDimensionalUnit.NON_DIMENSIONAL
740+
741+
return unit

src/property_utils/tests/properties/test_property.py

+12
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,10 @@ def test_with_exponentiated_property(self):
346346
def test_with_inverse_property(self):
347347
self.assert_result("10.4 ")
348348

349+
@args({"other": Property(2, Unit1.A ** (-1))})
350+
def test_produced_units_with_inverse_property(self):
351+
self.assertEqual(self.result().unit, NonDimensionalUnit.NON_DIMENSIONAL)
352+
349353
@args({"other": Property(4, Unit2.B)})
350354
def test_with_other_propperty(self):
351355
self.assert_result("20.8 A * B")
@@ -499,6 +503,10 @@ def test_with_exponentiated_property(self):
499503
def test_with_same_property(self):
500504
self.assert_result("3.0 ")
501505

506+
@args({"other": Property(2, Unit1.A)})
507+
def test_produced_units_with_same_property(self):
508+
self.assertEqual(self.result().unit, NonDimensionalUnit.NON_DIMENSIONAL)
509+
502510
@args({"other": Property(2, Unit2.B)})
503511
def test_with_other_propperty(self):
504512
self.assert_result("3.0 A / B")
@@ -639,6 +647,10 @@ def test_with_exponentiated_property(self):
639647
def test_with_same_property(self):
640648
self.assert_result("0.2 ")
641649

650+
@args({"other": Property(2, Unit1.A)})
651+
def test_produced_units_with_same_property(self):
652+
self.assertEqual(self.result().unit, NonDimensionalUnit.NON_DIMENSIONAL)
653+
642654
@args({"other": Property(2, Unit2.B)})
643655
def test_with_other_propperty(self):
644656
self.assert_result("0.2 B / A")

src/property_utils/tests/units/test_descriptors.py

+21
Original file line numberDiff line numberDiff line change
@@ -2006,6 +2006,14 @@ def test_with_aliased_denominator_composite_dimension(self):
20062006
def test_with_fully_aliased_composite_dimension(self):
20072007
self.assertResultTrue()
20082008

2009+
@add_to(GenericCompositeDimension_test_suite)
2010+
class TestGenericCompositeDimensionHasNoUnits(TestDescriptor):
2011+
def test_with_measurement_units(self):
2012+
self.assertFalse(generic_composite_dimension().has_no_units())
2013+
2014+
def test_with_no_measurement_units(self):
2015+
self.assertTrue(GenericCompositeDimension().has_no_units())
2016+
20092017

20102018
@add_to(CompositeDimension_test_suite)
20112019
class TestCompositeDimensionFromDescriptor(TestDescriptor):
@@ -2568,6 +2576,19 @@ def test_objects_are_not_persisted(self):
25682576
self.assertNotEqual(ids(composite.numerator), ids(inverse.denominator))
25692577
self.assertNotEqual(ids(composite.denominator), ids(inverse.numerator))
25702578

2579+
@add_to(CompositeDimension_test_suite)
2580+
class TestCompositeDimensionHasNoUnits(TestDescriptor):
2581+
def test_with_units(self):
2582+
self.assertFalse(composite_dimension().has_no_units())
2583+
2584+
def test_with_no_units(self):
2585+
self.assertTrue(CompositeDimension().has_no_units())
2586+
2587+
def test_with_same_unit_type(self):
2588+
self.assertFalse(CompositeDimension([Unit1.A],[Unit1.a]).has_no_units())
2589+
2590+
def test_with_same_unit(self):
2591+
self.assertFalse(CompositeDimension([Unit1.A],[Unit1.A]).has_no_units())
25712592

25722593
@add_to(CompositeDimension_test_suite)
25732594
class TestCompositeDimensionMultiplication(TestDescriptorBinaryOperation):

src/property_utils/units/descriptors.py

+30
Original file line numberDiff line numberDiff line change
@@ -1314,6 +1314,21 @@ def is_equivalent(self, other: GenericUnitDescriptor) -> bool:
13141314

13151315
return False
13161316

1317+
def has_no_units(self) -> bool:
1318+
"""
1319+
Returns True if the generic composite dimension does not have any units, False
1320+
otherwise.
1321+
1322+
Examples:
1323+
>>> class LengthUnit(MeasurementUnit): ...
1324+
1325+
>>> GenericCompositeDimension().has_no_units()
1326+
True
1327+
>>> GenericCompositeDimension([LengthUnit]).has_no_units()
1328+
False
1329+
"""
1330+
return len(self.denominator) == 0 and len(self.numerator) == 0
1331+
13171332
def _numerator_copy(self) -> List[GenericDimension]:
13181333
return [replace(n) for n in self.numerator]
13191334

@@ -1743,6 +1758,21 @@ def inverse(self) -> "CompositeDimension":
17431758
"""
17441759
return CompositeDimension(self._denominator_copy(), self._numerator_copy())
17451760

1761+
def has_no_units(self) -> bool:
1762+
"""
1763+
Returns True if the composite dimension does not have any units, False otherwise.
1764+
1765+
Examples:
1766+
>>> class LengthUnit(MeasurementUnit):
1767+
... METER = "m"
1768+
1769+
>>> CompositeDimension().has_no_units()
1770+
True
1771+
>>> CompositeDimension([LengthUnit.METER]).has_no_units()
1772+
False
1773+
"""
1774+
return len(self.denominator) == 0 and len(self.numerator) == 0
1775+
17461776
def _numerator_copy(self) -> List[Dimension]:
17471777
return [replace(n) for n in self.numerator]
17481778

0 commit comments

Comments
 (0)