diff --git a/converters/index.html b/converters/index.html index ef1f96f..6cf9d41 100644 --- a/converters/index.html +++ b/converters/index.html @@ -823,6 +823,15 @@ + + +
  • + + + NonDimensionalUnitConverter + + +
  • @@ -1098,6 +1107,15 @@ +
  • + +
  • + + + NonDimensionalUnitConverter + + +
  • @@ -1236,7 +1254,8 @@

    Source code in src/property_utils/units/converters.py -
    123
    +                
    122
    +123
     124
     125
     126
    @@ -1267,40 +1286,39 @@ 

    151 152 153 -154 -155

    @register_converter(AbsoluteTemperatureUnit)
    -class AbsoluteTemperatureUnitConverter(AbsoluteUnitConverter):
    -    """
    -    Convert absolute temperature with this converter.
    -
    -    Examples:
    -        >>> AbsoluteTemperatureUnitConverter.convert(10, AbsoluteTemperatureUnit.KELVIN, AbsoluteTemperatureUnit.RANKINE)
    -        18.0
    -    """
    -
    -    reference_unit = AbsoluteTemperatureUnit.KELVIN
    -    conversion_map = {
    -        AbsoluteTemperatureUnit.KELVIN: 1,
    -        AbsoluteTemperatureUnit.RANKINE: 1.8,
    -    }
    -
    -    @override
    -    @classmethod
    -    def convert(
    -        cls,
    -        value: float,
    -        from_descriptor: UnitDescriptor,
    -        to_descriptor: UnitDescriptor,
    -    ) -> float:
    -        if not isinstance(value, (float, int)):
    -            raise UnitConversionError(f"invalid 'value': {value}; expected numeric. ")
    -        if from_descriptor.isinstance(
    -            RelativeTemperatureUnit
    -        ) or to_descriptor.isinstance(RelativeTemperatureUnit):
    -            return RelativeTemperatureUnitConverter.convert(
    -                value, from_descriptor, to_descriptor
    -            )
    -        return value * cls.get_factor(from_descriptor, to_descriptor)
    +154
    @register_converter(AbsoluteTemperatureUnit)
    +class AbsoluteTemperatureUnitConverter(AbsoluteUnitConverter):
    +    """
    +    Convert absolute temperature with this converter.
    +
    +    Examples:
    +        >>> AbsoluteTemperatureUnitConverter.convert(10, AbsoluteTemperatureUnit.KELVIN, AbsoluteTemperatureUnit.RANKINE)
    +        18.0
    +    """
    +
    +    reference_unit = AbsoluteTemperatureUnit.KELVIN
    +    conversion_map = {
    +        AbsoluteTemperatureUnit.KELVIN: 1,
    +        AbsoluteTemperatureUnit.RANKINE: 1.8,
    +    }
    +
    +    @override
    +    @classmethod
    +    def convert(
    +        cls,
    +        value: float,
    +        from_descriptor: UnitDescriptor,
    +        to_descriptor: UnitDescriptor,
    +    ) -> float:
    +        if not isinstance(value, (float, int)):
    +            raise UnitConversionError(f"invalid 'value': {value}; expected numeric. ")
    +        if from_descriptor.isinstance(
    +            RelativeTemperatureUnit
    +        ) or to_descriptor.isinstance(RelativeTemperatureUnit):
    +            return RelativeTemperatureUnitConverter.convert(
    +                value, from_descriptor, to_descriptor
    +            )
    +        return value * cls.get_factor(from_descriptor, to_descriptor)
     
    @@ -1350,17 +1368,7 @@

    Source code in src/property_utils/units/converters.py -
    292
    -293
    -294
    -295
    -296
    -297
    -298
    -299
    -300
    -301
    -302
    +                
    302
     303
     304
     305
    @@ -1372,29 +1380,39 @@ 

    311 312 313 -314

    @register_converter(EnergyUnit)
    -class AliasEnergyUnitConverter(AbsoluteUnitConverter):
    -    """
    -    Convert energy units with this converter.
    -
    -    Examples:
    -        >>> AliasEnergyUnitConverter.convert(2500, EnergyUnit.JOULE, EnergyUnit.KILO_JOULE)
    -        2.5
    -    """
    -
    -    reference_unit = EnergyUnit.JOULE
    -    conversion_map = {
    -        EnergyUnit.JOULE: 1,
    -        EnergyUnit.KILO_JOULE: UnitPrefix.KILO.inverse(),
    -        EnergyUnit.MEGA_JOULE: UnitPrefix.MEGA.inverse(),
    -        EnergyUnit.GIGA_JOULE: UnitPrefix.GIGA.inverse(),
    -        EnergyUnit.CALORIE: 1 / 4.184,
    -        EnergyUnit.KILO_CALORIE: (1 / 4.184) * UnitPrefix.KILO.inverse(),
    -        EnergyUnit.BTU: 1 / 1055.0,
    -        EnergyUnit.ELECTRONVOLT: 6.242e18,
    -        EnergyUnit.WATTHOUR: 1 / 3600,
    -        EnergyUnit.KILO_WATTHOUR: (1 / 3600) * UnitPrefix.KILO.inverse(),
    -    }
    +314
    +315
    +316
    +317
    +318
    +319
    +320
    +321
    +322
    +323
    +324
    @register_converter(EnergyUnit)
    +class AliasEnergyUnitConverter(AbsoluteUnitConverter):
    +    """
    +    Convert energy units with this converter.
    +
    +    Examples:
    +        >>> AliasEnergyUnitConverter.convert(2500, EnergyUnit.JOULE, EnergyUnit.KILO_JOULE)
    +        2.5
    +    """
    +
    +    reference_unit = EnergyUnit.JOULE
    +    conversion_map = {
    +        EnergyUnit.JOULE: 1,
    +        EnergyUnit.KILO_JOULE: UnitPrefix.KILO.inverse(),
    +        EnergyUnit.MEGA_JOULE: UnitPrefix.MEGA.inverse(),
    +        EnergyUnit.GIGA_JOULE: UnitPrefix.GIGA.inverse(),
    +        EnergyUnit.CALORIE: 1 / 4.184,
    +        EnergyUnit.KILO_CALORIE: (1 / 4.184) * UnitPrefix.KILO.inverse(),
    +        EnergyUnit.BTU: 1 / 1055.0,
    +        EnergyUnit.ELECTRONVOLT: 6.242e18,
    +        EnergyUnit.WATTHOUR: 1 / 3600,
    +        EnergyUnit.KILO_WATTHOUR: (1 / 3600) * UnitPrefix.KILO.inverse(),
    +    }
     
    @@ -1444,29 +1462,29 @@

    Source code in src/property_utils/units/converters.py -
    @register_converter(ForceUnit)
    -class AliasForceUnitConverter(AbsoluteUnitConverter):
    -    """
    -    Convert force units with this converter.
    -
    -    Examples:
    -        >>> AliasForceUnitConverter.convert(2, ForceUnit.NEWTON, ForceUnit.DYNE)
    -        200000.0
    -    """
    -
    -    reference_unit = ForceUnit.NEWTON
    -    conversion_map = {ForceUnit.NEWTON: 1, ForceUnit.DYNE: 100_000}
    +                
    @register_converter(ForceUnit)
    +class AliasForceUnitConverter(AbsoluteUnitConverter):
    +    """
    +    Convert force units with this converter.
    +
    +    Examples:
    +        >>> AliasForceUnitConverter.convert(2, ForceUnit.NEWTON, ForceUnit.DYNE)
    +        200000.0
    +    """
    +
    +    reference_unit = ForceUnit.NEWTON
    +    conversion_map = {ForceUnit.NEWTON: 1, ForceUnit.DYNE: 100_000}
     
    @@ -1516,39 +1534,39 @@

    Source code in src/property_utils/units/converters.py -
    317
    -318
    -319
    -320
    -321
    -322
    -323
    -324
    -325
    -326
    -327
    +                
    @register_converter(PowerUnit)
    -class AliasPowerUnitConverter(AbsoluteUnitConverter):
    -    """
    -    Convert power units with this converter.
    -
    -    Examples:
    -        >>> AliasPowerUnitConverter.convert(5, PowerUnit.KILO_WATT, PowerUnit.WATT)
    -        5000.0
    -    """
    -
    -    reference_unit = PowerUnit.WATT
    -    conversion_map = {
    -        PowerUnit.WATT: 1,
    -        PowerUnit.KILO_WATT: UnitPrefix.KILO.inverse(),
    -        PowerUnit.MEGA_WATT: UnitPrefix.MEGA.inverse(),
    -        PowerUnit.GIGA_WATT: UnitPrefix.GIGA.inverse(),
    -    }
    +333
    +334
    +335
    +336
    +337
    +338
    +339
    +340
    +341
    +342
    +343
    @register_converter(PowerUnit)
    +class AliasPowerUnitConverter(AbsoluteUnitConverter):
    +    """
    +    Convert power units with this converter.
    +
    +    Examples:
    +        >>> AliasPowerUnitConverter.convert(5, PowerUnit.KILO_WATT, PowerUnit.WATT)
    +        5000.0
    +    """
    +
    +    reference_unit = PowerUnit.WATT
    +    conversion_map = {
    +        PowerUnit.WATT: 1,
    +        PowerUnit.KILO_WATT: UnitPrefix.KILO.inverse(),
    +        PowerUnit.MEGA_WATT: UnitPrefix.MEGA.inverse(),
    +        PowerUnit.GIGA_WATT: UnitPrefix.GIGA.inverse(),
    +    }
     
    @@ -1598,17 +1616,7 @@

    Source code in src/property_utils/units/converters.py -
    271
    -272
    -273
    -274
    -275
    -276
    -277
    -278
    -279
    -280
    -281
    +                
    281
     282
     283
     284
    @@ -1616,25 +1624,35 @@ 

    286 287 288 -289

    @register_converter(PressureUnit)
    -class AliasPressureUnitConverter(AbsoluteUnitConverter):
    -    """
    -    Convert pressure units with this converter.
    -
    -    Examples:
    -        >>> AliasPressureUnitConverter.convert(2, PressureUnit.BAR, PressureUnit.KILO_PASCAL)
    -        200.0
    -    """
    -
    -    reference_unit = PressureUnit.BAR
    -    conversion_map = {
    -        PressureUnit.MILLI_BAR: UnitPrefix.MILLI.inverse(),
    -        PressureUnit.BAR: 1,
    -        PressureUnit.PSI: 14.5038,
    -        PressureUnit.PASCAL: 100_000,
    -        PressureUnit.KILO_PASCAL: 100,
    -        PressureUnit.MEGA_PASCAL: 0.1,
    -    }
    +289
    +290
    +291
    +292
    +293
    +294
    +295
    +296
    +297
    +298
    +299
    @register_converter(PressureUnit)
    +class AliasPressureUnitConverter(AbsoluteUnitConverter):
    +    """
    +    Convert pressure units with this converter.
    +
    +    Examples:
    +        >>> AliasPressureUnitConverter.convert(2, PressureUnit.BAR, PressureUnit.KILO_PASCAL)
    +        200.0
    +    """
    +
    +    reference_unit = PressureUnit.BAR
    +    conversion_map = {
    +        PressureUnit.MILLI_BAR: UnitPrefix.MILLI.inverse(),
    +        PressureUnit.BAR: 1,
    +        PressureUnit.PSI: 14.5038,
    +        PressureUnit.PASCAL: 100_000,
    +        PressureUnit.KILO_PASCAL: 100,
    +        PressureUnit.MEGA_PASCAL: 0.1,
    +    }
     
    @@ -1684,29 +1702,29 @@

    Source code in src/property_utils/units/converters.py -
    @register_converter(AmountUnit)
    -class AmountUnitConverter(AbsoluteUnitConverter):
    -    """
    -    Convert amount units with this converter.
    -
    -    Examples:
    -        >>> AmountUnitConverter.convert(2000, AmountUnit.MOL, AmountUnit.KILO_MOL)
    -        2.0
    -    """
    -
    -    reference_unit = AmountUnit.MOL
    -    conversion_map = {AmountUnit.MOL: 1, AmountUnit.KILO_MOL: UnitPrefix.KILO.inverse()}
    +                
    @register_converter(AmountUnit)
    +class AmountUnitConverter(AbsoluteUnitConverter):
    +    """
    +    Convert amount units with this converter.
    +
    +    Examples:
    +        >>> AmountUnitConverter.convert(2000, AmountUnit.MOL, AmountUnit.KILO_MOL)
    +        2.0
    +    """
    +
    +    reference_unit = AmountUnit.MOL
    +    conversion_map = {AmountUnit.MOL: 1, AmountUnit.KILO_MOL: UnitPrefix.KILO.inverse()}
     
    @@ -1756,23 +1774,23 @@

    Source code in src/property_utils/units/converters.py -
    @register_converter(LengthUnit**2)
    -class AreaUnitConverter(ExponentiatedUnitConverter):
    -    """
    -    Convert area units with this converter.
    -
    -    Examples:
    -        >>> AreaUnitConverter.convert(1, LengthUnit.METER**2, LengthUnit.CENTI_METER**2)
    -        10000.0
    -    """
    +                
    @register_converter(LengthUnit**2)
    +class AreaUnitConverter(ExponentiatedUnitConverter):
    +    """
    +    Convert area units with this converter.
    +
    +    Examples:
    +        >>> AreaUnitConverter.convert(1, LengthUnit.METER**2, LengthUnit.CENTI_METER**2)
    +        10000.0
    +    """
     
    @@ -1822,37 +1840,37 @@

    Source code in src/property_utils/units/converters.py -
    239
    -240
    -241
    -242
    -243
    -244
    -245
    -246
    -247
    -248
    -249
    +                
    @register_converter(ElectricCurrentUnit)
    -class ElectricCurrentUnitConverter(AbsoluteUnitConverter):
    -    """
    -    Convert electric current units with this converter.
    -
    -    Examples:
    -        >>> ElectricCurrentUnitConverter.convert(1000, ElectricCurrentUnit.MILLI_AMPERE, ElectricCurrentUnit.AMPERE)
    -        1.0
    -    """
    -
    -    reference_unit = ElectricCurrentUnit.AMPERE
    -    conversion_map = {
    -        ElectricCurrentUnit.MILLI_AMPERE: UnitPrefix.MILLI.inverse(),
    -        ElectricCurrentUnit.AMPERE: 1,
    -        ElectricCurrentUnit.KILO_AMPERE: UnitPrefix.KILO.inverse(),
    -    }
    +254
    +255
    +256
    +257
    +258
    +259
    +260
    +261
    +262
    +263
    +264
    @register_converter(ElectricCurrentUnit)
    +class ElectricCurrentUnitConverter(AbsoluteUnitConverter):
    +    """
    +    Convert electric current units with this converter.
    +
    +    Examples:
    +        >>> ElectricCurrentUnitConverter.convert(1000, ElectricCurrentUnit.MILLI_AMPERE, ElectricCurrentUnit.AMPERE)
    +        1.0
    +    """
    +
    +    reference_unit = ElectricCurrentUnit.AMPERE
    +    conversion_map = {
    +        ElectricCurrentUnit.MILLI_AMPERE: UnitPrefix.MILLI.inverse(),
    +        ElectricCurrentUnit.AMPERE: 1,
    +        ElectricCurrentUnit.KILO_AMPERE: UnitPrefix.KILO.inverse(),
    +    }
     
    @@ -1904,27 +1922,27 @@

    Source code in src/property_utils/units/converters.py -
    @register_converter(EnergyUnit.aliased_generic_descriptor())
    -class EnergyUnitConverter(CompositeUnitConverter):
    -    """
    -    Convert energy units (mass * length^2 / time^2) with this converter.
    -
    -    Examples:
    -        >>> from_unit = MassUnit.KILO_GRAM * (LengthUnit.METER**2) / (TimeUnit.MINUTE**2)
    -        >>> to_unit = MassUnit.METRIC_TONNE * (LengthUnit.CENTI_METER**2) / (TimeUnit.MINUTE**2)
    -        >>> EnergyUnitConverter.convert(25, from_unit, to_unit)
    -        250.0
    -    """
    +                
    @register_converter(EnergyUnit.aliased_generic_descriptor())
    +class EnergyUnitConverter(CompositeUnitConverter):
    +    """
    +    Convert energy units (mass * length^2 / time^2) with this converter.
    +
    +    Examples:
    +        >>> from_unit = MassUnit.KILO_GRAM * (LengthUnit.METER**2) / (TimeUnit.MINUTE**2)
    +        >>> to_unit = MassUnit.METRIC_TONNE * (LengthUnit.CENTI_METER**2) / (TimeUnit.MINUTE**2)
    +        >>> EnergyUnitConverter.convert(25, from_unit, to_unit)
    +        250.0
    +    """
     
    @@ -1976,27 +1994,27 @@

    Source code in src/property_utils/units/converters.py -
    @register_converter(ForceUnit.aliased_generic_descriptor())
    -class ForceUnitConverter(CompositeUnitConverter):
    -    """
    -    Convert force units (mass * length / time^2) with this converter.
    -
    -    Examples:
    -        >>> from_unit = MassUnit.KILO_GRAM * LengthUnit.CENTI_METER / (TimeUnit.SECOND**2)
    -        >>> to_unit = MassUnit.GRAM * LengthUnit.METER / (TimeUnit.SECOND**2)
    -        >>> ForceUnitConverter.convert(100, from_unit, to_unit)
    -        1000.0
    -    """
    +                
    @register_converter(ForceUnit.aliased_generic_descriptor())
    +class ForceUnitConverter(CompositeUnitConverter):
    +    """
    +    Convert force units (mass * length / time^2) with this converter.
    +
    +    Examples:
    +        >>> from_unit = MassUnit.KILO_GRAM * LengthUnit.CENTI_METER / (TimeUnit.SECOND**2)
    +        >>> to_unit = MassUnit.GRAM * LengthUnit.METER / (TimeUnit.SECOND**2)
    +        >>> ForceUnitConverter.convert(100, from_unit, to_unit)
    +        1000.0
    +    """
     
    @@ -2046,17 +2064,7 @@

    Source code in src/property_utils/units/converters.py -
    158
    -159
    -160
    -161
    -162
    -163
    -164
    -165
    -166
    -167
    -168
    +                
    168
     169
     170
     171
    @@ -2067,28 +2075,38 @@ 

    176 177 178 -179

    @register_converter(LengthUnit)
    -class LengthUnitConverter(AbsoluteUnitConverter):
    -    """
    -    Convert length units with this converter.
    -
    -    Examples:
    -        >>> LengthUnitConverter.convert(2000, LengthUnit.MILLI_METER, LengthUnit.METER)
    -        2.0
    -    """
    -
    -    reference_unit = LengthUnit.METER
    -    conversion_map = {
    -        LengthUnit.MILLI_METER: UnitPrefix.MILLI.inverse(),
    -        LengthUnit.CENTI_METER: UnitPrefix.CENTI.inverse(),
    -        LengthUnit.METER: 1,
    -        LengthUnit.KILO_METER: UnitPrefix.KILO.inverse(),
    -        LengthUnit.INCH: 39.37,
    -        LengthUnit.FOOT: 3.281,
    -        LengthUnit.YARD: 1.094,
    -        LengthUnit.MILE: 1 / 1609,
    -        LengthUnit.NAUTICAL_MILE: 1 / 1852,
    -    }
    +179
    +180
    +181
    +182
    +183
    +184
    +185
    +186
    +187
    +188
    +189
    @register_converter(LengthUnit)
    +class LengthUnitConverter(AbsoluteUnitConverter):
    +    """
    +    Convert length units with this converter.
    +
    +    Examples:
    +        >>> LengthUnitConverter.convert(2000, LengthUnit.MILLI_METER, LengthUnit.METER)
    +        2.0
    +    """
    +
    +    reference_unit = LengthUnit.METER
    +    conversion_map = {
    +        LengthUnit.MILLI_METER: UnitPrefix.MILLI.inverse(),
    +        LengthUnit.CENTI_METER: UnitPrefix.CENTI.inverse(),
    +        LengthUnit.METER: 1,
    +        LengthUnit.KILO_METER: UnitPrefix.KILO.inverse(),
    +        LengthUnit.INCH: 39.37,
    +        LengthUnit.FOOT: 3.281,
    +        LengthUnit.YARD: 1.094,
    +        LengthUnit.MILE: 1 / 1609,
    +        LengthUnit.NAUTICAL_MILE: 1 / 1852,
    +    }
     
    @@ -2138,41 +2156,102 @@

    Source code in src/property_utils/units/converters.py -
    182
    -183
    -184
    -185
    -186
    -187
    -188
    -189
    -190
    -191
    -192
    +                
    @register_converter(MassUnit)
    -class MassUnitConverter(AbsoluteUnitConverter):
    -    """
    -    Convert mass units with this converter.
    -
    -    Examples:
    -        >>> MassUnitConverter.convert(10, MassUnit.KILO_GRAM, MassUnit.GRAM)
    -        10000.0
    -    """
    -
    -    reference_unit = MassUnit.KILO_GRAM
    -    conversion_map = {
    -        MassUnit.MILLI_GRAM: UnitPrefix.KILO * UnitPrefix.MILLI.inverse(),
    -        MassUnit.GRAM: UnitPrefix.KILO,
    -        MassUnit.KILO_GRAM: 1,
    -        MassUnit.METRIC_TONNE: 1 / 1_000.0,
    -        MassUnit.POUND: 2.205,
    -    }
    +199
    +200
    +201
    +202
    +203
    +204
    +205
    +206
    +207
    +208
    +209
    @register_converter(MassUnit)
    +class MassUnitConverter(AbsoluteUnitConverter):
    +    """
    +    Convert mass units with this converter.
    +
    +    Examples:
    +        >>> MassUnitConverter.convert(10, MassUnit.KILO_GRAM, MassUnit.GRAM)
    +        10000.0
    +    """
    +
    +    reference_unit = MassUnit.KILO_GRAM
    +    conversion_map = {
    +        MassUnit.MILLI_GRAM: UnitPrefix.KILO * UnitPrefix.MILLI.inverse(),
    +        MassUnit.GRAM: UnitPrefix.KILO,
    +        MassUnit.KILO_GRAM: 1,
    +        MassUnit.METRIC_TONNE: 1 / 1_000.0,
    +        MassUnit.POUND: 2.205,
    +    }
    +
    + + + + +
    + + + + + + + + + + + +
    + +
    + + + +
    + + + +

    + NonDimensionalUnitConverter + + +

    + + +
    +

    + Bases: AbsoluteUnitConverter

    + + +

    This converter is needed for compatibility, i.e. for conversions to work from +non-dimensional units to non-dimensional dimensions.

    + +
    + Source code in src/property_utils/units/converters.py +
    @register_converter(NonDimensionalUnit)
    +class NonDimensionalUnitConverter(AbsoluteUnitConverter):
    +    """
    +    This converter is needed for compatibility, i.e. for conversions to work from
    +    non-dimensional units to non-dimensional dimensions.
    +    """
    +
    +    reference_unit = NonDimensionalUnit.NON_DIMENSIONAL
    +    conversion_map = {NonDimensionalUnit.NON_DIMENSIONAL: 1}
     
    @@ -2224,27 +2303,27 @@

    Source code in src/property_utils/units/converters.py -
    @register_converter(PowerUnit.aliased_generic_descriptor())
    -class PowerUnitConverter(CompositeUnitConverter):
    -    """
    -    Convert power units (mass * length^2 / time^3) with this converter.
    -
    -    Examples:
    -        >>> from_unit = MassUnit.KILO_GRAM * (LengthUnit.METER**2) / (TimeUnit.MINUTE**3)
    -        >>> to_unit = MassUnit.METRIC_TONNE * (LengthUnit.CENTI_METER**2) / (TimeUnit.MINUTE**3)
    -        >>> PowerUnitConverter.convert(15, from_unit, to_unit)
    -        150.0
    -    """
    +                
    @register_converter(PowerUnit.aliased_generic_descriptor())
    +class PowerUnitConverter(CompositeUnitConverter):
    +    """
    +    Convert power units (mass * length^2 / time^3) with this converter.
    +
    +    Examples:
    +        >>> from_unit = MassUnit.KILO_GRAM * (LengthUnit.METER**2) / (TimeUnit.MINUTE**3)
    +        >>> to_unit = MassUnit.METRIC_TONNE * (LengthUnit.CENTI_METER**2) / (TimeUnit.MINUTE**3)
    +        >>> PowerUnitConverter.convert(15, from_unit, to_unit)
    +        150.0
    +    """
     
    @@ -2296,27 +2375,27 @@

    Source code in src/property_utils/units/converters.py -
    @register_converter(PressureUnit.aliased_generic_descriptor())
    -class PressureUnitConverter(CompositeUnitConverter):
    -    """
    -    Convert pressure units (mass / length / time^2) with this converter.
    -
    -    Examples:
    -        >>> from_unit = MassUnit.GRAM / LengthUnit.CENTI_METER / (TimeUnit.HOUR**2)
    -        >>> to_unit = MassUnit.KILO_GRAM / LengthUnit.METER / (TimeUnit.HOUR**2)
    -        >>> PressureUnitConverter.convert(50, from_unit, to_unit)
    -        5.0
    -    """
    +                
    @register_converter(PressureUnit.aliased_generic_descriptor())
    +class PressureUnitConverter(CompositeUnitConverter):
    +    """
    +    Convert pressure units (mass / length / time^2) with this converter.
    +
    +    Examples:
    +        >>> from_unit = MassUnit.GRAM / LengthUnit.CENTI_METER / (TimeUnit.HOUR**2)
    +        >>> to_unit = MassUnit.KILO_GRAM / LengthUnit.METER / (TimeUnit.HOUR**2)
    +        >>> PressureUnitConverter.convert(50, from_unit, to_unit)
    +        5.0
    +    """
     
    @@ -2366,8 +2445,7 @@

    Source code in src/property_utils/units/converters.py -
     96
    - 97
    +                
     97
      98
      99
     100
    @@ -2389,32 +2467,29 @@ 

    116 117 118 -119 -120

    @register_converter(RelativeTemperatureUnit)
    -class RelativeTemperatureUnitConverter(
    -    RelativeUnitConverter
    -):  # pylint: disable=too-few-public-methods
    -    """
    -    Convert temperature units with this converter.
    -
    -    Examples:
    -        >>> RelativeTemperatureUnitConverter.convert(100, RelativeTemperatureUnit.CELCIUS, RelativeTemperatureUnit.FAHRENHEIT)
    -        212.0
    -    """
    -
    -    reference_unit = RelativeTemperatureUnit.CELCIUS
    -    conversion_map = {
    -        RelativeTemperatureUnit.CELCIUS: lambda t: t,
    -        AbsoluteTemperatureUnit.KELVIN: lambda t: t - 273.15,
    -        RelativeTemperatureUnit.FAHRENHEIT: lambda t: (t - 32) / 1.8,
    -        AbsoluteTemperatureUnit.RANKINE: lambda t: (t / 1.8) - 273.15,
    -    }
    -    reference_conversion_map = {
    -        RelativeTemperatureUnit.CELCIUS: lambda t: t,
    -        AbsoluteTemperatureUnit.KELVIN: lambda t: t + 273.15,
    -        RelativeTemperatureUnit.FAHRENHEIT: lambda t: (t * 1.8) + 32,
    -        AbsoluteTemperatureUnit.RANKINE: lambda t: (t + 273.15) * 1.8,
    -    }
    +119
    @register_converter(RelativeTemperatureUnit)
    +class RelativeTemperatureUnitConverter(RelativeUnitConverter):  # pylint: disable=too-few-public-methods
    +    """
    +    Convert temperature units with this converter.
    +
    +    Examples:
    +        >>> RelativeTemperatureUnitConverter.convert(100, RelativeTemperatureUnit.CELCIUS, RelativeTemperatureUnit.FAHRENHEIT)
    +        212.0
    +    """
    +
    +    reference_unit = RelativeTemperatureUnit.CELCIUS
    +    conversion_map = {
    +        RelativeTemperatureUnit.CELCIUS: lambda t: t,
    +        AbsoluteTemperatureUnit.KELVIN: lambda t: t - 273.15,
    +        RelativeTemperatureUnit.FAHRENHEIT: lambda t: (t - 32) / 1.8,
    +        AbsoluteTemperatureUnit.RANKINE: lambda t: (t / 1.8) - 273.15,
    +    }
    +    reference_conversion_map = {
    +        RelativeTemperatureUnit.CELCIUS: lambda t: t,
    +        AbsoluteTemperatureUnit.KELVIN: lambda t: t + 273.15,
    +        RelativeTemperatureUnit.FAHRENHEIT: lambda t: (t * 1.8) + 32,
    +        AbsoluteTemperatureUnit.RANKINE: lambda t: (t + 273.15) * 1.8,
    +    }
     
    @@ -2464,17 +2539,7 @@

    Source code in src/property_utils/units/converters.py -
    216
    -217
    -218
    -219
    -220
    -221
    -222
    -223
    -224
    -225
    -226
    +                
    226
     227
     228
     229
    @@ -2484,27 +2549,37 @@ 

    233 234 235 -236

    @register_converter(TimeUnit)
    -class TimeUnitConverter(AbsoluteUnitConverter):
    -    """
    -    Convert time units with this converter.
    -
    -    Examples:
    -        >>> TimeUnitConverter.convert(1, TimeUnit.HOUR, TimeUnit.SECOND)
    -        3600.0
    -    """
    -
    -    reference_unit = TimeUnit.SECOND
    -    conversion_map = {
    -        TimeUnit.MILLI_SECOND: UnitPrefix.MILLI.inverse(),
    -        TimeUnit.SECOND: 1,
    -        TimeUnit.MINUTE: 1 / 60.0,
    -        TimeUnit.HOUR: 1 / 60.0 / 60.0,
    -        TimeUnit.DAY: 1 / 60.0 / 60.0 / 24.0,
    -        TimeUnit.WEEK: 1 / 60.0 / 60.0 / 24.0 / 7,
    -        TimeUnit.MONTH: 1 / 60.0 / 60.0 / 24.0 / (365 / 12),
    -        TimeUnit.YEAR: 1 / 60.0 / 60.0 / 24.0 / 365,
    -    }
    +236
    +237
    +238
    +239
    +240
    +241
    +242
    +243
    +244
    +245
    +246
    @register_converter(TimeUnit)
    +class TimeUnitConverter(AbsoluteUnitConverter):
    +    """
    +    Convert time units with this converter.
    +
    +    Examples:
    +        >>> TimeUnitConverter.convert(1, TimeUnit.HOUR, TimeUnit.SECOND)
    +        3600.0
    +    """
    +
    +    reference_unit = TimeUnit.SECOND
    +    conversion_map = {
    +        TimeUnit.MILLI_SECOND: UnitPrefix.MILLI.inverse(),
    +        TimeUnit.SECOND: 1,
    +        TimeUnit.MINUTE: 1 / 60.0,
    +        TimeUnit.HOUR: 1 / 60.0 / 60.0,
    +        TimeUnit.DAY: 1 / 60.0 / 60.0 / 24.0,
    +        TimeUnit.WEEK: 1 / 60.0 / 60.0 / 24.0 / 7,
    +        TimeUnit.MONTH: 1 / 60.0 / 60.0 / 24.0 / (365 / 12),
    +        TimeUnit.YEAR: 1 / 60.0 / 60.0 / 24.0 / 365,
    +    }
     
    @@ -2557,8 +2632,7 @@

    Source code in src/property_utils/units/converters.py -
    58
    -59
    +                
    59
     60
     61
     62
    @@ -2592,42 +2666,43 @@ 

    90 91 92 -93

    class UnitPrefix(float, Enum):
    -    """
    -    Enumeration of unit prefixes.
    -    Handy when converting to and fro prefixed units.
    -
    -    Examples:
    -        >>> centimeters = 225
    -        >>> meters = centimeters * UnitPrefix.CENTI
    -        >>> meters
    -        2.25
    -    """
    -
    -    PICO = 1e-12
    -    NANO = 1e-9
    -    MICRO = 1e-6
    -    MILLI = 1e-3
    -    CENTI = 1e-2
    -    DECI = 1e-1
    -    DECA = 1e1
    -    HECTO = 1e2
    -    KILO = 1e3
    -    MEGA = 1e6
    -    GIGA = 1e9
    -    TERA = 1e12
    -
    -    def inverse(self) -> float:
    -        """
    -        Return the inverse of the unit prefix. Use when prefixing a unit.
    -
    -        Examples:
    -            >>> meters = 50.26
    -            >>> centimeters = meters * UnitPrefix.CENTI.inverse()
    -            >>> centimeters
    -            5026.0
    -        """
    -        return 1 / self.value
    +93
    +94
    class UnitPrefix(float, Enum):
    +    """
    +    Enumeration of unit prefixes.
    +    Handy when converting to and fro prefixed units.
    +
    +    Examples:
    +        >>> centimeters = 225
    +        >>> meters = centimeters * UnitPrefix.CENTI
    +        >>> meters
    +        2.25
    +    """
    +
    +    PICO = 1e-12
    +    NANO = 1e-9
    +    MICRO = 1e-6
    +    MILLI = 1e-3
    +    CENTI = 1e-2
    +    DECI = 1e-1
    +    DECA = 1e1
    +    HECTO = 1e2
    +    KILO = 1e3
    +    MEGA = 1e6
    +    GIGA = 1e9
    +    TERA = 1e12
    +
    +    def inverse(self) -> float:
    +        """
    +        Return the inverse of the unit prefix. Use when prefixing a unit.
    +
    +        Examples:
    +            >>> meters = 50.26
    +            >>> centimeters = meters * UnitPrefix.CENTI.inverse()
    +            >>> centimeters
    +            5026.0
    +        """
    +        return 1 / self.value
     
    @@ -2666,8 +2741,7 @@

    Source code in src/property_utils/units/converters.py -
    83
    -84
    +              
    84
     85
     86
     87
    @@ -2676,17 +2750,18 @@ 

    90 91 92 -93

    def inverse(self) -> float:
    -    """
    -    Return the inverse of the unit prefix. Use when prefixing a unit.
    -
    -    Examples:
    -        >>> meters = 50.26
    -        >>> centimeters = meters * UnitPrefix.CENTI.inverse()
    -        >>> centimeters
    -        5026.0
    -    """
    -    return 1 / self.value
    +93
    +94
    def inverse(self) -> float:
    +    """
    +    Return the inverse of the unit prefix. Use when prefixing a unit.
    +
    +    Examples:
    +        >>> meters = 50.26
    +        >>> centimeters = meters * UnitPrefix.CENTI.inverse()
    +        >>> centimeters
    +        5026.0
    +    """
    +    return 1 / self.value
     
    @@ -2727,23 +2802,23 @@

    Source code in src/property_utils/units/converters.py -
    @register_converter(LengthUnit**3)
    -class VolumeUnitConverter(ExponentiatedUnitConverter):
    -    """
    -    Convert volume units with this converter.
    -
    -    Examples:
    -        >>> VolumeUnitConverter.convert(1, LengthUnit.METER**3, LengthUnit.CENTI_METER**3)
    -        1000000.0
    -    """
    +                
    @register_converter(LengthUnit**3)
    +class VolumeUnitConverter(ExponentiatedUnitConverter):
    +    """
    +    Convert volume units with this converter.
    +
    +    Examples:
    +        >>> VolumeUnitConverter.convert(1, LengthUnit.METER**3, LengthUnit.CENTI_METER**3)
    +        1000000.0
    +    """
     
    diff --git a/descriptors/index.html b/descriptors/index.html index 546536c..7be9060 100644 --- a/descriptors/index.html +++ b/descriptors/index.html @@ -1280,6 +1280,15 @@
    + + +
  • + + + is_non_dimensional + + +
  • @@ -2155,6 +2164,15 @@ +
  • + +
  • + + + is_non_dimensional + + +
  • @@ -2406,26 +2424,7 @@

    Source code in src/property_utils/units/descriptors.py -
    488
    -489
    -490
    -491
    -492
    -493
    -494
    -495
    -496
    -497
    -498
    -499
    -500
    -501
    -502
    -503
    -504
    -505
    -506
    -507
    +                
    507
     508
     509
     510
    @@ -2474,75 +2473,94 @@ 

    553 554 555 -556

    class AliasMeasurementUnit(MeasurementUnit):
    -    """
    -    Base class for common composite units of physical quantities.
    -
    -    Subclasses of `MeasurementUnit` represent only primitive physical quantities.
    -    However, many common physical properties have composite units (e.g. pressure, force,
    -    energy, etc), thus subclasses of this class alias composite units as primitive ones.
    -
    -    Only very common composite units should be aliased.
    -
    -    e.g. you can create an alias for pressure units, instead of using mass * length / (
    -        time^2) units.
    -
    -    Examples:
    -        >>> class PressureUnit(AliasMeasurementUnit):
    -        ...     BAR = "bar"
    -        ...     PASCAL = "Pa"
    -        ...     KILO_PASCAL = "kPa"
    -        ...     PSI = "psi"
    -    """
    -
    -    @staticmethod
    -    def from_descriptor(descriptor: UnitDescriptor) -> MeasurementUnit:
    -        """
    -        Create an AliasMeasurementUnit from given descriptor.
    -        If descriptor is already an AliasMeasurementUnit, it returns the same object.
    +556
    +557
    +558
    +559
    +560
    +561
    +562
    +563
    +564
    +565
    +566
    +567
    +568
    +569
    +570
    +571
    +572
    +573
    +574
    +575
    class AliasMeasurementUnit(MeasurementUnit):
    +    """
    +    Base class for common composite units of physical quantities.
    +
    +    Subclasses of `MeasurementUnit` represent only primitive physical quantities.
    +    However, many common physical properties have composite units (e.g. pressure, force,
    +    energy, etc), thus subclasses of this class alias composite units as primitive ones.
     
    -        This function does not serve as a constructor for AliasMeasurementUnit, rather
    -        it is intended to be used to convert an unknown unit descriptor to an
    -        AliasMeasurementUnit.
    -
    -        Subclasses should implement aliased_generic_descriptor and alias_mapping
    -        methods.
    -
    -        Raises `UnitDescriptorTypeError` if given descriptor cannot be translated
    -        to an AliasMeasurementUnit  instance.
    -
    -        Examples:
    -            >>> class PressureUnit(AliasMeasurementUnit):
    -            ...     BAR = "bar"
    -
    -            >>> bar = MeasurementUnit.from_descriptor(PressureUnit.BAR**(-1))
    -            >>> bar
    -            <PressureUnit: bar>
    -        """
    -        if isinstance(descriptor, Dimension) and isinstance(
    -            descriptor.unit, AliasMeasurementUnit
    -        ):
    -            return descriptor.unit
    -        if isinstance(descriptor, AliasMeasurementUnit):
    -            return descriptor
    -        raise UnitDescriptorTypeError(
    -            f"cannot create AliasMeasurementUnit from descriptor {descriptor}"
    -        )
    -
    -    @classmethod
    -    def aliased_generic_descriptor(cls) -> GenericUnitDescriptor:
    -        """
    -        Implement this method by returning the generic of the unit descriptor that this
    -        measurement unit aliases.
    -
    -        Examples:
    -            >>> class LengthUnit(MeasurementUnit): ...
    -            >>> class AreaUnit(AliasMeasurementUnit):
    -            ...     @classmethod
    -            ...     def aliased_generic_descriptor(cls):
    -            ...         return LengthUnit**2
    -        """
    -        raise NotImplementedError
    +    Only very common composite units should be aliased.
    +
    +    e.g. you can create an alias for pressure units, instead of using mass * length / (
    +        time^2) units.
    +
    +    Examples:
    +        >>> class PressureUnit(AliasMeasurementUnit):
    +        ...     BAR = "bar"
    +        ...     PASCAL = "Pa"
    +        ...     KILO_PASCAL = "kPa"
    +        ...     PSI = "psi"
    +    """
    +
    +    @staticmethod
    +    def from_descriptor(descriptor: UnitDescriptor) -> MeasurementUnit:
    +        """
    +        Create an AliasMeasurementUnit from given descriptor.
    +        If descriptor is already an AliasMeasurementUnit, it returns the same object.
    +
    +        This function does not serve as a constructor for AliasMeasurementUnit, rather
    +        it is intended to be used to convert an unknown unit descriptor to an
    +        AliasMeasurementUnit.
    +
    +        Subclasses should implement aliased_generic_descriptor and alias_mapping
    +        methods.
    +
    +        Raises `UnitDescriptorTypeError` if given descriptor cannot be translated
    +        to an AliasMeasurementUnit  instance.
    +
    +        Examples:
    +            >>> class PressureUnit(AliasMeasurementUnit):
    +            ...     BAR = "bar"
    +
    +            >>> bar = MeasurementUnit.from_descriptor(PressureUnit.BAR**(-1))
    +            >>> bar
    +            <PressureUnit: bar>
    +        """
    +        if isinstance(descriptor, Dimension) and isinstance(
    +            descriptor.unit, AliasMeasurementUnit
    +        ):
    +            return descriptor.unit
    +        if isinstance(descriptor, AliasMeasurementUnit):
    +            return descriptor
    +        raise UnitDescriptorTypeError(
    +            f"cannot create AliasMeasurementUnit from descriptor {descriptor}"
    +        )
    +
    +    @classmethod
    +    def aliased_generic_descriptor(cls) -> GenericUnitDescriptor:
    +        """
    +        Implement this method by returning the generic of the unit descriptor that this
    +        measurement unit aliases.
    +
    +        Examples:
    +            >>> class LengthUnit(MeasurementUnit): ...
    +            >>> class AreaUnit(AliasMeasurementUnit):
    +            ...     @classmethod
    +            ...     def aliased_generic_descriptor(cls):
    +            ...         return LengthUnit**2
    +        """
    +        raise NotImplementedError
     
    @@ -2587,33 +2605,33 @@

    Source code in src/property_utils/units/descriptors.py -
    @classmethod
    -def aliased_generic_descriptor(cls) -> GenericUnitDescriptor:
    -    """
    -    Implement this method by returning the generic of the unit descriptor that this
    -    measurement unit aliases.
    -
    -    Examples:
    -        >>> class LengthUnit(MeasurementUnit): ...
    -        >>> class AreaUnit(AliasMeasurementUnit):
    -        ...     @classmethod
    -        ...     def aliased_generic_descriptor(cls):
    -        ...         return LengthUnit**2
    -    """
    -    raise NotImplementedError
    +              
    @classmethod
    +def aliased_generic_descriptor(cls) -> GenericUnitDescriptor:
    +    """
    +    Implement this method by returning the generic of the unit descriptor that this
    +    measurement unit aliases.
    +
    +    Examples:
    +        >>> class LengthUnit(MeasurementUnit): ...
    +        >>> class AreaUnit(AliasMeasurementUnit):
    +        ...     @classmethod
    +        ...     def aliased_generic_descriptor(cls):
    +        ...         return LengthUnit**2
    +    """
    +    raise NotImplementedError
     
    @@ -2657,26 +2675,7 @@

    Source code in src/property_utils/units/descriptors.py -
    509
    -510
    -511
    -512
    -513
    -514
    -515
    -516
    -517
    -518
    -519
    -520
    -521
    -522
    -523
    -524
    -525
    -526
    -527
    -528
    +              
    528
     529
     530
     531
    @@ -2689,39 +2688,58 @@ 

    538 539 540 -541

    @staticmethod
    -def from_descriptor(descriptor: UnitDescriptor) -> MeasurementUnit:
    -    """
    -    Create an AliasMeasurementUnit from given descriptor.
    -    If descriptor is already an AliasMeasurementUnit, it returns the same object.
    -
    -    This function does not serve as a constructor for AliasMeasurementUnit, rather
    -    it is intended to be used to convert an unknown unit descriptor to an
    -    AliasMeasurementUnit.
    -
    -    Subclasses should implement aliased_generic_descriptor and alias_mapping
    -    methods.
    -
    -    Raises `UnitDescriptorTypeError` if given descriptor cannot be translated
    -    to an AliasMeasurementUnit  instance.
    -
    -    Examples:
    -        >>> class PressureUnit(AliasMeasurementUnit):
    -        ...     BAR = "bar"
    -
    -        >>> bar = MeasurementUnit.from_descriptor(PressureUnit.BAR**(-1))
    -        >>> bar
    -        <PressureUnit: bar>
    -    """
    -    if isinstance(descriptor, Dimension) and isinstance(
    -        descriptor.unit, AliasMeasurementUnit
    -    ):
    -        return descriptor.unit
    -    if isinstance(descriptor, AliasMeasurementUnit):
    -        return descriptor
    -    raise UnitDescriptorTypeError(
    -        f"cannot create AliasMeasurementUnit from descriptor {descriptor}"
    -    )
    +541
    +542
    +543
    +544
    +545
    +546
    +547
    +548
    +549
    +550
    +551
    +552
    +553
    +554
    +555
    +556
    +557
    +558
    +559
    +560
    @staticmethod
    +def from_descriptor(descriptor: UnitDescriptor) -> MeasurementUnit:
    +    """
    +    Create an AliasMeasurementUnit from given descriptor.
    +    If descriptor is already an AliasMeasurementUnit, it returns the same object.
    +
    +    This function does not serve as a constructor for AliasMeasurementUnit, rather
    +    it is intended to be used to convert an unknown unit descriptor to an
    +    AliasMeasurementUnit.
    +
    +    Subclasses should implement aliased_generic_descriptor and alias_mapping
    +    methods.
    +
    +    Raises `UnitDescriptorTypeError` if given descriptor cannot be translated
    +    to an AliasMeasurementUnit  instance.
    +
    +    Examples:
    +        >>> class PressureUnit(AliasMeasurementUnit):
    +        ...     BAR = "bar"
    +
    +        >>> bar = MeasurementUnit.from_descriptor(PressureUnit.BAR**(-1))
    +        >>> bar
    +        <PressureUnit: bar>
    +    """
    +    if isinstance(descriptor, Dimension) and isinstance(
    +        descriptor.unit, AliasMeasurementUnit
    +    ):
    +        return descriptor.unit
    +    if isinstance(descriptor, AliasMeasurementUnit):
    +        return descriptor
    +    raise UnitDescriptorTypeError(
    +        f"cannot create AliasMeasurementUnit from descriptor {descriptor}"
    +    )
     
    @@ -2775,29 +2793,7 @@

    Source code in src/property_utils/units/descriptors.py -
    1460
    -1461
    -1462
    -1463
    -1464
    -1465
    -1466
    -1467
    -1468
    -1469
    -1470
    -1471
    -1472
    -1473
    -1474
    -1475
    -1476
    -1477
    -1478
    -1479
    -1480
    -1481
    -1482
    +                
    1482
     1483
     1484
     1485
    @@ -3212,444 +3208,472 @@ 

    1894 1895 1896 -1897

    @dataclass
    -class CompositeDimension:
    -    """
    -    A CompositeDimension represents a measurement unit that is composed from other
    -    measurement units.
    -
    -    Objects of this class can represent either multiplication or division between two
    -    Dimension objects.
    -
    -    Create objects by multiplying and diving Dimension or MeasurementUnit objects.
    -
    -    Examples:
    -        >>> class LengthUnit(MeasurementUnit):
    -        ...     METER = "m"
    -
    -        >>> class AmountUnit(MeasurementUnit):
    -        ...     KILO_MOL = "kmol"
    -
    -        >>> molal_volume_dimension = (LengthUnit.METER**3) / AmountUnit.KILO_MOL
    -        >>> molal_volume_dimension
    -        <CompositeDimension: (m^3) / kmol>
    -    """
    -
    -    Default = TypeVar("Default")  # default return type for `get` functions.
    -
    -    numerator: List[Dimension] = field(default_factory=list)
    -    denominator: List[Dimension] = field(default_factory=list)
    +1897
    +1898
    +1899
    +1900
    +1901
    +1902
    +1903
    +1904
    +1905
    +1906
    +1907
    +1908
    +1909
    +1910
    +1911
    +1912
    +1913
    +1914
    +1915
    +1916
    +1917
    +1918
    +1919
    +1920
    +1921
    +1922
    @dataclass
    +class CompositeDimension:
    +    """
    +    A CompositeDimension represents a measurement unit that is composed from other
    +    measurement units.
     
    -    @staticmethod
    -    def from_descriptor(descriptor: UnitDescriptor) -> "CompositeDimension":
    -        """
    -        Create a CompositeDimension from given descriptor.
    -        If descriptor is already a CompositeDimension, it returns the same object.
    -
    -        This function does not serve as a constructor for CompositeDimension, rather it
    -        is intended to be used to convert an unknown unit descriptor to a
    -        CompositeDimension.
    -
    -        Raises `UnitDescriptorTypeError` if given descriptor cannot be translated
    -        to a CompositeDimension instance.
    -        """
    -        if not isinstance(descriptor, CompositeDimension):
    -            raise UnitDescriptorTypeError(
    -                f"cannot create CompositeDimension from descriptor {descriptor}"
    -            )
    -        return descriptor
    +    Objects of this class can represent either multiplication or division between two
    +    Dimension objects.
    +
    +    Create objects by multiplying and diving Dimension or MeasurementUnit objects.
    +
    +    Examples:
    +        >>> class LengthUnit(MeasurementUnit):
    +        ...     METER = "m"
    +
    +        >>> class AmountUnit(MeasurementUnit):
    +        ...     KILO_MOL = "kmol"
    +
    +        >>> molal_volume_dimension = (LengthUnit.METER**3) / AmountUnit.KILO_MOL
    +        >>> molal_volume_dimension
    +        <CompositeDimension: (m^3) / kmol>
    +    """
    +
    +    Default = TypeVar("Default")  # default return type for `get` functions.
     
    -    def si(self) -> "CompositeDimension":
    -        """
    -        Returns this composite dimension in SI units.
    -
    -        Examples:
    -            >>> class TemperatureUnit(MeasurementUnit):
    -            ...     KELVIN = "K"
    -            ...     RANKINE = "R"
    -            ...     @classmethod
    -            ...     def si(cls): return cls.KELVIN
    -
    -            >>> class LengthUnit(MeasurementUnit):
    -            ...     METER = "m"
    -            ...     FOOT = "ft"
    -            ...     @classmethod
    -            ...     def si(cls): return cls.METER
    -
    -            >>> (TemperatureUnit.RANKINE / LengthUnit.FOOT**2).si()
    -            <CompositeDimension: K / (m^2)>
    -        """
    -        return CompositeDimension(
    -            [n.si() for n in self.numerator], [d.si() for d in self.denominator]
    -        )
    -
    -    def isinstance(self, generic: GenericUnitDescriptor) -> bool:
    -        """
    -        Returns True if the CompositeDimension is an instance of the generic, False
    -        otherwise.
    -
    -        Examples:
    -            >>> class TemperatureUnit(MeasurementUnit):
    -            ...     CELCIUS = "C"
    +    numerator: List[Dimension] = field(default_factory=list)
    +    denominator: List[Dimension] = field(default_factory=list)
    +
    +    @staticmethod
    +    def from_descriptor(descriptor: UnitDescriptor) -> "CompositeDimension":
    +        """
    +        Create a CompositeDimension from given descriptor.
    +        If descriptor is already a CompositeDimension, it returns the same object.
    +
    +        This function does not serve as a constructor for CompositeDimension, rather it
    +        is intended to be used to convert an unknown unit descriptor to a
    +        CompositeDimension.
    +
    +        Raises `UnitDescriptorTypeError` if given descriptor cannot be translated
    +        to a CompositeDimension instance.
    +        """
    +        if not isinstance(descriptor, CompositeDimension):
    +            raise UnitDescriptorTypeError(
    +                f"cannot create CompositeDimension from descriptor {descriptor}"
    +            )
    +        return descriptor
    +
    +    def si(self) -> "CompositeDimension":
    +        """
    +        Returns this composite dimension in SI units.
    +
    +        Examples:
    +            >>> class TemperatureUnit(MeasurementUnit):
    +            ...     KELVIN = "K"
    +            ...     RANKINE = "R"
    +            ...     @classmethod
    +            ...     def si(cls): return cls.KELVIN
     
                 >>> class LengthUnit(MeasurementUnit):
                 ...     METER = "m"
    -
    -            >>> (TemperatureUnit.CELCIUS / LengthUnit.METER).isinstance(TemperatureUnit / LengthUnit)
    -            True
    +            ...     FOOT = "ft"
    +            ...     @classmethod
    +            ...     def si(cls): return cls.METER
     
    -            >>> (TemperatureUnit.CELCIUS * LengthUnit.METER).isinstance(TemperatureUnit**2)
    -            False
    +            >>> (TemperatureUnit.RANKINE / LengthUnit.FOOT**2).si()
    +            <CompositeDimension: K / (m^2)>
             """
    -        if not isinstance(generic, GenericCompositeDimension):
    -            return False
    -
    -        return self.to_generic() == generic
    -
    -    def isinstance_equivalent(self, generic: GenericUnitDescriptor) -> bool:
    -        """
    -        Returns True if the UnitDescriptor is an instance-equivalent of the generic,
    -        False otherwise.
    -
    -        A unit descriptor is an instance-equivalent of a generic if the generic of the
    -        unit descriptor is equivalent to the generic.
    +        return CompositeDimension(
    +            [n.si() for n in self.numerator], [d.si() for d in self.denominator]
    +        )
    +
    +    def isinstance(self, generic: GenericUnitDescriptor) -> bool:
    +        """
    +        Returns True if the CompositeDimension is an instance of the generic, False
    +        otherwise.
    +
    +        Examples:
    +            >>> class TemperatureUnit(MeasurementUnit):
    +            ...     CELCIUS = "C"
     
    -        Equivalence between generics is checked with the `is_equivalent` method.
    -
    -        Examples:
    -            >>> class MassUnit(MeasurementUnit):
    -            ...     KILO_GRAM = "kg"
    -            >>> class LengthUnit(MeasurementUnit):
    -            ...     METER = "m"
    -            >>> class TimeUnit(MeasurementUnit):
    -            ...     SECOND = "s"
    -
    -            >>> class ForceUnit(AliasMeasurementUnit):
    -            ...     NEWTON = "N"
    -            ...     @classmethod
    -            ...     def aliased_generic_descriptor(cls):
    -            ...         return MassUnit * LengthUnit / (TimeUnit**2)
    -
    -            >>> (MassUnit.KILO_GRAM * LengthUnit.METER / (TimeUnit.SECOND**2)).isinstance_equivalent(ForceUnit)
    -            True
    -        """
    -        return self.to_generic().is_equivalent(generic)
    -
    -    def to_generic(self) -> GenericCompositeDimension:
    -        """
    -        Create a generic descriptor from this CompositeDimension.
    -
    -        Examples:
    -            >>> class AmountUnit(MeasurementUnit):
    -            ...     MOL = "mol"
    -
    -            >>> class MassUnit(MeasurementUnit):
    -            ...     KILO_GRAM = "kg"
    +            >>> class LengthUnit(MeasurementUnit):
    +            ...     METER = "m"
    +
    +            >>> (TemperatureUnit.CELCIUS / LengthUnit.METER).isinstance(TemperatureUnit / LengthUnit)
    +            True
    +
    +            >>> (TemperatureUnit.CELCIUS * LengthUnit.METER).isinstance(TemperatureUnit**2)
    +            False
    +        """
    +        if not isinstance(generic, GenericCompositeDimension):
    +            return False
    +
    +        return self.to_generic() == generic
    +
    +    def isinstance_equivalent(self, generic: GenericUnitDescriptor) -> bool:
    +        """
    +        Returns True if the UnitDescriptor is an instance-equivalent of the generic,
    +        False otherwise.
    +
    +        A unit descriptor is an instance-equivalent of a generic if the generic of the
    +        unit descriptor is equivalent to the generic.
    +
    +        Equivalence between generics is checked with the `is_equivalent` method.
    +
    +        Examples:
    +            >>> class MassUnit(MeasurementUnit):
    +            ...     KILO_GRAM = "kg"
    +            >>> class LengthUnit(MeasurementUnit):
    +            ...     METER = "m"
    +            >>> class TimeUnit(MeasurementUnit):
    +            ...     SECOND = "s"
     
    -            >>> (AmountUnit.MOL / MassUnit.KILO_GRAM).to_generic()
    -            <GenericCompositeDimension: AmountUnit / MassUnit>
    -        """
    -        return GenericCompositeDimension(
    -            numerator=[n.to_generic() for n in self.numerator],
    -            denominator=[d.to_generic() for d in self.denominator],
    -        )
    -
    -    def get_numerator(
    -        self,
    -        generic: Union[MeasurementUnitType, GenericDimension],
    -        default: Optional[Default] = None,
    -    ) -> Union[Dimension, Optional[Default]]:
    -        """
    -        Get a dimension from the numerator. If the dimension is not found it returns
    -        the default.
    -
    -        Examples:
    -            >>> class LengthUnit(MeasurementUnit):
    -            ...     METER = "m"
    -
    -            >>> class TemperatureUnit(MeasurementUnit):
    -            ...     KELVIN = "K"
    -
    -            >>> composite = TemperatureUnit.KELVIN / (LengthUnit.METER**3)
    -            >>> composite.get_numerator(TemperatureUnit)
    -            <Dimension: K>
    -            >>> composite.get_numerator(LengthUnit, "default")
    -            'default'
    -        """
    -        for n in self.numerator:
    -            if n.isinstance(generic):
    -                return n
    -        return default
    -
    -    def get_denominator(
    -        self,
    -        generic: Union[MeasurementUnitType, GenericDimension],
    -        default: Optional[Default] = None,
    -    ) -> Union[Dimension, Optional[Default]]:
    -        """
    -        Get a dimension from the denominator. If the dimension is not found it returns
    -        the default.
    -
    -        Examples:
    -            >>> class LengthUnit(MeasurementUnit):
    -            ...     METER = "m"
    -
    -            >>> class TemperatureUnit(MeasurementUnit):
    -            ...     KELVIN = "K"
    -
    -            >>> composite = TemperatureUnit.KELVIN / (LengthUnit.METER**3)
    -            >>> composite.get_denominator(LengthUnit**3)
    -            <Dimension: m^3>
    -            >>> composite.get_denominator(LengthUnit, "default")
    -            'default'
    -        """
    -        for d in self.denominator:
    -            if d.isinstance(generic):
    -                return d
    -        return default
    -
    -    def simplify(self) -> None:
    -        """
    -        Simplify the composite by merging common dimensions.
    +            >>> class ForceUnit(AliasMeasurementUnit):
    +            ...     NEWTON = "N"
    +            ...     @classmethod
    +            ...     def aliased_generic_descriptor(cls):
    +            ...         return MassUnit * LengthUnit / (TimeUnit**2)
    +
    +            >>> (MassUnit.KILO_GRAM * LengthUnit.METER / (TimeUnit.SECOND**2)).isinstance_equivalent(ForceUnit)
    +            True
    +        """
    +        return self.to_generic().is_equivalent(generic)
    +
    +    def to_generic(self) -> GenericCompositeDimension:
    +        """
    +        Create a generic descriptor from this CompositeDimension.
    +
    +        Examples:
    +            >>> class AmountUnit(MeasurementUnit):
    +            ...     MOL = "mol"
    +
    +            >>> class MassUnit(MeasurementUnit):
    +            ...     KILO_GRAM = "kg"
    +
    +            >>> (AmountUnit.MOL / MassUnit.KILO_GRAM).to_generic()
    +            <GenericCompositeDimension: AmountUnit / MassUnit>
    +        """
    +        return GenericCompositeDimension(
    +            numerator=[n.to_generic() for n in self.numerator],
    +            denominator=[d.to_generic() for d in self.denominator],
    +        )
    +
    +    def get_numerator(
    +        self,
    +        generic: Union[MeasurementUnitType, GenericDimension],
    +        default: Optional[Default] = None,
    +    ) -> Union[Dimension, Optional[Default]]:
    +        """
    +        Get a dimension from the numerator. If the dimension is not found it returns
    +        the default.
    +
    +        Examples:
    +            >>> class LengthUnit(MeasurementUnit):
    +            ...     METER = "m"
    +
    +            >>> class TemperatureUnit(MeasurementUnit):
    +            ...     KELVIN = "K"
    +
    +            >>> composite = TemperatureUnit.KELVIN / (LengthUnit.METER**3)
    +            >>> composite.get_numerator(TemperatureUnit)
    +            <Dimension: K>
    +            >>> composite.get_numerator(LengthUnit, "default")
    +            'default'
    +        """
    +        for n in self.numerator:
    +            if n.isinstance(generic):
    +                return n
    +        return default
    +
    +    def get_denominator(
    +        self,
    +        generic: Union[MeasurementUnitType, GenericDimension],
    +        default: Optional[Default] = None,
    +    ) -> Union[Dimension, Optional[Default]]:
    +        """
    +        Get a dimension from the denominator. If the dimension is not found it returns
    +        the default.
     
             Examples:
    -            >>> class PressureUnit(AliasMeasurementUnit):
    -            ...     BAR = "bar"
    -            ...     PASCAL = "Pa"
    -
    -            >>> class TemperatureUnit(MeasurementUnit):
    -            ...     KELVIN = "K"
    -
    -            >>> class LengthUnit(MeasurementUnit):
    -            ...     METER = "m"
    -
    -            >>> class TimeUnit(MeasurementUnit):
    -            ...     SECOND = "s"
    -
    -            >>> composite = (PressureUnit.BAR**(-2)) / (TemperatureUnit.KELVIN**(-1))
    -            >>> composite
    -            <CompositeDimension: (bar^-2) / (K^-1)>
    -            >>> composite.simplify()
    -            >>> composite
    -            <CompositeDimension: K / (bar^2)>
    -
    -            >>> composite = PressureUnit.PASCAL * LengthUnit.METER * PressureUnit.PASCAL /TimeUnit.SECOND
    -            >>> composite
    -            <CompositeDimension: Pa * Pa * m / s>
    -            >>> composite.simplify()
    -            >>> composite
    -            <CompositeDimension: (Pa^2) * m / s>
    -        """
    -        exponents: Dict[MeasurementUnit, float] = {}
    -        for n in self.numerator:
    -            if n.unit in exponents:
    -                exponents[n.unit] += n.power
    -            else:
    -                exponents[n.unit] = n.power
    -
    -        for d in self.denominator:
    -            if d.unit in exponents:
    -                exponents[d.unit] -= d.power
    -            else:
    -                exponents[d.unit] = 0 - d.power
    -
    -        numerator = []
    -        denominator = []
    -        for unit, exponent in exponents.items():
    -            if exponent > 0:
    -                numerator.append(Dimension(unit) ** exponent)
    -            elif exponent < 0:
    -                denominator.append(Dimension(unit) ** abs(exponent))
    -
    -        self.numerator = numerator
    -        self.denominator = denominator
    -
    -    def simplified(self) -> "CompositeDimension":
    -        """
    -        Returns a simplified version of this composite dimension as a new object.
    -
    -        Examples:
    -            >>> class PressureUnit(AliasMeasurementUnit):
    -            ...     BAR = "bar"
    -            ...     PASCAL = "Pa"
    -
    -            >>> class TemperatureUnit(MeasurementUnit):
    -            ...     KELVIN = "K"
    -
    -            >>> class LengthUnit(MeasurementUnit):
    -            ...     METER = "m"
    -
    -            >>> class TimeUnit(MeasurementUnit):
    -            ...     SECOND = "s"
    -
    -            >>> composite = (PressureUnit.BAR**(-2)) / (TemperatureUnit.KELVIN**(-1))
    -            >>> composite
    -            <CompositeDimension: (bar^-2) / (K^-1)>
    -            >>> composite.simplified()
    -            <CompositeDimension: K / (bar^2)>
    -
    -            >>> composite = PressureUnit.PASCAL * LengthUnit.METER * PressureUnit.PASCAL /TimeUnit.SECOND
    -            >>> composite
    -            <CompositeDimension: Pa * Pa * m / s>
    -            >>> composite.simplified()
    -            <CompositeDimension: (Pa^2) * m / s>
    -        """
    -        copy = replace(self)
    -        copy.simplify()
    -        return copy
    +            >>> class LengthUnit(MeasurementUnit):
    +            ...     METER = "m"
    +
    +            >>> class TemperatureUnit(MeasurementUnit):
    +            ...     KELVIN = "K"
    +
    +            >>> composite = TemperatureUnit.KELVIN / (LengthUnit.METER**3)
    +            >>> composite.get_denominator(LengthUnit**3)
    +            <Dimension: m^3>
    +            >>> composite.get_denominator(LengthUnit, "default")
    +            'default'
    +        """
    +        for d in self.denominator:
    +            if d.isinstance(generic):
    +                return d
    +        return default
    +
    +    def simplify(self) -> None:
    +        """
    +        Simplify the composite by merging common dimensions.
    +
    +        Examples:
    +            >>> class PressureUnit(AliasMeasurementUnit):
    +            ...     BAR = "bar"
    +            ...     PASCAL = "Pa"
    +
    +            >>> class TemperatureUnit(MeasurementUnit):
    +            ...     KELVIN = "K"
    +
    +            >>> class LengthUnit(MeasurementUnit):
    +            ...     METER = "m"
    +
    +            >>> class TimeUnit(MeasurementUnit):
    +            ...     SECOND = "s"
    +
    +            >>> composite = (PressureUnit.BAR**(-2)) / (TemperatureUnit.KELVIN**(-1))
    +            >>> composite
    +            <CompositeDimension: (bar^-2) / (K^-1)>
    +            >>> composite.simplify()
    +            >>> composite
    +            <CompositeDimension: K / (bar^2)>
    +
    +            >>> composite = PressureUnit.PASCAL * LengthUnit.METER * PressureUnit.PASCAL /TimeUnit.SECOND
    +            >>> composite
    +            <CompositeDimension: Pa * Pa * m / s>
    +            >>> composite.simplify()
    +            >>> composite
    +            <CompositeDimension: (Pa^2) * m / s>
    +        """
    +        exponents: Dict[MeasurementUnit, float] = {}
    +        for n in self.numerator:
    +            if n.unit in exponents:
    +                exponents[n.unit] += n.power
    +            else:
    +                exponents[n.unit] = n.power
    +
    +        for d in self.denominator:
    +            if d.unit in exponents:
    +                exponents[d.unit] -= d.power
    +            else:
    +                exponents[d.unit] = 0 - d.power
    +
    +        numerator = []
    +        denominator = []
    +        for unit, exponent in exponents.items():
    +            if unit.is_non_dimensional():
    +                continue  # do not add non dimensional units to the simplified composite
    +
    +            if exponent > 0:
    +                numerator.append(Dimension(unit) ** exponent)
    +            elif exponent < 0:
    +                denominator.append(Dimension(unit) ** abs(exponent))
    +
    +        self.numerator = numerator
    +        self.denominator = denominator
    +
    +    def simplified(self) -> "CompositeDimension":
    +        """
    +        Returns a simplified version of this composite dimension as a new object.
    +
    +        Examples:
    +            >>> class PressureUnit(AliasMeasurementUnit):
    +            ...     BAR = "bar"
    +            ...     PASCAL = "Pa"
     
    -    def inverse(self) -> "CompositeDimension":
    -        """
    -        Create a composite with inverse units.
    -
    -        Examples:
    -            >>> class LengthUnit(MeasurementUnit):
    -            ...     METER = "m"
    -            >>> class TimeUnit(MeasurementUnit):
    -            ...     SECOND = "s"
    -
    -            >>> (LengthUnit.METER / TimeUnit.SECOND).inverse()
    -            <CompositeDimension: s / m>
    -        """
    -        return CompositeDimension(self._denominator_copy(), self._numerator_copy())
    +            >>> class TemperatureUnit(MeasurementUnit):
    +            ...     KELVIN = "K"
    +
    +            >>> class LengthUnit(MeasurementUnit):
    +            ...     METER = "m"
    +
    +            >>> class TimeUnit(MeasurementUnit):
    +            ...     SECOND = "s"
    +
    +            >>> composite = (PressureUnit.BAR**(-2)) / (TemperatureUnit.KELVIN**(-1))
    +            >>> composite
    +            <CompositeDimension: (bar^-2) / (K^-1)>
    +            >>> composite.simplified()
    +            <CompositeDimension: K / (bar^2)>
     
    -    def has_no_units(self) -> bool:
    -        """
    -        Returns True if the composite dimension does not have any units, False otherwise.
    -
    -        Examples:
    -            >>> class LengthUnit(MeasurementUnit):
    -            ...     METER = "m"
    -
    -            >>> CompositeDimension().has_no_units()
    -            True
    -            >>> CompositeDimension([LengthUnit.METER]).has_no_units()
    -            False
    -        """
    -        return len(self.denominator) == 0 and len(self.numerator) == 0
    -
    -    def _numerator_copy(self) -> List[Dimension]:
    -        return [replace(n) for n in self.numerator]
    -
    -    def _denominator_copy(self) -> List[Dimension]:
    -        return [replace(d) for d in self.denominator]
    -
    -    def __mul__(self, descriptor: "UnitDescriptor") -> "CompositeDimension":
    -        """
    -        Defines multiplication between CompositeDimension(s) and other unit descriptors.
    +            >>> composite = PressureUnit.PASCAL * LengthUnit.METER * PressureUnit.PASCAL /TimeUnit.SECOND
    +            >>> composite
    +            <CompositeDimension: Pa * Pa * m / s>
    +            >>> composite.simplified()
    +            <CompositeDimension: (Pa^2) * m / s>
    +        """
    +        copy = replace(self)
    +        copy.simplify()
    +        return copy
    +
    +    def inverse(self) -> "CompositeDimension":
    +        """
    +        Create a composite with inverse units.
    +
    +        Examples:
    +            >>> class LengthUnit(MeasurementUnit):
    +            ...     METER = "m"
    +            >>> class TimeUnit(MeasurementUnit):
    +            ...     SECOND = "s"
    +
    +            >>> (LengthUnit.METER / TimeUnit.SECOND).inverse()
    +            <CompositeDimension: s / m>
    +        """
    +        return CompositeDimension(self._denominator_copy(), self._numerator_copy())
     
    -        Examples:
    -            >>> class TemperatureUnit(MeasurementUnit):
    -            ...     CELCIUS = "C"
    -            >>> class TimeUnit(MeasurementUnit):
    -            ...     SECOND = "s"
    +    def has_no_units(self) -> bool:
    +        """
    +        Returns True if the composite dimension does not have any units, False otherwise.
    +
    +        Examples:
                 >>> class LengthUnit(MeasurementUnit):
    -            ...     CENTI_METER = "cm"
    -            >>> (TemperatureUnit.CELCIUS / LengthUnit.CENTI_METER) * TimeUnit.SECOND
    -            <CompositeDimension: C * s / cm>
    -        """
    -        numerator = self.numerator.copy()
    -        denominator = self.denominator.copy()
    -        if isinstance(descriptor, CompositeDimension):
    -            numerator.extend(descriptor.numerator)
    -            denominator.extend(descriptor.denominator)
    -            return CompositeDimension(numerator=numerator, denominator=denominator)
    -        if isinstance(descriptor, Dimension):
    -            numerator.append(descriptor)
    -            return CompositeDimension(numerator=numerator, denominator=denominator)
    -        if isinstance(descriptor, MeasurementUnit):
    -            numerator.append(Dimension(descriptor))
    -            return CompositeDimension(numerator=numerator, denominator=denominator)
    -        raise DescriptorBinaryOperationError(
    -            f"cannot multiply {self} with {descriptor}. "
    -        )
    -
    -    def __truediv__(self, descriptor: "UnitDescriptor") -> "CompositeDimension":
    -        """
    -        Defines multiplication between CompositeDimension(s) and other unit descriptors.
    -
    -        Examples:
    -            >>> class TemperatureUnit(MeasurementUnit):
    -            ...     CELCIUS = "C"
    -            >>> class TimeUnit(MeasurementUnit):
    -            ...     SECOND = "s"
    -            >>> class LengthUnit(MeasurementUnit):
    -            ...     CENTI_METER = "cm"
    -            >>> (TemperatureUnit.CELCIUS * LengthUnit.CENTI_METER) / TimeUnit.SECOND
    -            <CompositeDimension: C * cm / s>
    -        """
    -        numerator = self.numerator.copy()
    -        denominator = self.denominator.copy()
    -        if isinstance(descriptor, CompositeDimension):
    -            numerator.extend(descriptor.denominator)
    -            denominator.extend(descriptor.numerator)
    -            return CompositeDimension(numerator=numerator, denominator=denominator)
    -        if isinstance(descriptor, Dimension):
    -            denominator.append(descriptor)
    -            return CompositeDimension(numerator=numerator, denominator=denominator)
    -        if isinstance(descriptor, MeasurementUnit):
    -            denominator.append(Dimension(descriptor))
    -            return CompositeDimension(numerator=numerator, denominator=denominator)
    -        raise DescriptorBinaryOperationError(
    -            f"cannot divide {self} with {descriptor}. "
    -        )
    -
    -    def __pow__(self, power: float) -> "CompositeDimension":
    -        """
    -        Defines exponentiation for CompositeDimension(s).
    -
    -        Examples:
    -            >>> class TemperatureUnit(MeasurementUnit):
    -            ...     CELCIUS = "C"
    -            >>> class TimeUnit(MeasurementUnit):
    -            ...     HOUR = "hr"
    -
    -            >>> (TemperatureUnit.CELCIUS / TimeUnit.HOUR)**2
    -            <CompositeDimension: (C^2) / (hr^2)>
    -        """
    -        if not isinstance(power, (float, int)):
    -            raise DescriptorExponentError(
    -                f"invalid exponent: {{ value: {power}, type: {type(power)} }};"
    -                " expected float or int. "
    -            )
    -        numerator = [n**power for n in self._numerator_copy()]
    -        denominator = [d**power for d in self._denominator_copy()]
    -        return CompositeDimension(numerator, denominator)
    -
    -    def __eq__(self, dimension) -> bool:
    -        """
    -        Defines equality for CompositeDimension(s).
    -
    -        Examples:
    -            >>> class TemperatureUnit(MeasurementUnit):
    -            ...     CELCIUS = "C"
    -            >>> class TimeUnit(MeasurementUnit):
    -            ...     HOUR = "hr"
    -            >>> (TemperatureUnit.CELCIUS / TimeUnit.HOUR) != (TimeUnit.HOUR / TemperatureUnit.CELCIUS)
    -            True
    -        """
    -        if not isinstance(dimension, CompositeDimension):
    -            return False
    -        return Counter(self.numerator) == Counter(dimension.numerator) and (
    -            Counter(self.denominator) == Counter(dimension.denominator)
    -        )
    -
    -    def __hash__(self) -> int:
    -        return hash(str(self))
    -
    -    def __str__(self):
    -        numerators = " * ".join(sorted([str(n) for n in self.numerator]))
    -        denominators = " / ".join(sorted([str(d) for d in self.denominator]))
    -        if len(denominators) > 0:
    -            denominators = " / " + denominators
    -        return numerators + denominators
    -
    -    def __repr__(self) -> str:
    -        numerators = " * ".join(sorted([str(n) for n in self.numerator]))
    -        denominators = " / ".join(sorted([str(d) for d in self.denominator]))
    -        if len(denominators) > 0:
    -            denominators = " / " + denominators
    -        return f"<CompositeDimension: {numerators + denominators}>"
    +            ...     METER = "m"
    +
    +            >>> CompositeDimension().has_no_units()
    +            True
    +            >>> CompositeDimension([LengthUnit.METER]).has_no_units()
    +            False
    +        """
    +        return len(self.denominator) == 0 and len(self.numerator) == 0
    +
    +    def _numerator_copy(self) -> List[Dimension]:
    +        return [replace(n) for n in self.numerator]
    +
    +    def _denominator_copy(self) -> List[Dimension]:
    +        return [replace(d) for d in self.denominator]
    +
    +    def __mul__(self, descriptor: "UnitDescriptor") -> "CompositeDimension":
    +        """
    +        Defines multiplication between CompositeDimension(s) and other unit descriptors.
    +
    +        Examples:
    +            >>> class TemperatureUnit(MeasurementUnit):
    +            ...     CELCIUS = "C"
    +            >>> class TimeUnit(MeasurementUnit):
    +            ...     SECOND = "s"
    +            >>> class LengthUnit(MeasurementUnit):
    +            ...     CENTI_METER = "cm"
    +            >>> (TemperatureUnit.CELCIUS / LengthUnit.CENTI_METER) * TimeUnit.SECOND
    +            <CompositeDimension: C * s / cm>
    +        """
    +        numerator = self.numerator.copy()
    +        denominator = self.denominator.copy()
    +        if isinstance(descriptor, CompositeDimension):
    +            numerator.extend(descriptor.numerator)
    +            denominator.extend(descriptor.denominator)
    +            return CompositeDimension(numerator=numerator, denominator=denominator)
    +        if isinstance(descriptor, Dimension):
    +            numerator.append(descriptor)
    +            return CompositeDimension(numerator=numerator, denominator=denominator)
    +        if isinstance(descriptor, MeasurementUnit):
    +            numerator.append(Dimension(descriptor))
    +            return CompositeDimension(numerator=numerator, denominator=denominator)
    +        raise DescriptorBinaryOperationError(
    +            f"cannot multiply {self} with {descriptor}. "
    +        )
    +
    +    def __truediv__(self, descriptor: "UnitDescriptor") -> "CompositeDimension":
    +        """
    +        Defines multiplication between CompositeDimension(s) and other unit descriptors.
    +
    +        Examples:
    +            >>> class TemperatureUnit(MeasurementUnit):
    +            ...     CELCIUS = "C"
    +            >>> class TimeUnit(MeasurementUnit):
    +            ...     SECOND = "s"
    +            >>> class LengthUnit(MeasurementUnit):
    +            ...     CENTI_METER = "cm"
    +            >>> (TemperatureUnit.CELCIUS * LengthUnit.CENTI_METER) / TimeUnit.SECOND
    +            <CompositeDimension: C * cm / s>
    +        """
    +        numerator = self.numerator.copy()
    +        denominator = self.denominator.copy()
    +        if isinstance(descriptor, CompositeDimension):
    +            numerator.extend(descriptor.denominator)
    +            denominator.extend(descriptor.numerator)
    +            return CompositeDimension(numerator=numerator, denominator=denominator)
    +        if isinstance(descriptor, Dimension):
    +            denominator.append(descriptor)
    +            return CompositeDimension(numerator=numerator, denominator=denominator)
    +        if isinstance(descriptor, MeasurementUnit):
    +            denominator.append(Dimension(descriptor))
    +            return CompositeDimension(numerator=numerator, denominator=denominator)
    +        raise DescriptorBinaryOperationError(
    +            f"cannot divide {self} with {descriptor}. "
    +        )
    +
    +    def __pow__(self, power: float) -> "CompositeDimension":
    +        """
    +        Defines exponentiation for CompositeDimension(s).
    +
    +        Examples:
    +            >>> class TemperatureUnit(MeasurementUnit):
    +            ...     CELCIUS = "C"
    +            >>> class TimeUnit(MeasurementUnit):
    +            ...     HOUR = "hr"
    +
    +            >>> (TemperatureUnit.CELCIUS / TimeUnit.HOUR)**2
    +            <CompositeDimension: (C^2) / (hr^2)>
    +        """
    +        if not isinstance(power, (float, int)):
    +            raise DescriptorExponentError(
    +                f"invalid exponent: {{ value: {power}, type: {type(power)} }};"
    +                " expected float or int. "
    +            )
    +        numerator = [n**power for n in self._numerator_copy()]
    +        denominator = [d**power for d in self._denominator_copy()]
    +        return CompositeDimension(numerator, denominator)
    +
    +    def __eq__(self, dimension) -> bool:
    +        """
    +        Defines equality for CompositeDimension(s).
    +
    +        Examples:
    +            >>> class TemperatureUnit(MeasurementUnit):
    +            ...     CELCIUS = "C"
    +            >>> class TimeUnit(MeasurementUnit):
    +            ...     HOUR = "hr"
    +            >>> (TemperatureUnit.CELCIUS / TimeUnit.HOUR) != (TimeUnit.HOUR / TemperatureUnit.CELCIUS)
    +            True
    +        """
    +        if not isinstance(dimension, CompositeDimension):
    +            return False
    +        return Counter(self.numerator) == Counter(dimension.numerator) and (
    +            Counter(self.denominator) == Counter(dimension.denominator)
    +        )
    +
    +    def __hash__(self) -> int:
    +        return hash(str(self))
    +
    +    def __str__(self):
    +        numerators = " * ".join(sorted([str(n) for n in self.numerator]))
    +        denominators = " / ".join(sorted([str(d) for d in self.denominator]))
    +        if len(denominators) > 0:
    +            denominators = " / " + denominators
    +        return numerators + denominators
    +
    +    def __repr__(self) -> str:
    +        numerators = " * ".join(sorted([str(n) for n in self.numerator]))
    +        denominators = " / ".join(sorted([str(d) for d in self.denominator]))
    +        if len(denominators) > 0:
    +            denominators = " / " + denominators
    +        return f"<CompositeDimension: {numerators + denominators}>"
     
    @@ -3690,39 +3714,39 @@

    Source code in src/property_utils/units/descriptors.py -
    def __eq__(self, dimension) -> bool:
    -    """
    -    Defines equality for CompositeDimension(s).
    -
    -    Examples:
    -        >>> class TemperatureUnit(MeasurementUnit):
    -        ...     CELCIUS = "C"
    -        >>> class TimeUnit(MeasurementUnit):
    -        ...     HOUR = "hr"
    -        >>> (TemperatureUnit.CELCIUS / TimeUnit.HOUR) != (TimeUnit.HOUR / TemperatureUnit.CELCIUS)
    -        True
    -    """
    -    if not isinstance(dimension, CompositeDimension):
    -        return False
    -    return Counter(self.numerator) == Counter(dimension.numerator) and (
    -        Counter(self.denominator) == Counter(dimension.denominator)
    -    )
    +              
    def __eq__(self, dimension) -> bool:
    +    """
    +    Defines equality for CompositeDimension(s).
    +
    +    Examples:
    +        >>> class TemperatureUnit(MeasurementUnit):
    +        ...     CELCIUS = "C"
    +        >>> class TimeUnit(MeasurementUnit):
    +        ...     HOUR = "hr"
    +        >>> (TemperatureUnit.CELCIUS / TimeUnit.HOUR) != (TimeUnit.HOUR / TemperatureUnit.CELCIUS)
    +        True
    +    """
    +    if not isinstance(dimension, CompositeDimension):
    +        return False
    +    return Counter(self.numerator) == Counter(dimension.numerator) and (
    +        Counter(self.denominator) == Counter(dimension.denominator)
    +    )
     
    @@ -3756,63 +3780,63 @@

    Source code in src/property_utils/units/descriptors.py -
    1782
    -1783
    -1784
    -1785
    -1786
    -1787
    -1788
    -1789
    -1790
    -1791
    -1792
    -1793
    -1794
    -1795
    -1796
    -1797
    -1798
    -1799
    -1800
    -1801
    -1802
    -1803
    -1804
    -1805
    -1806
    -1807
    +              
    def __mul__(self, descriptor: "UnitDescriptor") -> "CompositeDimension":
    -    """
    -    Defines multiplication between CompositeDimension(s) and other unit descriptors.
    -
    -    Examples:
    -        >>> class TemperatureUnit(MeasurementUnit):
    -        ...     CELCIUS = "C"
    -        >>> class TimeUnit(MeasurementUnit):
    -        ...     SECOND = "s"
    -        >>> class LengthUnit(MeasurementUnit):
    -        ...     CENTI_METER = "cm"
    -        >>> (TemperatureUnit.CELCIUS / LengthUnit.CENTI_METER) * TimeUnit.SECOND
    -        <CompositeDimension: C * s / cm>
    -    """
    -    numerator = self.numerator.copy()
    -    denominator = self.denominator.copy()
    -    if isinstance(descriptor, CompositeDimension):
    -        numerator.extend(descriptor.numerator)
    -        denominator.extend(descriptor.denominator)
    -        return CompositeDimension(numerator=numerator, denominator=denominator)
    -    if isinstance(descriptor, Dimension):
    -        numerator.append(descriptor)
    -        return CompositeDimension(numerator=numerator, denominator=denominator)
    -    if isinstance(descriptor, MeasurementUnit):
    -        numerator.append(Dimension(descriptor))
    -        return CompositeDimension(numerator=numerator, denominator=denominator)
    -    raise DescriptorBinaryOperationError(
    -        f"cannot multiply {self} with {descriptor}. "
    -    )
    +1810
    +1811
    +1812
    +1813
    +1814
    +1815
    +1816
    +1817
    +1818
    +1819
    +1820
    +1821
    +1822
    +1823
    +1824
    +1825
    +1826
    +1827
    +1828
    +1829
    +1830
    +1831
    +1832
    +1833
    +1834
    +1835
    def __mul__(self, descriptor: "UnitDescriptor") -> "CompositeDimension":
    +    """
    +    Defines multiplication between CompositeDimension(s) and other unit descriptors.
    +
    +    Examples:
    +        >>> class TemperatureUnit(MeasurementUnit):
    +        ...     CELCIUS = "C"
    +        >>> class TimeUnit(MeasurementUnit):
    +        ...     SECOND = "s"
    +        >>> class LengthUnit(MeasurementUnit):
    +        ...     CENTI_METER = "cm"
    +        >>> (TemperatureUnit.CELCIUS / LengthUnit.CENTI_METER) * TimeUnit.SECOND
    +        <CompositeDimension: C * s / cm>
    +    """
    +    numerator = self.numerator.copy()
    +    denominator = self.denominator.copy()
    +    if isinstance(descriptor, CompositeDimension):
    +        numerator.extend(descriptor.numerator)
    +        denominator.extend(descriptor.denominator)
    +        return CompositeDimension(numerator=numerator, denominator=denominator)
    +    if isinstance(descriptor, Dimension):
    +        numerator.append(descriptor)
    +        return CompositeDimension(numerator=numerator, denominator=denominator)
    +    if isinstance(descriptor, MeasurementUnit):
    +        numerator.append(Dimension(descriptor))
    +        return CompositeDimension(numerator=numerator, denominator=denominator)
    +    raise DescriptorBinaryOperationError(
    +        f"cannot multiply {self} with {descriptor}. "
    +    )
     
    @@ -3845,47 +3869,47 @@

    Source code in src/property_utils/units/descriptors.py -
    def __pow__(self, power: float) -> "CompositeDimension":
    -    """
    -    Defines exponentiation for CompositeDimension(s).
    -
    -    Examples:
    -        >>> class TemperatureUnit(MeasurementUnit):
    -        ...     CELCIUS = "C"
    -        >>> class TimeUnit(MeasurementUnit):
    -        ...     HOUR = "hr"
    -
    -        >>> (TemperatureUnit.CELCIUS / TimeUnit.HOUR)**2
    -        <CompositeDimension: (C^2) / (hr^2)>
    -    """
    -    if not isinstance(power, (float, int)):
    -        raise DescriptorExponentError(
    -            f"invalid exponent: {{ value: {power}, type: {type(power)} }};"
    -            " expected float or int. "
    -        )
    -    numerator = [n**power for n in self._numerator_copy()]
    -    denominator = [d**power for d in self._denominator_copy()]
    -    return CompositeDimension(numerator, denominator)
    +              
    def __pow__(self, power: float) -> "CompositeDimension":
    +    """
    +    Defines exponentiation for CompositeDimension(s).
    +
    +    Examples:
    +        >>> class TemperatureUnit(MeasurementUnit):
    +        ...     CELCIUS = "C"
    +        >>> class TimeUnit(MeasurementUnit):
    +        ...     HOUR = "hr"
    +
    +        >>> (TemperatureUnit.CELCIUS / TimeUnit.HOUR)**2
    +        <CompositeDimension: (C^2) / (hr^2)>
    +    """
    +    if not isinstance(power, (float, int)):
    +        raise DescriptorExponentError(
    +            f"invalid exponent: {{ value: {power}, type: {type(power)} }};"
    +            " expected float or int. "
    +        )
    +    numerator = [n**power for n in self._numerator_copy()]
    +    denominator = [d**power for d in self._denominator_copy()]
    +    return CompositeDimension(numerator, denominator)
     
    @@ -3919,64 +3943,64 @@

    Source code in src/property_utils/units/descriptors.py -
    1812
    -1813
    -1814
    -1815
    -1816
    -1817
    -1818
    -1819
    -1820
    -1821
    -1822
    -1823
    -1824
    -1825
    -1826
    -1827
    -1828
    -1829
    -1830
    -1831
    -1832
    -1833
    -1834
    -1835
    -1836
    -1837
    +              
    def __truediv__(self, descriptor: "UnitDescriptor") -> "CompositeDimension":
    -    """
    -    Defines multiplication between CompositeDimension(s) and other unit descriptors.
    -
    -    Examples:
    -        >>> class TemperatureUnit(MeasurementUnit):
    -        ...     CELCIUS = "C"
    -        >>> class TimeUnit(MeasurementUnit):
    -        ...     SECOND = "s"
    -        >>> class LengthUnit(MeasurementUnit):
    -        ...     CENTI_METER = "cm"
    -        >>> (TemperatureUnit.CELCIUS * LengthUnit.CENTI_METER) / TimeUnit.SECOND
    -        <CompositeDimension: C * cm / s>
    -    """
    -    numerator = self.numerator.copy()
    -    denominator = self.denominator.copy()
    -    if isinstance(descriptor, CompositeDimension):
    -        numerator.extend(descriptor.denominator)
    -        denominator.extend(descriptor.numerator)
    -        return CompositeDimension(numerator=numerator, denominator=denominator)
    -    if isinstance(descriptor, Dimension):
    -        denominator.append(descriptor)
    -        return CompositeDimension(numerator=numerator, denominator=denominator)
    -    if isinstance(descriptor, MeasurementUnit):
    -        denominator.append(Dimension(descriptor))
    -        return CompositeDimension(numerator=numerator, denominator=denominator)
    -    raise DescriptorBinaryOperationError(
    -        f"cannot divide {self} with {descriptor}. "
    -    )
    -
    +1840 +1841 +1842 +1843 +1844 +1845 +1846 +1847 +1848 +1849 +1850 +1851 +1852 +1853 +1854 +1855 +1856 +1857 +1858 +1859 +1860 +1861 +1862 +1863 +1864 +1865
    def __truediv__(self, descriptor: "UnitDescriptor") -> "CompositeDimension":
    +    """
    +    Defines multiplication between CompositeDimension(s) and other unit descriptors.
    +
    +    Examples:
    +        >>> class TemperatureUnit(MeasurementUnit):
    +        ...     CELCIUS = "C"
    +        >>> class TimeUnit(MeasurementUnit):
    +        ...     SECOND = "s"
    +        >>> class LengthUnit(MeasurementUnit):
    +        ...     CENTI_METER = "cm"
    +        >>> (TemperatureUnit.CELCIUS * LengthUnit.CENTI_METER) / TimeUnit.SECOND
    +        <CompositeDimension: C * cm / s>
    +    """
    +    numerator = self.numerator.copy()
    +    denominator = self.denominator.copy()
    +    if isinstance(descriptor, CompositeDimension):
    +        numerator.extend(descriptor.denominator)
    +        denominator.extend(descriptor.numerator)
    +        return CompositeDimension(numerator=numerator, denominator=denominator)
    +    if isinstance(descriptor, Dimension):
    +        denominator.append(descriptor)
    +        return CompositeDimension(numerator=numerator, denominator=denominator)
    +    if isinstance(descriptor, MeasurementUnit):
    +        denominator.append(Dimension(descriptor))
    +        return CompositeDimension(numerator=numerator, denominator=denominator)
    +    raise DescriptorBinaryOperationError(
    +        f"cannot divide {self} with {descriptor}. "
    +    )
    +
    @@ -4007,41 +4031,41 @@

    Source code in src/property_utils/units/descriptors.py -
    @staticmethod
    -def from_descriptor(descriptor: UnitDescriptor) -> "CompositeDimension":
    -    """
    -    Create a CompositeDimension from given descriptor.
    -    If descriptor is already a CompositeDimension, it returns the same object.
    -
    -    This function does not serve as a constructor for CompositeDimension, rather it
    -    is intended to be used to convert an unknown unit descriptor to a
    -    CompositeDimension.
    -
    -    Raises `UnitDescriptorTypeError` if given descriptor cannot be translated
    -    to a CompositeDimension instance.
    -    """
    -    if not isinstance(descriptor, CompositeDimension):
    -        raise UnitDescriptorTypeError(
    -            f"cannot create CompositeDimension from descriptor {descriptor}"
    -        )
    -    return descriptor
    +              
    @staticmethod
    +def from_descriptor(descriptor: UnitDescriptor) -> "CompositeDimension":
    +    """
    +    Create a CompositeDimension from given descriptor.
    +    If descriptor is already a CompositeDimension, it returns the same object.
    +
    +    This function does not serve as a constructor for CompositeDimension, rather it
    +    is intended to be used to convert an unknown unit descriptor to a
    +    CompositeDimension.
    +
    +    Raises `UnitDescriptorTypeError` if given descriptor cannot be translated
    +    to a CompositeDimension instance.
    +    """
    +    if not isinstance(descriptor, CompositeDimension):
    +        raise UnitDescriptorTypeError(
    +            f"cannot create CompositeDimension from descriptor {descriptor}"
    +        )
    +    return descriptor
     
    @@ -4079,57 +4103,57 @@

    Source code in src/property_utils/units/descriptors.py -
    1629
    -1630
    -1631
    -1632
    -1633
    -1634
    -1635
    -1636
    -1637
    -1638
    -1639
    -1640
    -1641
    -1642
    -1643
    -1644
    -1645
    -1646
    -1647
    -1648
    -1649
    -1650
    -1651
    +              
    def get_denominator(
    -    self,
    -    generic: Union[MeasurementUnitType, GenericDimension],
    -    default: Optional[Default] = None,
    -) -> Union[Dimension, Optional[Default]]:
    -    """
    -    Get a dimension from the denominator. If the dimension is not found it returns
    -    the default.
    -
    -    Examples:
    -        >>> class LengthUnit(MeasurementUnit):
    -        ...     METER = "m"
    -
    -        >>> class TemperatureUnit(MeasurementUnit):
    -        ...     KELVIN = "K"
    -
    -        >>> composite = TemperatureUnit.KELVIN / (LengthUnit.METER**3)
    -        >>> composite.get_denominator(LengthUnit**3)
    -        <Dimension: m^3>
    -        >>> composite.get_denominator(LengthUnit, "default")
    -        'default'
    -    """
    -    for d in self.denominator:
    -        if d.isinstance(generic):
    -            return d
    -    return default
    +1654
    +1655
    +1656
    +1657
    +1658
    +1659
    +1660
    +1661
    +1662
    +1663
    +1664
    +1665
    +1666
    +1667
    +1668
    +1669
    +1670
    +1671
    +1672
    +1673
    +1674
    +1675
    +1676
    def get_denominator(
    +    self,
    +    generic: Union[MeasurementUnitType, GenericDimension],
    +    default: Optional[Default] = None,
    +) -> Union[Dimension, Optional[Default]]:
    +    """
    +    Get a dimension from the denominator. If the dimension is not found it returns
    +    the default.
    +
    +    Examples:
    +        >>> class LengthUnit(MeasurementUnit):
    +        ...     METER = "m"
    +
    +        >>> class TemperatureUnit(MeasurementUnit):
    +        ...     KELVIN = "K"
    +
    +        >>> composite = TemperatureUnit.KELVIN / (LengthUnit.METER**3)
    +        >>> composite.get_denominator(LengthUnit**3)
    +        <Dimension: m^3>
    +        >>> composite.get_denominator(LengthUnit, "default")
    +        'default'
    +    """
    +    for d in self.denominator:
    +        if d.isinstance(generic):
    +            return d
    +    return default
     
    @@ -4167,57 +4191,57 @@

    Source code in src/property_utils/units/descriptors.py -
    1602
    -1603
    -1604
    -1605
    -1606
    -1607
    -1608
    -1609
    -1610
    -1611
    -1612
    -1613
    -1614
    -1615
    -1616
    -1617
    -1618
    -1619
    -1620
    -1621
    -1622
    -1623
    -1624
    +              
    def get_numerator(
    -    self,
    -    generic: Union[MeasurementUnitType, GenericDimension],
    -    default: Optional[Default] = None,
    -) -> Union[Dimension, Optional[Default]]:
    -    """
    -    Get a dimension from the numerator. If the dimension is not found it returns
    -    the default.
    -
    -    Examples:
    -        >>> class LengthUnit(MeasurementUnit):
    -        ...     METER = "m"
    -
    -        >>> class TemperatureUnit(MeasurementUnit):
    -        ...     KELVIN = "K"
    -
    -        >>> composite = TemperatureUnit.KELVIN / (LengthUnit.METER**3)
    -        >>> composite.get_numerator(TemperatureUnit)
    -        <Dimension: K>
    -        >>> composite.get_numerator(LengthUnit, "default")
    -        'default'
    -    """
    -    for n in self.numerator:
    -        if n.isinstance(generic):
    -            return n
    -    return default
    +1627
    +1628
    +1629
    +1630
    +1631
    +1632
    +1633
    +1634
    +1635
    +1636
    +1637
    +1638
    +1639
    +1640
    +1641
    +1642
    +1643
    +1644
    +1645
    +1646
    +1647
    +1648
    +1649
    def get_numerator(
    +    self,
    +    generic: Union[MeasurementUnitType, GenericDimension],
    +    default: Optional[Default] = None,
    +) -> Union[Dimension, Optional[Default]]:
    +    """
    +    Get a dimension from the numerator. If the dimension is not found it returns
    +    the default.
    +
    +    Examples:
    +        >>> class LengthUnit(MeasurementUnit):
    +        ...     METER = "m"
    +
    +        >>> class TemperatureUnit(MeasurementUnit):
    +        ...     KELVIN = "K"
    +
    +        >>> composite = TemperatureUnit.KELVIN / (LengthUnit.METER**3)
    +        >>> composite.get_numerator(TemperatureUnit)
    +        <Dimension: K>
    +        >>> composite.get_numerator(LengthUnit, "default")
    +        'default'
    +    """
    +    for n in self.numerator:
    +        if n.isinstance(generic):
    +            return n
    +    return default
     
    @@ -4250,33 +4274,33 @@

    Source code in src/property_utils/units/descriptors.py -
    def has_no_units(self) -> bool:
    -    """
    -    Returns True if the composite dimension does not have any units, False otherwise.
    -
    -    Examples:
    -        >>> class LengthUnit(MeasurementUnit):
    -        ...     METER = "m"
    -
    -        >>> CompositeDimension().has_no_units()
    -        True
    -        >>> CompositeDimension([LengthUnit.METER]).has_no_units()
    -        False
    -    """
    -    return len(self.denominator) == 0 and len(self.numerator) == 0
    +              
    def has_no_units(self) -> bool:
    +    """
    +    Returns True if the composite dimension does not have any units, False otherwise.
    +
    +    Examples:
    +        >>> class LengthUnit(MeasurementUnit):
    +        ...     METER = "m"
    +
    +        >>> CompositeDimension().has_no_units()
    +        True
    +        >>> CompositeDimension([LengthUnit.METER]).has_no_units()
    +        False
    +    """
    +    return len(self.denominator) == 0 and len(self.numerator) == 0
     
    @@ -4309,33 +4333,33 @@

    Source code in src/property_utils/units/descriptors.py -
    def inverse(self) -> "CompositeDimension":
    -    """
    -    Create a composite with inverse units.
    -
    -    Examples:
    -        >>> class LengthUnit(MeasurementUnit):
    -        ...     METER = "m"
    -        >>> class TimeUnit(MeasurementUnit):
    -        ...     SECOND = "s"
    -
    -        >>> (LengthUnit.METER / TimeUnit.SECOND).inverse()
    -        <CompositeDimension: s / m>
    -    """
    -    return CompositeDimension(self._denominator_copy(), self._numerator_copy())
    +              
    def inverse(self) -> "CompositeDimension":
    +    """
    +    Create a composite with inverse units.
    +
    +    Examples:
    +        >>> class LengthUnit(MeasurementUnit):
    +        ...     METER = "m"
    +        >>> class TimeUnit(MeasurementUnit):
    +        ...     SECOND = "s"
    +
    +        >>> (LengthUnit.METER / TimeUnit.SECOND).inverse()
    +        <CompositeDimension: s / m>
    +    """
    +    return CompositeDimension(self._denominator_copy(), self._numerator_copy())
     
    @@ -4373,49 +4397,49 @@

    Source code in src/property_utils/units/descriptors.py -
    def isinstance(self, generic: GenericUnitDescriptor) -> bool:
    -    """
    -    Returns True if the CompositeDimension is an instance of the generic, False
    -    otherwise.
    -
    -    Examples:
    -        >>> class TemperatureUnit(MeasurementUnit):
    -        ...     CELCIUS = "C"
    -
    -        >>> class LengthUnit(MeasurementUnit):
    -        ...     METER = "m"
    -
    -        >>> (TemperatureUnit.CELCIUS / LengthUnit.METER).isinstance(TemperatureUnit / LengthUnit)
    -        True
    -
    -        >>> (TemperatureUnit.CELCIUS * LengthUnit.METER).isinstance(TemperatureUnit**2)
    -        False
    -    """
    -    if not isinstance(generic, GenericCompositeDimension):
    -        return False
    -
    -    return self.to_generic() == generic
    +              
    def isinstance(self, generic: GenericUnitDescriptor) -> bool:
    +    """
    +    Returns True if the CompositeDimension is an instance of the generic, False
    +    otherwise.
    +
    +    Examples:
    +        >>> class TemperatureUnit(MeasurementUnit):
    +        ...     CELCIUS = "C"
    +
    +        >>> class LengthUnit(MeasurementUnit):
    +        ...     METER = "m"
    +
    +        >>> (TemperatureUnit.CELCIUS / LengthUnit.METER).isinstance(TemperatureUnit / LengthUnit)
    +        True
    +
    +        >>> (TemperatureUnit.CELCIUS * LengthUnit.METER).isinstance(TemperatureUnit**2)
    +        False
    +    """
    +    if not isinstance(generic, GenericCompositeDimension):
    +        return False
    +
    +    return self.to_generic() == generic
     
    @@ -4460,61 +4484,61 @@

    Source code in src/property_utils/units/descriptors.py -
    1554
    -1555
    -1556
    -1557
    -1558
    -1559
    -1560
    -1561
    -1562
    -1563
    -1564
    -1565
    -1566
    -1567
    -1568
    -1569
    -1570
    -1571
    -1572
    -1573
    -1574
    -1575
    -1576
    +              
    def isinstance_equivalent(self, generic: GenericUnitDescriptor) -> bool:
    -    """
    -    Returns True if the UnitDescriptor is an instance-equivalent of the generic,
    -    False otherwise.
    -
    -    A unit descriptor is an instance-equivalent of a generic if the generic of the
    -    unit descriptor is equivalent to the generic.
    -
    -    Equivalence between generics is checked with the `is_equivalent` method.
    -
    -    Examples:
    -        >>> class MassUnit(MeasurementUnit):
    -        ...     KILO_GRAM = "kg"
    -        >>> class LengthUnit(MeasurementUnit):
    -        ...     METER = "m"
    -        >>> class TimeUnit(MeasurementUnit):
    -        ...     SECOND = "s"
    -
    -        >>> class ForceUnit(AliasMeasurementUnit):
    -        ...     NEWTON = "N"
    -        ...     @classmethod
    -        ...     def aliased_generic_descriptor(cls):
    -        ...         return MassUnit * LengthUnit / (TimeUnit**2)
    -
    -        >>> (MassUnit.KILO_GRAM * LengthUnit.METER / (TimeUnit.SECOND**2)).isinstance_equivalent(ForceUnit)
    -        True
    -    """
    -    return self.to_generic().is_equivalent(generic)
    +1581
    +1582
    +1583
    +1584
    +1585
    +1586
    +1587
    +1588
    +1589
    +1590
    +1591
    +1592
    +1593
    +1594
    +1595
    +1596
    +1597
    +1598
    +1599
    +1600
    +1601
    +1602
    +1603
    def isinstance_equivalent(self, generic: GenericUnitDescriptor) -> bool:
    +    """
    +    Returns True if the UnitDescriptor is an instance-equivalent of the generic,
    +    False otherwise.
    +
    +    A unit descriptor is an instance-equivalent of a generic if the generic of the
    +    unit descriptor is equivalent to the generic.
    +
    +    Equivalence between generics is checked with the `is_equivalent` method.
    +
    +    Examples:
    +        >>> class MassUnit(MeasurementUnit):
    +        ...     KILO_GRAM = "kg"
    +        >>> class LengthUnit(MeasurementUnit):
    +        ...     METER = "m"
    +        >>> class TimeUnit(MeasurementUnit):
    +        ...     SECOND = "s"
    +
    +        >>> class ForceUnit(AliasMeasurementUnit):
    +        ...     NEWTON = "N"
    +        ...     @classmethod
    +        ...     def aliased_generic_descriptor(cls):
    +        ...         return MassUnit * LengthUnit / (TimeUnit**2)
    +
    +        >>> (MassUnit.KILO_GRAM * LengthUnit.METER / (TimeUnit.SECOND**2)).isinstance_equivalent(ForceUnit)
    +        True
    +    """
    +    return self.to_generic().is_equivalent(generic)
     
    @@ -4554,51 +4578,51 @@

    Source code in src/property_utils/units/descriptors.py -
    def si(self) -> "CompositeDimension":
    -    """
    -    Returns this composite dimension in SI units.
    -
    -    Examples:
    -        >>> class TemperatureUnit(MeasurementUnit):
    -        ...     KELVIN = "K"
    -        ...     RANKINE = "R"
    -        ...     @classmethod
    -        ...     def si(cls): return cls.KELVIN
    -
    -        >>> class LengthUnit(MeasurementUnit):
    -        ...     METER = "m"
    -        ...     FOOT = "ft"
    -        ...     @classmethod
    -        ...     def si(cls): return cls.METER
    -
    -        >>> (TemperatureUnit.RANKINE / LengthUnit.FOOT**2).si()
    -        <CompositeDimension: K / (m^2)>
    -    """
    -    return CompositeDimension(
    -        [n.si() for n in self.numerator], [d.si() for d in self.denominator]
    -    )
    +              
    def si(self) -> "CompositeDimension":
    +    """
    +    Returns this composite dimension in SI units.
    +
    +    Examples:
    +        >>> class TemperatureUnit(MeasurementUnit):
    +        ...     KELVIN = "K"
    +        ...     RANKINE = "R"
    +        ...     @classmethod
    +        ...     def si(cls): return cls.KELVIN
    +
    +        >>> class LengthUnit(MeasurementUnit):
    +        ...     METER = "m"
    +        ...     FOOT = "ft"
    +        ...     @classmethod
    +        ...     def si(cls): return cls.METER
    +
    +        >>> (TemperatureUnit.RANKINE / LengthUnit.FOOT**2).si()
    +        <CompositeDimension: K / (m^2)>
    +    """
    +    return CompositeDimension(
    +        [n.si() for n in self.numerator], [d.si() for d in self.denominator]
    +    )
     
    @@ -4648,71 +4672,71 @@

    Source code in src/property_utils/units/descriptors.py -
    1712
    -1713
    -1714
    -1715
    -1716
    -1717
    -1718
    -1719
    -1720
    -1721
    -1722
    -1723
    -1724
    -1725
    -1726
    -1727
    -1728
    -1729
    -1730
    -1731
    -1732
    -1733
    -1734
    -1735
    -1736
    -1737
    +              
    def simplified(self) -> "CompositeDimension":
    -    """
    -    Returns a simplified version of this composite dimension as a new object.
    -
    -    Examples:
    -        >>> class PressureUnit(AliasMeasurementUnit):
    -        ...     BAR = "bar"
    -        ...     PASCAL = "Pa"
    -
    -        >>> class TemperatureUnit(MeasurementUnit):
    -        ...     KELVIN = "K"
    -
    -        >>> class LengthUnit(MeasurementUnit):
    -        ...     METER = "m"
    -
    -        >>> class TimeUnit(MeasurementUnit):
    -        ...     SECOND = "s"
    -
    -        >>> composite = (PressureUnit.BAR**(-2)) / (TemperatureUnit.KELVIN**(-1))
    -        >>> composite
    -        <CompositeDimension: (bar^-2) / (K^-1)>
    -        >>> composite.simplified()
    -        <CompositeDimension: K / (bar^2)>
    -
    -        >>> composite = PressureUnit.PASCAL * LengthUnit.METER * PressureUnit.PASCAL /TimeUnit.SECOND
    -        >>> composite
    -        <CompositeDimension: Pa * Pa * m / s>
    -        >>> composite.simplified()
    -        <CompositeDimension: (Pa^2) * m / s>
    -    """
    -    copy = replace(self)
    -    copy.simplify()
    -    return copy
    +1744
    +1745
    +1746
    +1747
    +1748
    +1749
    +1750
    +1751
    +1752
    +1753
    +1754
    +1755
    +1756
    +1757
    +1758
    +1759
    +1760
    +1761
    +1762
    +1763
    +1764
    +1765
    +1766
    +1767
    +1768
    +1769
    def simplified(self) -> "CompositeDimension":
    +    """
    +    Returns a simplified version of this composite dimension as a new object.
    +
    +    Examples:
    +        >>> class PressureUnit(AliasMeasurementUnit):
    +        ...     BAR = "bar"
    +        ...     PASCAL = "Pa"
    +
    +        >>> class TemperatureUnit(MeasurementUnit):
    +        ...     KELVIN = "K"
    +
    +        >>> class LengthUnit(MeasurementUnit):
    +        ...     METER = "m"
    +
    +        >>> class TimeUnit(MeasurementUnit):
    +        ...     SECOND = "s"
    +
    +        >>> composite = (PressureUnit.BAR**(-2)) / (TemperatureUnit.KELVIN**(-1))
    +        >>> composite
    +        <CompositeDimension: (bar^-2) / (K^-1)>
    +        >>> composite.simplified()
    +        <CompositeDimension: K / (bar^2)>
    +
    +        >>> composite = PressureUnit.PASCAL * LengthUnit.METER * PressureUnit.PASCAL /TimeUnit.SECOND
    +        >>> composite
    +        <CompositeDimension: Pa * Pa * m / s>
    +        >>> composite.simplified()
    +        <CompositeDimension: (Pa^2) * m / s>
    +    """
    +    copy = replace(self)
    +    copy.simplify()
    +    return copy
     
    @@ -4764,29 +4788,7 @@

    Source code in src/property_utils/units/descriptors.py -
    1656
    -1657
    -1658
    -1659
    -1660
    -1661
    -1662
    -1663
    -1664
    -1665
    -1666
    -1667
    -1668
    -1669
    -1670
    -1671
    -1672
    -1673
    -1674
    -1675
    -1676
    -1677
    -1678
    +              
    1678
     1679
     1680
     1681
    @@ -4818,61 +4820,89 @@ 

    1707 1708 1709 -1710

    def simplify(self) -> None:
    -    """
    -    Simplify the composite by merging common dimensions.
    -
    -    Examples:
    -        >>> class PressureUnit(AliasMeasurementUnit):
    -        ...     BAR = "bar"
    -        ...     PASCAL = "Pa"
    -
    -        >>> class TemperatureUnit(MeasurementUnit):
    -        ...     KELVIN = "K"
    -
    -        >>> class LengthUnit(MeasurementUnit):
    -        ...     METER = "m"
    -
    -        >>> class TimeUnit(MeasurementUnit):
    -        ...     SECOND = "s"
    -
    -        >>> composite = (PressureUnit.BAR**(-2)) / (TemperatureUnit.KELVIN**(-1))
    -        >>> composite
    -        <CompositeDimension: (bar^-2) / (K^-1)>
    -        >>> composite.simplify()
    -        >>> composite
    -        <CompositeDimension: K / (bar^2)>
    -
    -        >>> composite = PressureUnit.PASCAL * LengthUnit.METER * PressureUnit.PASCAL /TimeUnit.SECOND
    -        >>> composite
    -        <CompositeDimension: Pa * Pa * m / s>
    -        >>> composite.simplify()
    -        >>> composite
    -        <CompositeDimension: (Pa^2) * m / s>
    -    """
    -    exponents: Dict[MeasurementUnit, float] = {}
    -    for n in self.numerator:
    -        if n.unit in exponents:
    -            exponents[n.unit] += n.power
    -        else:
    -            exponents[n.unit] = n.power
    -
    -    for d in self.denominator:
    -        if d.unit in exponents:
    -            exponents[d.unit] -= d.power
    -        else:
    -            exponents[d.unit] = 0 - d.power
    -
    -    numerator = []
    -    denominator = []
    -    for unit, exponent in exponents.items():
    -        if exponent > 0:
    -            numerator.append(Dimension(unit) ** exponent)
    -        elif exponent < 0:
    -            denominator.append(Dimension(unit) ** abs(exponent))
    -
    -    self.numerator = numerator
    -    self.denominator = denominator
    +1710
    +1711
    +1712
    +1713
    +1714
    +1715
    +1716
    +1717
    +1718
    +1719
    +1720
    +1721
    +1722
    +1723
    +1724
    +1725
    +1726
    +1727
    +1728
    +1729
    +1730
    +1731
    +1732
    +1733
    +1734
    +1735
    def simplify(self) -> None:
    +    """
    +    Simplify the composite by merging common dimensions.
    +
    +    Examples:
    +        >>> class PressureUnit(AliasMeasurementUnit):
    +        ...     BAR = "bar"
    +        ...     PASCAL = "Pa"
    +
    +        >>> class TemperatureUnit(MeasurementUnit):
    +        ...     KELVIN = "K"
    +
    +        >>> class LengthUnit(MeasurementUnit):
    +        ...     METER = "m"
    +
    +        >>> class TimeUnit(MeasurementUnit):
    +        ...     SECOND = "s"
    +
    +        >>> composite = (PressureUnit.BAR**(-2)) / (TemperatureUnit.KELVIN**(-1))
    +        >>> composite
    +        <CompositeDimension: (bar^-2) / (K^-1)>
    +        >>> composite.simplify()
    +        >>> composite
    +        <CompositeDimension: K / (bar^2)>
    +
    +        >>> composite = PressureUnit.PASCAL * LengthUnit.METER * PressureUnit.PASCAL /TimeUnit.SECOND
    +        >>> composite
    +        <CompositeDimension: Pa * Pa * m / s>
    +        >>> composite.simplify()
    +        >>> composite
    +        <CompositeDimension: (Pa^2) * m / s>
    +    """
    +    exponents: Dict[MeasurementUnit, float] = {}
    +    for n in self.numerator:
    +        if n.unit in exponents:
    +            exponents[n.unit] += n.power
    +        else:
    +            exponents[n.unit] = n.power
    +
    +    for d in self.denominator:
    +        if d.unit in exponents:
    +            exponents[d.unit] -= d.power
    +        else:
    +            exponents[d.unit] = 0 - d.power
    +
    +    numerator = []
    +    denominator = []
    +    for unit, exponent in exponents.items():
    +        if unit.is_non_dimensional():
    +            continue  # do not add non dimensional units to the simplified composite
    +
    +        if exponent > 0:
    +            numerator.append(Dimension(unit) ** exponent)
    +        elif exponent < 0:
    +            denominator.append(Dimension(unit) ** abs(exponent))
    +
    +    self.numerator = numerator
    +    self.denominator = denominator
     
    @@ -4906,41 +4936,41 @@

    Source code in src/property_utils/units/descriptors.py -
    def to_generic(self) -> GenericCompositeDimension:
    -    """
    -    Create a generic descriptor from this CompositeDimension.
    -
    -    Examples:
    -        >>> class AmountUnit(MeasurementUnit):
    -        ...     MOL = "mol"
    -
    -        >>> class MassUnit(MeasurementUnit):
    -        ...     KILO_GRAM = "kg"
    -
    -        >>> (AmountUnit.MOL / MassUnit.KILO_GRAM).to_generic()
    -        <GenericCompositeDimension: AmountUnit / MassUnit>
    -    """
    -    return GenericCompositeDimension(
    -        numerator=[n.to_generic() for n in self.numerator],
    -        denominator=[d.to_generic() for d in self.denominator],
    -    )
    +              
    def to_generic(self) -> GenericCompositeDimension:
    +    """
    +    Create a generic descriptor from this CompositeDimension.
    +
    +    Examples:
    +        >>> class AmountUnit(MeasurementUnit):
    +        ...     MOL = "mol"
    +
    +        >>> class MassUnit(MeasurementUnit):
    +        ...     KILO_GRAM = "kg"
    +
    +        >>> (AmountUnit.MOL / MassUnit.KILO_GRAM).to_generic()
    +        <GenericCompositeDimension: AmountUnit / MassUnit>
    +    """
    +    return GenericCompositeDimension(
    +        numerator=[n.to_generic() for n in self.numerator],
    +        denominator=[d.to_generic() for d in self.denominator],
    +    )
     
    @@ -4988,26 +5018,7 @@

    Source code in src/property_utils/units/descriptors.py -
     773
    - 774
    - 775
    - 776
    - 777
    - 778
    - 779
    - 780
    - 781
    - 782
    - 783
    - 784
    - 785
    - 786
    - 787
    - 788
    - 789
    - 790
    - 791
    - 792
    +                
     792
      793
      794
      795
    @@ -5256,275 +5267,300 @@ 

    1038 1039 1040 -1041

    @dataclass
    -class Dimension:
    -    """
    -    A Dimension is a wrapper around MeasurementUnit.
    -
    -    Objects of this class can represent either a simple MeasurementUnit or a
    -    MeasurementUnit to some power.
    -
    -    Examples:
    -        >>> class TimeUnit(MeasurementUnit):
    -        ...     SECOND = "s"
    -
    -        >>> TimeUnit.SECOND**2
    -        <Dimension: s^2>
    -    """
    -
    -    unit: MeasurementUnit
    -    power: float = 1
    -
    -    def __init__(self, unit: MeasurementUnit, power: float = 1) -> None:
    -        if not isinstance(power, (float, int)):
    -            raise DescriptorExponentError(
    -                f"invalid exponent: {{ value: {power}, type: {type(power)} }};"
    -                " expected float or int. "
    -            )
    -        self.unit = unit
    -        self.power = power
    -
    -    @staticmethod
    -    def from_descriptor(descriptor: UnitDescriptor) -> "Dimension":
    -        """
    -        Create a Dimension from given descriptor.
    -        If descriptor is already a Dimension, it returns the same object.
    -
    -        This function does not serve as a constructor for Dimension, rather it
    -        is intended to be used to convert an unknown unit descriptor to a Dimension.
    -
    -        Raises `UnitDescriptorTypeError` if given descriptor cannot be translated
    -        to a Dimension instance.
    -        """
    -        if isinstance(descriptor, Dimension):
    -            return descriptor
    -        if isinstance(descriptor, MeasurementUnit):
    -            return Dimension(descriptor)
    -        raise UnitDescriptorTypeError(
    -            f"cannot create Dimension from descriptor: {descriptor}"
    -        )
    -
    -    def si(self) -> "Dimension":
    +1041
    +1042
    +1043
    +1044
    +1045
    +1046
    +1047
    +1048
    +1049
    +1050
    +1051
    +1052
    +1053
    +1054
    +1055
    +1056
    +1057
    +1058
    +1059
    +1060
    +1061
    +1062
    +1063
    @dataclass
    +class Dimension:
    +    """
    +    A Dimension is a wrapper around MeasurementUnit.
    +
    +    Objects of this class can represent either a simple MeasurementUnit or a
    +    MeasurementUnit to some power.
    +
    +    Examples:
    +        >>> class TimeUnit(MeasurementUnit):
    +        ...     SECOND = "s"
    +
    +        >>> TimeUnit.SECOND**2
    +        <Dimension: s^2>
    +    """
    +
    +    unit: MeasurementUnit
    +    power: float = 1
    +
    +    def __init__(self, unit: MeasurementUnit, power: float = 1) -> None:
    +        if not isinstance(power, (float, int)):
    +            raise DescriptorExponentError(
    +                f"invalid exponent: {{ value: {power}, type: {type(power)} }};"
    +                " expected float or int. "
    +            )
    +        self.unit = unit
    +        self.power = power
    +
    +    @staticmethod
    +    def from_descriptor(descriptor: UnitDescriptor) -> "Dimension":
             """
    -        Returns this dimension in SI units.
    -
    -        Examples:
    -            >>> class LengthUnit(MeasurementUnit):
    -            ...     METER = "m"
    -            ...     FOOT = "ft"
    -            ...     @classmethod
    -            ...     def si(cls): return cls.METER
    -
    -            >>> (LengthUnit.FOOT**2).si()
    -            <Dimension: m^2>
    -        """
    -        return Dimension(self.unit.si(), self.power)
    -
    -    def isinstance(self, generic: GenericUnitDescriptor) -> bool:
    -        """
    -        Returns True if the Dimension is an instance of the generic, False
    -        otherwise.
    -
    -        Examples:
    -            >>> class TemperatureUnit(MeasurementUnit):
    -            ...     CELCIUS = "C"
    -
    -            >>> Dimension(TemperatureUnit.CELCIUS).isinstance(TemperatureUnit)
    -            True
    -
    -            >>> Dimension(TemperatureUnit.CELCIUS).isinstance(TemperatureUnit**2)
    -            False
    -        """
    -        if isinstance(generic, MeasurementUnitType):
    -            generic = GenericDimension(generic)
    -        if not isinstance(generic, GenericDimension):
    -            return False
    -
    -        if isinstance(self.unit, generic.unit_type) and self.power == generic.power:
    -            return True
    -
    -        return False
    -
    -    def isinstance_equivalent(self, generic: GenericUnitDescriptor) -> bool:
    -        """
    -        Returns True if the UnitDescriptor is an instance-equivalent of the generic,
    -        False otherwise.
    -
    -        A unit descriptor is an instance-equivalent of a generic if the generic of the
    -        unit descriptor is equivalent to the generic.
    -
    -        Equivalence between generics is checked with the `is_equivalent` method.
    -
    -        Examples:
    -            >>> class LengthUnit(MeasurementUnit):
    -            ...     METER = "m"
    -            >>> class VolumeUnit(AliasMeasurementUnit):
    -            ...     @classmethod
    -            ...     def aliased_generic_descriptor(cls): return LengthUnit**3
    +        Create a Dimension from given descriptor.
    +        If descriptor is already a Dimension, it returns the same object.
    +
    +        This function does not serve as a constructor for Dimension, rather it
    +        is intended to be used to convert an unknown unit descriptor to a Dimension.
    +
    +        Raises `UnitDescriptorTypeError` if given descriptor cannot be translated
    +        to a Dimension instance.
    +        """
    +        if isinstance(descriptor, Dimension):
    +            return descriptor
    +        if isinstance(descriptor, MeasurementUnit):
    +            return Dimension(descriptor)
    +        raise UnitDescriptorTypeError(
    +            f"cannot create Dimension from descriptor: {descriptor}"
    +        )
    +
    +    def si(self) -> "Dimension":
    +        """
    +        Returns this dimension in SI units.
    +
    +        Examples:
    +            >>> class LengthUnit(MeasurementUnit):
    +            ...     METER = "m"
    +            ...     FOOT = "ft"
    +            ...     @classmethod
    +            ...     def si(cls): return cls.METER
    +
    +            >>> (LengthUnit.FOOT**2).si()
    +            <Dimension: m^2>
    +        """
    +        return Dimension(self.unit.si(), self.power)
    +
    +    def isinstance(self, generic: GenericUnitDescriptor) -> bool:
    +        """
    +        Returns True if the Dimension is an instance of the generic, False
    +        otherwise.
    +
    +        Examples:
    +            >>> class TemperatureUnit(MeasurementUnit):
    +            ...     CELCIUS = "C"
    +
    +            >>> Dimension(TemperatureUnit.CELCIUS).isinstance(TemperatureUnit)
    +            True
    +
    +            >>> Dimension(TemperatureUnit.CELCIUS).isinstance(TemperatureUnit**2)
    +            False
    +        """
    +        if isinstance(generic, MeasurementUnitType):
    +            generic = GenericDimension(generic)
    +        if not isinstance(generic, GenericDimension):
    +            return False
    +
    +        if isinstance(self.unit, generic.unit_type) and self.power == generic.power:
    +            return True
     
    -            >>> (LengthUnit.METER**3).isinstance_equivalent(VolumeUnit)
    -            True
    -        """
    -        return self.to_generic().is_equivalent(generic)
    -
    -    def to_generic(self) -> GenericDimension:
    -        """
    -        Create a generic descriptor from this Dimension.
    -
    -        Examples:
    -            >>> class AmountUnit(MeasurementUnit):
    -            ...     MOL = "mol"
    -
    -            >>> (AmountUnit.MOL**3.56).to_generic()
    -            <GenericDimension: AmountUnit^3.56>
    -        """
    -        return GenericDimension(type(self.unit), self.power)
    -
    -    def inverse(self) -> "CompositeDimension":
    -        """
    -        Create a composite with inverse units.
    -
    -        Examples:
    -            >>> class LengthUnit(MeasurementUnit):
    -            ...     METER = "m"
    -            >>> (LengthUnit.METER**2).inverse()
    -            <CompositeDimension:  / (m^2)>
    -        """
    -        return CompositeDimension([], [replace(self)])
    -
    -    def _isinstance_aliased(self, generic: GenericUnitDescriptor) -> bool:
    -        """
    -        Returns True if the generic is the aliased unit descriptor of this Dimension,
    -        False otherwise.
    -
    -        Only applicable if this Dimension's unit is of type AliasMeasurementUnit.
    -        """
    -        return (
    -            isinstance(self.unit, AliasMeasurementUnit)
    -            and (self.unit.aliased_generic_descriptor() ** self.power) == generic
    -        )
    -
    -    def _isinstance_alias(self, generic: GenericUnitDescriptor) -> bool:
    -        """
    -        Returns True if this Dimension's unit is an instance of the aliased unit
    -        descriptor of the generic, False otherwise.
    -
    -        Only applicable if generic is an AliasMeasurementUnit.
    -        """
    -        if isinstance(generic, MeasurementUnitType):
    -            generic = GenericDimension(generic)
    -
    -        if not isinstance(generic, GenericDimension):
    -            return False
    -
    -        if not issubclass(generic.unit_type, AliasMeasurementUnit):
    -            return False
    -
    -        if (
    -            generic.unit_type.aliased_generic_descriptor() ** generic.power
    -            == self.to_generic()
    -        ):
    -            return True
    -
    -        return False
    +        return False
    +
    +    def isinstance_equivalent(self, generic: GenericUnitDescriptor) -> bool:
    +        """
    +        Returns True if the UnitDescriptor is an instance-equivalent of the generic,
    +        False otherwise.
    +
    +        A unit descriptor is an instance-equivalent of a generic if the generic of the
    +        unit descriptor is equivalent to the generic.
    +
    +        Equivalence between generics is checked with the `is_equivalent` method.
    +
    +        Examples:
    +            >>> class LengthUnit(MeasurementUnit):
    +            ...     METER = "m"
    +            >>> class VolumeUnit(AliasMeasurementUnit):
    +            ...     @classmethod
    +            ...     def aliased_generic_descriptor(cls): return LengthUnit**3
    +
    +            >>> (LengthUnit.METER**3).isinstance_equivalent(VolumeUnit)
    +            True
    +        """
    +        return self.to_generic().is_equivalent(generic)
    +
    +    def to_generic(self) -> GenericDimension:
    +        """
    +        Create a generic descriptor from this Dimension.
    +
    +        Examples:
    +            >>> class AmountUnit(MeasurementUnit):
    +            ...     MOL = "mol"
    +
    +            >>> (AmountUnit.MOL**3.56).to_generic()
    +            <GenericDimension: AmountUnit^3.56>
    +        """
    +        return GenericDimension(type(self.unit), self.power)
    +
    +    def inverse(self) -> "CompositeDimension":
    +        """
    +        Create a composite with inverse units.
    +
    +        Examples:
    +            >>> class LengthUnit(MeasurementUnit):
    +            ...     METER = "m"
    +            >>> (LengthUnit.METER**2).inverse()
    +            <CompositeDimension:  / (m^2)>
    +        """
    +        return CompositeDimension([], [replace(self)])
    +
    +    def _isinstance_aliased(self, generic: GenericUnitDescriptor) -> bool:
    +        """
    +        Returns True if the generic is the aliased unit descriptor of this Dimension,
    +        False otherwise.
    +
    +        Only applicable if this Dimension's unit is of type AliasMeasurementUnit.
    +        """
    +        return (
    +            isinstance(self.unit, AliasMeasurementUnit)
    +            and (self.unit.aliased_generic_descriptor() ** self.power) == generic
    +        )
    +
    +    def _isinstance_alias(self, generic: GenericUnitDescriptor) -> bool:
    +        """
    +        Returns True if this Dimension's unit is an instance of the aliased unit
    +        descriptor of the generic, False otherwise.
     
    -    def __mul__(self, descriptor: "UnitDescriptor") -> "CompositeDimension":
    -        """
    -        Defines multiplication between Dimension(s) and other unit descriptors.
    -
    -        Examples:
    -            >>> class TemperatureUnit(MeasurementUnit):
    -            ...     CELCIUS = "C"
    -            >>> class TimeUnit(MeasurementUnit):
    -            ...     MINUTE = "min"
    -            >>> (TemperatureUnit.CELCIUS**3) * TimeUnit.MINUTE
    -            <CompositeDimension: (C^3) * min>
    -        """
    -        if isinstance(descriptor, CompositeDimension):
    -            numerator = descriptor.numerator.copy()
    -            denominator = descriptor.denominator.copy()
    -            numerator.append(self)
    -            return CompositeDimension(numerator=numerator, denominator=denominator)
    -        if isinstance(descriptor, Dimension):
    -            return CompositeDimension(numerator=[self, descriptor])
    -        if isinstance(descriptor, MeasurementUnit):
    -            return CompositeDimension(numerator=[self, Dimension(descriptor)])
    -        raise DescriptorBinaryOperationError(
    -            f"cannot multiply {self} with {descriptor}. "
    -        )
    -
    -    def __truediv__(self, descriptor: "UnitDescriptor") -> "CompositeDimension":
    -        """
    -        Defines division between Dimension(s) and other unit descriptors.
    -
    -        Examples:
    -            >>> class TemperatureUnit(MeasurementUnit):
    -            ...     CELCIUS = "C"
    -            >>> class TimeUnit(MeasurementUnit):
    -            ...     MINUTE = "min"
    -            >>> (TemperatureUnit.CELCIUS**3) / TimeUnit.MINUTE
    -            <CompositeDimension: (C^3) / min>
    -        """
    -        if isinstance(descriptor, CompositeDimension):
    -            numerator = descriptor.denominator.copy()
    -            denominator = descriptor.numerator.copy()
    -            numerator.append(self)
    -            return CompositeDimension(numerator=numerator, denominator=denominator)
    -        if isinstance(descriptor, Dimension):
    -            return CompositeDimension(numerator=[self], denominator=[descriptor])
    -        if isinstance(descriptor, MeasurementUnit):
    -            return CompositeDimension(
    -                numerator=[self], denominator=[Dimension(descriptor)]
    -            )
    -        raise DescriptorBinaryOperationError(
    -            f"cannot divide {self} with  {descriptor}. "
    -        )
    -
    -    def __pow__(self, power: float) -> "Dimension":
    -        """
    -        Defines exponentiation for Dimension(s).
    -
    -        Examples:
    -            >>> class TimeUnit(MeasurementUnit):
    -            ...     SECOND = "s"
    -            >>> (TimeUnit.SECOND**2)**3
    -            <Dimension: s^6>
    -        """
    -        if not isinstance(power, (float, int)):
    -            raise DescriptorExponentError(
    -                f"invalid exponent: {{ value: {power}, type: {type(power)} }};"
    -                " expected float or int. "
    +        Only applicable if generic is an AliasMeasurementUnit.
    +        """
    +        if isinstance(generic, MeasurementUnitType):
    +            generic = GenericDimension(generic)
    +
    +        if not isinstance(generic, GenericDimension):
    +            return False
    +
    +        if not issubclass(generic.unit_type, AliasMeasurementUnit):
    +            return False
    +
    +        if (
    +            generic.unit_type.aliased_generic_descriptor() ** generic.power
    +            == self.to_generic()
    +        ):
    +            return True
    +
    +        return False
    +
    +    def __mul__(self, descriptor: "UnitDescriptor") -> "CompositeDimension":
    +        """
    +        Defines multiplication between Dimension(s) and other unit descriptors.
    +
    +        Examples:
    +            >>> class TemperatureUnit(MeasurementUnit):
    +            ...     CELCIUS = "C"
    +            >>> class TimeUnit(MeasurementUnit):
    +            ...     MINUTE = "min"
    +            >>> (TemperatureUnit.CELCIUS**3) * TimeUnit.MINUTE
    +            <CompositeDimension: (C^3) * min>
    +        """
    +        if isinstance(descriptor, CompositeDimension):
    +            numerator = descriptor.numerator.copy()
    +            denominator = descriptor.denominator.copy()
    +            numerator.append(self)
    +            return CompositeDimension(numerator=numerator, denominator=denominator)
    +        if isinstance(descriptor, Dimension):
    +            return CompositeDimension(numerator=[self, descriptor])
    +        if isinstance(descriptor, MeasurementUnit):
    +            return CompositeDimension(numerator=[self, Dimension(descriptor)])
    +        raise DescriptorBinaryOperationError(
    +            f"cannot multiply {self} with {descriptor}. "
    +        )
    +
    +    def __truediv__(self, descriptor: "UnitDescriptor") -> "CompositeDimension":
    +        """
    +        Defines division between Dimension(s) and other unit descriptors.
    +
    +        Examples:
    +            >>> class TemperatureUnit(MeasurementUnit):
    +            ...     CELCIUS = "C"
    +            >>> class TimeUnit(MeasurementUnit):
    +            ...     MINUTE = "min"
    +            >>> (TemperatureUnit.CELCIUS**3) / TimeUnit.MINUTE
    +            <CompositeDimension: (C^3) / min>
    +        """
    +        if isinstance(descriptor, CompositeDimension):
    +            numerator = descriptor.denominator.copy()
    +            denominator = descriptor.numerator.copy()
    +            numerator.append(self)
    +            return CompositeDimension(numerator=numerator, denominator=denominator)
    +        if isinstance(descriptor, Dimension):
    +            return CompositeDimension(numerator=[self], denominator=[descriptor])
    +        if isinstance(descriptor, MeasurementUnit):
    +            return CompositeDimension(
    +                numerator=[self], denominator=[Dimension(descriptor)]
                 )
    -        self.power *= power
    -        return self
    -
    -    def __eq__(self, dimension) -> bool:
    -        """
    -        Defines equality for Dimension(s).
    -
    -        Examples:
    -            >>> class TemperatureUnit(MeasurementUnit):
    -            ...     KELVIN = "K"
    -            >>> (TemperatureUnit.KELVIN**2) != TemperatureUnit.KELVIN
    -            True
    -        """
    -        if not isinstance(dimension, Dimension):
    -            return False
    -        return self.unit == dimension.unit and self.power == dimension.power
    -
    -    def __hash__(self) -> int:
    -        return hash(str(self))
    -
    -    def __repr__(self) -> str:
    -        if self.power != 1:
    -            return f"<Dimension: {self.unit.value}^{self.power}>"
    -        return f"<Dimension: {self.unit.value}>"
    +        raise DescriptorBinaryOperationError(
    +            f"cannot divide {self} with  {descriptor}. "
    +        )
    +
    +    def __pow__(self, power: float) -> "Dimension":
    +        """
    +        Defines exponentiation for Dimension(s).
    +
    +        Examples:
    +            >>> class TimeUnit(MeasurementUnit):
    +            ...     SECOND = "s"
    +            >>> (TimeUnit.SECOND**2)**3
    +            <Dimension: s^6>
    +        """
    +        if not isinstance(power, (float, int)):
    +            raise DescriptorExponentError(
    +                f"invalid exponent: {{ value: {power}, type: {type(power)} }};"
    +                " expected float or int. "
    +            )
    +        if self.unit.is_non_dimensional():
    +            self.power = 1
    +        else:
    +            self.power *= power
    +        return self
     
    -    def __str__(self) -> str:
    -        s = self.unit.value
    -        if self.power != 1:
    -            return f"({s}^{self.power})"
    -        return s
    +    def __eq__(self, dimension) -> bool:
    +        """
    +        Defines equality for Dimension(s).
    +
    +        Examples:
    +            >>> class TemperatureUnit(MeasurementUnit):
    +            ...     KELVIN = "K"
    +            >>> (TemperatureUnit.KELVIN**2) != TemperatureUnit.KELVIN
    +            True
    +        """
    +        if not isinstance(dimension, Dimension):
    +            return False
    +        return self.unit == dimension.unit and self.power == dimension.power
    +
    +    def __hash__(self) -> int:
    +        return hash(str(self))
    +
    +    def __repr__(self) -> str:
    +        if self.power != 1:
    +            return f"<Dimension: {self.unit.value}^{self.power}>"
    +        return f"<Dimension: {self.unit.value}>"
    +
    +    def __str__(self) -> str:
    +        s = self.unit.value
    +        if self.power != 1:
    +            return f"({s}^{self.power})"
    +        return s
     
    @@ -5557,37 +5593,37 @@

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):
     ...     KELVIN = "K"
    ->>> (TemperatureUnit.KELVIN**2) != TemperatureUnit.KELVIN
    -True
    -
    - -
    - Source code in src/property_utils/units/descriptors.py -
    def __eq__(self, dimension) -> bool:
    -    """
    -    Defines equality for Dimension(s).
    -
    -    Examples:
    -        >>> class TemperatureUnit(MeasurementUnit):
    -        ...     KELVIN = "K"
    -        >>> (TemperatureUnit.KELVIN**2) != TemperatureUnit.KELVIN
    -        True
    -    """
    -    if not isinstance(dimension, Dimension):
    -        return False
    -    return self.unit == dimension.unit and self.power == dimension.power
    +>>> (TemperatureUnit.KELVIN**2) != TemperatureUnit.KELVIN
    +True
    +
    + +
    + Source code in src/property_utils/units/descriptors.py +
    def __eq__(self, dimension) -> bool:
    +    """
    +    Defines equality for Dimension(s).
    +
    +    Examples:
    +        >>> class TemperatureUnit(MeasurementUnit):
    +        ...     KELVIN = "K"
    +        >>> (TemperatureUnit.KELVIN**2) != TemperatureUnit.KELVIN
    +        True
    +    """
    +    if not isinstance(dimension, Dimension):
    +        return False
    +    return self.unit == dimension.unit and self.power == dimension.power
     
    @@ -5619,53 +5655,53 @@

    Source code in src/property_utils/units/descriptors.py -
    945
    -946
    -947
    -948
    -949
    -950
    -951
    -952
    -953
    -954
    -955
    -956
    -957
    -958
    -959
    -960
    -961
    -962
    -963
    -964
    +              
    def __mul__(self, descriptor: "UnitDescriptor") -> "CompositeDimension":
    -    """
    -    Defines multiplication between Dimension(s) and other unit descriptors.
    -
    -    Examples:
    -        >>> class TemperatureUnit(MeasurementUnit):
    -        ...     CELCIUS = "C"
    -        >>> class TimeUnit(MeasurementUnit):
    -        ...     MINUTE = "min"
    -        >>> (TemperatureUnit.CELCIUS**3) * TimeUnit.MINUTE
    -        <CompositeDimension: (C^3) * min>
    -    """
    -    if isinstance(descriptor, CompositeDimension):
    -        numerator = descriptor.numerator.copy()
    -        denominator = descriptor.denominator.copy()
    -        numerator.append(self)
    -        return CompositeDimension(numerator=numerator, denominator=denominator)
    -    if isinstance(descriptor, Dimension):
    -        return CompositeDimension(numerator=[self, descriptor])
    -    if isinstance(descriptor, MeasurementUnit):
    -        return CompositeDimension(numerator=[self, Dimension(descriptor)])
    -    raise DescriptorBinaryOperationError(
    -        f"cannot multiply {self} with {descriptor}. "
    -    )
    +968
    +969
    +970
    +971
    +972
    +973
    +974
    +975
    +976
    +977
    +978
    +979
    +980
    +981
    +982
    +983
    +984
    +985
    +986
    +987
    def __mul__(self, descriptor: "UnitDescriptor") -> "CompositeDimension":
    +    """
    +    Defines multiplication between Dimension(s) and other unit descriptors.
    +
    +    Examples:
    +        >>> class TemperatureUnit(MeasurementUnit):
    +        ...     CELCIUS = "C"
    +        >>> class TimeUnit(MeasurementUnit):
    +        ...     MINUTE = "min"
    +        >>> (TemperatureUnit.CELCIUS**3) * TimeUnit.MINUTE
    +        <CompositeDimension: (C^3) * min>
    +    """
    +    if isinstance(descriptor, CompositeDimension):
    +        numerator = descriptor.numerator.copy()
    +        denominator = descriptor.denominator.copy()
    +        numerator.append(self)
    +        return CompositeDimension(numerator=numerator, denominator=denominator)
    +    if isinstance(descriptor, Dimension):
    +        return CompositeDimension(numerator=[self, descriptor])
    +    if isinstance(descriptor, MeasurementUnit):
    +        return CompositeDimension(numerator=[self, Dimension(descriptor)])
    +    raise DescriptorBinaryOperationError(
    +        f"cannot multiply {self} with {descriptor}. "
    +    )
     
    @@ -5695,39 +5731,45 @@

    Source code in src/property_utils/units/descriptors.py -
    def __pow__(self, power: float) -> "Dimension":
    -    """
    -    Defines exponentiation for Dimension(s).
    -
    -    Examples:
    -        >>> class TimeUnit(MeasurementUnit):
    -        ...     SECOND = "s"
    -        >>> (TimeUnit.SECOND**2)**3
    -        <Dimension: s^6>
    -    """
    -    if not isinstance(power, (float, int)):
    -        raise DescriptorExponentError(
    -            f"invalid exponent: {{ value: {power}, type: {type(power)} }};"
    -            " expected float or int. "
    -        )
    -    self.power *= power
    -    return self
    +              
    def __pow__(self, power: float) -> "Dimension":
    +    """
    +    Defines exponentiation for Dimension(s).
    +
    +    Examples:
    +        >>> class TimeUnit(MeasurementUnit):
    +        ...     SECOND = "s"
    +        >>> (TimeUnit.SECOND**2)**3
    +        <Dimension: s^6>
    +    """
    +    if not isinstance(power, (float, int)):
    +        raise DescriptorExponentError(
    +            f"invalid exponent: {{ value: {power}, type: {type(power)} }};"
    +            " expected float or int. "
    +        )
    +    if self.unit.is_non_dimensional():
    +        self.power = 1
    +    else:
    +        self.power *= power
    +    return self
     
    @@ -5759,57 +5801,57 @@

    Source code in src/property_utils/units/descriptors.py -
    def __truediv__(self, descriptor: "UnitDescriptor") -> "CompositeDimension":
    -    """
    -    Defines division between Dimension(s) and other unit descriptors.
    -
    -    Examples:
    -        >>> class TemperatureUnit(MeasurementUnit):
    -        ...     CELCIUS = "C"
    -        >>> class TimeUnit(MeasurementUnit):
    -        ...     MINUTE = "min"
    -        >>> (TemperatureUnit.CELCIUS**3) / TimeUnit.MINUTE
    -        <CompositeDimension: (C^3) / min>
    -    """
    -    if isinstance(descriptor, CompositeDimension):
    -        numerator = descriptor.denominator.copy()
    -        denominator = descriptor.numerator.copy()
    -        numerator.append(self)
    -        return CompositeDimension(numerator=numerator, denominator=denominator)
    -    if isinstance(descriptor, Dimension):
    -        return CompositeDimension(numerator=[self], denominator=[descriptor])
    -    if isinstance(descriptor, MeasurementUnit):
    -        return CompositeDimension(
    -            numerator=[self], denominator=[Dimension(descriptor)]
    -        )
    -    raise DescriptorBinaryOperationError(
    -        f"cannot divide {self} with  {descriptor}. "
    -    )
    +              
    def __truediv__(self, descriptor: "UnitDescriptor") -> "CompositeDimension":
    +    """
    +    Defines division between Dimension(s) and other unit descriptors.
    +
    +    Examples:
    +        >>> class TemperatureUnit(MeasurementUnit):
    +        ...     CELCIUS = "C"
    +        >>> class TimeUnit(MeasurementUnit):
    +        ...     MINUTE = "min"
    +        >>> (TemperatureUnit.CELCIUS**3) / TimeUnit.MINUTE
    +        <CompositeDimension: (C^3) / min>
    +    """
    +    if isinstance(descriptor, CompositeDimension):
    +        numerator = descriptor.denominator.copy()
    +        denominator = descriptor.numerator.copy()
    +        numerator.append(self)
    +        return CompositeDimension(numerator=numerator, denominator=denominator)
    +    if isinstance(descriptor, Dimension):
    +        return CompositeDimension(numerator=[self], denominator=[descriptor])
    +    if isinstance(descriptor, MeasurementUnit):
    +        return CompositeDimension(
    +            numerator=[self], denominator=[Dimension(descriptor)]
    +        )
    +    raise DescriptorBinaryOperationError(
    +        f"cannot divide {self} with  {descriptor}. "
    +    )
     
    @@ -5840,43 +5882,43 @@

    Source code in src/property_utils/units/descriptors.py -
    @staticmethod
    -def from_descriptor(descriptor: UnitDescriptor) -> "Dimension":
    -    """
    -    Create a Dimension from given descriptor.
    -    If descriptor is already a Dimension, it returns the same object.
    -
    -    This function does not serve as a constructor for Dimension, rather it
    -    is intended to be used to convert an unknown unit descriptor to a Dimension.
    -
    -    Raises `UnitDescriptorTypeError` if given descriptor cannot be translated
    -    to a Dimension instance.
    -    """
    -    if isinstance(descriptor, Dimension):
    -        return descriptor
    -    if isinstance(descriptor, MeasurementUnit):
    -        return Dimension(descriptor)
    -    raise UnitDescriptorTypeError(
    -        f"cannot create Dimension from descriptor: {descriptor}"
    -    )
    +              
    @staticmethod
    +def from_descriptor(descriptor: UnitDescriptor) -> "Dimension":
    +    """
    +    Create a Dimension from given descriptor.
    +    If descriptor is already a Dimension, it returns the same object.
    +
    +    This function does not serve as a constructor for Dimension, rather it
    +    is intended to be used to convert an unknown unit descriptor to a Dimension.
    +
    +    Raises `UnitDescriptorTypeError` if given descriptor cannot be translated
    +    to a Dimension instance.
    +    """
    +    if isinstance(descriptor, Dimension):
    +        return descriptor
    +    if isinstance(descriptor, MeasurementUnit):
    +        return Dimension(descriptor)
    +    raise UnitDescriptorTypeError(
    +        f"cannot create Dimension from descriptor: {descriptor}"
    +    )
     
    @@ -5906,27 +5948,27 @@

    Source code in src/property_utils/units/descriptors.py -
    def inverse(self) -> "CompositeDimension":
    -    """
    -    Create a composite with inverse units.
    -
    -    Examples:
    -        >>> class LengthUnit(MeasurementUnit):
    -        ...     METER = "m"
    -        >>> (LengthUnit.METER**2).inverse()
    -        <CompositeDimension:  / (m^2)>
    -    """
    -    return CompositeDimension([], [replace(self)])
    +              
    def inverse(self) -> "CompositeDimension":
    +    """
    +    Create a composite with inverse units.
    +
    +    Examples:
    +        >>> class LengthUnit(MeasurementUnit):
    +        ...     METER = "m"
    +        >>> (LengthUnit.METER**2).inverse()
    +        <CompositeDimension:  / (m^2)>
    +    """
    +    return CompositeDimension([], [replace(self)])
     
    @@ -5961,53 +6003,53 @@

    Source code in src/property_utils/units/descriptors.py -
    837
    -838
    -839
    -840
    -841
    -842
    -843
    -844
    -845
    -846
    -847
    -848
    -849
    -850
    -851
    -852
    -853
    -854
    -855
    -856
    +              
    def isinstance(self, generic: GenericUnitDescriptor) -> bool:
    -    """
    -    Returns True if the Dimension is an instance of the generic, False
    -    otherwise.
    -
    -    Examples:
    -        >>> class TemperatureUnit(MeasurementUnit):
    -        ...     CELCIUS = "C"
    -
    -        >>> Dimension(TemperatureUnit.CELCIUS).isinstance(TemperatureUnit)
    -        True
    -
    -        >>> Dimension(TemperatureUnit.CELCIUS).isinstance(TemperatureUnit**2)
    -        False
    -    """
    -    if isinstance(generic, MeasurementUnitType):
    -        generic = GenericDimension(generic)
    -    if not isinstance(generic, GenericDimension):
    -        return False
    -
    -    if isinstance(self.unit, generic.unit_type) and self.power == generic.power:
    -        return True
    -
    -    return False
    +860
    +861
    +862
    +863
    +864
    +865
    +866
    +867
    +868
    +869
    +870
    +871
    +872
    +873
    +874
    +875
    +876
    +877
    +878
    +879
    def isinstance(self, generic: GenericUnitDescriptor) -> bool:
    +    """
    +    Returns True if the Dimension is an instance of the generic, False
    +    otherwise.
    +
    +    Examples:
    +        >>> class TemperatureUnit(MeasurementUnit):
    +        ...     CELCIUS = "C"
    +
    +        >>> Dimension(TemperatureUnit.CELCIUS).isinstance(TemperatureUnit)
    +        True
    +
    +        >>> Dimension(TemperatureUnit.CELCIUS).isinstance(TemperatureUnit**2)
    +        False
    +    """
    +    if isinstance(generic, MeasurementUnitType):
    +        generic = GenericDimension(generic)
    +    if not isinstance(generic, GenericDimension):
    +        return False
    +
    +    if isinstance(self.unit, generic.unit_type) and self.power == generic.power:
    +        return True
    +
    +    return False
     
    @@ -6045,47 +6087,47 @@

    Source code in src/property_utils/units/descriptors.py -
    def isinstance_equivalent(self, generic: GenericUnitDescriptor) -> bool:
    -    """
    -    Returns True if the UnitDescriptor is an instance-equivalent of the generic,
    -    False otherwise.
    -
    -    A unit descriptor is an instance-equivalent of a generic if the generic of the
    -    unit descriptor is equivalent to the generic.
    -
    -    Equivalence between generics is checked with the `is_equivalent` method.
    -
    -    Examples:
    -        >>> class LengthUnit(MeasurementUnit):
    -        ...     METER = "m"
    -        >>> class VolumeUnit(AliasMeasurementUnit):
    -        ...     @classmethod
    -        ...     def aliased_generic_descriptor(cls): return LengthUnit**3
    -
    -        >>> (LengthUnit.METER**3).isinstance_equivalent(VolumeUnit)
    -        True
    -    """
    -    return self.to_generic().is_equivalent(generic)
    +              
    def isinstance_equivalent(self, generic: GenericUnitDescriptor) -> bool:
    +    """
    +    Returns True if the UnitDescriptor is an instance-equivalent of the generic,
    +    False otherwise.
    +
    +    A unit descriptor is an instance-equivalent of a generic if the generic of the
    +    unit descriptor is equivalent to the generic.
    +
    +    Equivalence between generics is checked with the `is_equivalent` method.
    +
    +    Examples:
    +        >>> class LengthUnit(MeasurementUnit):
    +        ...     METER = "m"
    +        >>> class VolumeUnit(AliasMeasurementUnit):
    +        ...     @classmethod
    +        ...     def aliased_generic_descriptor(cls): return LengthUnit**3
    +
    +        >>> (LengthUnit.METER**3).isinstance_equivalent(VolumeUnit)
    +        True
    +    """
    +    return self.to_generic().is_equivalent(generic)
     
    @@ -6119,35 +6161,35 @@

    Source code in src/property_utils/units/descriptors.py -
    def si(self) -> "Dimension":
    -    """
    -    Returns this dimension in SI units.
    -
    -    Examples:
    -        >>> class LengthUnit(MeasurementUnit):
    -        ...     METER = "m"
    -        ...     FOOT = "ft"
    -        ...     @classmethod
    -        ...     def si(cls): return cls.METER
    -
    -        >>> (LengthUnit.FOOT**2).si()
    -        <Dimension: m^2>
    -    """
    -    return Dimension(self.unit.si(), self.power)
    +              
    def si(self) -> "Dimension":
    +    """
    +    Returns this dimension in SI units.
    +
    +    Examples:
    +        >>> class LengthUnit(MeasurementUnit):
    +        ...     METER = "m"
    +        ...     FOOT = "ft"
    +        ...     @classmethod
    +        ...     def si(cls): return cls.METER
    +
    +        >>> (LengthUnit.FOOT**2).si()
    +        <Dimension: m^2>
    +    """
    +    return Dimension(self.unit.si(), self.power)
     
    @@ -6178,29 +6220,29 @@

    Source code in src/property_utils/units/descriptors.py -
    def to_generic(self) -> GenericDimension:
    -    """
    -    Create a generic descriptor from this Dimension.
    -
    -    Examples:
    -        >>> class AmountUnit(MeasurementUnit):
    -        ...     MOL = "mol"
    -
    -        >>> (AmountUnit.MOL**3.56).to_generic()
    -        <GenericDimension: AmountUnit^3.56>
    -    """
    -    return GenericDimension(type(self.unit), self.power)
    +              
    def to_generic(self) -> GenericDimension:
    +    """
    +    Create a generic descriptor from this Dimension.
    +
    +    Examples:
    +        >>> class AmountUnit(MeasurementUnit):
    +        ...     MOL = "mol"
    +
    +        >>> (AmountUnit.MOL**3.56).to_generic()
    +        <GenericDimension: AmountUnit^3.56>
    +    """
    +    return GenericDimension(type(self.unit), self.power)
     
    @@ -6238,43 +6280,21 @@

    Examples:

    -
    >>> class LengthUnit(MeasurementUnit): ...
    ->>> class AmountUnit(MeasurementUnit): ...
    -
    -
    >>> generic_molal_volume_dimension = (LengthUnit**3) / AmountUnit
    ->>> generic_molal_volume_dimension
    -<GenericCompositeDimension: (LengthUnit^3) / AmountUnit>
    -
    - -
    - Source code in src/property_utils/units/descriptors.py -
    1044
    -1045
    -1046
    -1047
    -1048
    -1049
    -1050
    -1051
    -1052
    -1053
    -1054
    -1055
    -1056
    -1057
    -1058
    -1059
    -1060
    -1061
    -1062
    -1063
    -1064
    -1065
    -1066
    +class objects:

    + + +

    Examples:

    +
    >>> class LengthUnit(MeasurementUnit): ...
    +>>> class AmountUnit(MeasurementUnit): ...
    +
    +
    >>> generic_molal_volume_dimension = (LengthUnit**3) / AmountUnit
    +>>> generic_molal_volume_dimension
    +<GenericCompositeDimension: (LengthUnit^3) / AmountUnit>
    +
    + +
    + Source code in src/property_utils/units/descriptors.py +
    1066
     1067
     1068
     1069
    @@ -6665,420 +6685,442 @@ 

    1454 1455 1456 -1457

    @dataclass
    -class GenericCompositeDimension:
    -    """
    -    A `GenericCompositeDimension` represents a generic measurement unit that is composed
    -    from other generic measurement units.
    -
    -    Objects of this class can represent either multiplication or division between two
    -    `GenericDimension` objects.
    -
    -    Create objects by multiplying and diving GenericDimension or MeasurementUnitMeta
    -    class objects:
    -
    -    Examples:
    -        >>> class LengthUnit(MeasurementUnit): ...
    -        >>> class AmountUnit(MeasurementUnit): ...
    -
    -        >>> generic_molal_volume_dimension = (LengthUnit**3) / AmountUnit
    -        >>> generic_molal_volume_dimension
    -        <GenericCompositeDimension: (LengthUnit^3) / AmountUnit>
    -    """
    -
    -    numerator: List[GenericDimension] = field(default_factory=list)
    -    denominator: List[GenericDimension] = field(default_factory=list)
    -
    -    def to_si(self) -> "CompositeDimension":
    -        """
    -        Create a CompositeDimension with SI units.
    +1457
    +1458
    +1459
    +1460
    +1461
    +1462
    +1463
    +1464
    +1465
    +1466
    +1467
    +1468
    +1469
    +1470
    +1471
    +1472
    +1473
    +1474
    +1475
    +1476
    +1477
    +1478
    +1479
    @dataclass
    +class GenericCompositeDimension:
    +    """
    +    A `GenericCompositeDimension` represents a generic measurement unit that is composed
    +    from other generic measurement units.
     
    -        Examples:
    -            >>> class TemperatureUnit(MeasurementUnit):
    -            ...     KELVIN = "K"
    -            ...     @classmethod
    -            ...     def si(cls): return cls.KELVIN
    -            >>> class TimeUnit(MeasurementUnit):
    -            ...     SECOND = "s"
    -            ...     @classmethod
    -            ...     def si(cls): return cls.SECOND
    -            >>> class LengthUnit(MeasurementUnit):
    -            ...     METER = "m"
    -            ...     @classmethod
    -            ...     def si(cls): return cls.METER
    -            >>> (TemperatureUnit * LengthUnit / TimeUnit).to_si()
    -            <CompositeDimension: K * m / s>
    -        """
    -        return CompositeDimension(
    -            [n.to_si() for n in self.numerator], [d.to_si() for d in self.denominator]
    -        )
    -
    -    def simplify(self) -> None:
    -        """
    -        Simplify the composite by merging common dimensions.
    -
    -        Examples:
    -            >>> class PressureUnit(AliasMeasurementUnit): ...
    -
    -            >>> class TemperatureUnit(MeasurementUnit): ...
    -
    -            >>> class LengthUnit(MeasurementUnit): ...
    -
    -            >>> class TimeUnit(MeasurementUnit): ...
    -
    -            >>> composite = (PressureUnit**(-2)) / (TemperatureUnit**(-1))
    -            >>> composite
    -            <GenericCompositeDimension: (PressureUnit^-2) / (TemperatureUnit^-1)>
    -            >>> composite.simplify()
    -            >>> composite
    -            <GenericCompositeDimension: TemperatureUnit / (PressureUnit^2)>
    -
    -            >>> composite = PressureUnit * LengthUnit * PressureUnit / TimeUnit
    -            >>> composite
    -            <GenericCompositeDimension: LengthUnit * PressureUnit * PressureUnit / TimeUnit>
    -            >>> composite.simplify()
    -            >>> composite
    -            <GenericCompositeDimension: (PressureUnit^2) * LengthUnit / TimeUnit>
    -        """
    -        exponents: Dict[MeasurementUnitType, float] = {}
    -        for n in self.numerator:
    -            if n.unit_type in exponents:
    -                exponents[n.unit_type] += n.power
    -            else:
    -                exponents[n.unit_type] = n.power
    -
    -        for d in self.denominator:
    -            if d.unit_type in exponents:
    -                exponents[d.unit_type] -= d.power
    -            else:
    -                exponents[d.unit_type] = 0 - d.power
    -
    -        numerator = []
    -        denominator = []
    -        for unit_type, exponent in exponents.items():
    -            if exponent > 0:
    -                numerator.append(GenericDimension(unit_type) ** exponent)
    -            elif exponent < 0:
    -                denominator.append(GenericDimension(unit_type) ** abs(exponent))
    -
    -        self.numerator = numerator
    -        self.denominator = denominator
    -
    -    def simplified(self) -> "GenericCompositeDimension":
    -        """
    -        Returns a simplified version of this composite generic as a new object.
    -
    -        Examples:
    -            >>> class PressureUnit(AliasMeasurementUnit): ...
    -
    -            >>> class TemperatureUnit(MeasurementUnit): ...
    -
    -            >>> class LengthUnit(MeasurementUnit): ...
    +    Objects of this class can represent either multiplication or division between two
    +    `GenericDimension` objects.
    +
    +    Create objects by multiplying and diving GenericDimension or MeasurementUnitMeta
    +    class objects:
    +
    +    Examples:
    +        >>> class LengthUnit(MeasurementUnit): ...
    +        >>> class AmountUnit(MeasurementUnit): ...
    +
    +        >>> generic_molal_volume_dimension = (LengthUnit**3) / AmountUnit
    +        >>> generic_molal_volume_dimension
    +        <GenericCompositeDimension: (LengthUnit^3) / AmountUnit>
    +    """
    +
    +    numerator: List[GenericDimension] = field(default_factory=list)
    +    denominator: List[GenericDimension] = field(default_factory=list)
    +
    +    def to_si(self) -> "CompositeDimension":
    +        """
    +        Create a CompositeDimension with SI units.
    +
    +        Examples:
    +            >>> class TemperatureUnit(MeasurementUnit):
    +            ...     KELVIN = "K"
    +            ...     @classmethod
    +            ...     def si(cls): return cls.KELVIN
    +            >>> class TimeUnit(MeasurementUnit):
    +            ...     SECOND = "s"
    +            ...     @classmethod
    +            ...     def si(cls): return cls.SECOND
    +            >>> class LengthUnit(MeasurementUnit):
    +            ...     METER = "m"
    +            ...     @classmethod
    +            ...     def si(cls): return cls.METER
    +            >>> (TemperatureUnit * LengthUnit / TimeUnit).to_si()
    +            <CompositeDimension: K * m / s>
    +        """
    +        return CompositeDimension(
    +            [n.to_si() for n in self.numerator], [d.to_si() for d in self.denominator]
    +        )
    +
    +    def simplify(self) -> None:
    +        """
    +        Simplify the composite by merging common dimensions.
    +
    +        Examples:
    +            >>> class PressureUnit(AliasMeasurementUnit): ...
    +
    +            >>> class TemperatureUnit(MeasurementUnit): ...
    +
    +            >>> class LengthUnit(MeasurementUnit): ...
    +
    +            >>> class TimeUnit(MeasurementUnit): ...
    +
    +            >>> composite = (PressureUnit**(-2)) / (TemperatureUnit**(-1))
    +            >>> composite
    +            <GenericCompositeDimension: (PressureUnit^-2) / (TemperatureUnit^-1)>
    +            >>> composite.simplify()
    +            >>> composite
    +            <GenericCompositeDimension: TemperatureUnit / (PressureUnit^2)>
    +
    +            >>> composite = PressureUnit * LengthUnit * PressureUnit / TimeUnit
    +            >>> composite
    +            <GenericCompositeDimension: LengthUnit * PressureUnit * PressureUnit / TimeUnit>
    +            >>> composite.simplify()
    +            >>> composite
    +            <GenericCompositeDimension: (PressureUnit^2) * LengthUnit / TimeUnit>
    +        """
    +        exponents: Dict[MeasurementUnitType, float] = {}
    +        for n in self.numerator:
    +            if n.unit_type in exponents:
    +                exponents[n.unit_type] += n.power
    +            else:
    +                exponents[n.unit_type] = n.power
    +
    +        for d in self.denominator:
    +            if d.unit_type in exponents:
    +                exponents[d.unit_type] -= d.power
    +            else:
    +                exponents[d.unit_type] = 0 - d.power
     
    -            >>> class TimeUnit(MeasurementUnit): ...
    -
    -            >>> composite = (PressureUnit**(-2)) / (TemperatureUnit**(-1))
    -            >>> composite
    -            <GenericCompositeDimension: (PressureUnit^-2) / (TemperatureUnit^-1)>
    -            >>> composite.simplified()
    -            <GenericCompositeDimension: TemperatureUnit / (PressureUnit^2)>
    +        numerator = []
    +        denominator = []
    +        for unit_type, exponent in exponents.items():
    +            if exponent > 0:
    +                numerator.append(GenericDimension(unit_type) ** exponent)
    +            elif exponent < 0:
    +                denominator.append(GenericDimension(unit_type) ** abs(exponent))
     
    -            >>> composite = PressureUnit * LengthUnit * PressureUnit /TimeUnit
    -            >>> composite
    -            <GenericCompositeDimension: LengthUnit * PressureUnit * PressureUnit / TimeUnit>
    -            >>> composite.simplified()
    -            <GenericCompositeDimension: (PressureUnit^2) * LengthUnit / TimeUnit>
    -        """
    -        copy = replace(self)
    -        copy.simplify()
    -        return copy
    +        self.numerator = numerator
    +        self.denominator = denominator
    +
    +    def simplified(self) -> "GenericCompositeDimension":
    +        """
    +        Returns a simplified version of this composite generic as a new object.
    +
    +        Examples:
    +            >>> class PressureUnit(AliasMeasurementUnit): ...
     
    -    def analyse(self) -> None:
    -        """
    -        Analyse this composite by replacing its alias units with their aliased units.
    +            >>> class TemperatureUnit(MeasurementUnit): ...
    +
    +            >>> class LengthUnit(MeasurementUnit): ...
     
    -        Examples:
    -            >>> class MassUnit(MeasurementUnit): ...
    -            >>> class LengthUnit(MeasurementUnit): ...
    -            >>> class TimeUnit(MeasurementUnit): ...
    -
    -            >>> class PressureUnit(AliasMeasurementUnit):
    -            ...     @classmethod
    -            ...     def aliased_generic_descriptor(cls) -> GenericCompositeDimension:
    -            ...         return MassUnit / LengthUnit / (TimeUnit**2)
    -
    -            >>> composite = PressureUnit / LengthUnit
    -            >>> composite
    -            <GenericCompositeDimension: PressureUnit / LengthUnit>
    -
    -            >>> composite.analyse()
    -            >>> composite
    -            <GenericCompositeDimension: MassUnit / (TimeUnit^2) / LengthUnit / LengthUnit>
    -        """
    -        for n in self.numerator:
    -            if issubclass(n.unit_type, AliasMeasurementUnit):
    -                aliased = n.unit_type.aliased_generic_descriptor() ** n.power
    -                if isinstance(aliased, GenericDimension):
    -                    self.numerator.append(aliased)
    -                elif isinstance(aliased, GenericCompositeDimension):
    -                    self.numerator.extend(aliased.numerator)
    -                    self.denominator.extend(aliased.denominator)
    +            >>> class TimeUnit(MeasurementUnit): ...
    +
    +            >>> composite = (PressureUnit**(-2)) / (TemperatureUnit**(-1))
    +            >>> composite
    +            <GenericCompositeDimension: (PressureUnit^-2) / (TemperatureUnit^-1)>
    +            >>> composite.simplified()
    +            <GenericCompositeDimension: TemperatureUnit / (PressureUnit^2)>
    +
    +            >>> composite = PressureUnit * LengthUnit * PressureUnit /TimeUnit
    +            >>> composite
    +            <GenericCompositeDimension: LengthUnit * PressureUnit * PressureUnit / TimeUnit>
    +            >>> composite.simplified()
    +            <GenericCompositeDimension: (PressureUnit^2) * LengthUnit / TimeUnit>
    +        """
    +        copy = replace(self)
    +        copy.simplify()
    +        return copy
    +
    +    def analyse(self) -> None:
    +        """
    +        Analyse this composite by replacing its alias units with their aliased units.
    +
    +        Examples:
    +            >>> class MassUnit(MeasurementUnit): ...
    +            >>> class LengthUnit(MeasurementUnit): ...
    +            >>> class TimeUnit(MeasurementUnit): ...
     
    -                self.numerator.remove(n)
    -
    -        for d in self.denominator:
    -            if issubclass(d.unit_type, AliasMeasurementUnit):
    -                aliased = d.unit_type.aliased_generic_descriptor() ** d.power
    -                if isinstance(aliased, GenericDimension):
    -                    self.denominator.append(aliased)
    -                elif isinstance(aliased, GenericCompositeDimension):
    -                    self.denominator.extend(aliased.numerator)
    -                    self.numerator.extend(aliased.denominator)
    -
    -                self.denominator.remove(d)
    -
    -    def analysed(self) -> "GenericCompositeDimension":
    -        """
    -        Returns an analysed version of this composite generic as a new object.
    -
    -        Examples:
    -            >>> class MassUnit(MeasurementUnit): ...
    -            >>> class LengthUnit(MeasurementUnit): ...
    -            >>> class TimeUnit(MeasurementUnit): ...
    +            >>> class PressureUnit(AliasMeasurementUnit):
    +            ...     @classmethod
    +            ...     def aliased_generic_descriptor(cls) -> GenericCompositeDimension:
    +            ...         return MassUnit / LengthUnit / (TimeUnit**2)
    +
    +            >>> composite = PressureUnit / LengthUnit
    +            >>> composite
    +            <GenericCompositeDimension: PressureUnit / LengthUnit>
    +
    +            >>> composite.analyse()
    +            >>> composite
    +            <GenericCompositeDimension: MassUnit / (TimeUnit^2) / LengthUnit / LengthUnit>
    +        """
    +        for n in self.numerator:
    +            if issubclass(n.unit_type, AliasMeasurementUnit):
    +                aliased = n.unit_type.aliased_generic_descriptor() ** n.power
    +                if isinstance(aliased, GenericDimension):
    +                    self.numerator.append(aliased)
    +                elif isinstance(aliased, GenericCompositeDimension):
    +                    self.numerator.extend(aliased.numerator)
    +                    self.denominator.extend(aliased.denominator)
     
    -            >>> class PressureUnit(AliasMeasurementUnit):
    -            ...     @classmethod
    -            ...     def aliased_generic_descriptor(cls) -> GenericCompositeDimension:
    -            ...         return MassUnit / LengthUnit / (TimeUnit**2)
    -
    -            >>> composite = PressureUnit / LengthUnit
    -            >>> composite
    -            <GenericCompositeDimension: PressureUnit / LengthUnit>
    -
    -            >>> composite.analysed()
    -            <GenericCompositeDimension: MassUnit / (TimeUnit^2) / LengthUnit / LengthUnit>
    -        """
    -        copy = replace(self)
    -        copy.analyse()
    -        return copy
    -
    -    def inverse_generic(self):
    -        """
    -        Create a generic composite with inverse units.
    -
    -        Examples:
    -            >>> class LengthUnit(MeasurementUnit): ...
    -            >>> class TimeUnit(MeasurementUnit): ...
    -
    -            >>> (LengthUnit / TimeUnit).inverse_generic()
    -            <GenericCompositeDimension: TimeUnit / LengthUnit>
    -        """
    -        return GenericCompositeDimension(
    -            self._denominator_copy(), self._numerator_copy()
    -        )
    +                self.numerator.remove(n)
    +
    +        for d in self.denominator:
    +            if issubclass(d.unit_type, AliasMeasurementUnit):
    +                aliased = d.unit_type.aliased_generic_descriptor() ** d.power
    +                if isinstance(aliased, GenericDimension):
    +                    self.denominator.append(aliased)
    +                elif isinstance(aliased, GenericCompositeDimension):
    +                    self.denominator.extend(aliased.numerator)
    +                    self.numerator.extend(aliased.denominator)
    +
    +                self.denominator.remove(d)
    +
    +    def analysed(self) -> "GenericCompositeDimension":
    +        """
    +        Returns an analysed version of this composite generic as a new object.
    +
    +        Examples:
    +            >>> class MassUnit(MeasurementUnit): ...
    +            >>> class LengthUnit(MeasurementUnit): ...
    +            >>> class TimeUnit(MeasurementUnit): ...
    +
    +            >>> class PressureUnit(AliasMeasurementUnit):
    +            ...     @classmethod
    +            ...     def aliased_generic_descriptor(cls) -> GenericCompositeDimension:
    +            ...         return MassUnit / LengthUnit / (TimeUnit**2)
    +
    +            >>> composite = PressureUnit / LengthUnit
    +            >>> composite
    +            <GenericCompositeDimension: PressureUnit / LengthUnit>
     
    -    def is_equivalent(self, other: GenericUnitDescriptor) -> bool:
    -        """
    -        Returns True if this generic is equivalent to the given one, False otherwise.
    -
    -        A generic can be equivalent with another generic if the latter or the former
    -        is an alias.
    +            >>> composite.analysed()
    +            <GenericCompositeDimension: MassUnit / (TimeUnit^2) / LengthUnit / LengthUnit>
    +        """
    +        copy = replace(self)
    +        copy.analyse()
    +        return copy
     
    -        Examples:
    -            >>> class LengthUnit(MeasurementUnit): ...
    -            >>> class MassUnit(MeasurementUnit): ...
    -            >>> class TimeUnit(MeasurementUnit): ...
    -            >>> class ForceUnit(AliasMeasurementUnit):
    -            ...     @classmethod
    -            ...     def aliased_generic_descriptor(cls):
    -            ...         return MassUnit * LengthUnit / (TimeUnit**2)
    -
    -            >>> ForceUnit.is_equivalent(MassUnit * LengthUnit / (TimeUnit**2))
    -            True
    -
    -            >>> class EnergyUnit(AliasMeasurementUnit):
    -            ...     @classmethod
    -            ...     def aliased_generic_descriptor(cls):
    -            ...         return ForceUnit * LengthUnit
    -
    -            >>> EnergyUnit.is_equivalent(MassUnit * (LengthUnit**2) / (TimeUnit**2))
    -            True
    -        """
    -        if isinstance(other, MeasurementUnitType):
    -            if (
    -                self.denominator == []
    -                and len(self.numerator) == 1
    -                and self.numerator[0].is_equivalent(other)
    -            ):
    -                return True
    -
    -            if issubclass(other, AliasMeasurementUnit):
    -                return other.aliased_generic_descriptor().is_equivalent(self)  # type: ignore[attr-defined]
    +    def inverse_generic(self):
    +        """
    +        Create a generic composite with inverse units.
    +
    +        Examples:
    +            >>> class LengthUnit(MeasurementUnit): ...
    +            >>> class TimeUnit(MeasurementUnit): ...
    +
    +            >>> (LengthUnit / TimeUnit).inverse_generic()
    +            <GenericCompositeDimension: TimeUnit / LengthUnit>
    +        """
    +        return GenericCompositeDimension(
    +            self._denominator_copy(), self._numerator_copy()
    +        )
    +
    +    def is_equivalent(self, other: GenericUnitDescriptor) -> bool:
    +        """
    +        Returns True if this generic is equivalent to the given one, False otherwise.
    +
    +        A generic can be equivalent with another generic if the latter or the former
    +        is an alias.
    +
    +        Examples:
    +            >>> class LengthUnit(MeasurementUnit): ...
    +            >>> class MassUnit(MeasurementUnit): ...
    +            >>> class TimeUnit(MeasurementUnit): ...
    +            >>> class ForceUnit(AliasMeasurementUnit):
    +            ...     @classmethod
    +            ...     def aliased_generic_descriptor(cls):
    +            ...         return MassUnit * LengthUnit / (TimeUnit**2)
     
    -        elif isinstance(other, GenericDimension):
    -            if (
    -                self.denominator == []
    -                and len(self.numerator) == 1
    -                and self.numerator[0].is_equivalent(other)
    -            ):
    -                return True
    +            >>> ForceUnit.is_equivalent(MassUnit * LengthUnit / (TimeUnit**2))
    +            True
    +
    +            >>> class EnergyUnit(AliasMeasurementUnit):
    +            ...     @classmethod
    +            ...     def aliased_generic_descriptor(cls):
    +            ...         return ForceUnit * LengthUnit
     
    -            if issubclass(other.unit_type, AliasMeasurementUnit):
    -                return (
    -                    other.unit_type.aliased_generic_descriptor() ** other.power
    -                ).is_equivalent(self)
    -
    -        elif isinstance(other, GenericCompositeDimension):
    -            _generic = other.analysed().simplified()
    -            _self = self.analysed().simplified()
    -
    -            return Counter(_self.numerator) == Counter(_generic.numerator) and (
    -                Counter(_self.denominator) == Counter(_generic.denominator)
    -            )
    -
    -        return False
    -
    -    def has_no_units(self) -> bool:
    -        """
    -        Returns True if the generic composite dimension does not have any units, False
    -        otherwise.
    -
    -        Examples:
    -            >>> class LengthUnit(MeasurementUnit): ...
    -
    -            >>> GenericCompositeDimension().has_no_units()
    -            True
    -            >>> GenericCompositeDimension([LengthUnit]).has_no_units()
    -            False
    -        """
    -        return len(self.denominator) == 0 and len(self.numerator) == 0
    -
    -    def _numerator_copy(self) -> List[GenericDimension]:
    -        return [replace(n) for n in self.numerator]
    -
    -    def _denominator_copy(self) -> List[GenericDimension]:
    -        return [replace(d) for d in self.denominator]
    -
    -    def __mul__(self, generic: GenericUnitDescriptor) -> "GenericCompositeDimension":
    -        """
    -        Defines multiplication between GenericCompositeDimension(s) and other generic
    -        descriptors.
    -
    -        Examples:
    -            >>> class TemperatureUnit(MeasurementUnit): ...
    -            >>> class TimeUnit(MeasurementUnit): ...
    -            >>> class LengthUnit(MeasurementUnit): ...
    -            >>> (TemperatureUnit / LengthUnit) * TimeUnit
    -            <GenericCompositeDimension: TemperatureUnit * TimeUnit / LengthUnit>
    -        """
    -        numerator = self.numerator.copy()
    -        denominator = self.denominator.copy()
    -        if isinstance(generic, GenericCompositeDimension):
    -            numerator.extend(generic.numerator)
    -            denominator.extend(generic.denominator)
    -            return GenericCompositeDimension(
    -                numerator=numerator, denominator=denominator
    -            )
    -
    -        if isinstance(generic, GenericDimension):
    -            numerator.append(generic)
    -            return GenericCompositeDimension(
    -                numerator=numerator, denominator=denominator
    -            )
    +            >>> EnergyUnit.is_equivalent(MassUnit * (LengthUnit**2) / (TimeUnit**2))
    +            True
    +        """
    +        if isinstance(other, MeasurementUnitType):
    +            if (
    +                self.denominator == []
    +                and len(self.numerator) == 1
    +                and self.numerator[0].is_equivalent(other)
    +            ):
    +                return True
    +
    +            if issubclass(other, AliasMeasurementUnit):
    +                return other.aliased_generic_descriptor().is_equivalent(self)  # type: ignore[attr-defined]
    +
    +        elif isinstance(other, GenericDimension):
    +            if (
    +                self.denominator == []
    +                and len(self.numerator) == 1
    +                and self.numerator[0].is_equivalent(other)
    +            ):
    +                return True
    +
    +            if issubclass(other.unit_type, AliasMeasurementUnit):
    +                return (
    +                    other.unit_type.aliased_generic_descriptor() ** other.power
    +                ).is_equivalent(self)
    +
    +        elif isinstance(other, GenericCompositeDimension):
    +            _generic = other.analysed().simplified()
    +            _self = self.analysed().simplified()
    +
    +            return Counter(_self.numerator) == Counter(_generic.numerator) and (
    +                Counter(_self.denominator) == Counter(_generic.denominator)
    +            )
    +
    +        return False
    +
    +    def has_no_units(self) -> bool:
    +        """
    +        Returns True if the generic composite dimension does not have any units, False
    +        otherwise.
    +
    +        Examples:
    +            >>> class LengthUnit(MeasurementUnit): ...
    +
    +            >>> GenericCompositeDimension().has_no_units()
    +            True
    +            >>> GenericCompositeDimension([LengthUnit]).has_no_units()
    +            False
    +        """
    +        return len(self.denominator) == 0 and len(self.numerator) == 0
    +
    +    def _numerator_copy(self) -> List[GenericDimension]:
    +        return [replace(n) for n in self.numerator]
    +
    +    def _denominator_copy(self) -> List[GenericDimension]:
    +        return [replace(d) for d in self.denominator]
    +
    +    def __mul__(self, generic: GenericUnitDescriptor) -> "GenericCompositeDimension":
    +        """
    +        Defines multiplication between GenericCompositeDimension(s) and other generic
    +        descriptors.
     
    -        if isinstance(generic, MeasurementUnitType):
    -            numerator.append(GenericDimension(generic))
    -            return GenericCompositeDimension(
    -                numerator=numerator, denominator=denominator
    -            )
    -        raise DescriptorBinaryOperationError(f"cannot multiply {self} with {generic}. ")
    -
    -    def __truediv__(
    -        self, generic: GenericUnitDescriptor
    -    ) -> "GenericCompositeDimension":
    -        """
    -        Defines division between GenericCompositeDimension(s) and other generic
    -        descriptors.
    -
    -        Examples:
    -            >>> class TemperatureUnit(MeasurementUnit): ...
    -            >>> class TimeUnit(MeasurementUnit): ...
    -            >>> class LengthUnit(MeasurementUnit): ...
    -            >>> (TemperatureUnit * LengthUnit) / TimeUnit
    -            <GenericCompositeDimension: LengthUnit * TemperatureUnit / TimeUnit>
    -        """
    -        numerator = self.numerator.copy()
    -        denominator = self.denominator.copy()
    -        if isinstance(generic, GenericCompositeDimension):
    -            numerator.extend(generic.denominator)
    -            denominator.extend(generic.numerator)
    -            return GenericCompositeDimension(
    -                numerator=numerator, denominator=denominator
    -            )
    -        if isinstance(generic, GenericDimension):
    -            denominator.append(generic)
    -            return GenericCompositeDimension(
    -                numerator=numerator, denominator=denominator
    -            )
    -        if isinstance(generic, MeasurementUnitType):
    -            denominator.append(GenericDimension(generic))
    -            return GenericCompositeDimension(
    -                numerator=numerator, denominator=denominator
    -            )
    -        raise DescriptorBinaryOperationError(f"cannot divide {self} with {generic}. ")
    -
    -    def __pow__(self, power: float) -> "GenericCompositeDimension":
    -        """
    -        Defines exponentiation for GenericCompositeDimension(s).
    -
    -        Examples:
    -            >>> class TemperatureUnit(MeasurementUnit): ...
    -            >>> class TimeUnit(MeasurementUnit): ...
    -
    -            >>> (TemperatureUnit / TimeUnit)**2
    -            <GenericCompositeDimension: (TemperatureUnit^2) / (TimeUnit^2)>
    -        """
    -        if not isinstance(power, (float, int)):
    -            raise DescriptorExponentError(
    -                f"invalid exponent: {{ value: {power}, type: {type(power)} }};"
    -                " expected float or int. "
    -            )
    -        numerator = [n**power for n in self._numerator_copy()]
    -        denominator = [d**power for d in self._denominator_copy()]
    -        return GenericCompositeDimension(numerator, denominator)
    -
    -    def __eq__(self, generic) -> bool:
    -        """
    -        Defines equality for GenericCompositeDimension(s).
    -
    -        Examples:
    -            >>> class TemperatureUnit(MeasurementUnit): ...
    -            >>> class TimeUnit(MeasurementUnit): ...
    -            >>> (TemperatureUnit / TimeUnit) != (TimeUnit / TemperatureUnit)
    -            True
    -        """
    -        if not isinstance(generic, GenericCompositeDimension):
    -            return False
    -        return Counter(self.numerator) == Counter(generic.numerator) and (
    -            Counter(self.denominator) == Counter(generic.denominator)
    -        )
    -
    -    def __hash__(self) -> int:
    -        return hash(str(self))
    -
    -    def __str__(self) -> str:
    -        numerators = " * ".join(sorted([str(n) for n in self.numerator]))
    -        denominators = " / ".join(sorted([str(d) for d in self.denominator]))
    -        if len(denominators) > 0:
    -            denominators = " / " + denominators
    -        return numerators + denominators
    +        Examples:
    +            >>> class TemperatureUnit(MeasurementUnit): ...
    +            >>> class TimeUnit(MeasurementUnit): ...
    +            >>> class LengthUnit(MeasurementUnit): ...
    +            >>> (TemperatureUnit / LengthUnit) * TimeUnit
    +            <GenericCompositeDimension: TemperatureUnit * TimeUnit / LengthUnit>
    +        """
    +        numerator = self.numerator.copy()
    +        denominator = self.denominator.copy()
    +        if isinstance(generic, GenericCompositeDimension):
    +            numerator.extend(generic.numerator)
    +            denominator.extend(generic.denominator)
    +            return GenericCompositeDimension(
    +                numerator=numerator, denominator=denominator
    +            )
    +
    +        if isinstance(generic, GenericDimension):
    +            numerator.append(generic)
    +            return GenericCompositeDimension(
    +                numerator=numerator, denominator=denominator
    +            )
    +
    +        if isinstance(generic, MeasurementUnitType):
    +            numerator.append(GenericDimension(generic))
    +            return GenericCompositeDimension(
    +                numerator=numerator, denominator=denominator
    +            )
    +        raise DescriptorBinaryOperationError(f"cannot multiply {self} with {generic}. ")
    +
    +    def __truediv__(
    +        self, generic: GenericUnitDescriptor
    +    ) -> "GenericCompositeDimension":
    +        """
    +        Defines division between GenericCompositeDimension(s) and other generic
    +        descriptors.
    +
    +        Examples:
    +            >>> class TemperatureUnit(MeasurementUnit): ...
    +            >>> class TimeUnit(MeasurementUnit): ...
    +            >>> class LengthUnit(MeasurementUnit): ...
    +            >>> (TemperatureUnit * LengthUnit) / TimeUnit
    +            <GenericCompositeDimension: LengthUnit * TemperatureUnit / TimeUnit>
    +        """
    +        numerator = self.numerator.copy()
    +        denominator = self.denominator.copy()
    +        if isinstance(generic, GenericCompositeDimension):
    +            numerator.extend(generic.denominator)
    +            denominator.extend(generic.numerator)
    +            return GenericCompositeDimension(
    +                numerator=numerator, denominator=denominator
    +            )
    +        if isinstance(generic, GenericDimension):
    +            denominator.append(generic)
    +            return GenericCompositeDimension(
    +                numerator=numerator, denominator=denominator
    +            )
    +        if isinstance(generic, MeasurementUnitType):
    +            denominator.append(GenericDimension(generic))
    +            return GenericCompositeDimension(
    +                numerator=numerator, denominator=denominator
    +            )
    +        raise DescriptorBinaryOperationError(f"cannot divide {self} with {generic}. ")
    +
    +    def __pow__(self, power: float) -> "GenericCompositeDimension":
    +        """
    +        Defines exponentiation for GenericCompositeDimension(s).
    +
    +        Examples:
    +            >>> class TemperatureUnit(MeasurementUnit): ...
    +            >>> class TimeUnit(MeasurementUnit): ...
    +
    +            >>> (TemperatureUnit / TimeUnit)**2
    +            <GenericCompositeDimension: (TemperatureUnit^2) / (TimeUnit^2)>
    +        """
    +        if not isinstance(power, (float, int)):
    +            raise DescriptorExponentError(
    +                f"invalid exponent: {{ value: {power}, type: {type(power)} }};"
    +                " expected float or int. "
    +            )
    +        numerator = [n**power for n in self._numerator_copy()]
    +        denominator = [d**power for d in self._denominator_copy()]
    +        return GenericCompositeDimension(numerator, denominator)
    +
    +    def __eq__(self, generic) -> bool:
    +        """
    +        Defines equality for GenericCompositeDimension(s).
     
    -    def __repr__(self) -> str:
    -        numerators = " * ".join(sorted([str(n) for n in self.numerator]))
    -        denominators = " / ".join(sorted([str(d) for d in self.denominator]))
    -        if len(denominators) > 0:
    -            denominators = " / " + denominators
    -        return f"<GenericCompositeDimension: {numerators + denominators}>"
    +        Examples:
    +            >>> class TemperatureUnit(MeasurementUnit): ...
    +            >>> class TimeUnit(MeasurementUnit): ...
    +            >>> (TemperatureUnit / TimeUnit) != (TimeUnit / TemperatureUnit)
    +            True
    +        """
    +        if not isinstance(generic, GenericCompositeDimension):
    +            return False
    +        return Counter(self.numerator) == Counter(generic.numerator) and (
    +            Counter(self.denominator) == Counter(generic.denominator)
    +        )
    +
    +    def __hash__(self) -> int:
    +        return hash(str(self))
    +
    +    def __str__(self) -> str:
    +        numerators = " * ".join(sorted([str(n) for n in self.numerator]))
    +        denominators = " / ".join(sorted([str(d) for d in self.denominator]))
    +        if len(denominators) > 0:
    +            denominators = " / " + denominators
    +        return numerators + denominators
    +
    +    def __repr__(self) -> str:
    +        numerators = " * ".join(sorted([str(n) for n in self.numerator]))
    +        denominators = " / ".join(sorted([str(d) for d in self.denominator]))
    +        if len(denominators) > 0:
    +            denominators = " / " + denominators
    +        return f"<GenericCompositeDimension: {numerators + denominators}>"
     
    @@ -7117,35 +7159,35 @@

    Source code in src/property_utils/units/descriptors.py -
    def __eq__(self, generic) -> bool:
    -    """
    -    Defines equality for GenericCompositeDimension(s).
    -
    -    Examples:
    -        >>> class TemperatureUnit(MeasurementUnit): ...
    -        >>> class TimeUnit(MeasurementUnit): ...
    -        >>> (TemperatureUnit / TimeUnit) != (TimeUnit / TemperatureUnit)
    -        True
    -    """
    -    if not isinstance(generic, GenericCompositeDimension):
    -        return False
    -    return Counter(self.numerator) == Counter(generic.numerator) and (
    -        Counter(self.denominator) == Counter(generic.denominator)
    -    )
    +              
    def __eq__(self, generic) -> bool:
    +    """
    +    Defines equality for GenericCompositeDimension(s).
    +
    +    Examples:
    +        >>> class TemperatureUnit(MeasurementUnit): ...
    +        >>> class TimeUnit(MeasurementUnit): ...
    +        >>> (TemperatureUnit / TimeUnit) != (TimeUnit / TemperatureUnit)
    +        True
    +    """
    +    if not isinstance(generic, GenericCompositeDimension):
    +        return False
    +    return Counter(self.numerator) == Counter(generic.numerator) and (
    +        Counter(self.denominator) == Counter(generic.denominator)
    +    )
     
    @@ -7177,29 +7219,7 @@

    Source code in src/property_utils/units/descriptors.py -
    1338
    -1339
    -1340
    -1341
    -1342
    -1343
    -1344
    -1345
    -1346
    -1347
    -1348
    -1349
    -1350
    -1351
    -1352
    -1353
    -1354
    -1355
    -1356
    -1357
    -1358
    -1359
    -1360
    +              
    1360
     1361
     1362
     1363
    @@ -7209,39 +7229,61 @@ 

    1367 1368 1369 -1370

    def __mul__(self, generic: GenericUnitDescriptor) -> "GenericCompositeDimension":
    -    """
    -    Defines multiplication between GenericCompositeDimension(s) and other generic
    -    descriptors.
    -
    -    Examples:
    -        >>> class TemperatureUnit(MeasurementUnit): ...
    -        >>> class TimeUnit(MeasurementUnit): ...
    -        >>> class LengthUnit(MeasurementUnit): ...
    -        >>> (TemperatureUnit / LengthUnit) * TimeUnit
    -        <GenericCompositeDimension: TemperatureUnit * TimeUnit / LengthUnit>
    -    """
    -    numerator = self.numerator.copy()
    -    denominator = self.denominator.copy()
    -    if isinstance(generic, GenericCompositeDimension):
    -        numerator.extend(generic.numerator)
    -        denominator.extend(generic.denominator)
    -        return GenericCompositeDimension(
    -            numerator=numerator, denominator=denominator
    -        )
    -
    -    if isinstance(generic, GenericDimension):
    -        numerator.append(generic)
    -        return GenericCompositeDimension(
    -            numerator=numerator, denominator=denominator
    -        )
    +1370
    +1371
    +1372
    +1373
    +1374
    +1375
    +1376
    +1377
    +1378
    +1379
    +1380
    +1381
    +1382
    +1383
    +1384
    +1385
    +1386
    +1387
    +1388
    +1389
    +1390
    +1391
    +1392
    def __mul__(self, generic: GenericUnitDescriptor) -> "GenericCompositeDimension":
    +    """
    +    Defines multiplication between GenericCompositeDimension(s) and other generic
    +    descriptors.
     
    -    if isinstance(generic, MeasurementUnitType):
    -        numerator.append(GenericDimension(generic))
    -        return GenericCompositeDimension(
    -            numerator=numerator, denominator=denominator
    -        )
    -    raise DescriptorBinaryOperationError(f"cannot multiply {self} with {generic}. ")
    +    Examples:
    +        >>> class TemperatureUnit(MeasurementUnit): ...
    +        >>> class TimeUnit(MeasurementUnit): ...
    +        >>> class LengthUnit(MeasurementUnit): ...
    +        >>> (TemperatureUnit / LengthUnit) * TimeUnit
    +        <GenericCompositeDimension: TemperatureUnit * TimeUnit / LengthUnit>
    +    """
    +    numerator = self.numerator.copy()
    +    denominator = self.denominator.copy()
    +    if isinstance(generic, GenericCompositeDimension):
    +        numerator.extend(generic.numerator)
    +        denominator.extend(generic.denominator)
    +        return GenericCompositeDimension(
    +            numerator=numerator, denominator=denominator
    +        )
    +
    +    if isinstance(generic, GenericDimension):
    +        numerator.append(generic)
    +        return GenericCompositeDimension(
    +            numerator=numerator, denominator=denominator
    +        )
    +
    +    if isinstance(generic, MeasurementUnitType):
    +        numerator.append(GenericDimension(generic))
    +        return GenericCompositeDimension(
    +            numerator=numerator, denominator=denominator
    +        )
    +    raise DescriptorBinaryOperationError(f"cannot multiply {self} with {generic}. ")
     
    @@ -7272,43 +7314,43 @@

    Source code in src/property_utils/units/descriptors.py -
    def __pow__(self, power: float) -> "GenericCompositeDimension":
    -    """
    -    Defines exponentiation for GenericCompositeDimension(s).
    -
    -    Examples:
    -        >>> class TemperatureUnit(MeasurementUnit): ...
    -        >>> class TimeUnit(MeasurementUnit): ...
    -
    -        >>> (TemperatureUnit / TimeUnit)**2
    -        <GenericCompositeDimension: (TemperatureUnit^2) / (TimeUnit^2)>
    -    """
    -    if not isinstance(power, (float, int)):
    -        raise DescriptorExponentError(
    -            f"invalid exponent: {{ value: {power}, type: {type(power)} }};"
    -            " expected float or int. "
    -        )
    -    numerator = [n**power for n in self._numerator_copy()]
    -    denominator = [d**power for d in self._denominator_copy()]
    -    return GenericCompositeDimension(numerator, denominator)
    +              
    def __pow__(self, power: float) -> "GenericCompositeDimension":
    +    """
    +    Defines exponentiation for GenericCompositeDimension(s).
    +
    +    Examples:
    +        >>> class TemperatureUnit(MeasurementUnit): ...
    +        >>> class TimeUnit(MeasurementUnit): ...
    +
    +        >>> (TemperatureUnit / TimeUnit)**2
    +        <GenericCompositeDimension: (TemperatureUnit^2) / (TimeUnit^2)>
    +    """
    +    if not isinstance(power, (float, int)):
    +        raise DescriptorExponentError(
    +            f"invalid exponent: {{ value: {power}, type: {type(power)} }};"
    +            " expected float or int. "
    +        )
    +    numerator = [n**power for n in self._numerator_copy()]
    +    denominator = [d**power for d in self._denominator_copy()]
    +    return GenericCompositeDimension(numerator, denominator)
     
    @@ -7340,29 +7382,7 @@

    Source code in src/property_utils/units/descriptors.py -
    1372
    -1373
    -1374
    -1375
    -1376
    -1377
    -1378
    -1379
    -1380
    -1381
    -1382
    -1383
    -1384
    -1385
    -1386
    -1387
    -1388
    -1389
    -1390
    -1391
    -1392
    -1393
    -1394
    +              
    1394
     1395
     1396
     1397
    @@ -7372,39 +7392,61 @@ 

    1401 1402 1403 -1404

    def __truediv__(
    -    self, generic: GenericUnitDescriptor
    -) -> "GenericCompositeDimension":
    -    """
    -    Defines division between GenericCompositeDimension(s) and other generic
    -    descriptors.
    -
    -    Examples:
    -        >>> class TemperatureUnit(MeasurementUnit): ...
    -        >>> class TimeUnit(MeasurementUnit): ...
    -        >>> class LengthUnit(MeasurementUnit): ...
    -        >>> (TemperatureUnit * LengthUnit) / TimeUnit
    -        <GenericCompositeDimension: LengthUnit * TemperatureUnit / TimeUnit>
    -    """
    -    numerator = self.numerator.copy()
    -    denominator = self.denominator.copy()
    -    if isinstance(generic, GenericCompositeDimension):
    -        numerator.extend(generic.denominator)
    -        denominator.extend(generic.numerator)
    -        return GenericCompositeDimension(
    -            numerator=numerator, denominator=denominator
    -        )
    -    if isinstance(generic, GenericDimension):
    -        denominator.append(generic)
    -        return GenericCompositeDimension(
    -            numerator=numerator, denominator=denominator
    -        )
    -    if isinstance(generic, MeasurementUnitType):
    -        denominator.append(GenericDimension(generic))
    -        return GenericCompositeDimension(
    -            numerator=numerator, denominator=denominator
    -        )
    -    raise DescriptorBinaryOperationError(f"cannot divide {self} with {generic}. ")
    +1404
    +1405
    +1406
    +1407
    +1408
    +1409
    +1410
    +1411
    +1412
    +1413
    +1414
    +1415
    +1416
    +1417
    +1418
    +1419
    +1420
    +1421
    +1422
    +1423
    +1424
    +1425
    +1426
    def __truediv__(
    +    self, generic: GenericUnitDescriptor
    +) -> "GenericCompositeDimension":
    +    """
    +    Defines division between GenericCompositeDimension(s) and other generic
    +    descriptors.
    +
    +    Examples:
    +        >>> class TemperatureUnit(MeasurementUnit): ...
    +        >>> class TimeUnit(MeasurementUnit): ...
    +        >>> class LengthUnit(MeasurementUnit): ...
    +        >>> (TemperatureUnit * LengthUnit) / TimeUnit
    +        <GenericCompositeDimension: LengthUnit * TemperatureUnit / TimeUnit>
    +    """
    +    numerator = self.numerator.copy()
    +    denominator = self.denominator.copy()
    +    if isinstance(generic, GenericCompositeDimension):
    +        numerator.extend(generic.denominator)
    +        denominator.extend(generic.numerator)
    +        return GenericCompositeDimension(
    +            numerator=numerator, denominator=denominator
    +        )
    +    if isinstance(generic, GenericDimension):
    +        denominator.append(generic)
    +        return GenericCompositeDimension(
    +            numerator=numerator, denominator=denominator
    +        )
    +    if isinstance(generic, MeasurementUnitType):
    +        denominator.append(GenericDimension(generic))
    +        return GenericCompositeDimension(
    +            numerator=numerator, denominator=denominator
    +        )
    +    raise DescriptorBinaryOperationError(f"cannot divide {self} with {generic}. ")
     
    @@ -7446,29 +7488,7 @@

    Source code in src/property_utils/units/descriptors.py -
    1172
    -1173
    -1174
    -1175
    -1176
    -1177
    -1178
    -1179
    -1180
    -1181
    -1182
    -1183
    -1184
    -1185
    -1186
    -1187
    -1188
    -1189
    -1190
    -1191
    -1192
    -1193
    -1194
    +              
    1194
     1195
     1196
     1197
    @@ -7488,49 +7508,71 @@ 

    1211 1212 1213 -1214

    def analyse(self) -> None:
    -    """
    -    Analyse this composite by replacing its alias units with their aliased units.
    -
    -    Examples:
    -        >>> class MassUnit(MeasurementUnit): ...
    -        >>> class LengthUnit(MeasurementUnit): ...
    -        >>> class TimeUnit(MeasurementUnit): ...
    -
    -        >>> class PressureUnit(AliasMeasurementUnit):
    -        ...     @classmethod
    -        ...     def aliased_generic_descriptor(cls) -> GenericCompositeDimension:
    -        ...         return MassUnit / LengthUnit / (TimeUnit**2)
    -
    -        >>> composite = PressureUnit / LengthUnit
    -        >>> composite
    -        <GenericCompositeDimension: PressureUnit / LengthUnit>
    -
    -        >>> composite.analyse()
    -        >>> composite
    -        <GenericCompositeDimension: MassUnit / (TimeUnit^2) / LengthUnit / LengthUnit>
    -    """
    -    for n in self.numerator:
    -        if issubclass(n.unit_type, AliasMeasurementUnit):
    -            aliased = n.unit_type.aliased_generic_descriptor() ** n.power
    -            if isinstance(aliased, GenericDimension):
    -                self.numerator.append(aliased)
    -            elif isinstance(aliased, GenericCompositeDimension):
    -                self.numerator.extend(aliased.numerator)
    -                self.denominator.extend(aliased.denominator)
    +1214
    +1215
    +1216
    +1217
    +1218
    +1219
    +1220
    +1221
    +1222
    +1223
    +1224
    +1225
    +1226
    +1227
    +1228
    +1229
    +1230
    +1231
    +1232
    +1233
    +1234
    +1235
    +1236
    def analyse(self) -> None:
    +    """
    +    Analyse this composite by replacing its alias units with their aliased units.
    +
    +    Examples:
    +        >>> class MassUnit(MeasurementUnit): ...
    +        >>> class LengthUnit(MeasurementUnit): ...
    +        >>> class TimeUnit(MeasurementUnit): ...
     
    -            self.numerator.remove(n)
    -
    -    for d in self.denominator:
    -        if issubclass(d.unit_type, AliasMeasurementUnit):
    -            aliased = d.unit_type.aliased_generic_descriptor() ** d.power
    -            if isinstance(aliased, GenericDimension):
    -                self.denominator.append(aliased)
    -            elif isinstance(aliased, GenericCompositeDimension):
    -                self.denominator.extend(aliased.numerator)
    -                self.numerator.extend(aliased.denominator)
    -
    -            self.denominator.remove(d)
    +        >>> class PressureUnit(AliasMeasurementUnit):
    +        ...     @classmethod
    +        ...     def aliased_generic_descriptor(cls) -> GenericCompositeDimension:
    +        ...         return MassUnit / LengthUnit / (TimeUnit**2)
    +
    +        >>> composite = PressureUnit / LengthUnit
    +        >>> composite
    +        <GenericCompositeDimension: PressureUnit / LengthUnit>
    +
    +        >>> composite.analyse()
    +        >>> composite
    +        <GenericCompositeDimension: MassUnit / (TimeUnit^2) / LengthUnit / LengthUnit>
    +    """
    +    for n in self.numerator:
    +        if issubclass(n.unit_type, AliasMeasurementUnit):
    +            aliased = n.unit_type.aliased_generic_descriptor() ** n.power
    +            if isinstance(aliased, GenericDimension):
    +                self.numerator.append(aliased)
    +            elif isinstance(aliased, GenericCompositeDimension):
    +                self.numerator.extend(aliased.numerator)
    +                self.denominator.extend(aliased.denominator)
    +
    +            self.numerator.remove(n)
    +
    +    for d in self.denominator:
    +        if issubclass(d.unit_type, AliasMeasurementUnit):
    +            aliased = d.unit_type.aliased_generic_descriptor() ** d.power
    +            if isinstance(aliased, GenericDimension):
    +                self.denominator.append(aliased)
    +            elif isinstance(aliased, GenericCompositeDimension):
    +                self.denominator.extend(aliased.numerator)
    +                self.numerator.extend(aliased.denominator)
    +
    +            self.denominator.remove(d)
     
    @@ -7561,63 +7603,63 @@

    ... def aliased_generic_descriptor(cls) -> GenericCompositeDimension: ... return MassUnit / LengthUnit / (TimeUnit**2) -
    >>> composite = PressureUnit / LengthUnit
    ->>> composite
    -<GenericCompositeDimension: PressureUnit / LengthUnit>
    -
    -
    >>> composite.analysed()
    -<GenericCompositeDimension: MassUnit / (TimeUnit^2) / LengthUnit / LengthUnit>
    -
    - -
    - Source code in src/property_utils/units/descriptors.py -
    def analysed(self) -> "GenericCompositeDimension":
    -    """
    -    Returns an analysed version of this composite generic as a new object.
    -
    -    Examples:
    -        >>> class MassUnit(MeasurementUnit): ...
    -        >>> class LengthUnit(MeasurementUnit): ...
    -        >>> class TimeUnit(MeasurementUnit): ...
    -
    -        >>> class PressureUnit(AliasMeasurementUnit):
    -        ...     @classmethod
    -        ...     def aliased_generic_descriptor(cls) -> GenericCompositeDimension:
    -        ...         return MassUnit / LengthUnit / (TimeUnit**2)
    -
    -        >>> composite = PressureUnit / LengthUnit
    -        >>> composite
    -        <GenericCompositeDimension: PressureUnit / LengthUnit>
    -
    -        >>> composite.analysed()
    -        <GenericCompositeDimension: MassUnit / (TimeUnit^2) / LengthUnit / LengthUnit>
    -    """
    -    copy = replace(self)
    -    copy.analyse()
    -    return copy
    +    
    >>> composite = PressureUnit / LengthUnit
    +>>> composite
    +<GenericCompositeDimension: PressureUnit / LengthUnit>
    +
    +
    >>> composite.analysed()
    +<GenericCompositeDimension: MassUnit / (TimeUnit^2) / LengthUnit / LengthUnit>
    +
    + +
    + Source code in src/property_utils/units/descriptors.py +
    def analysed(self) -> "GenericCompositeDimension":
    +    """
    +    Returns an analysed version of this composite generic as a new object.
    +
    +    Examples:
    +        >>> class MassUnit(MeasurementUnit): ...
    +        >>> class LengthUnit(MeasurementUnit): ...
    +        >>> class TimeUnit(MeasurementUnit): ...
    +
    +        >>> class PressureUnit(AliasMeasurementUnit):
    +        ...     @classmethod
    +        ...     def aliased_generic_descriptor(cls) -> GenericCompositeDimension:
    +        ...         return MassUnit / LengthUnit / (TimeUnit**2)
    +
    +        >>> composite = PressureUnit / LengthUnit
    +        >>> composite
    +        <GenericCompositeDimension: PressureUnit / LengthUnit>
    +
    +        >>> composite.analysed()
    +        <GenericCompositeDimension: MassUnit / (TimeUnit^2) / LengthUnit / LengthUnit>
    +    """
    +    copy = replace(self)
    +    copy.analyse()
    +    return copy
     
    @@ -7650,33 +7692,33 @@

    Source code in src/property_utils/units/descriptors.py -
    def has_no_units(self) -> bool:
    -    """
    -    Returns True if the generic composite dimension does not have any units, False
    -    otherwise.
    -
    -    Examples:
    -        >>> class LengthUnit(MeasurementUnit): ...
    -
    -        >>> GenericCompositeDimension().has_no_units()
    -        True
    -        >>> GenericCompositeDimension([LengthUnit]).has_no_units()
    -        False
    -    """
    -    return len(self.denominator) == 0 and len(self.numerator) == 0
    +              
    def has_no_units(self) -> bool:
    +    """
    +    Returns True if the generic composite dimension does not have any units, False
    +    otherwise.
    +
    +    Examples:
    +        >>> class LengthUnit(MeasurementUnit): ...
    +
    +        >>> GenericCompositeDimension().has_no_units()
    +        True
    +        >>> GenericCompositeDimension([LengthUnit]).has_no_units()
    +        False
    +    """
    +    return len(self.denominator) == 0 and len(self.numerator) == 0
     
    @@ -7707,33 +7749,33 @@

    Source code in src/property_utils/units/descriptors.py -
    def inverse_generic(self):
    -    """
    -    Create a generic composite with inverse units.
    -
    -    Examples:
    -        >>> class LengthUnit(MeasurementUnit): ...
    -        >>> class TimeUnit(MeasurementUnit): ...
    -
    -        >>> (LengthUnit / TimeUnit).inverse_generic()
    -        <GenericCompositeDimension: TimeUnit / LengthUnit>
    -    """
    -    return GenericCompositeDimension(
    -        self._denominator_copy(), self._numerator_copy()
    -    )
    +              
    def inverse_generic(self):
    +    """
    +    Create a generic composite with inverse units.
    +
    +    Examples:
    +        >>> class LengthUnit(MeasurementUnit): ...
    +        >>> class TimeUnit(MeasurementUnit): ...
    +
    +        >>> (LengthUnit / TimeUnit).inverse_generic()
    +        <GenericCompositeDimension: TimeUnit / LengthUnit>
    +    """
    +    return GenericCompositeDimension(
    +        self._denominator_copy(), self._numerator_copy()
    +    )
     
    @@ -7779,29 +7821,7 @@

    Source code in src/property_utils/units/descriptors.py -
    1256
    -1257
    -1258
    -1259
    -1260
    -1261
    -1262
    -1263
    -1264
    -1265
    -1266
    -1267
    -1268
    -1269
    -1270
    -1271
    -1272
    -1273
    -1274
    -1275
    -1276
    -1277
    -1278
    +              
    1278
     1279
     1280
     1281
    @@ -7838,66 +7858,88 @@ 

    1312 1313 1314 -1315

    def is_equivalent(self, other: GenericUnitDescriptor) -> bool:
    -    """
    -    Returns True if this generic is equivalent to the given one, False otherwise.
    -
    -    A generic can be equivalent with another generic if the latter or the former
    -    is an alias.
    -
    -    Examples:
    -        >>> class LengthUnit(MeasurementUnit): ...
    -        >>> class MassUnit(MeasurementUnit): ...
    -        >>> class TimeUnit(MeasurementUnit): ...
    -        >>> class ForceUnit(AliasMeasurementUnit):
    -        ...     @classmethod
    -        ...     def aliased_generic_descriptor(cls):
    -        ...         return MassUnit * LengthUnit / (TimeUnit**2)
    -
    -        >>> ForceUnit.is_equivalent(MassUnit * LengthUnit / (TimeUnit**2))
    -        True
    -
    -        >>> class EnergyUnit(AliasMeasurementUnit):
    -        ...     @classmethod
    -        ...     def aliased_generic_descriptor(cls):
    -        ...         return ForceUnit * LengthUnit
    -
    -        >>> EnergyUnit.is_equivalent(MassUnit * (LengthUnit**2) / (TimeUnit**2))
    -        True
    -    """
    -    if isinstance(other, MeasurementUnitType):
    -        if (
    -            self.denominator == []
    -            and len(self.numerator) == 1
    -            and self.numerator[0].is_equivalent(other)
    -        ):
    -            return True
    -
    -        if issubclass(other, AliasMeasurementUnit):
    -            return other.aliased_generic_descriptor().is_equivalent(self)  # type: ignore[attr-defined]
    +1315
    +1316
    +1317
    +1318
    +1319
    +1320
    +1321
    +1322
    +1323
    +1324
    +1325
    +1326
    +1327
    +1328
    +1329
    +1330
    +1331
    +1332
    +1333
    +1334
    +1335
    +1336
    +1337
    def is_equivalent(self, other: GenericUnitDescriptor) -> bool:
    +    """
    +    Returns True if this generic is equivalent to the given one, False otherwise.
    +
    +    A generic can be equivalent with another generic if the latter or the former
    +    is an alias.
    +
    +    Examples:
    +        >>> class LengthUnit(MeasurementUnit): ...
    +        >>> class MassUnit(MeasurementUnit): ...
    +        >>> class TimeUnit(MeasurementUnit): ...
    +        >>> class ForceUnit(AliasMeasurementUnit):
    +        ...     @classmethod
    +        ...     def aliased_generic_descriptor(cls):
    +        ...         return MassUnit * LengthUnit / (TimeUnit**2)
     
    -    elif isinstance(other, GenericDimension):
    -        if (
    -            self.denominator == []
    -            and len(self.numerator) == 1
    -            and self.numerator[0].is_equivalent(other)
    -        ):
    -            return True
    +        >>> ForceUnit.is_equivalent(MassUnit * LengthUnit / (TimeUnit**2))
    +        True
    +
    +        >>> class EnergyUnit(AliasMeasurementUnit):
    +        ...     @classmethod
    +        ...     def aliased_generic_descriptor(cls):
    +        ...         return ForceUnit * LengthUnit
     
    -        if issubclass(other.unit_type, AliasMeasurementUnit):
    -            return (
    -                other.unit_type.aliased_generic_descriptor() ** other.power
    -            ).is_equivalent(self)
    -
    -    elif isinstance(other, GenericCompositeDimension):
    -        _generic = other.analysed().simplified()
    -        _self = self.analysed().simplified()
    -
    -        return Counter(_self.numerator) == Counter(_generic.numerator) and (
    -            Counter(_self.denominator) == Counter(_generic.denominator)
    -        )
    -
    -    return False
    +        >>> EnergyUnit.is_equivalent(MassUnit * (LengthUnit**2) / (TimeUnit**2))
    +        True
    +    """
    +    if isinstance(other, MeasurementUnitType):
    +        if (
    +            self.denominator == []
    +            and len(self.numerator) == 1
    +            and self.numerator[0].is_equivalent(other)
    +        ):
    +            return True
    +
    +        if issubclass(other, AliasMeasurementUnit):
    +            return other.aliased_generic_descriptor().is_equivalent(self)  # type: ignore[attr-defined]
    +
    +    elif isinstance(other, GenericDimension):
    +        if (
    +            self.denominator == []
    +            and len(self.numerator) == 1
    +            and self.numerator[0].is_equivalent(other)
    +        ):
    +            return True
    +
    +        if issubclass(other.unit_type, AliasMeasurementUnit):
    +            return (
    +                other.unit_type.aliased_generic_descriptor() ** other.power
    +            ).is_equivalent(self)
    +
    +    elif isinstance(other, GenericCompositeDimension):
    +        _generic = other.analysed().simplified()
    +        _self = self.analysed().simplified()
    +
    +        return Counter(_self.numerator) == Counter(_generic.numerator) and (
    +            Counter(_self.denominator) == Counter(_generic.denominator)
    +        )
    +
    +    return False
     
    @@ -7942,61 +7984,61 @@

    Source code in src/property_utils/units/descriptors.py -
    1143
    -1144
    -1145
    -1146
    -1147
    -1148
    -1149
    -1150
    -1151
    -1152
    -1153
    -1154
    -1155
    -1156
    -1157
    -1158
    -1159
    -1160
    -1161
    -1162
    -1163
    -1164
    -1165
    +              
    def simplified(self) -> "GenericCompositeDimension":
    -    """
    -    Returns a simplified version of this composite generic as a new object.
    -
    -    Examples:
    -        >>> class PressureUnit(AliasMeasurementUnit): ...
    -
    -        >>> class TemperatureUnit(MeasurementUnit): ...
    -
    -        >>> class LengthUnit(MeasurementUnit): ...
    -
    -        >>> class TimeUnit(MeasurementUnit): ...
    -
    -        >>> composite = (PressureUnit**(-2)) / (TemperatureUnit**(-1))
    -        >>> composite
    -        <GenericCompositeDimension: (PressureUnit^-2) / (TemperatureUnit^-1)>
    -        >>> composite.simplified()
    -        <GenericCompositeDimension: TemperatureUnit / (PressureUnit^2)>
    -
    -        >>> composite = PressureUnit * LengthUnit * PressureUnit /TimeUnit
    -        >>> composite
    -        <GenericCompositeDimension: LengthUnit * PressureUnit * PressureUnit / TimeUnit>
    -        >>> composite.simplified()
    -        <GenericCompositeDimension: (PressureUnit^2) * LengthUnit / TimeUnit>
    -    """
    -    copy = replace(self)
    -    copy.simplify()
    -    return copy
    +1170
    +1171
    +1172
    +1173
    +1174
    +1175
    +1176
    +1177
    +1178
    +1179
    +1180
    +1181
    +1182
    +1183
    +1184
    +1185
    +1186
    +1187
    +1188
    +1189
    +1190
    +1191
    +1192
    def simplified(self) -> "GenericCompositeDimension":
    +    """
    +    Returns a simplified version of this composite generic as a new object.
    +
    +    Examples:
    +        >>> class PressureUnit(AliasMeasurementUnit): ...
    +
    +        >>> class TemperatureUnit(MeasurementUnit): ...
    +
    +        >>> class LengthUnit(MeasurementUnit): ...
    +
    +        >>> class TimeUnit(MeasurementUnit): ...
    +
    +        >>> composite = (PressureUnit**(-2)) / (TemperatureUnit**(-1))
    +        >>> composite
    +        <GenericCompositeDimension: (PressureUnit^-2) / (TemperatureUnit^-1)>
    +        >>> composite.simplified()
    +        <GenericCompositeDimension: TemperatureUnit / (PressureUnit^2)>
    +
    +        >>> composite = PressureUnit * LengthUnit * PressureUnit /TimeUnit
    +        >>> composite
    +        <GenericCompositeDimension: LengthUnit * PressureUnit * PressureUnit / TimeUnit>
    +        >>> composite.simplified()
    +        <GenericCompositeDimension: (PressureUnit^2) * LengthUnit / TimeUnit>
    +    """
    +    copy = replace(self)
    +    copy.simplify()
    +    return copy
     
    @@ -8043,29 +8085,7 @@

    Source code in src/property_utils/units/descriptors.py -
    1092
    -1093
    -1094
    -1095
    -1096
    -1097
    -1098
    -1099
    -1100
    -1101
    -1102
    -1103
    -1104
    -1105
    -1106
    -1107
    -1108
    -1109
    -1110
    -1111
    -1112
    -1113
    -1114
    +              
    1114
     1115
     1116
     1117
    @@ -8092,56 +8112,78 @@ 

    1138 1139 1140 -1141

    def simplify(self) -> None:
    -    """
    -    Simplify the composite by merging common dimensions.
    -
    -    Examples:
    -        >>> class PressureUnit(AliasMeasurementUnit): ...
    -
    -        >>> class TemperatureUnit(MeasurementUnit): ...
    -
    -        >>> class LengthUnit(MeasurementUnit): ...
    -
    -        >>> class TimeUnit(MeasurementUnit): ...
    -
    -        >>> composite = (PressureUnit**(-2)) / (TemperatureUnit**(-1))
    -        >>> composite
    -        <GenericCompositeDimension: (PressureUnit^-2) / (TemperatureUnit^-1)>
    -        >>> composite.simplify()
    -        >>> composite
    -        <GenericCompositeDimension: TemperatureUnit / (PressureUnit^2)>
    -
    -        >>> composite = PressureUnit * LengthUnit * PressureUnit / TimeUnit
    -        >>> composite
    -        <GenericCompositeDimension: LengthUnit * PressureUnit * PressureUnit / TimeUnit>
    -        >>> composite.simplify()
    -        >>> composite
    -        <GenericCompositeDimension: (PressureUnit^2) * LengthUnit / TimeUnit>
    -    """
    -    exponents: Dict[MeasurementUnitType, float] = {}
    -    for n in self.numerator:
    -        if n.unit_type in exponents:
    -            exponents[n.unit_type] += n.power
    -        else:
    -            exponents[n.unit_type] = n.power
    -
    -    for d in self.denominator:
    -        if d.unit_type in exponents:
    -            exponents[d.unit_type] -= d.power
    -        else:
    -            exponents[d.unit_type] = 0 - d.power
    -
    -    numerator = []
    -    denominator = []
    -    for unit_type, exponent in exponents.items():
    -        if exponent > 0:
    -            numerator.append(GenericDimension(unit_type) ** exponent)
    -        elif exponent < 0:
    -            denominator.append(GenericDimension(unit_type) ** abs(exponent))
    -
    -    self.numerator = numerator
    -    self.denominator = denominator
    +1141
    +1142
    +1143
    +1144
    +1145
    +1146
    +1147
    +1148
    +1149
    +1150
    +1151
    +1152
    +1153
    +1154
    +1155
    +1156
    +1157
    +1158
    +1159
    +1160
    +1161
    +1162
    +1163
    def simplify(self) -> None:
    +    """
    +    Simplify the composite by merging common dimensions.
    +
    +    Examples:
    +        >>> class PressureUnit(AliasMeasurementUnit): ...
    +
    +        >>> class TemperatureUnit(MeasurementUnit): ...
    +
    +        >>> class LengthUnit(MeasurementUnit): ...
    +
    +        >>> class TimeUnit(MeasurementUnit): ...
    +
    +        >>> composite = (PressureUnit**(-2)) / (TemperatureUnit**(-1))
    +        >>> composite
    +        <GenericCompositeDimension: (PressureUnit^-2) / (TemperatureUnit^-1)>
    +        >>> composite.simplify()
    +        >>> composite
    +        <GenericCompositeDimension: TemperatureUnit / (PressureUnit^2)>
    +
    +        >>> composite = PressureUnit * LengthUnit * PressureUnit / TimeUnit
    +        >>> composite
    +        <GenericCompositeDimension: LengthUnit * PressureUnit * PressureUnit / TimeUnit>
    +        >>> composite.simplify()
    +        >>> composite
    +        <GenericCompositeDimension: (PressureUnit^2) * LengthUnit / TimeUnit>
    +    """
    +    exponents: Dict[MeasurementUnitType, float] = {}
    +    for n in self.numerator:
    +        if n.unit_type in exponents:
    +            exponents[n.unit_type] += n.power
    +        else:
    +            exponents[n.unit_type] = n.power
    +
    +    for d in self.denominator:
    +        if d.unit_type in exponents:
    +            exponents[d.unit_type] -= d.power
    +        else:
    +            exponents[d.unit_type] = 0 - d.power
    +
    +    numerator = []
    +    denominator = []
    +    for unit_type, exponent in exponents.items():
    +        if exponent > 0:
    +            numerator.append(GenericDimension(unit_type) ** exponent)
    +        elif exponent < 0:
    +            denominator.append(GenericDimension(unit_type) ** abs(exponent))
    +
    +    self.numerator = numerator
    +    self.denominator = denominator
     
    @@ -8181,51 +8223,51 @@

    Source code in src/property_utils/units/descriptors.py -
    def to_si(self) -> "CompositeDimension":
    -    """
    -    Create a CompositeDimension with SI units.
    -
    -    Examples:
    -        >>> class TemperatureUnit(MeasurementUnit):
    -        ...     KELVIN = "K"
    -        ...     @classmethod
    -        ...     def si(cls): return cls.KELVIN
    -        >>> class TimeUnit(MeasurementUnit):
    -        ...     SECOND = "s"
    -        ...     @classmethod
    -        ...     def si(cls): return cls.SECOND
    -        >>> class LengthUnit(MeasurementUnit):
    -        ...     METER = "m"
    -        ...     @classmethod
    -        ...     def si(cls): return cls.METER
    -        >>> (TemperatureUnit * LengthUnit / TimeUnit).to_si()
    -        <CompositeDimension: K * m / s>
    -    """
    -    return CompositeDimension(
    -        [n.to_si() for n in self.numerator], [d.to_si() for d in self.denominator]
    -    )
    +              
    def to_si(self) -> "CompositeDimension":
    +    """
    +    Create a CompositeDimension with SI units.
    +
    +    Examples:
    +        >>> class TemperatureUnit(MeasurementUnit):
    +        ...     KELVIN = "K"
    +        ...     @classmethod
    +        ...     def si(cls): return cls.KELVIN
    +        >>> class TimeUnit(MeasurementUnit):
    +        ...     SECOND = "s"
    +        ...     @classmethod
    +        ...     def si(cls): return cls.SECOND
    +        >>> class LengthUnit(MeasurementUnit):
    +        ...     METER = "m"
    +        ...     @classmethod
    +        ...     def si(cls): return cls.METER
    +        >>> (TemperatureUnit * LengthUnit / TimeUnit).to_si()
    +        <CompositeDimension: K * m / s>
    +    """
    +    return CompositeDimension(
    +        [n.to_si() for n in self.numerator], [d.to_si() for d in self.denominator]
    +    )
     
    @@ -8271,26 +8313,7 @@

    Source code in src/property_utils/units/descriptors.py -
    559
    -560
    -561
    -562
    -563
    -564
    -565
    -566
    -567
    -568
    -569
    -570
    -571
    -572
    -573
    -574
    -575
    -576
    -577
    -578
    +                
    578
     579
     580
     581
    @@ -8482,218 +8505,237 @@ 

    767 768 769 -770

    @dataclass
    -class GenericDimension:
    -    """
    -    Represents a generic property unit or a generic property unit to some power.
    -
    -    e.g. a generic dimension can be a temperature dimension or a volume dimension
    -    (length dimension to the 3rd power).
    -
    -    Examples:
    -        >>> class MassUnit(MeasurementUnit): ...
    -        >>> MassUnit**2
    -        <GenericDimension: MassUnit^2>
    -    """
    -
    -    unit_type: MeasurementUnitType
    -    power: float = 1
    -
    -    def __init__(self, unit_type: MeasurementUnitType, power: float = 1) -> None:
    -        if not isinstance(power, (float, int)):
    -            raise DescriptorExponentError(
    -                f"invalid exponent: {{ value: {power}, type: {type(power)} }};"
    -                " expected float or int. "
    -            )
    -        self.unit_type = unit_type
    -        self.power = power
    -
    -    def to_si(self) -> "Dimension":
    -        """
    -        Create a Dimension with SI units.
    -
    -        Examples:
    -            >>> class TemperatureUnit(MeasurementUnit):
    -            ...     CELCIUS = "C"
    -            ...     KELVIN = "K"
    -            ...     @classmethod
    -            ...     def si(cls): return cls.KELVIN
    -            >>> (TemperatureUnit**2).to_si()
    -            <Dimension: K^2>
    -        """
    -        return Dimension(self.unit_type.to_si(), self.power)
    -
    -    def inverse_generic(self) -> "GenericCompositeDimension":
    -        """
    -        Create a generic composite with inverse units.
    +770
    +771
    +772
    +773
    +774
    +775
    +776
    +777
    +778
    +779
    +780
    +781
    +782
    +783
    +784
    +785
    +786
    +787
    +788
    +789
    @dataclass
    +class GenericDimension:
    +    """
    +    Represents a generic property unit or a generic property unit to some power.
    +
    +    e.g. a generic dimension can be a temperature dimension or a volume dimension
    +    (length dimension to the 3rd power).
    +
    +    Examples:
    +        >>> class MassUnit(MeasurementUnit): ...
    +        >>> MassUnit**2
    +        <GenericDimension: MassUnit^2>
    +    """
    +
    +    unit_type: MeasurementUnitType
    +    power: float = 1
    +
    +    def __init__(self, unit_type: MeasurementUnitType, power: float = 1) -> None:
    +        if not isinstance(power, (float, int)):
    +            raise DescriptorExponentError(
    +                f"invalid exponent: {{ value: {power}, type: {type(power)} }};"
    +                " expected float or int. "
    +            )
    +        self.unit_type = unit_type
    +        self.power = power
     
    -        Examples:
    -            >>> class LengthUnit(MeasurementUnit): ...
    -            >>> (LengthUnit**2).inverse_generic()
    -            <GenericCompositeDimension:  / (LengthUnit^2)>
    -        """
    -        return GenericCompositeDimension([], [replace(self)])
    -
    -    # pylint: disable=too-many-return-statements
    -    def is_equivalent(self, other: GenericUnitDescriptor) -> bool:
    -        """
    -        Returns True if this generic is equivalent to the given one, False otherwise.
    -
    -        A generic can be equivalent with another generic if the latter or the former
    -        is an alias.
    +    def to_si(self) -> "Dimension":
    +        """
    +        Create a Dimension with SI units.
    +
    +        Examples:
    +            >>> class TemperatureUnit(MeasurementUnit):
    +            ...     CELCIUS = "C"
    +            ...     KELVIN = "K"
    +            ...     @classmethod
    +            ...     def si(cls): return cls.KELVIN
    +            >>> (TemperatureUnit**2).to_si()
    +            <Dimension: K^2>
    +        """
    +        return Dimension(self.unit_type.to_si(), self.power)
     
    -        Examples:
    -            >>> class LengthUnit(MeasurementUnit): ...
    -            >>> class MassUnit(MeasurementUnit): ...
    -            >>> class TimeUnit(MeasurementUnit): ...
    -            >>> class ForceUnit(AliasMeasurementUnit):
    -            ...     @classmethod
    -            ...     def aliased_generic_descriptor(cls):
    -            ...         return MassUnit * LengthUnit / (TimeUnit**2)
    -
    -            >>> ForceUnit.is_equivalent(MassUnit * LengthUnit / (TimeUnit**2))
    -            True
    -
    -            >>> class EnergyUnit(AliasMeasurementUnit):
    -            ...     @classmethod
    -            ...     def aliased_generic_descriptor(cls):
    -            ...         return ForceUnit * LengthUnit
    -
    -            >>> EnergyUnit.is_equivalent(MassUnit * (LengthUnit**2) / (TimeUnit**2))
    -            True
    -        """
    -        if isinstance(other, MeasurementUnitType):
    -            if self.unit_type == other and self.power == 1:
    -                return True
    -
    -            if issubclass(other, AliasMeasurementUnit):
    -                return other.aliased_generic_descriptor().is_equivalent(self)  # type: ignore[attr-defined]
    -
    -        elif isinstance(other, GenericDimension):
    -            if self.unit_type == other.unit_type and self.power == other.power:
    -                return True
    +    def inverse_generic(self) -> "GenericCompositeDimension":
    +        """
    +        Create a generic composite with inverse units.
    +
    +        Examples:
    +            >>> class LengthUnit(MeasurementUnit): ...
    +            >>> (LengthUnit**2).inverse_generic()
    +            <GenericCompositeDimension:  / (LengthUnit^2)>
    +        """
    +        return GenericCompositeDimension([], [replace(self)])
    +
    +    # pylint: disable=too-many-return-statements
    +    def is_equivalent(self, other: GenericUnitDescriptor) -> bool:
    +        """
    +        Returns True if this generic is equivalent to the given one, False otherwise.
    +
    +        A generic can be equivalent with another generic if the latter or the former
    +        is an alias.
    +
    +        Examples:
    +            >>> class LengthUnit(MeasurementUnit): ...
    +            >>> class MassUnit(MeasurementUnit): ...
    +            >>> class TimeUnit(MeasurementUnit): ...
    +            >>> class ForceUnit(AliasMeasurementUnit):
    +            ...     @classmethod
    +            ...     def aliased_generic_descriptor(cls):
    +            ...         return MassUnit * LengthUnit / (TimeUnit**2)
    +
    +            >>> ForceUnit.is_equivalent(MassUnit * LengthUnit / (TimeUnit**2))
    +            True
     
    -            if issubclass(other.unit_type, AliasMeasurementUnit):
    -                return (
    -                    other.unit_type.aliased_generic_descriptor() ** other.power
    -                ).is_equivalent(self)
    +            >>> class EnergyUnit(AliasMeasurementUnit):
    +            ...     @classmethod
    +            ...     def aliased_generic_descriptor(cls):
    +            ...         return ForceUnit * LengthUnit
     
    -            if issubclass(self.unit_type, AliasMeasurementUnit):
    -                return (
    -                    self.unit_type.aliased_generic_descriptor() ** self.power
    -                ).is_equivalent(other)
    -
    -        elif isinstance(other, GenericCompositeDimension):
    -            if (
    -                other.denominator == []
    -                and len(other.numerator) == 1
    -                and other.numerator[0].is_equivalent(self)
    -            ):
    -                return True
    -
    -            if issubclass(self.unit_type, AliasMeasurementUnit):
    -                return (
    -                    self.unit_type.aliased_generic_descriptor() ** self.power
    -                ).is_equivalent(other)
    -
    -        return False
    -
    -    def __mul__(self, generic: GenericUnitDescriptor) -> "GenericCompositeDimension":
    -        """
    -        Defines multiplication between GenericDimension(s) and other generic
    -        descriptors.
    -
    -        Examples:
    -            >>> class TemperatureUnit(MeasurementUnit): ...
    -            >>> class TimeUnit(MeasurementUnit): ...
    -            >>> (TemperatureUnit**2) * TimeUnit
    -            <GenericCompositeDimension: (TemperatureUnit^2) * TimeUnit>
    -        """
    -        if isinstance(generic, GenericCompositeDimension):
    -            numerator = generic.numerator.copy()
    -            denominator = generic.denominator.copy()
    -            numerator.append(self)
    -            return GenericCompositeDimension(
    -                numerator=numerator, denominator=denominator
    -            )
    -        if isinstance(generic, GenericDimension):
    -            return GenericCompositeDimension(numerator=[self, generic])
    -        if isinstance(generic, MeasurementUnitType):
    -            return GenericCompositeDimension(
    -                numerator=[self, GenericDimension(generic)]
    -            )
    -        raise DescriptorBinaryOperationError(f"cannot multiply {self} with {generic}. ")
    -
    -    def __truediv__(
    -        self, generic: GenericUnitDescriptor
    -    ) -> "GenericCompositeDimension":
    -        """
    -        Defines division between GenericDimension(s) and other generic descriptors.
    -
    -        Examples:
    -            >>> class TemperatureUnit(MeasurementUnit): ...
    -            >>> class TimeUnit(MeasurementUnit): ...
    -            >>> TemperatureUnit / (TimeUnit**2)
    -            <GenericCompositeDimension: TemperatureUnit / (TimeUnit^2)>
    -        """
    -        if isinstance(generic, GenericCompositeDimension):
    -            numerator = generic.denominator.copy()
    -            denominator = generic.numerator.copy()
    -            numerator.append(self)
    -            return GenericCompositeDimension(
    -                numerator=numerator, denominator=denominator
    -            )
    -        if isinstance(generic, GenericDimension):
    -            return GenericCompositeDimension(numerator=[self], denominator=[generic])
    -        if isinstance(generic, MeasurementUnitType):
    -            return GenericCompositeDimension(
    -                numerator=[self], denominator=[GenericDimension(generic)]
    -            )
    -        raise DescriptorBinaryOperationError(f"cannot divide {self} with {generic}. ")
    -
    -    def __pow__(self, power: float) -> "GenericDimension":
    -        """
    -        Defines exponentiation of GenericDimension.
    -
    -        Examples:
    -            >>> class TimeUnit(MeasurementUnit): ...
    -            >>> (TimeUnit**2)**3
    -            <GenericDimension: TimeUnit^6>
    -        """
    -        if not isinstance(power, (float, int)):
    -            raise DescriptorExponentError(
    -                f"invalid exponent: {{ value: {power}, type: {type(power)} }};"
    -                " expected float or int. "
    -            )
    -        self.power *= power
    -        return self
    -
    -    def __eq__(self, generic) -> bool:
    -        """
    -        Defines equality for GenericDimension(s).
    -
    -        Examples:
    -            >>> class TemperatureUnit(MeasurementUnit): ...
    -            >>> (TemperatureUnit**2) != TemperatureUnit
    -            True
    -        """
    -        if not isinstance(generic, GenericDimension):
    -            return False
    -        return self.unit_type == generic.unit_type and self.power == generic.power
    -
    -    def __hash__(self) -> int:
    -        return hash(str(self))
    -
    -    def __str__(self) -> str:
    -        s = self.unit_type.__name__
    -        if self.power != 1:
    -            return f"({s}^{self.power})"
    -        return s
    -
    -    def __repr__(self) -> str:
    -        if self.power != 1:
    -            return f"<GenericDimension: {self.unit_type.__name__}^{self.power}>"
    -        return f"<GenericDimension: {self.unit_type.__name__}>"
    +            >>> EnergyUnit.is_equivalent(MassUnit * (LengthUnit**2) / (TimeUnit**2))
    +            True
    +        """
    +        if isinstance(other, MeasurementUnitType):
    +            if self.unit_type == other and self.power == 1:
    +                return True
    +
    +            if issubclass(other, AliasMeasurementUnit):
    +                return other.aliased_generic_descriptor().is_equivalent(self)  # type: ignore[attr-defined]
    +
    +        elif isinstance(other, GenericDimension):
    +            if self.unit_type == other.unit_type and self.power == other.power:
    +                return True
    +
    +            if issubclass(other.unit_type, AliasMeasurementUnit):
    +                return (
    +                    other.unit_type.aliased_generic_descriptor() ** other.power
    +                ).is_equivalent(self)
    +
    +            if issubclass(self.unit_type, AliasMeasurementUnit):
    +                return (
    +                    self.unit_type.aliased_generic_descriptor() ** self.power
    +                ).is_equivalent(other)
    +
    +        elif isinstance(other, GenericCompositeDimension):
    +            if (
    +                other.denominator == []
    +                and len(other.numerator) == 1
    +                and other.numerator[0].is_equivalent(self)
    +            ):
    +                return True
    +
    +            if issubclass(self.unit_type, AliasMeasurementUnit):
    +                return (
    +                    self.unit_type.aliased_generic_descriptor() ** self.power
    +                ).is_equivalent(other)
    +
    +        return False
    +
    +    def __mul__(self, generic: GenericUnitDescriptor) -> "GenericCompositeDimension":
    +        """
    +        Defines multiplication between GenericDimension(s) and other generic
    +        descriptors.
    +
    +        Examples:
    +            >>> class TemperatureUnit(MeasurementUnit): ...
    +            >>> class TimeUnit(MeasurementUnit): ...
    +            >>> (TemperatureUnit**2) * TimeUnit
    +            <GenericCompositeDimension: (TemperatureUnit^2) * TimeUnit>
    +        """
    +        if isinstance(generic, GenericCompositeDimension):
    +            numerator = generic.numerator.copy()
    +            denominator = generic.denominator.copy()
    +            numerator.append(self)
    +            return GenericCompositeDimension(
    +                numerator=numerator, denominator=denominator
    +            )
    +        if isinstance(generic, GenericDimension):
    +            return GenericCompositeDimension(numerator=[self, generic])
    +        if isinstance(generic, MeasurementUnitType):
    +            return GenericCompositeDimension(
    +                numerator=[self, GenericDimension(generic)]
    +            )
    +        raise DescriptorBinaryOperationError(f"cannot multiply {self} with {generic}. ")
    +
    +    def __truediv__(
    +        self, generic: GenericUnitDescriptor
    +    ) -> "GenericCompositeDimension":
    +        """
    +        Defines division between GenericDimension(s) and other generic descriptors.
    +
    +        Examples:
    +            >>> class TemperatureUnit(MeasurementUnit): ...
    +            >>> class TimeUnit(MeasurementUnit): ...
    +            >>> TemperatureUnit / (TimeUnit**2)
    +            <GenericCompositeDimension: TemperatureUnit / (TimeUnit^2)>
    +        """
    +        if isinstance(generic, GenericCompositeDimension):
    +            numerator = generic.denominator.copy()
    +            denominator = generic.numerator.copy()
    +            numerator.append(self)
    +            return GenericCompositeDimension(
    +                numerator=numerator, denominator=denominator
    +            )
    +        if isinstance(generic, GenericDimension):
    +            return GenericCompositeDimension(numerator=[self], denominator=[generic])
    +        if isinstance(generic, MeasurementUnitType):
    +            return GenericCompositeDimension(
    +                numerator=[self], denominator=[GenericDimension(generic)]
    +            )
    +        raise DescriptorBinaryOperationError(f"cannot divide {self} with {generic}. ")
    +
    +    def __pow__(self, power: float) -> "GenericDimension":
    +        """
    +        Defines exponentiation of GenericDimension.
    +
    +        Examples:
    +            >>> class TimeUnit(MeasurementUnit): ...
    +            >>> (TimeUnit**2)**3
    +            <GenericDimension: TimeUnit^6>
    +        """
    +        if not isinstance(power, (float, int)):
    +            raise DescriptorExponentError(
    +                f"invalid exponent: {{ value: {power}, type: {type(power)} }};"
    +                " expected float or int. "
    +            )
    +        self.power *= power
    +        return self
    +
    +    def __eq__(self, generic) -> bool:
    +        """
    +        Defines equality for GenericDimension(s).
    +
    +        Examples:
    +            >>> class TemperatureUnit(MeasurementUnit): ...
    +            >>> (TemperatureUnit**2) != TemperatureUnit
    +            True
    +        """
    +        if not isinstance(generic, GenericDimension):
    +            return False
    +        return self.unit_type == generic.unit_type and self.power == generic.power
    +
    +    def __hash__(self) -> int:
    +        return hash(str(self))
    +
    +    def __str__(self) -> str:
    +        s = self.unit_type.__name__
    +        if self.power != 1:
    +            return f"({s}^{self.power})"
    +        return s
    +
    +    def __repr__(self) -> str:
    +        if self.power != 1:
    +            return f"<GenericDimension: {self.unit_type.__name__}^{self.power}>"
    +        return f"<GenericDimension: {self.unit_type.__name__}>"
     
    @@ -8731,29 +8773,29 @@

    Source code in src/property_utils/units/descriptors.py -
    def __eq__(self, generic) -> bool:
    -    """
    -    Defines equality for GenericDimension(s).
    -
    -    Examples:
    -        >>> class TemperatureUnit(MeasurementUnit): ...
    -        >>> (TemperatureUnit**2) != TemperatureUnit
    -        True
    -    """
    -    if not isinstance(generic, GenericDimension):
    -        return False
    -    return self.unit_type == generic.unit_type and self.power == generic.power
    +              
    def __eq__(self, generic) -> bool:
    +    """
    +    Defines equality for GenericDimension(s).
    +
    +    Examples:
    +        >>> class TemperatureUnit(MeasurementUnit): ...
    +        >>> (TemperatureUnit**2) != TemperatureUnit
    +        True
    +    """
    +    if not isinstance(generic, GenericDimension):
    +        return False
    +    return self.unit_type == generic.unit_type and self.power == generic.power
     
    @@ -8784,55 +8826,55 @@

    Source code in src/property_utils/units/descriptors.py -
    675
    -676
    -677
    -678
    -679
    -680
    -681
    -682
    -683
    -684
    -685
    -686
    -687
    -688
    -689
    -690
    -691
    -692
    -693
    -694
    +              
    def __mul__(self, generic: GenericUnitDescriptor) -> "GenericCompositeDimension":
    -    """
    -    Defines multiplication between GenericDimension(s) and other generic
    -    descriptors.
    -
    -    Examples:
    -        >>> class TemperatureUnit(MeasurementUnit): ...
    -        >>> class TimeUnit(MeasurementUnit): ...
    -        >>> (TemperatureUnit**2) * TimeUnit
    -        <GenericCompositeDimension: (TemperatureUnit^2) * TimeUnit>
    -    """
    -    if isinstance(generic, GenericCompositeDimension):
    -        numerator = generic.numerator.copy()
    -        denominator = generic.denominator.copy()
    -        numerator.append(self)
    -        return GenericCompositeDimension(
    -            numerator=numerator, denominator=denominator
    -        )
    -    if isinstance(generic, GenericDimension):
    -        return GenericCompositeDimension(numerator=[self, generic])
    -    if isinstance(generic, MeasurementUnitType):
    -        return GenericCompositeDimension(
    -            numerator=[self, GenericDimension(generic)]
    -        )
    -    raise DescriptorBinaryOperationError(f"cannot multiply {self} with {generic}. ")
    +699
    +700
    +701
    +702
    +703
    +704
    +705
    +706
    +707
    +708
    +709
    +710
    +711
    +712
    +713
    +714
    +715
    +716
    +717
    +718
    def __mul__(self, generic: GenericUnitDescriptor) -> "GenericCompositeDimension":
    +    """
    +    Defines multiplication between GenericDimension(s) and other generic
    +    descriptors.
    +
    +    Examples:
    +        >>> class TemperatureUnit(MeasurementUnit): ...
    +        >>> class TimeUnit(MeasurementUnit): ...
    +        >>> (TemperatureUnit**2) * TimeUnit
    +        <GenericCompositeDimension: (TemperatureUnit^2) * TimeUnit>
    +    """
    +    if isinstance(generic, GenericCompositeDimension):
    +        numerator = generic.numerator.copy()
    +        denominator = generic.denominator.copy()
    +        numerator.append(self)
    +        return GenericCompositeDimension(
    +            numerator=numerator, denominator=denominator
    +        )
    +    if isinstance(generic, GenericDimension):
    +        return GenericCompositeDimension(numerator=[self, generic])
    +    if isinstance(generic, MeasurementUnitType):
    +        return GenericCompositeDimension(
    +            numerator=[self, GenericDimension(generic)]
    +        )
    +    raise DescriptorBinaryOperationError(f"cannot multiply {self} with {generic}. ")
     
    @@ -8861,37 +8903,37 @@

    Source code in src/property_utils/units/descriptors.py -
    def __pow__(self, power: float) -> "GenericDimension":
    -    """
    -    Defines exponentiation of GenericDimension.
    -
    -    Examples:
    -        >>> class TimeUnit(MeasurementUnit): ...
    -        >>> (TimeUnit**2)**3
    -        <GenericDimension: TimeUnit^6>
    -    """
    -    if not isinstance(power, (float, int)):
    -        raise DescriptorExponentError(
    -            f"invalid exponent: {{ value: {power}, type: {type(power)} }};"
    -            " expected float or int. "
    -        )
    -    self.power *= power
    -    return self
    +              
    def __pow__(self, power: float) -> "GenericDimension":
    +    """
    +    Defines exponentiation of GenericDimension.
    +
    +    Examples:
    +        >>> class TimeUnit(MeasurementUnit): ...
    +        >>> (TimeUnit**2)**3
    +        <GenericDimension: TimeUnit^6>
    +    """
    +    if not isinstance(power, (float, int)):
    +        raise DescriptorExponentError(
    +            f"invalid exponent: {{ value: {power}, type: {type(power)} }};"
    +            " expected float or int. "
    +        )
    +    self.power *= power
    +    return self
     
    @@ -8921,57 +8963,57 @@

    Source code in src/property_utils/units/descriptors.py -
    701
    -702
    -703
    -704
    -705
    -706
    -707
    -708
    -709
    -710
    -711
    -712
    -713
    -714
    -715
    -716
    -717
    -718
    -719
    -720
    +              
    def __truediv__(
    -    self, generic: GenericUnitDescriptor
    -) -> "GenericCompositeDimension":
    -    """
    -    Defines division between GenericDimension(s) and other generic descriptors.
    -
    -    Examples:
    -        >>> class TemperatureUnit(MeasurementUnit): ...
    -        >>> class TimeUnit(MeasurementUnit): ...
    -        >>> TemperatureUnit / (TimeUnit**2)
    -        <GenericCompositeDimension: TemperatureUnit / (TimeUnit^2)>
    -    """
    -    if isinstance(generic, GenericCompositeDimension):
    -        numerator = generic.denominator.copy()
    -        denominator = generic.numerator.copy()
    -        numerator.append(self)
    -        return GenericCompositeDimension(
    -            numerator=numerator, denominator=denominator
    -        )
    -    if isinstance(generic, GenericDimension):
    -        return GenericCompositeDimension(numerator=[self], denominator=[generic])
    -    if isinstance(generic, MeasurementUnitType):
    -        return GenericCompositeDimension(
    -            numerator=[self], denominator=[GenericDimension(generic)]
    -        )
    -    raise DescriptorBinaryOperationError(f"cannot divide {self} with {generic}. ")
    +726
    +727
    +728
    +729
    +730
    +731
    +732
    +733
    +734
    +735
    +736
    +737
    +738
    +739
    +740
    +741
    +742
    +743
    +744
    +745
    def __truediv__(
    +    self, generic: GenericUnitDescriptor
    +) -> "GenericCompositeDimension":
    +    """
    +    Defines division between GenericDimension(s) and other generic descriptors.
    +
    +    Examples:
    +        >>> class TemperatureUnit(MeasurementUnit): ...
    +        >>> class TimeUnit(MeasurementUnit): ...
    +        >>> TemperatureUnit / (TimeUnit**2)
    +        <GenericCompositeDimension: TemperatureUnit / (TimeUnit^2)>
    +    """
    +    if isinstance(generic, GenericCompositeDimension):
    +        numerator = generic.denominator.copy()
    +        denominator = generic.numerator.copy()
    +        numerator.append(self)
    +        return GenericCompositeDimension(
    +            numerator=numerator, denominator=denominator
    +        )
    +    if isinstance(generic, GenericDimension):
    +        return GenericCompositeDimension(numerator=[self], denominator=[generic])
    +    if isinstance(generic, MeasurementUnitType):
    +        return GenericCompositeDimension(
    +            numerator=[self], denominator=[GenericDimension(generic)]
    +        )
    +    raise DescriptorBinaryOperationError(f"cannot divide {self} with {generic}. ")
     
    @@ -9000,25 +9042,25 @@

    Source code in src/property_utils/units/descriptors.py -
    def inverse_generic(self) -> "GenericCompositeDimension":
    -    """
    -    Create a generic composite with inverse units.
    -
    -    Examples:
    -        >>> class LengthUnit(MeasurementUnit): ...
    -        >>> (LengthUnit**2).inverse_generic()
    -        <GenericCompositeDimension:  / (LengthUnit^2)>
    -    """
    -    return GenericCompositeDimension([], [replace(self)])
    +              
    def inverse_generic(self) -> "GenericCompositeDimension":
    +    """
    +    Create a generic composite with inverse units.
    +
    +    Examples:
    +        >>> class LengthUnit(MeasurementUnit): ...
    +        >>> (LengthUnit**2).inverse_generic()
    +        <GenericCompositeDimension:  / (LengthUnit^2)>
    +    """
    +    return GenericCompositeDimension([], [replace(self)])
     
    @@ -9064,26 +9106,7 @@

    Source code in src/property_utils/units/descriptors.py -
    612
    -613
    -614
    -615
    -616
    -617
    -618
    -619
    -620
    -621
    -622
    -623
    -624
    -625
    -626
    -627
    -628
    -629
    -630
    -631
    +              
    631
     632
     633
     634
    @@ -9125,68 +9148,87 @@ 

    670 671 672 -673

    def is_equivalent(self, other: GenericUnitDescriptor) -> bool:
    -    """
    -    Returns True if this generic is equivalent to the given one, False otherwise.
    -
    -    A generic can be equivalent with another generic if the latter or the former
    -    is an alias.
    -
    -    Examples:
    -        >>> class LengthUnit(MeasurementUnit): ...
    -        >>> class MassUnit(MeasurementUnit): ...
    -        >>> class TimeUnit(MeasurementUnit): ...
    -        >>> class ForceUnit(AliasMeasurementUnit):
    -        ...     @classmethod
    -        ...     def aliased_generic_descriptor(cls):
    -        ...         return MassUnit * LengthUnit / (TimeUnit**2)
    -
    -        >>> ForceUnit.is_equivalent(MassUnit * LengthUnit / (TimeUnit**2))
    -        True
    -
    -        >>> class EnergyUnit(AliasMeasurementUnit):
    -        ...     @classmethod
    -        ...     def aliased_generic_descriptor(cls):
    -        ...         return ForceUnit * LengthUnit
    -
    -        >>> EnergyUnit.is_equivalent(MassUnit * (LengthUnit**2) / (TimeUnit**2))
    -        True
    -    """
    -    if isinstance(other, MeasurementUnitType):
    -        if self.unit_type == other and self.power == 1:
    -            return True
    -
    -        if issubclass(other, AliasMeasurementUnit):
    -            return other.aliased_generic_descriptor().is_equivalent(self)  # type: ignore[attr-defined]
    -
    -    elif isinstance(other, GenericDimension):
    -        if self.unit_type == other.unit_type and self.power == other.power:
    -            return True
    +673
    +674
    +675
    +676
    +677
    +678
    +679
    +680
    +681
    +682
    +683
    +684
    +685
    +686
    +687
    +688
    +689
    +690
    +691
    +692
    def is_equivalent(self, other: GenericUnitDescriptor) -> bool:
    +    """
    +    Returns True if this generic is equivalent to the given one, False otherwise.
    +
    +    A generic can be equivalent with another generic if the latter or the former
    +    is an alias.
    +
    +    Examples:
    +        >>> class LengthUnit(MeasurementUnit): ...
    +        >>> class MassUnit(MeasurementUnit): ...
    +        >>> class TimeUnit(MeasurementUnit): ...
    +        >>> class ForceUnit(AliasMeasurementUnit):
    +        ...     @classmethod
    +        ...     def aliased_generic_descriptor(cls):
    +        ...         return MassUnit * LengthUnit / (TimeUnit**2)
    +
    +        >>> ForceUnit.is_equivalent(MassUnit * LengthUnit / (TimeUnit**2))
    +        True
     
    -        if issubclass(other.unit_type, AliasMeasurementUnit):
    -            return (
    -                other.unit_type.aliased_generic_descriptor() ** other.power
    -            ).is_equivalent(self)
    +        >>> class EnergyUnit(AliasMeasurementUnit):
    +        ...     @classmethod
    +        ...     def aliased_generic_descriptor(cls):
    +        ...         return ForceUnit * LengthUnit
     
    -        if issubclass(self.unit_type, AliasMeasurementUnit):
    -            return (
    -                self.unit_type.aliased_generic_descriptor() ** self.power
    -            ).is_equivalent(other)
    -
    -    elif isinstance(other, GenericCompositeDimension):
    -        if (
    -            other.denominator == []
    -            and len(other.numerator) == 1
    -            and other.numerator[0].is_equivalent(self)
    -        ):
    -            return True
    -
    -        if issubclass(self.unit_type, AliasMeasurementUnit):
    -            return (
    -                self.unit_type.aliased_generic_descriptor() ** self.power
    -            ).is_equivalent(other)
    -
    -    return False
    +        >>> EnergyUnit.is_equivalent(MassUnit * (LengthUnit**2) / (TimeUnit**2))
    +        True
    +    """
    +    if isinstance(other, MeasurementUnitType):
    +        if self.unit_type == other and self.power == 1:
    +            return True
    +
    +        if issubclass(other, AliasMeasurementUnit):
    +            return other.aliased_generic_descriptor().is_equivalent(self)  # type: ignore[attr-defined]
    +
    +    elif isinstance(other, GenericDimension):
    +        if self.unit_type == other.unit_type and self.power == other.power:
    +            return True
    +
    +        if issubclass(other.unit_type, AliasMeasurementUnit):
    +            return (
    +                other.unit_type.aliased_generic_descriptor() ** other.power
    +            ).is_equivalent(self)
    +
    +        if issubclass(self.unit_type, AliasMeasurementUnit):
    +            return (
    +                self.unit_type.aliased_generic_descriptor() ** self.power
    +            ).is_equivalent(other)
    +
    +    elif isinstance(other, GenericCompositeDimension):
    +        if (
    +            other.denominator == []
    +            and len(other.numerator) == 1
    +            and other.numerator[0].is_equivalent(self)
    +        ):
    +            return True
    +
    +        if issubclass(self.unit_type, AliasMeasurementUnit):
    +            return (
    +                self.unit_type.aliased_generic_descriptor() ** self.power
    +            ).is_equivalent(other)
    +
    +    return False
     
    @@ -9219,33 +9261,33 @@

    Source code in src/property_utils/units/descriptors.py -
    def to_si(self) -> "Dimension":
    -    """
    -    Create a Dimension with SI units.
    -
    -    Examples:
    -        >>> class TemperatureUnit(MeasurementUnit):
    -        ...     CELCIUS = "C"
    -        ...     KELVIN = "K"
    -        ...     @classmethod
    -        ...     def si(cls): return cls.KELVIN
    -        >>> (TemperatureUnit**2).to_si()
    -        <Dimension: K^2>
    -    """
    -    return Dimension(self.unit_type.to_si(), self.power)
    +              
    def to_si(self) -> "Dimension":
    +    """
    +    Create a Dimension with SI units.
    +
    +    Examples:
    +        >>> class TemperatureUnit(MeasurementUnit):
    +        ...     CELCIUS = "C"
    +        ...     KELVIN = "K"
    +        ...     @classmethod
    +        ...     def si(cls): return cls.KELVIN
    +        >>> (TemperatureUnit**2).to_si()
    +        <Dimension: K^2>
    +    """
    +    return Dimension(self.unit_type.to_si(), self.power)
     
    @@ -9697,7 +9739,26 @@

    477 478 479 -480

    class MeasurementUnit(Enum, metaclass=MeasurementUnitMeta):
    +480
    +481
    +482
    +483
    +484
    +485
    +486
    +487
    +488
    +489
    +490
    +491
    +492
    +493
    +494
    +495
    +496
    +497
    +498
    +499
    class MeasurementUnit(Enum, metaclass=MeasurementUnitMeta):
         """
         Base class for all measurement units of physical quantities.
     
    @@ -9724,164 +9785,183 @@ 

    """ raise NotImplementedError - @staticmethod - def from_descriptor(descriptor: UnitDescriptor) -> "MeasurementUnit": + @classmethod + def is_non_dimensional(cls) -> bool: """ - Create a MeasurementUnit from given descriptor. - If descriptor is already a MeasurementUnit, it returns the same object. - - This function does not serve as a constructor for MeasurementUnit, rather it - is intended to be used to convert an unknown unit descriptor to a - MeasurementUnit. - - Raises `UnitDescriptorTypeError` if given descriptor cannot be translated - to a MeasurementUnit instance. - - Examples: - >>> class TemperatureUnit(MeasurementUnit): - ... CELCIUS = "C" - - >>> celcius = MeasurementUnit.from_descriptor(TemperatureUnit.CELCIUS**2) - >>> celcius - <TemperatureUnit: C> - """ - if isinstance(descriptor, Dimension): - return descriptor.unit - if isinstance(descriptor, MeasurementUnit): - return descriptor - raise UnitDescriptorTypeError( - f"cannot create MeasurementUnit from descriptor: {descriptor}" - ) + Implement this function for defined measurement units that are non dimensional. + + Examples: + >>> class NonDimensionalUnit(MeasurementUnit): + ... NON_DIMENSIONAL = "" + ... @classmethod + ... def is_non_dimensional(cls) -> bool: return True + + >>> NonDimensionalUnit.is_non_dimensional() + True + """ + return False + + @staticmethod + def from_descriptor(descriptor: UnitDescriptor) -> "MeasurementUnit": + """ + Create a MeasurementUnit from given descriptor. + If descriptor is already a MeasurementUnit, it returns the same object. + + This function does not serve as a constructor for MeasurementUnit, rather it + is intended to be used to convert an unknown unit descriptor to a + MeasurementUnit. + + Raises `UnitDescriptorTypeError` if given descriptor cannot be translated + to a MeasurementUnit instance. - def isinstance(self, generic: GenericUnitDescriptor) -> bool: - """ - Returns True if the MeasurementUnit is an instance of the generic, False - otherwise. - - Examples: - >>> class TemperatureUnit(MeasurementUnit): - ... CELCIUS = "C" - - >>> class LengthUnit(MeasurementUnit): - ... METER = "m" - - >>> TemperatureUnit.CELCIUS.isinstance(TemperatureUnit) - True - - >>> TemperatureUnit.CELCIUS.isinstance(LengthUnit) - False - """ - return type(self) == generic # pylint: disable=unidiomatic-typecheck - - def isinstance_equivalent(self, generic: GenericUnitDescriptor) -> bool: - """ - Returns True if the UnitDescriptor is an instance-equivalent of the generic, - False otherwise. + Examples: + >>> class TemperatureUnit(MeasurementUnit): + ... CELCIUS = "C" + + >>> celcius = MeasurementUnit.from_descriptor(TemperatureUnit.CELCIUS**2) + >>> celcius + <TemperatureUnit: C> + """ + if isinstance(descriptor, Dimension): + return descriptor.unit + if isinstance(descriptor, MeasurementUnit): + return descriptor + raise UnitDescriptorTypeError( + f"cannot create MeasurementUnit from descriptor: {descriptor}" + ) + + def isinstance(self, generic: GenericUnitDescriptor) -> bool: + """ + Returns True if the MeasurementUnit is an instance of the generic, False + otherwise. + + Examples: + >>> class TemperatureUnit(MeasurementUnit): + ... CELCIUS = "C" - A unit descriptor is an instance-equivalent of a generic if the generic of the - unit descriptor is equivalent to the generic. + >>> class LengthUnit(MeasurementUnit): + ... METER = "m" - Equivalence between generics is checked with the `is_equivalent` method. - - Examples: - >>> class LengthUnit(MeasurementUnit): ... - >>> class AreaUnit(AliasMeasurementUnit): - ... HECTARE = "ha" - ... @classmethod - ... def aliased_generic_descriptor(cls): return LengthUnit**2 - - >>> AreaUnit.HECTARE.isinstance_equivalent(AreaUnit) - True - >>> AreaUnit.HECTARE.isinstance_equivalent(LengthUnit**2) - True - """ - return self.to_generic().is_equivalent(generic) + >>> TemperatureUnit.CELCIUS.isinstance(TemperatureUnit) + True + + >>> TemperatureUnit.CELCIUS.isinstance(LengthUnit) + False + """ + return type(self) == generic # pylint: disable=unidiomatic-typecheck + + def isinstance_equivalent(self, generic: GenericUnitDescriptor) -> bool: + """ + Returns True if the UnitDescriptor is an instance-equivalent of the generic, + False otherwise. + + A unit descriptor is an instance-equivalent of a generic if the generic of the + unit descriptor is equivalent to the generic. - def to_generic(self) -> GenericUnitDescriptor: - """ - Create a generic descriptor from this MeasurementUnit. - - Examples: - >>> class AmountUnit(MeasurementUnit): - ... MOL = "mol" - - >>> AmountUnit.MOL.to_generic() - <MeasurementUnit: AmountUnit> - """ - return self.__class__ - - def inverse(self) -> "CompositeDimension": - """ - Create a composite with inverse units. - - Examples: - >>> class TemperatureUnit(MeasurementUnit): - ... KELVIN = "K" - >>> TemperatureUnit.KELVIN.inverse() - <CompositeDimension: / K> - """ - return CompositeDimension([], [Dimension(self)]) - - def __mul__(self, descriptor: UnitDescriptor) -> "CompositeDimension": - """ - Defines multiplication between MeasurementUnit objects and other unit descriptors. + Equivalence between generics is checked with the `is_equivalent` method. + + Examples: + >>> class LengthUnit(MeasurementUnit): ... + >>> class AreaUnit(AliasMeasurementUnit): + ... HECTARE = "ha" + ... @classmethod + ... def aliased_generic_descriptor(cls): return LengthUnit**2 + + >>> AreaUnit.HECTARE.isinstance_equivalent(AreaUnit) + True + >>> AreaUnit.HECTARE.isinstance_equivalent(LengthUnit**2) + True + """ + return self.to_generic().is_equivalent(generic) + + def to_generic(self) -> GenericUnitDescriptor: + """ + Create a generic descriptor from this MeasurementUnit. + + Examples: + >>> class AmountUnit(MeasurementUnit): + ... MOL = "mol" + + >>> AmountUnit.MOL.to_generic() + <MeasurementUnit: AmountUnit> + """ + return self.__class__ - Examples: - >>> class TemperatureUnit(MeasurementUnit): - ... FAHRENHEIT = "F" - >>> class TimeUnit(MeasurementUnit): - ... HOUR = "hr" - >>> TemperatureUnit.FAHRENHEIT * TimeUnit.HOUR - <CompositeDimension: F * hr> - """ - if isinstance(descriptor, MeasurementUnit): - return Dimension(self) * Dimension(descriptor) - if isinstance(descriptor, (Dimension, CompositeDimension)): - return Dimension(self) * descriptor - raise DescriptorBinaryOperationError( - f"cannot multiply {self} with {descriptor}. " - ) + def inverse(self) -> "CompositeDimension": + """ + Create a composite with inverse units. + + Examples: + >>> class TemperatureUnit(MeasurementUnit): + ... KELVIN = "K" + >>> TemperatureUnit.KELVIN.inverse() + <CompositeDimension: / K> + """ + return CompositeDimension([], [Dimension(self)]) + + def __mul__(self, descriptor: UnitDescriptor) -> "CompositeDimension": + """ + Defines multiplication between MeasurementUnit objects and other unit descriptors. - def __truediv__(self, descriptor: UnitDescriptor) -> "CompositeDimension": - """ - Defines division between MeasurementUnit objects and other unit descriptors. - - Examples: - >>> class TemperatureUnit(MeasurementUnit): - ... FAHRENHEIT = "F" - >>> class TimeUnit(MeasurementUnit): - ... HOUR = "hr" - >>> TemperatureUnit.FAHRENHEIT / TimeUnit.HOUR - <CompositeDimension: F / hr> - """ - if isinstance(descriptor, MeasurementUnit): - return Dimension(self) / Dimension(descriptor) - if isinstance(descriptor, (Dimension, CompositeDimension)): - return Dimension(self) / descriptor - raise DescriptorBinaryOperationError( - f"cannot divide {self} with {descriptor}. " - ) + Examples: + >>> class TemperatureUnit(MeasurementUnit): + ... FAHRENHEIT = "F" + >>> class TimeUnit(MeasurementUnit): + ... HOUR = "hr" + >>> TemperatureUnit.FAHRENHEIT * TimeUnit.HOUR + <CompositeDimension: F * hr> + """ + if isinstance(descriptor, MeasurementUnit): + return Dimension(self) * Dimension(descriptor) + if isinstance(descriptor, (Dimension, CompositeDimension)): + return Dimension(self) * descriptor + raise DescriptorBinaryOperationError( + f"cannot multiply {self} with {descriptor}. " + ) + + def __truediv__(self, descriptor: UnitDescriptor) -> "CompositeDimension": + """ + Defines division between MeasurementUnit objects and other unit descriptors. - def __pow__(self, power: float) -> "Dimension": - """ - Defines exponentiation of MeasurementUnit objects. - - Examples: - >>> class LengthUnit(MeasurementUnit): - ... FEET = "ft" - >>> LengthUnit.FEET**3 - <Dimension: ft^3> - """ - return Dimension(self, power) - - def __hash__(self) -> int: - return hash(self.value) - - def __repr__(self) -> str: - return f"<{self.__class__.__name__}: {str(self)}>" - - def __str__(self) -> str: - return self.value + Examples: + >>> class TemperatureUnit(MeasurementUnit): + ... FAHRENHEIT = "F" + >>> class TimeUnit(MeasurementUnit): + ... HOUR = "hr" + >>> TemperatureUnit.FAHRENHEIT / TimeUnit.HOUR + <CompositeDimension: F / hr> + """ + if isinstance(descriptor, MeasurementUnit): + return Dimension(self) / Dimension(descriptor) + if isinstance(descriptor, (Dimension, CompositeDimension)): + return Dimension(self) / descriptor + raise DescriptorBinaryOperationError( + f"cannot divide {self} with {descriptor}. " + ) + + def __pow__(self, power: float) -> "Dimension": + """ + Defines exponentiation of MeasurementUnit objects. + + Examples: + >>> class LengthUnit(MeasurementUnit): + ... FEET = "ft" + >>> LengthUnit.FEET**3 + <Dimension: ft^3> + """ + # always keep non dimensional units to the first power + power = 1 if self.is_non_dimensional() else power + + return Dimension(self, power) + + def __hash__(self) -> int: + return hash(self.value) + + def __repr__(self) -> str: + return f"<{self.__class__.__name__}: {str(self)}>" + + def __str__(self) -> str: + return self.value

    @@ -9915,50 +9995,50 @@

    >>> class TemperatureUnit(MeasurementUnit):
     ...     FAHRENHEIT = "F"
     >>> class TimeUnit(MeasurementUnit):
    -...     HOUR = "hr"
    ->>> TemperatureUnit.FAHRENHEIT * TimeUnit.HOUR
    -<CompositeDimension: F * hr>
    -
    - -
    - Source code in src/property_utils/units/descriptors.py -
    421
    -422
    -423
    -424
    -425
    -426
    -427
    -428
    -429
    -430
    -431
    -432
    -433
    -434
    -435
    -436
    -437
    +...     HOUR = "hr"
    +>>> TemperatureUnit.FAHRENHEIT * TimeUnit.HOUR
    +<CompositeDimension: F * hr>
    +
    + +
    + Source code in src/property_utils/units/descriptors.py +
    def __mul__(self, descriptor: UnitDescriptor) -> "CompositeDimension":
    -    """
    -    Defines multiplication between MeasurementUnit objects and other unit descriptors.
    -
    -    Examples:
    -        >>> class TemperatureUnit(MeasurementUnit):
    -        ...     FAHRENHEIT = "F"
    -        >>> class TimeUnit(MeasurementUnit):
    -        ...     HOUR = "hr"
    -        >>> TemperatureUnit.FAHRENHEIT * TimeUnit.HOUR
    -        <CompositeDimension: F * hr>
    -    """
    -    if isinstance(descriptor, MeasurementUnit):
    -        return Dimension(self) * Dimension(descriptor)
    -    if isinstance(descriptor, (Dimension, CompositeDimension)):
    -        return Dimension(self) * descriptor
    -    raise DescriptorBinaryOperationError(
    -        f"cannot multiply {self} with {descriptor}. "
    -    )
    +439
    +440
    +441
    +442
    +443
    +444
    +445
    +446
    +447
    +448
    +449
    +450
    +451
    +452
    +453
    +454
    +455
    def __mul__(self, descriptor: UnitDescriptor) -> "CompositeDimension":
    +    """
    +    Defines multiplication between MeasurementUnit objects and other unit descriptors.
    +
    +    Examples:
    +        >>> class TemperatureUnit(MeasurementUnit):
    +        ...     FAHRENHEIT = "F"
    +        >>> class TimeUnit(MeasurementUnit):
    +        ...     HOUR = "hr"
    +        >>> TemperatureUnit.FAHRENHEIT * TimeUnit.HOUR
    +        <CompositeDimension: F * hr>
    +    """
    +    if isinstance(descriptor, MeasurementUnit):
    +        return Dimension(self) * Dimension(descriptor)
    +    if isinstance(descriptor, (Dimension, CompositeDimension)):
    +        return Dimension(self) * descriptor
    +    raise DescriptorBinaryOperationError(
    +        f"cannot multiply {self} with {descriptor}. "
    +    )
     
    @@ -9988,27 +10068,33 @@

    Source code in src/property_utils/units/descriptors.py -
    def __pow__(self, power: float) -> "Dimension":
    -    """
    -    Defines exponentiation of MeasurementUnit objects.
    -
    -    Examples:
    -        >>> class LengthUnit(MeasurementUnit):
    -        ...     FEET = "ft"
    -        >>> LengthUnit.FEET**3
    -        <Dimension: ft^3>
    -    """
    -    return Dimension(self, power)
    +              
    def __pow__(self, power: float) -> "Dimension":
    +    """
    +    Defines exponentiation of MeasurementUnit objects.
    +
    +    Examples:
    +        >>> class LengthUnit(MeasurementUnit):
    +        ...     FEET = "ft"
    +        >>> LengthUnit.FEET**3
    +        <Dimension: ft^3>
    +    """
    +    # always keep non dimensional units to the first power
    +    power = 1 if self.is_non_dimensional() else power
    +
    +    return Dimension(self, power)
     
    @@ -10040,43 +10126,43 @@

    Source code in src/property_utils/units/descriptors.py -
    441
    -442
    -443
    -444
    -445
    -446
    -447
    -448
    -449
    -450
    -451
    -452
    -453
    -454
    -455
    -456
    -457
    +              
    def __truediv__(self, descriptor: UnitDescriptor) -> "CompositeDimension":
    -    """
    -    Defines division between MeasurementUnit objects and other unit descriptors.
    -
    -    Examples:
    -        >>> class TemperatureUnit(MeasurementUnit):
    -        ...     FAHRENHEIT = "F"
    -        >>> class TimeUnit(MeasurementUnit):
    -        ...     HOUR = "hr"
    -        >>> TemperatureUnit.FAHRENHEIT / TimeUnit.HOUR
    -        <CompositeDimension: F / hr>
    -    """
    -    if isinstance(descriptor, MeasurementUnit):
    -        return Dimension(self) / Dimension(descriptor)
    -    if isinstance(descriptor, (Dimension, CompositeDimension)):
    -        return Dimension(self) / descriptor
    -    raise DescriptorBinaryOperationError(
    -        f"cannot divide {self} with {descriptor}. "
    -    )
    +459
    +460
    +461
    +462
    +463
    +464
    +465
    +466
    +467
    +468
    +469
    +470
    +471
    +472
    +473
    +474
    +475
    def __truediv__(self, descriptor: UnitDescriptor) -> "CompositeDimension":
    +    """
    +    Defines division between MeasurementUnit objects and other unit descriptors.
    +
    +    Examples:
    +        >>> class TemperatureUnit(MeasurementUnit):
    +        ...     FAHRENHEIT = "F"
    +        >>> class TimeUnit(MeasurementUnit):
    +        ...     HOUR = "hr"
    +        >>> TemperatureUnit.FAHRENHEIT / TimeUnit.HOUR
    +        <CompositeDimension: F / hr>
    +    """
    +    if isinstance(descriptor, MeasurementUnit):
    +        return Dimension(self) / Dimension(descriptor)
    +    if isinstance(descriptor, (Dimension, CompositeDimension)):
    +        return Dimension(self) / descriptor
    +    raise DescriptorBinaryOperationError(
    +        f"cannot divide {self} with {descriptor}. "
    +    )
     
    @@ -10118,23 +10204,7 @@

    Source code in src/property_utils/units/descriptors.py -
    323
    -324
    -325
    -326
    -327
    -328
    -329
    -330
    -331
    -332
    -333
    -334
    -335
    -336
    -337
    -338
    -339
    +              
    339
     340
     341
     342
    @@ -10145,34 +10215,50 @@ 

    347 348 349 -350

    @staticmethod
    -def from_descriptor(descriptor: UnitDescriptor) -> "MeasurementUnit":
    -    """
    -    Create a MeasurementUnit from given descriptor.
    -    If descriptor is already a MeasurementUnit, it returns the same object.
    -
    -    This function does not serve as a constructor for MeasurementUnit, rather it
    -    is intended to be used to convert an unknown unit descriptor to a
    -    MeasurementUnit.
    -
    -    Raises `UnitDescriptorTypeError` if given descriptor cannot be translated
    -    to a MeasurementUnit instance.
    -
    -    Examples:
    -        >>> class TemperatureUnit(MeasurementUnit):
    -        ...     CELCIUS = "C"
    -
    -        >>> celcius = MeasurementUnit.from_descriptor(TemperatureUnit.CELCIUS**2)
    -        >>> celcius
    -        <TemperatureUnit: C>
    -    """
    -    if isinstance(descriptor, Dimension):
    -        return descriptor.unit
    -    if isinstance(descriptor, MeasurementUnit):
    -        return descriptor
    -    raise UnitDescriptorTypeError(
    -        f"cannot create MeasurementUnit from descriptor: {descriptor}"
    -    )
    +350
    +351
    +352
    +353
    +354
    +355
    +356
    +357
    +358
    +359
    +360
    +361
    +362
    +363
    +364
    +365
    +366
    @staticmethod
    +def from_descriptor(descriptor: UnitDescriptor) -> "MeasurementUnit":
    +    """
    +    Create a MeasurementUnit from given descriptor.
    +    If descriptor is already a MeasurementUnit, it returns the same object.
    +
    +    This function does not serve as a constructor for MeasurementUnit, rather it
    +    is intended to be used to convert an unknown unit descriptor to a
    +    MeasurementUnit.
    +
    +    Raises `UnitDescriptorTypeError` if given descriptor cannot be translated
    +    to a MeasurementUnit instance.
    +
    +    Examples:
    +        >>> class TemperatureUnit(MeasurementUnit):
    +        ...     CELCIUS = "C"
    +
    +        >>> celcius = MeasurementUnit.from_descriptor(TemperatureUnit.CELCIUS**2)
    +        >>> celcius
    +        <TemperatureUnit: C>
    +    """
    +    if isinstance(descriptor, Dimension):
    +        return descriptor.unit
    +    if isinstance(descriptor, MeasurementUnit):
    +        return descriptor
    +    raise UnitDescriptorTypeError(
    +        f"cannot create MeasurementUnit from descriptor: {descriptor}"
    +    )
     
    @@ -10202,27 +10288,92 @@

    Source code in src/property_utils/units/descriptors.py -
    def inverse(self) -> "CompositeDimension":
    -    """
    -    Create a composite with inverse units.
    -
    -    Examples:
    -        >>> class TemperatureUnit(MeasurementUnit):
    -        ...     KELVIN = "K"
    -        >>> TemperatureUnit.KELVIN.inverse()
    -        <CompositeDimension:  / K>
    -    """
    -    return CompositeDimension([], [Dimension(self)])
    +              
    def inverse(self) -> "CompositeDimension":
    +    """
    +    Create a composite with inverse units.
    +
    +    Examples:
    +        >>> class TemperatureUnit(MeasurementUnit):
    +        ...     KELVIN = "K"
    +        >>> TemperatureUnit.KELVIN.inverse()
    +        <CompositeDimension:  / K>
    +    """
    +    return CompositeDimension([], [Dimension(self)])
    +
    + +
    + + + +
    + + +

    + is_non_dimensional() + + + classmethod + + +

    + + +
    + +

    Implement this function for defined measurement units that are non dimensional.

    + + +

    Examples:

    +
    >>> class NonDimensionalUnit(MeasurementUnit):
    +...     NON_DIMENSIONAL = ""
    +...     @classmethod
    +...     def is_non_dimensional(cls) -> bool: return True
    +
    +
    >>> NonDimensionalUnit.is_non_dimensional()
    +True
    +
    + +
    + Source code in src/property_utils/units/descriptors.py +
    @classmethod
    +def is_non_dimensional(cls) -> bool:
    +    """
    +    Implement this function for defined measurement units that are non dimensional.
    +
    +    Examples:
    +        >>> class NonDimensionalUnit(MeasurementUnit):
    +        ...     NON_DIMENSIONAL = ""
    +        ...     @classmethod
    +        ...     def is_non_dimensional(cls) -> bool: return True
    +
    +        >>> NonDimensionalUnit.is_non_dimensional()
    +        True
    +    """
    +    return False
     
    @@ -10260,43 +10411,43 @@

    Source code in src/property_utils/units/descriptors.py -
    352
    -353
    -354
    -355
    -356
    -357
    -358
    -359
    -360
    -361
    -362
    -363
    -364
    -365
    -366
    -367
    -368
    +              
    def isinstance(self, generic: GenericUnitDescriptor) -> bool:
    -    """
    -    Returns True if the MeasurementUnit is an instance of the generic, False
    -    otherwise.
    -
    -    Examples:
    -        >>> class TemperatureUnit(MeasurementUnit):
    -        ...     CELCIUS = "C"
    -
    -        >>> class LengthUnit(MeasurementUnit):
    -        ...     METER = "m"
    -
    -        >>> TemperatureUnit.CELCIUS.isinstance(TemperatureUnit)
    -        True
    -
    -        >>> TemperatureUnit.CELCIUS.isinstance(LengthUnit)
    -        False
    -    """
    -    return type(self) == generic  # pylint: disable=unidiomatic-typecheck
    +370
    +371
    +372
    +373
    +374
    +375
    +376
    +377
    +378
    +379
    +380
    +381
    +382
    +383
    +384
    +385
    +386
    def isinstance(self, generic: GenericUnitDescriptor) -> bool:
    +    """
    +    Returns True if the MeasurementUnit is an instance of the generic, False
    +    otherwise.
    +
    +    Examples:
    +        >>> class TemperatureUnit(MeasurementUnit):
    +        ...     CELCIUS = "C"
    +
    +        >>> class LengthUnit(MeasurementUnit):
    +        ...     METER = "m"
    +
    +        >>> TemperatureUnit.CELCIUS.isinstance(TemperatureUnit)
    +        True
    +
    +        >>> TemperatureUnit.CELCIUS.isinstance(LengthUnit)
    +        False
    +    """
    +    return type(self) == generic  # pylint: disable=unidiomatic-typecheck
     
    @@ -10336,51 +10487,51 @@

    Source code in src/property_utils/units/descriptors.py -
    372
    -373
    -374
    -375
    -376
    -377
    -378
    -379
    -380
    -381
    -382
    -383
    -384
    -385
    -386
    -387
    -388
    +              
    def isinstance_equivalent(self, generic: GenericUnitDescriptor) -> bool:
    -    """
    -    Returns True if the UnitDescriptor is an instance-equivalent of the generic,
    -    False otherwise.
    -
    -    A unit descriptor is an instance-equivalent of a generic if the generic of the
    -    unit descriptor is equivalent to the generic.
    -
    -    Equivalence between generics is checked with the `is_equivalent` method.
    -
    -    Examples:
    -        >>> class LengthUnit(MeasurementUnit): ...
    -        >>> class AreaUnit(AliasMeasurementUnit):
    -        ...     HECTARE = "ha"
    -        ...     @classmethod
    -        ...     def aliased_generic_descriptor(cls): return LengthUnit**2
    -
    -        >>> AreaUnit.HECTARE.isinstance_equivalent(AreaUnit)
    -        True
    -        >>> AreaUnit.HECTARE.isinstance_equivalent(LengthUnit**2)
    -        True
    -    """
    -    return self.to_generic().is_equivalent(generic)
    +394
    +395
    +396
    +397
    +398
    +399
    +400
    +401
    +402
    +403
    +404
    +405
    +406
    +407
    +408
    +409
    +410
    def isinstance_equivalent(self, generic: GenericUnitDescriptor) -> bool:
    +    """
    +    Returns True if the UnitDescriptor is an instance-equivalent of the generic,
    +    False otherwise.
    +
    +    A unit descriptor is an instance-equivalent of a generic if the generic of the
    +    unit descriptor is equivalent to the generic.
    +
    +    Equivalence between generics is checked with the `is_equivalent` method.
    +
    +    Examples:
    +        >>> class LengthUnit(MeasurementUnit): ...
    +        >>> class AreaUnit(AliasMeasurementUnit):
    +        ...     HECTARE = "ha"
    +        ...     @classmethod
    +        ...     def aliased_generic_descriptor(cls): return LengthUnit**2
    +
    +        >>> AreaUnit.HECTARE.isinstance_equivalent(AreaUnit)
    +        True
    +        >>> AreaUnit.HECTARE.isinstance_equivalent(LengthUnit**2)
    +        True
    +    """
    +    return self.to_generic().is_equivalent(generic)
     
    @@ -10447,29 +10598,29 @@

    Source code in src/property_utils/units/descriptors.py -
    def to_generic(self) -> GenericUnitDescriptor:
    -    """
    -    Create a generic descriptor from this MeasurementUnit.
    -
    -    Examples:
    -        >>> class AmountUnit(MeasurementUnit):
    -        ...     MOL = "mol"
    -
    -        >>> AmountUnit.MOL.to_generic()
    -        <MeasurementUnit: AmountUnit>
    -    """
    -    return self.__class__
    +              
    def to_generic(self) -> GenericUnitDescriptor:
    +    """
    +    Create a generic descriptor from this MeasurementUnit.
    +
    +    Examples:
    +        >>> class AmountUnit(MeasurementUnit):
    +        ...     MOL = "mol"
    +
    +        >>> AmountUnit.MOL.to_generic()
    +        <MeasurementUnit: AmountUnit>
    +    """
    +    return self.__class__
     
    diff --git a/objects.inv b/objects.inv index 3a7fa8a..9efc4af 100644 Binary files a/objects.inv and b/objects.inv differ diff --git a/property/index.html b/property/index.html index afff7d2..03fbc03 100644 --- a/property/index.html +++ b/property/index.html @@ -1625,7 +1625,8 @@

    Source code in src/property_utils/units/converters.py -
    123
    +                
    122
    +123
     124
     125
     126
    @@ -1656,40 +1657,39 @@ 

    151 152 153 -154 -155

    @register_converter(AbsoluteTemperatureUnit)
    -class AbsoluteTemperatureUnitConverter(AbsoluteUnitConverter):
    -    """
    -    Convert absolute temperature with this converter.
    -
    -    Examples:
    -        >>> AbsoluteTemperatureUnitConverter.convert(10, AbsoluteTemperatureUnit.KELVIN, AbsoluteTemperatureUnit.RANKINE)
    -        18.0
    -    """
    -
    -    reference_unit = AbsoluteTemperatureUnit.KELVIN
    -    conversion_map = {
    -        AbsoluteTemperatureUnit.KELVIN: 1,
    -        AbsoluteTemperatureUnit.RANKINE: 1.8,
    -    }
    -
    -    @override
    -    @classmethod
    -    def convert(
    -        cls,
    -        value: float,
    -        from_descriptor: UnitDescriptor,
    -        to_descriptor: UnitDescriptor,
    -    ) -> float:
    -        if not isinstance(value, (float, int)):
    -            raise UnitConversionError(f"invalid 'value': {value}; expected numeric. ")
    -        if from_descriptor.isinstance(
    -            RelativeTemperatureUnit
    -        ) or to_descriptor.isinstance(RelativeTemperatureUnit):
    -            return RelativeTemperatureUnitConverter.convert(
    -                value, from_descriptor, to_descriptor
    -            )
    -        return value * cls.get_factor(from_descriptor, to_descriptor)
    +154
    @register_converter(AbsoluteTemperatureUnit)
    +class AbsoluteTemperatureUnitConverter(AbsoluteUnitConverter):
    +    """
    +    Convert absolute temperature with this converter.
    +
    +    Examples:
    +        >>> AbsoluteTemperatureUnitConverter.convert(10, AbsoluteTemperatureUnit.KELVIN, AbsoluteTemperatureUnit.RANKINE)
    +        18.0
    +    """
    +
    +    reference_unit = AbsoluteTemperatureUnit.KELVIN
    +    conversion_map = {
    +        AbsoluteTemperatureUnit.KELVIN: 1,
    +        AbsoluteTemperatureUnit.RANKINE: 1.8,
    +    }
    +
    +    @override
    +    @classmethod
    +    def convert(
    +        cls,
    +        value: float,
    +        from_descriptor: UnitDescriptor,
    +        to_descriptor: UnitDescriptor,
    +    ) -> float:
    +        if not isinstance(value, (float, int)):
    +            raise UnitConversionError(f"invalid 'value': {value}; expected numeric. ")
    +        if from_descriptor.isinstance(
    +            RelativeTemperatureUnit
    +        ) or to_descriptor.isinstance(RelativeTemperatureUnit):
    +            return RelativeTemperatureUnitConverter.convert(
    +                value, from_descriptor, to_descriptor
    +            )
    +        return value * cls.get_factor(from_descriptor, to_descriptor)
     
    @@ -1739,17 +1739,7 @@

    Source code in src/property_utils/units/converters.py -
    292
    -293
    -294
    -295
    -296
    -297
    -298
    -299
    -300
    -301
    -302
    +                
    302
     303
     304
     305
    @@ -1761,29 +1751,39 @@ 

    311 312 313 -314

    @register_converter(EnergyUnit)
    -class AliasEnergyUnitConverter(AbsoluteUnitConverter):
    -    """
    -    Convert energy units with this converter.
    -
    -    Examples:
    -        >>> AliasEnergyUnitConverter.convert(2500, EnergyUnit.JOULE, EnergyUnit.KILO_JOULE)
    -        2.5
    -    """
    -
    -    reference_unit = EnergyUnit.JOULE
    -    conversion_map = {
    -        EnergyUnit.JOULE: 1,
    -        EnergyUnit.KILO_JOULE: UnitPrefix.KILO.inverse(),
    -        EnergyUnit.MEGA_JOULE: UnitPrefix.MEGA.inverse(),
    -        EnergyUnit.GIGA_JOULE: UnitPrefix.GIGA.inverse(),
    -        EnergyUnit.CALORIE: 1 / 4.184,
    -        EnergyUnit.KILO_CALORIE: (1 / 4.184) * UnitPrefix.KILO.inverse(),
    -        EnergyUnit.BTU: 1 / 1055.0,
    -        EnergyUnit.ELECTRONVOLT: 6.242e18,
    -        EnergyUnit.WATTHOUR: 1 / 3600,
    -        EnergyUnit.KILO_WATTHOUR: (1 / 3600) * UnitPrefix.KILO.inverse(),
    -    }
    +314
    +315
    +316
    +317
    +318
    +319
    +320
    +321
    +322
    +323
    +324
    @register_converter(EnergyUnit)
    +class AliasEnergyUnitConverter(AbsoluteUnitConverter):
    +    """
    +    Convert energy units with this converter.
    +
    +    Examples:
    +        >>> AliasEnergyUnitConverter.convert(2500, EnergyUnit.JOULE, EnergyUnit.KILO_JOULE)
    +        2.5
    +    """
    +
    +    reference_unit = EnergyUnit.JOULE
    +    conversion_map = {
    +        EnergyUnit.JOULE: 1,
    +        EnergyUnit.KILO_JOULE: UnitPrefix.KILO.inverse(),
    +        EnergyUnit.MEGA_JOULE: UnitPrefix.MEGA.inverse(),
    +        EnergyUnit.GIGA_JOULE: UnitPrefix.GIGA.inverse(),
    +        EnergyUnit.CALORIE: 1 / 4.184,
    +        EnergyUnit.KILO_CALORIE: (1 / 4.184) * UnitPrefix.KILO.inverse(),
    +        EnergyUnit.BTU: 1 / 1055.0,
    +        EnergyUnit.ELECTRONVOLT: 6.242e18,
    +        EnergyUnit.WATTHOUR: 1 / 3600,
    +        EnergyUnit.KILO_WATTHOUR: (1 / 3600) * UnitPrefix.KILO.inverse(),
    +    }
     
    @@ -1833,29 +1833,29 @@

    Source code in src/property_utils/units/converters.py -
    @register_converter(ForceUnit)
    -class AliasForceUnitConverter(AbsoluteUnitConverter):
    -    """
    -    Convert force units with this converter.
    -
    -    Examples:
    -        >>> AliasForceUnitConverter.convert(2, ForceUnit.NEWTON, ForceUnit.DYNE)
    -        200000.0
    -    """
    -
    -    reference_unit = ForceUnit.NEWTON
    -    conversion_map = {ForceUnit.NEWTON: 1, ForceUnit.DYNE: 100_000}
    +                
    @register_converter(ForceUnit)
    +class AliasForceUnitConverter(AbsoluteUnitConverter):
    +    """
    +    Convert force units with this converter.
    +
    +    Examples:
    +        >>> AliasForceUnitConverter.convert(2, ForceUnit.NEWTON, ForceUnit.DYNE)
    +        200000.0
    +    """
    +
    +    reference_unit = ForceUnit.NEWTON
    +    conversion_map = {ForceUnit.NEWTON: 1, ForceUnit.DYNE: 100_000}
     
    @@ -1905,39 +1905,39 @@

    Source code in src/property_utils/units/converters.py -
    317
    -318
    -319
    -320
    -321
    -322
    -323
    -324
    -325
    -326
    -327
    +                
    @register_converter(PowerUnit)
    -class AliasPowerUnitConverter(AbsoluteUnitConverter):
    -    """
    -    Convert power units with this converter.
    -
    -    Examples:
    -        >>> AliasPowerUnitConverter.convert(5, PowerUnit.KILO_WATT, PowerUnit.WATT)
    -        5000.0
    -    """
    -
    -    reference_unit = PowerUnit.WATT
    -    conversion_map = {
    -        PowerUnit.WATT: 1,
    -        PowerUnit.KILO_WATT: UnitPrefix.KILO.inverse(),
    -        PowerUnit.MEGA_WATT: UnitPrefix.MEGA.inverse(),
    -        PowerUnit.GIGA_WATT: UnitPrefix.GIGA.inverse(),
    -    }
    +333
    +334
    +335
    +336
    +337
    +338
    +339
    +340
    +341
    +342
    +343
    @register_converter(PowerUnit)
    +class AliasPowerUnitConverter(AbsoluteUnitConverter):
    +    """
    +    Convert power units with this converter.
    +
    +    Examples:
    +        >>> AliasPowerUnitConverter.convert(5, PowerUnit.KILO_WATT, PowerUnit.WATT)
    +        5000.0
    +    """
    +
    +    reference_unit = PowerUnit.WATT
    +    conversion_map = {
    +        PowerUnit.WATT: 1,
    +        PowerUnit.KILO_WATT: UnitPrefix.KILO.inverse(),
    +        PowerUnit.MEGA_WATT: UnitPrefix.MEGA.inverse(),
    +        PowerUnit.GIGA_WATT: UnitPrefix.GIGA.inverse(),
    +    }
     
    @@ -1987,17 +1987,7 @@

    Source code in src/property_utils/units/converters.py -
    271
    -272
    -273
    -274
    -275
    -276
    -277
    -278
    -279
    -280
    -281
    +                
    281
     282
     283
     284
    @@ -2005,25 +1995,35 @@ 

    286 287 288 -289

    @register_converter(PressureUnit)
    -class AliasPressureUnitConverter(AbsoluteUnitConverter):
    -    """
    -    Convert pressure units with this converter.
    -
    -    Examples:
    -        >>> AliasPressureUnitConverter.convert(2, PressureUnit.BAR, PressureUnit.KILO_PASCAL)
    -        200.0
    -    """
    -
    -    reference_unit = PressureUnit.BAR
    -    conversion_map = {
    -        PressureUnit.MILLI_BAR: UnitPrefix.MILLI.inverse(),
    -        PressureUnit.BAR: 1,
    -        PressureUnit.PSI: 14.5038,
    -        PressureUnit.PASCAL: 100_000,
    -        PressureUnit.KILO_PASCAL: 100,
    -        PressureUnit.MEGA_PASCAL: 0.1,
    -    }
    +289
    +290
    +291
    +292
    +293
    +294
    +295
    +296
    +297
    +298
    +299
    @register_converter(PressureUnit)
    +class AliasPressureUnitConverter(AbsoluteUnitConverter):
    +    """
    +    Convert pressure units with this converter.
    +
    +    Examples:
    +        >>> AliasPressureUnitConverter.convert(2, PressureUnit.BAR, PressureUnit.KILO_PASCAL)
    +        200.0
    +    """
    +
    +    reference_unit = PressureUnit.BAR
    +    conversion_map = {
    +        PressureUnit.MILLI_BAR: UnitPrefix.MILLI.inverse(),
    +        PressureUnit.BAR: 1,
    +        PressureUnit.PSI: 14.5038,
    +        PressureUnit.PASCAL: 100_000,
    +        PressureUnit.KILO_PASCAL: 100,
    +        PressureUnit.MEGA_PASCAL: 0.1,
    +    }
     
    @@ -2073,29 +2073,29 @@

    Source code in src/property_utils/units/converters.py -
    @register_converter(AmountUnit)
    -class AmountUnitConverter(AbsoluteUnitConverter):
    -    """
    -    Convert amount units with this converter.
    -
    -    Examples:
    -        >>> AmountUnitConverter.convert(2000, AmountUnit.MOL, AmountUnit.KILO_MOL)
    -        2.0
    -    """
    -
    -    reference_unit = AmountUnit.MOL
    -    conversion_map = {AmountUnit.MOL: 1, AmountUnit.KILO_MOL: UnitPrefix.KILO.inverse()}
    +                
    @register_converter(AmountUnit)
    +class AmountUnitConverter(AbsoluteUnitConverter):
    +    """
    +    Convert amount units with this converter.
    +
    +    Examples:
    +        >>> AmountUnitConverter.convert(2000, AmountUnit.MOL, AmountUnit.KILO_MOL)
    +        2.0
    +    """
    +
    +    reference_unit = AmountUnit.MOL
    +    conversion_map = {AmountUnit.MOL: 1, AmountUnit.KILO_MOL: UnitPrefix.KILO.inverse()}
     
    @@ -2145,23 +2145,23 @@

    Source code in src/property_utils/units/converters.py -
    @register_converter(LengthUnit**2)
    -class AreaUnitConverter(ExponentiatedUnitConverter):
    -    """
    -    Convert area units with this converter.
    -
    -    Examples:
    -        >>> AreaUnitConverter.convert(1, LengthUnit.METER**2, LengthUnit.CENTI_METER**2)
    -        10000.0
    -    """
    +                
    @register_converter(LengthUnit**2)
    +class AreaUnitConverter(ExponentiatedUnitConverter):
    +    """
    +    Convert area units with this converter.
    +
    +    Examples:
    +        >>> AreaUnitConverter.convert(1, LengthUnit.METER**2, LengthUnit.CENTI_METER**2)
    +        10000.0
    +    """
     
    @@ -2211,37 +2211,37 @@

    Source code in src/property_utils/units/converters.py -
    239
    -240
    -241
    -242
    -243
    -244
    -245
    -246
    -247
    -248
    -249
    +                
    @register_converter(ElectricCurrentUnit)
    -class ElectricCurrentUnitConverter(AbsoluteUnitConverter):
    -    """
    -    Convert electric current units with this converter.
    -
    -    Examples:
    -        >>> ElectricCurrentUnitConverter.convert(1000, ElectricCurrentUnit.MILLI_AMPERE, ElectricCurrentUnit.AMPERE)
    -        1.0
    -    """
    -
    -    reference_unit = ElectricCurrentUnit.AMPERE
    -    conversion_map = {
    -        ElectricCurrentUnit.MILLI_AMPERE: UnitPrefix.MILLI.inverse(),
    -        ElectricCurrentUnit.AMPERE: 1,
    -        ElectricCurrentUnit.KILO_AMPERE: UnitPrefix.KILO.inverse(),
    -    }
    +254
    +255
    +256
    +257
    +258
    +259
    +260
    +261
    +262
    +263
    +264
    @register_converter(ElectricCurrentUnit)
    +class ElectricCurrentUnitConverter(AbsoluteUnitConverter):
    +    """
    +    Convert electric current units with this converter.
    +
    +    Examples:
    +        >>> ElectricCurrentUnitConverter.convert(1000, ElectricCurrentUnit.MILLI_AMPERE, ElectricCurrentUnit.AMPERE)
    +        1.0
    +    """
    +
    +    reference_unit = ElectricCurrentUnit.AMPERE
    +    conversion_map = {
    +        ElectricCurrentUnit.MILLI_AMPERE: UnitPrefix.MILLI.inverse(),
    +        ElectricCurrentUnit.AMPERE: 1,
    +        ElectricCurrentUnit.KILO_AMPERE: UnitPrefix.KILO.inverse(),
    +    }
     
    @@ -2293,27 +2293,27 @@

    Source code in src/property_utils/units/converters.py -
    @register_converter(EnergyUnit.aliased_generic_descriptor())
    -class EnergyUnitConverter(CompositeUnitConverter):
    -    """
    -    Convert energy units (mass * length^2 / time^2) with this converter.
    -
    -    Examples:
    -        >>> from_unit = MassUnit.KILO_GRAM * (LengthUnit.METER**2) / (TimeUnit.MINUTE**2)
    -        >>> to_unit = MassUnit.METRIC_TONNE * (LengthUnit.CENTI_METER**2) / (TimeUnit.MINUTE**2)
    -        >>> EnergyUnitConverter.convert(25, from_unit, to_unit)
    -        250.0
    -    """
    +                
    @register_converter(EnergyUnit.aliased_generic_descriptor())
    +class EnergyUnitConverter(CompositeUnitConverter):
    +    """
    +    Convert energy units (mass * length^2 / time^2) with this converter.
    +
    +    Examples:
    +        >>> from_unit = MassUnit.KILO_GRAM * (LengthUnit.METER**2) / (TimeUnit.MINUTE**2)
    +        >>> to_unit = MassUnit.METRIC_TONNE * (LengthUnit.CENTI_METER**2) / (TimeUnit.MINUTE**2)
    +        >>> EnergyUnitConverter.convert(25, from_unit, to_unit)
    +        250.0
    +    """
     
    @@ -2365,27 +2365,27 @@

    Source code in src/property_utils/units/converters.py -
    @register_converter(ForceUnit.aliased_generic_descriptor())
    -class ForceUnitConverter(CompositeUnitConverter):
    -    """
    -    Convert force units (mass * length / time^2) with this converter.
    -
    -    Examples:
    -        >>> from_unit = MassUnit.KILO_GRAM * LengthUnit.CENTI_METER / (TimeUnit.SECOND**2)
    -        >>> to_unit = MassUnit.GRAM * LengthUnit.METER / (TimeUnit.SECOND**2)
    -        >>> ForceUnitConverter.convert(100, from_unit, to_unit)
    -        1000.0
    -    """
    +                
    @register_converter(ForceUnit.aliased_generic_descriptor())
    +class ForceUnitConverter(CompositeUnitConverter):
    +    """
    +    Convert force units (mass * length / time^2) with this converter.
    +
    +    Examples:
    +        >>> from_unit = MassUnit.KILO_GRAM * LengthUnit.CENTI_METER / (TimeUnit.SECOND**2)
    +        >>> to_unit = MassUnit.GRAM * LengthUnit.METER / (TimeUnit.SECOND**2)
    +        >>> ForceUnitConverter.convert(100, from_unit, to_unit)
    +        1000.0
    +    """
     
    @@ -2435,17 +2435,7 @@

    Source code in src/property_utils/units/converters.py -
    158
    -159
    -160
    -161
    -162
    -163
    -164
    -165
    -166
    -167
    -168
    +                
    168
     169
     170
     171
    @@ -2456,28 +2446,38 @@ 

    176 177 178 -179

    @register_converter(LengthUnit)
    -class LengthUnitConverter(AbsoluteUnitConverter):
    -    """
    -    Convert length units with this converter.
    -
    -    Examples:
    -        >>> LengthUnitConverter.convert(2000, LengthUnit.MILLI_METER, LengthUnit.METER)
    -        2.0
    -    """
    -
    -    reference_unit = LengthUnit.METER
    -    conversion_map = {
    -        LengthUnit.MILLI_METER: UnitPrefix.MILLI.inverse(),
    -        LengthUnit.CENTI_METER: UnitPrefix.CENTI.inverse(),
    -        LengthUnit.METER: 1,
    -        LengthUnit.KILO_METER: UnitPrefix.KILO.inverse(),
    -        LengthUnit.INCH: 39.37,
    -        LengthUnit.FOOT: 3.281,
    -        LengthUnit.YARD: 1.094,
    -        LengthUnit.MILE: 1 / 1609,
    -        LengthUnit.NAUTICAL_MILE: 1 / 1852,
    -    }
    +179
    +180
    +181
    +182
    +183
    +184
    +185
    +186
    +187
    +188
    +189
    @register_converter(LengthUnit)
    +class LengthUnitConverter(AbsoluteUnitConverter):
    +    """
    +    Convert length units with this converter.
    +
    +    Examples:
    +        >>> LengthUnitConverter.convert(2000, LengthUnit.MILLI_METER, LengthUnit.METER)
    +        2.0
    +    """
    +
    +    reference_unit = LengthUnit.METER
    +    conversion_map = {
    +        LengthUnit.MILLI_METER: UnitPrefix.MILLI.inverse(),
    +        LengthUnit.CENTI_METER: UnitPrefix.CENTI.inverse(),
    +        LengthUnit.METER: 1,
    +        LengthUnit.KILO_METER: UnitPrefix.KILO.inverse(),
    +        LengthUnit.INCH: 39.37,
    +        LengthUnit.FOOT: 3.281,
    +        LengthUnit.YARD: 1.094,
    +        LengthUnit.MILE: 1 / 1609,
    +        LengthUnit.NAUTICAL_MILE: 1 / 1852,
    +    }
     
    @@ -2527,41 +2527,41 @@

    Source code in src/property_utils/units/converters.py -
    182
    -183
    -184
    -185
    -186
    -187
    -188
    -189
    -190
    -191
    -192
    +                
    @register_converter(MassUnit)
    -class MassUnitConverter(AbsoluteUnitConverter):
    -    """
    -    Convert mass units with this converter.
    -
    -    Examples:
    -        >>> MassUnitConverter.convert(10, MassUnit.KILO_GRAM, MassUnit.GRAM)
    -        10000.0
    -    """
    -
    -    reference_unit = MassUnit.KILO_GRAM
    -    conversion_map = {
    -        MassUnit.MILLI_GRAM: UnitPrefix.KILO * UnitPrefix.MILLI.inverse(),
    -        MassUnit.GRAM: UnitPrefix.KILO,
    -        MassUnit.KILO_GRAM: 1,
    -        MassUnit.METRIC_TONNE: 1 / 1_000.0,
    -        MassUnit.POUND: 2.205,
    -    }
    +199
    +200
    +201
    +202
    +203
    +204
    +205
    +206
    +207
    +208
    +209
    @register_converter(MassUnit)
    +class MassUnitConverter(AbsoluteUnitConverter):
    +    """
    +    Convert mass units with this converter.
    +
    +    Examples:
    +        >>> MassUnitConverter.convert(10, MassUnit.KILO_GRAM, MassUnit.GRAM)
    +        10000.0
    +    """
    +
    +    reference_unit = MassUnit.KILO_GRAM
    +    conversion_map = {
    +        MassUnit.MILLI_GRAM: UnitPrefix.KILO * UnitPrefix.MILLI.inverse(),
    +        MassUnit.GRAM: UnitPrefix.KILO,
    +        MassUnit.KILO_GRAM: 1,
    +        MassUnit.METRIC_TONNE: 1 / 1_000.0,
    +        MassUnit.POUND: 2.205,
    +    }
     
    @@ -2613,27 +2613,27 @@

    Source code in src/property_utils/units/converters.py -
    @register_converter(PowerUnit.aliased_generic_descriptor())
    -class PowerUnitConverter(CompositeUnitConverter):
    -    """
    -    Convert power units (mass * length^2 / time^3) with this converter.
    -
    -    Examples:
    -        >>> from_unit = MassUnit.KILO_GRAM * (LengthUnit.METER**2) / (TimeUnit.MINUTE**3)
    -        >>> to_unit = MassUnit.METRIC_TONNE * (LengthUnit.CENTI_METER**2) / (TimeUnit.MINUTE**3)
    -        >>> PowerUnitConverter.convert(15, from_unit, to_unit)
    -        150.0
    -    """
    +                
    @register_converter(PowerUnit.aliased_generic_descriptor())
    +class PowerUnitConverter(CompositeUnitConverter):
    +    """
    +    Convert power units (mass * length^2 / time^3) with this converter.
    +
    +    Examples:
    +        >>> from_unit = MassUnit.KILO_GRAM * (LengthUnit.METER**2) / (TimeUnit.MINUTE**3)
    +        >>> to_unit = MassUnit.METRIC_TONNE * (LengthUnit.CENTI_METER**2) / (TimeUnit.MINUTE**3)
    +        >>> PowerUnitConverter.convert(15, from_unit, to_unit)
    +        150.0
    +    """
     
    @@ -2685,27 +2685,27 @@

    Source code in src/property_utils/units/converters.py -
    @register_converter(PressureUnit.aliased_generic_descriptor())
    -class PressureUnitConverter(CompositeUnitConverter):
    -    """
    -    Convert pressure units (mass / length / time^2) with this converter.
    -
    -    Examples:
    -        >>> from_unit = MassUnit.GRAM / LengthUnit.CENTI_METER / (TimeUnit.HOUR**2)
    -        >>> to_unit = MassUnit.KILO_GRAM / LengthUnit.METER / (TimeUnit.HOUR**2)
    -        >>> PressureUnitConverter.convert(50, from_unit, to_unit)
    -        5.0
    -    """
    +                
    @register_converter(PressureUnit.aliased_generic_descriptor())
    +class PressureUnitConverter(CompositeUnitConverter):
    +    """
    +    Convert pressure units (mass / length / time^2) with this converter.
    +
    +    Examples:
    +        >>> from_unit = MassUnit.GRAM / LengthUnit.CENTI_METER / (TimeUnit.HOUR**2)
    +        >>> to_unit = MassUnit.KILO_GRAM / LengthUnit.METER / (TimeUnit.HOUR**2)
    +        >>> PressureUnitConverter.convert(50, from_unit, to_unit)
    +        5.0
    +    """
     
    @@ -5720,8 +5720,7 @@

    Source code in src/property_utils/units/converters.py -
     96
    - 97
    +                
     97
      98
      99
     100
    @@ -5743,32 +5742,29 @@ 

    116 117 118 -119 -120

    @register_converter(RelativeTemperatureUnit)
    -class RelativeTemperatureUnitConverter(
    -    RelativeUnitConverter
    -):  # pylint: disable=too-few-public-methods
    -    """
    -    Convert temperature units with this converter.
    -
    -    Examples:
    -        >>> RelativeTemperatureUnitConverter.convert(100, RelativeTemperatureUnit.CELCIUS, RelativeTemperatureUnit.FAHRENHEIT)
    -        212.0
    -    """
    -
    -    reference_unit = RelativeTemperatureUnit.CELCIUS
    -    conversion_map = {
    -        RelativeTemperatureUnit.CELCIUS: lambda t: t,
    -        AbsoluteTemperatureUnit.KELVIN: lambda t: t - 273.15,
    -        RelativeTemperatureUnit.FAHRENHEIT: lambda t: (t - 32) / 1.8,
    -        AbsoluteTemperatureUnit.RANKINE: lambda t: (t / 1.8) - 273.15,
    -    }
    -    reference_conversion_map = {
    -        RelativeTemperatureUnit.CELCIUS: lambda t: t,
    -        AbsoluteTemperatureUnit.KELVIN: lambda t: t + 273.15,
    -        RelativeTemperatureUnit.FAHRENHEIT: lambda t: (t * 1.8) + 32,
    -        AbsoluteTemperatureUnit.RANKINE: lambda t: (t + 273.15) * 1.8,
    -    }
    +119
    @register_converter(RelativeTemperatureUnit)
    +class RelativeTemperatureUnitConverter(RelativeUnitConverter):  # pylint: disable=too-few-public-methods
    +    """
    +    Convert temperature units with this converter.
    +
    +    Examples:
    +        >>> RelativeTemperatureUnitConverter.convert(100, RelativeTemperatureUnit.CELCIUS, RelativeTemperatureUnit.FAHRENHEIT)
    +        212.0
    +    """
    +
    +    reference_unit = RelativeTemperatureUnit.CELCIUS
    +    conversion_map = {
    +        RelativeTemperatureUnit.CELCIUS: lambda t: t,
    +        AbsoluteTemperatureUnit.KELVIN: lambda t: t - 273.15,
    +        RelativeTemperatureUnit.FAHRENHEIT: lambda t: (t - 32) / 1.8,
    +        AbsoluteTemperatureUnit.RANKINE: lambda t: (t / 1.8) - 273.15,
    +    }
    +    reference_conversion_map = {
    +        RelativeTemperatureUnit.CELCIUS: lambda t: t,
    +        AbsoluteTemperatureUnit.KELVIN: lambda t: t + 273.15,
    +        RelativeTemperatureUnit.FAHRENHEIT: lambda t: (t * 1.8) + 32,
    +        AbsoluteTemperatureUnit.RANKINE: lambda t: (t + 273.15) * 1.8,
    +    }
     
    @@ -5818,17 +5814,7 @@

    Source code in src/property_utils/units/converters.py -
    216
    -217
    -218
    -219
    -220
    -221
    -222
    -223
    -224
    -225
    -226
    +                
    226
     227
     228
     229
    @@ -5838,27 +5824,37 @@ 

    233 234 235 -236

    @register_converter(TimeUnit)
    -class TimeUnitConverter(AbsoluteUnitConverter):
    -    """
    -    Convert time units with this converter.
    -
    -    Examples:
    -        >>> TimeUnitConverter.convert(1, TimeUnit.HOUR, TimeUnit.SECOND)
    -        3600.0
    -    """
    -
    -    reference_unit = TimeUnit.SECOND
    -    conversion_map = {
    -        TimeUnit.MILLI_SECOND: UnitPrefix.MILLI.inverse(),
    -        TimeUnit.SECOND: 1,
    -        TimeUnit.MINUTE: 1 / 60.0,
    -        TimeUnit.HOUR: 1 / 60.0 / 60.0,
    -        TimeUnit.DAY: 1 / 60.0 / 60.0 / 24.0,
    -        TimeUnit.WEEK: 1 / 60.0 / 60.0 / 24.0 / 7,
    -        TimeUnit.MONTH: 1 / 60.0 / 60.0 / 24.0 / (365 / 12),
    -        TimeUnit.YEAR: 1 / 60.0 / 60.0 / 24.0 / 365,
    -    }
    +236
    +237
    +238
    +239
    +240
    +241
    +242
    +243
    +244
    +245
    +246
    @register_converter(TimeUnit)
    +class TimeUnitConverter(AbsoluteUnitConverter):
    +    """
    +    Convert time units with this converter.
    +
    +    Examples:
    +        >>> TimeUnitConverter.convert(1, TimeUnit.HOUR, TimeUnit.SECOND)
    +        3600.0
    +    """
    +
    +    reference_unit = TimeUnit.SECOND
    +    conversion_map = {
    +        TimeUnit.MILLI_SECOND: UnitPrefix.MILLI.inverse(),
    +        TimeUnit.SECOND: 1,
    +        TimeUnit.MINUTE: 1 / 60.0,
    +        TimeUnit.HOUR: 1 / 60.0 / 60.0,
    +        TimeUnit.DAY: 1 / 60.0 / 60.0 / 24.0,
    +        TimeUnit.WEEK: 1 / 60.0 / 60.0 / 24.0 / 7,
    +        TimeUnit.MONTH: 1 / 60.0 / 60.0 / 24.0 / (365 / 12),
    +        TimeUnit.YEAR: 1 / 60.0 / 60.0 / 24.0 / 365,
    +    }
     
    @@ -5911,8 +5907,7 @@

    Source code in src/property_utils/units/converters.py -
    58
    -59
    +                
    59
     60
     61
     62
    @@ -5946,42 +5941,43 @@ 

    90 91 92 -93

    class UnitPrefix(float, Enum):
    -    """
    -    Enumeration of unit prefixes.
    -    Handy when converting to and fro prefixed units.
    -
    -    Examples:
    -        >>> centimeters = 225
    -        >>> meters = centimeters * UnitPrefix.CENTI
    -        >>> meters
    -        2.25
    -    """
    -
    -    PICO = 1e-12
    -    NANO = 1e-9
    -    MICRO = 1e-6
    -    MILLI = 1e-3
    -    CENTI = 1e-2
    -    DECI = 1e-1
    -    DECA = 1e1
    -    HECTO = 1e2
    -    KILO = 1e3
    -    MEGA = 1e6
    -    GIGA = 1e9
    -    TERA = 1e12
    -
    -    def inverse(self) -> float:
    -        """
    -        Return the inverse of the unit prefix. Use when prefixing a unit.
    -
    -        Examples:
    -            >>> meters = 50.26
    -            >>> centimeters = meters * UnitPrefix.CENTI.inverse()
    -            >>> centimeters
    -            5026.0
    -        """
    -        return 1 / self.value
    +93
    +94
    class UnitPrefix(float, Enum):
    +    """
    +    Enumeration of unit prefixes.
    +    Handy when converting to and fro prefixed units.
    +
    +    Examples:
    +        >>> centimeters = 225
    +        >>> meters = centimeters * UnitPrefix.CENTI
    +        >>> meters
    +        2.25
    +    """
    +
    +    PICO = 1e-12
    +    NANO = 1e-9
    +    MICRO = 1e-6
    +    MILLI = 1e-3
    +    CENTI = 1e-2
    +    DECI = 1e-1
    +    DECA = 1e1
    +    HECTO = 1e2
    +    KILO = 1e3
    +    MEGA = 1e6
    +    GIGA = 1e9
    +    TERA = 1e12
    +
    +    def inverse(self) -> float:
    +        """
    +        Return the inverse of the unit prefix. Use when prefixing a unit.
    +
    +        Examples:
    +            >>> meters = 50.26
    +            >>> centimeters = meters * UnitPrefix.CENTI.inverse()
    +            >>> centimeters
    +            5026.0
    +        """
    +        return 1 / self.value
     
    @@ -6020,8 +6016,7 @@

    Source code in src/property_utils/units/converters.py -
    83
    -84
    +              
    84
     85
     86
     87
    @@ -6030,17 +6025,18 @@ 

    90 91 92 -93

    def inverse(self) -> float:
    -    """
    -    Return the inverse of the unit prefix. Use when prefixing a unit.
    -
    -    Examples:
    -        >>> meters = 50.26
    -        >>> centimeters = meters * UnitPrefix.CENTI.inverse()
    -        >>> centimeters
    -        5026.0
    -    """
    -    return 1 / self.value
    +93
    +94
    def inverse(self) -> float:
    +    """
    +    Return the inverse of the unit prefix. Use when prefixing a unit.
    +
    +    Examples:
    +        >>> meters = 50.26
    +        >>> centimeters = meters * UnitPrefix.CENTI.inverse()
    +        >>> centimeters
    +        5026.0
    +    """
    +    return 1 / self.value
     
    @@ -6081,23 +6077,23 @@

    Source code in src/property_utils/units/converters.py -
    @register_converter(LengthUnit**3)
    -class VolumeUnitConverter(ExponentiatedUnitConverter):
    -    """
    -    Convert volume units with this converter.
    -
    -    Examples:
    -        >>> VolumeUnitConverter.convert(1, LengthUnit.METER**3, LengthUnit.CENTI_METER**3)
    -        1000000.0
    -    """
    +                
    @register_converter(LengthUnit**3)
    +class VolumeUnitConverter(ExponentiatedUnitConverter):
    +    """
    +    Convert volume units with this converter.
    +
    +    Examples:
    +        >>> VolumeUnitConverter.convert(1, LengthUnit.METER**3, LengthUnit.CENTI_METER**3)
    +        1000000.0
    +    """
     
    diff --git a/search/search_index.json b/search/search_index.json index 724796c..faa9b00 100644 --- a/search/search_index.json +++ b/search/search_index.json @@ -1 +1 @@ -{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"What is property-utils?","text":"

    property-utils is a python library that aims at making programming with physical properties easier. It was created to be used by scientists and engineers with little programming experience.

    What is provided by property-utils?

    "},{"location":"#unit-arithmetics","title":"Unit arithmetics","text":"

    You can divide and multiply units to create new units. For example you can create velocity units by dividing length units with time units.

    "},{"location":"#unit-conversions","title":"Unit conversions","text":"

    You can easily convert a property from one unit to another by calling a method.

    "},{"location":"#property-arithmetics","title":"Property arithmetics","text":"

    You can add, subtract, divide and multiply properties to create new properties. For example, you can create a density property by dividing a mass property with a volume property.

    If you're not sure what all the above mean, head to Usage to see examples of how they're used.

    "},{"location":"converter_types/","title":"converter types","text":"

    This module defines: Functions to fetch and register unit converters Unit converter protocol Base abstract classes for different types of unit converters

    Converters implement a 2-step process to convert 'from_unit' to 'to_unit'. 1. Convert the 'from_unit' to a reference unit. 2. Convert the reference unit to the 'to_unit'.

    "},{"location":"converter_types/#property_utils.units.converter_types.AbsoluteUnitConverter","title":"AbsoluteUnitConverter","text":"

    Base converter class for measurement units that are absolute, i.e. not relative.

    e.g. Pressure units are absolute because the following applies: unit_i = unit_j * constant, where unit_i and unit_j can be any pressure units.

    Temperature units are not absolute because the above equation does not apply when converting from a relative temperature to an absolute temperature (e.g. from Celcius to Kelvin, or Fahrenheit to Rankine).

    Use the register_converter decorator when subclassing and define the reference_unit and conversion_map attributes. It does not matter what unit you shall choose to be the reference; although you have to define the conversion map accordingly. The conversion map is a dictionary that holds the conversion factors from the reference unit to other units. e.g. in the below example: 1 in = 2.54 cm

    Examples:

    >>> class LengthUnit(MeasurementUnit):\n...     CENTI_METER = \"cm\"\n...     INCH = \"in\"\n
    >>> @register_converter(LengthUnit)\n... class LengthUnitConverter(AbsoluteUnitConverter):\n...     reference_unit = LengthUnit.INCH\n...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n
    Source code in src/property_utils/units/converter_types.py
    class AbsoluteUnitConverter(metaclass=ABCMeta):\n    \"\"\"\n    Base converter class for measurement units that are absolute, i.e. not relative.\n\n    e.g.\n    Pressure units are absolute because the following applies:\n    unit_i = unit_j * constant,\n    where unit_i and unit_j can be any pressure units.\n\n    Temperature units are not absolute because the above equation does not apply when\n    converting from a relative temperature to an absolute temperature (e.g. from Celcius\n    to Kelvin, or Fahrenheit to Rankine).\n\n    Use the `register_converter` decorator when subclassing and define the\n    `reference_unit` and `conversion_map` attributes. It does not matter what unit you\n    shall choose to be the reference; although you have to define the conversion map\n    accordingly. The conversion map is a dictionary that holds the conversion factors\n    from the reference unit to other units. e.g. in the below example: 1 in = 2.54 cm\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit):\n        ...     CENTI_METER = \"cm\"\n        ...     INCH = \"in\"\n\n        >>> @register_converter(LengthUnit)\n        ... class LengthUnitConverter(AbsoluteUnitConverter):\n        ...     reference_unit = LengthUnit.INCH\n        ...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n    \"\"\"\n\n    generic_unit_descriptor: MeasurementUnitType\n    reference_unit: MeasurementUnit\n    conversion_map: Dict[MeasurementUnit, float]\n\n    @classmethod\n    def convert(\n        cls,\n        value: float,\n        from_descriptor: UnitDescriptor,\n        to_descriptor: UnitDescriptor,\n    ) -> float:\n        \"\"\"\n        Convert a value from an absolute unit to another absolute unit.\n        Raises `UnitConversionError` if `from_descriptor` or `to_descriptor` are not\n        an instance of the generic that is registered with the converter or if `value`\n        is not a numeric.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit):\n            ...     CENTI_METER = \"cm\"\n            ...     INCH = \"in\"\n\n            >>> @register_converter(LengthUnit)\n            ... class LengthUnitConverter(AbsoluteUnitConverter):\n            ...     reference_unit = LengthUnit.INCH\n            ...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n\n            >>> LengthUnitConverter.convert(2, LengthUnit.INCH, LengthUnit.CENTI_METER)\n            5.08\n        \"\"\"\n        if not isinstance(value, (float, int)):\n            raise UnitConversionError(f\"invalid 'value': {value}; expected numeric. \")\n        return value * cls.get_factor(from_descriptor, to_descriptor)\n\n    @classmethod\n    def get_factor(\n        cls, from_descriptor: UnitDescriptor, to_descriptor: UnitDescriptor\n    ) -> float:\n        \"\"\"\n        Get the multiplication factor for the conversion from `from_descriptor` to\n        `to_descriptor`.\n        Raises `UnitConversionError` if `from_descriptor` or `to_descriptor` are not\n        an instance of the generic that is registered with the converter.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit):\n            ...     CENTI_METER = \"cm\"\n            ...     INCH = \"in\"\n\n            >>> @register_converter(LengthUnit)\n            ... class LengthUnitConverter(AbsoluteUnitConverter):\n            ...     reference_unit = LengthUnit.INCH\n            ...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n\n            >>> LengthUnitConverter.get_factor(LengthUnit.INCH, LengthUnit.CENTI_METER)\n            2.54\n        \"\"\"\n        if not from_descriptor.isinstance_equivalent(cls.generic_unit_descriptor):\n            raise UnitConversionError(\n                f\"invalid 'from_descriptor; expected an instance-equivalent of {cls.generic_unit_descriptor}. \"\n            )\n        if not to_descriptor.isinstance_equivalent(cls.generic_unit_descriptor):\n            raise UnitConversionError(\n                f\"invalid 'to_descriptor'; expected an instance-equivalent of {cls.generic_unit_descriptor}. \"\n            )\n        from_unit = MeasurementUnit.from_descriptor(from_descriptor)\n\n        if isinstance(from_unit, AliasMeasurementUnit) and not isinstance(\n            to_descriptor, AliasMeasurementUnit\n        ):\n            return cls._get_aliased_factor(from_unit, to_descriptor)\n\n        to_unit = MeasurementUnit.from_descriptor(to_descriptor)\n        try:\n            return cls._to_reference(from_unit) * cls.conversion_map[to_unit]\n        except KeyError:\n            raise UnitConversionError(\n                f\"cannot convert to {to_unit}; unit is not registered in {cls.__name__}'s conversion map. \",\n            ) from None\n\n    @classmethod\n    def _to_reference(cls, from_unit: MeasurementUnit) -> float:\n        try:\n            return 1 / cls.conversion_map[from_unit]\n        except KeyError:\n            raise UnitConversionError(\n                f\"cannot convert from {from_unit}; unit is not registered in {cls.__name__}'s conversion map. \",\n            ) from None\n\n    @classmethod\n    def _get_aliased_factor(\n        cls, from_unit: AliasMeasurementUnit, to_descriptor: UnitDescriptor\n    ) -> float:\n        \"\"\"\n        Returns the conversion factor from an alias unit to its aliased.\n\n        The conversion happens in four steps:\n\n        1. Convert from the alias unit to the SI unit.\n        2. Convert from the SI unit to the aliased SI units (this step is not\n        implemented in code, because the conversion factor is 1)\n        3. Convert from the SI units to the target units.\n\n        e.g. if you want to convert from bar to kN/m^2:\n        1. bar -> Pa\n        2. Pa -> N/m^2 (conversion factor 1)\n        3. N/m^2 -> kN/m^2\n        \"\"\"\n        step_1_factor = cls.get_factor(from_unit, from_unit.si())\n\n        converter = get_converter(to_descriptor.to_generic())\n\n        step_3_factor = converter.convert(\n            1, to_descriptor.to_generic().to_si(), to_descriptor\n        )\n\n        return step_1_factor * step_3_factor\n
    "},{"location":"converter_types/#property_utils.units.converter_types.AbsoluteUnitConverter.convert","title":"convert(value, from_descriptor, to_descriptor) classmethod","text":"

    Convert a value from an absolute unit to another absolute unit. Raises UnitConversionError if from_descriptor or to_descriptor are not an instance of the generic that is registered with the converter or if value is not a numeric.

    Examples:

    >>> class LengthUnit(MeasurementUnit):\n...     CENTI_METER = \"cm\"\n...     INCH = \"in\"\n
    >>> @register_converter(LengthUnit)\n... class LengthUnitConverter(AbsoluteUnitConverter):\n...     reference_unit = LengthUnit.INCH\n...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n
    >>> LengthUnitConverter.convert(2, LengthUnit.INCH, LengthUnit.CENTI_METER)\n5.08\n
    Source code in src/property_utils/units/converter_types.py
    @classmethod\ndef convert(\n    cls,\n    value: float,\n    from_descriptor: UnitDescriptor,\n    to_descriptor: UnitDescriptor,\n) -> float:\n    \"\"\"\n    Convert a value from an absolute unit to another absolute unit.\n    Raises `UnitConversionError` if `from_descriptor` or `to_descriptor` are not\n    an instance of the generic that is registered with the converter or if `value`\n    is not a numeric.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit):\n        ...     CENTI_METER = \"cm\"\n        ...     INCH = \"in\"\n\n        >>> @register_converter(LengthUnit)\n        ... class LengthUnitConverter(AbsoluteUnitConverter):\n        ...     reference_unit = LengthUnit.INCH\n        ...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n\n        >>> LengthUnitConverter.convert(2, LengthUnit.INCH, LengthUnit.CENTI_METER)\n        5.08\n    \"\"\"\n    if not isinstance(value, (float, int)):\n        raise UnitConversionError(f\"invalid 'value': {value}; expected numeric. \")\n    return value * cls.get_factor(from_descriptor, to_descriptor)\n
    "},{"location":"converter_types/#property_utils.units.converter_types.AbsoluteUnitConverter.get_factor","title":"get_factor(from_descriptor, to_descriptor) classmethod","text":"

    Get the multiplication factor for the conversion from from_descriptor to to_descriptor. Raises UnitConversionError if from_descriptor or to_descriptor are not an instance of the generic that is registered with the converter.

    Examples:

    >>> class LengthUnit(MeasurementUnit):\n...     CENTI_METER = \"cm\"\n...     INCH = \"in\"\n
    >>> @register_converter(LengthUnit)\n... class LengthUnitConverter(AbsoluteUnitConverter):\n...     reference_unit = LengthUnit.INCH\n...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n
    >>> LengthUnitConverter.get_factor(LengthUnit.INCH, LengthUnit.CENTI_METER)\n2.54\n
    Source code in src/property_utils/units/converter_types.py
    @classmethod\ndef get_factor(\n    cls, from_descriptor: UnitDescriptor, to_descriptor: UnitDescriptor\n) -> float:\n    \"\"\"\n    Get the multiplication factor for the conversion from `from_descriptor` to\n    `to_descriptor`.\n    Raises `UnitConversionError` if `from_descriptor` or `to_descriptor` are not\n    an instance of the generic that is registered with the converter.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit):\n        ...     CENTI_METER = \"cm\"\n        ...     INCH = \"in\"\n\n        >>> @register_converter(LengthUnit)\n        ... class LengthUnitConverter(AbsoluteUnitConverter):\n        ...     reference_unit = LengthUnit.INCH\n        ...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n\n        >>> LengthUnitConverter.get_factor(LengthUnit.INCH, LengthUnit.CENTI_METER)\n        2.54\n    \"\"\"\n    if not from_descriptor.isinstance_equivalent(cls.generic_unit_descriptor):\n        raise UnitConversionError(\n            f\"invalid 'from_descriptor; expected an instance-equivalent of {cls.generic_unit_descriptor}. \"\n        )\n    if not to_descriptor.isinstance_equivalent(cls.generic_unit_descriptor):\n        raise UnitConversionError(\n            f\"invalid 'to_descriptor'; expected an instance-equivalent of {cls.generic_unit_descriptor}. \"\n        )\n    from_unit = MeasurementUnit.from_descriptor(from_descriptor)\n\n    if isinstance(from_unit, AliasMeasurementUnit) and not isinstance(\n        to_descriptor, AliasMeasurementUnit\n    ):\n        return cls._get_aliased_factor(from_unit, to_descriptor)\n\n    to_unit = MeasurementUnit.from_descriptor(to_descriptor)\n    try:\n        return cls._to_reference(from_unit) * cls.conversion_map[to_unit]\n    except KeyError:\n        raise UnitConversionError(\n            f\"cannot convert to {to_unit}; unit is not registered in {cls.__name__}'s conversion map. \",\n        ) from None\n
    "},{"location":"converter_types/#property_utils.units.converter_types.CompositeUnitConverter","title":"CompositeUnitConverter","text":"

    Base converter for composite units.

    Use the register_converter decorator when subclassing. This converter requires the converters for the individual measurement units to be defined.

    Examples:

    >>> class LengthUnit(MeasurementUnit):\n...     CENTI_METER = \"cm\"\n...     INCH = \"in\"\n
    >>> class TimeUnit(MeasurementUnit):\n...     SECOND = \"s\"\n...     MINUTE = \"min\"\n
    >>> @register_converter(LengthUnit)\n... class LengthUnitConverter(AbsoluteUnitConverter):\n...     reference_unit = LengthUnit.INCH\n...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n
    >>> @register_converter(TimeUnit)\n... class TimeUnitConverter(AbsoluteUnitConverter):\n...     reference_unit = TimeUnit.MINUTE\n...     conversion_map = {TimeUnit.MINUTE: 1, TimeUnit.SECOND: 60}\n
    >>> @register_converter(LengthUnit / TimeUnit)\n... class VelocityUnitConverter(CompositeUnitConverter): ...\n
    Source code in src/property_utils/units/converter_types.py
    class CompositeUnitConverter(metaclass=ABCMeta):\n    \"\"\"\n    Base converter for composite units.\n\n    Use the `register_converter` decorator when subclassing. This converter requires\n    the converters for the individual measurement units to be defined.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit):\n        ...     CENTI_METER = \"cm\"\n        ...     INCH = \"in\"\n\n        >>> class TimeUnit(MeasurementUnit):\n        ...     SECOND = \"s\"\n        ...     MINUTE = \"min\"\n\n        >>> @register_converter(LengthUnit)\n        ... class LengthUnitConverter(AbsoluteUnitConverter):\n        ...     reference_unit = LengthUnit.INCH\n        ...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n\n        >>> @register_converter(TimeUnit)\n        ... class TimeUnitConverter(AbsoluteUnitConverter):\n        ...     reference_unit = TimeUnit.MINUTE\n        ...     conversion_map = {TimeUnit.MINUTE: 1, TimeUnit.SECOND: 60}\n\n        >>> @register_converter(LengthUnit / TimeUnit)\n        ... class VelocityUnitConverter(CompositeUnitConverter): ...\n    \"\"\"\n\n    generic_unit_descriptor: GenericUnitDescriptor\n\n    @classmethod\n    def convert(\n        cls,\n        value: float,\n        from_descriptor: UnitDescriptor,\n        to_descriptor: UnitDescriptor,\n    ) -> float:\n        \"\"\"\n        Convert a value from a composite unit to another composite unit.\n\n        Raises `UnitConversionError` if `from_descriptor` or `to_descriptor` are not\n        an instance of the generic that is registered with the converter or if `value`\n        is not a numeric.\n\n        Raises `ConverterDependenciesError` if a converter for an invdividual unit has\n        not been defined/registered.\n\n        Raises `UnsupportedConverterError` if an individual unit is a relative unit.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit):\n            ...     CENTI_METER = \"cm\"\n            ...     INCH = \"in\"\n\n            >>> class TimeUnit(MeasurementUnit):\n            ...     SECOND = \"s\"\n            ...     MINUTE = \"min\"\n\n            >>> @register_converter(LengthUnit)\n            ... class LengthUnitConverter(AbsoluteUnitConverter):\n            ...     reference_unit = LengthUnit.INCH\n            ...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n\n            >>> @register_converter(TimeUnit)\n            ... class TimeUnitConverter(AbsoluteUnitConverter):\n            ...     reference_unit = TimeUnit.MINUTE\n            ...     conversion_map = {TimeUnit.MINUTE: 1, TimeUnit.SECOND: 60}\n\n            >>> @register_converter(LengthUnit / TimeUnit)\n            ... class VelocityUnitConverter(CompositeUnitConverter): ...\n\n            >>> VelocityUnitConverter.convert(100, LengthUnit.INCH/TimeUnit.SECOND, LengthUnit.CENTI_METER/TimeUnit.SECOND)\n            254.0\n        \"\"\"\n        if not isinstance(value, (float, int)):\n            raise UnitConversionError(f\"invalid 'value': {value}; expected numeric. \")\n        return value * cls.get_factor(from_descriptor, to_descriptor)\n\n    @classmethod\n    def get_factor(\n        cls, from_descriptor: UnitDescriptor, to_descriptor: UnitDescriptor\n    ) -> float:\n        \"\"\"\n        Get the multiplication factor for the conversion from `from_descriptor` to\n        `to_descriptor`.\n\n        Raises `UnitConversionError` if `from_descriptor` or `to_descriptor` are not\n        an instance of the generic that is registered with the converter.\n\n        Raises `ConverterDependenciesError` if a converter for an invdividual unit has\n        not been defined/registered.\n\n        Raises `UnsupportedConverterError` if an individual unit is a relative unit.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit):\n            ...     CENTI_METER = \"cm\"\n            ...     INCH = \"in\"\n\n            >>> class TimeUnit(MeasurementUnit):\n            ...     SECOND = \"s\"\n            ...     MINUTE = \"min\"\n\n            >>> @register_converter(LengthUnit)\n            ... class LengthUnitConverter(AbsoluteUnitConverter):\n            ...     reference_unit = LengthUnit.INCH\n            ...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n\n            >>> @register_converter(TimeUnit)\n            ... class TimeUnitConverter(AbsoluteUnitConverter):\n            ...     reference_unit = TimeUnit.MINUTE\n            ...     conversion_map = {TimeUnit.MINUTE: 1, TimeUnit.SECOND: 60}\n\n            >>> @register_converter(LengthUnit / TimeUnit)\n            ... class VelocityUnitConverter(CompositeUnitConverter): ...\n\n            >>> VelocityUnitConverter.get_factor(LengthUnit.INCH/TimeUnit.SECOND, LengthUnit.INCH/TimeUnit.MINUTE)\n            60.0\n        \"\"\"\n        if not from_descriptor.isinstance_equivalent(cls.generic_unit_descriptor):\n            raise UnitConversionError(\n                f\"invalid 'from_descriptor; expected an instance-equivalent of {cls.generic_unit_descriptor}. \"\n            )\n        if not to_descriptor.isinstance_equivalent(cls.generic_unit_descriptor):\n            raise UnitConversionError(\n                f\"invalid 'to_descriptor'; expected an instance-equivalent of {cls.generic_unit_descriptor}. \"\n            )\n\n        from_dimension = CompositeDimension.from_descriptor(from_descriptor)\n\n        if not to_descriptor.isinstance(from_descriptor.to_generic()):\n\n            if cls._is_alias(from_dimension, to_descriptor) or (\n                cls._is_aliased(from_dimension)\n            ):\n                return cls._get_aliased_factor(from_dimension, to_descriptor)\n\n        to_dimension = CompositeDimension.from_descriptor(to_descriptor)\n        return cls._get_numerator_factor(\n            from_dimension, to_dimension\n        ) / cls._get_denominator_factor(from_dimension, to_dimension)\n\n    @classmethod\n    def _get_numerator_factor(\n        cls, from_dimension: CompositeDimension, to_dimension: CompositeDimension\n    ) -> float:\n        numerator_factor = 1.0\n        for from_d in from_dimension.numerator:\n            to_d = to_dimension.get_numerator(from_d.to_generic())\n            if to_d is None:\n                raise UnitConversionError(\n                    f\"cannot convert from {from_dimension} to {to_dimension}\"\n                )\n            try:\n                converter = get_converter(type(from_d.unit))\n            except UndefinedConverterError:\n                raise ConverterDependenciesError(\n                    f\"converter {cls.__name__} depends on a converter for \"\n                    f\"{type(from_d.unit)}. Did you forget to register \"\n                    f\" a converter for {type(from_d.unit)}? \"\n                ) from None\n            if not issubclass(converter, AbsoluteUnitConverter):\n                # NOTE: provide a link to documentation for the error.\n                raise UnsupportedConverterError(\n                    f\"converter {cls.__name__} is not supported since \"\n                    f\"{type(from_d.unit)} is not an absolute unit;\"\n                    \" conversion between composite relative units is invalid. \"\n                )\n            factor = (converter.get_factor(from_d.unit, to_d.unit)) ** from_d.power\n            numerator_factor *= factor\n        return numerator_factor\n\n    @classmethod\n    def _get_denominator_factor(\n        cls, from_dimension: CompositeDimension, to_dimension: CompositeDimension\n    ) -> float:\n        denominator_factor = 1.0\n\n        for from_d in from_dimension.denominator:\n            to_d = to_dimension.get_denominator(from_d.to_generic())\n            if to_d is None:\n                raise UnitConversionError(\n                    f\"cannot convert from {from_dimension} to {to_dimension}\"\n                )\n            try:\n                converter = get_converter(type(from_d.unit))\n            except UndefinedConverterError:\n                raise ConverterDependenciesError(\n                    f\"converter {cls.__name__} depends on a converter for \"\n                    f\"{type(from_d.unit)}. Did you forget to register \"\n                    f\" a converter for {type(from_d.unit)}? \"\n                ) from None\n            if not issubclass(converter, AbsoluteUnitConverter):\n                # NOTE: provide a link to documentation for the error.\n                raise UnsupportedConverterError(\n                    f\"converter {cls.__name__} is not supported since \"\n                    f\"{type(from_d.unit)} is not an absolute unit;\"\n                    \" conversion between composite relative units is invalid. \"\n                )\n            factor = (converter.get_factor(from_d.unit, to_d.unit)) ** from_d.power\n            denominator_factor *= factor\n        return denominator_factor\n\n    @staticmethod\n    def _is_alias(\n        from_dimension: CompositeDimension, descriptor: UnitDescriptor\n    ) -> bool:\n        \"\"\"\n        Returns True if the descriptor is an alias of the from_dimension.\n\n        Assumes that from_dimension and descriptor are both an instance of the\n        converter's generic unit descriptor.\n        \"\"\"\n        if isinstance(descriptor, AliasMeasurementUnit):\n            return True\n\n        if isinstance(descriptor, Dimension):\n            if isinstance(descriptor.unit, AliasMeasurementUnit):\n                return True\n\n            return False\n\n        if isinstance(descriptor, CompositeDimension):\n            for n in descriptor.numerator:\n                if from_dimension.get_numerator(n.to_generic(), None) is None:\n                    return True\n\n            for d in descriptor.denominator:\n                if from_dimension.get_denominator(d.to_generic(), None) is None:\n                    return True\n\n        return False\n\n    @staticmethod\n    def _is_aliased(dimension: CompositeDimension) -> bool:\n        \"\"\"\n        Returns True if the dimension contains an alias, False otherwise.\n        \"\"\"\n        for n in dimension.numerator:\n            if isinstance(n.unit, AliasMeasurementUnit):\n                return True\n\n        for d in dimension.denominator:\n            if isinstance(d.unit, AliasMeasurementUnit):\n                return True\n\n        return False\n\n    @classmethod\n    def _get_aliased_factor(\n        cls, from_dimension: CompositeDimension, to_descriptor: UnitDescriptor\n    ) -> float:\n        \"\"\"\n        Returns the conversion factor from an alias unit to its aliased.\n\n        The conversion happens in three steps:\n\n        1. Convert from the alias unit to the SI unit.\n        2. Convert from the SI unit to the aliased SI units (this step is not\n        implemented in code, because the conversion factor is 1)\n        3. Convert from the SI units to the target units.\n\n        e.g. if you want to convert from cal/K/s to kW/K:\n        1. cal/K/s -> J/K/s\n        2. J/K/s -> W/K (conversion factor 1)\n        3. W/K -> kW/K\n        \"\"\"\n        step_1_factor = cls.get_factor(from_dimension, from_dimension.si())\n\n        converter = get_converter(to_descriptor.to_generic())\n\n        step_3_factor = converter.convert(\n            1, to_descriptor.to_generic().to_si(), to_descriptor\n        )\n\n        return step_1_factor * step_3_factor\n
    "},{"location":"converter_types/#property_utils.units.converter_types.CompositeUnitConverter.convert","title":"convert(value, from_descriptor, to_descriptor) classmethod","text":"

    Convert a value from a composite unit to another composite unit.

    Raises UnitConversionError if from_descriptor or to_descriptor are not an instance of the generic that is registered with the converter or if value is not a numeric.

    Raises ConverterDependenciesError if a converter for an invdividual unit has not been defined/registered.

    Raises UnsupportedConverterError if an individual unit is a relative unit.

    Examples:

    >>> class LengthUnit(MeasurementUnit):\n...     CENTI_METER = \"cm\"\n...     INCH = \"in\"\n
    >>> class TimeUnit(MeasurementUnit):\n...     SECOND = \"s\"\n...     MINUTE = \"min\"\n
    >>> @register_converter(LengthUnit)\n... class LengthUnitConverter(AbsoluteUnitConverter):\n...     reference_unit = LengthUnit.INCH\n...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n
    >>> @register_converter(TimeUnit)\n... class TimeUnitConverter(AbsoluteUnitConverter):\n...     reference_unit = TimeUnit.MINUTE\n...     conversion_map = {TimeUnit.MINUTE: 1, TimeUnit.SECOND: 60}\n
    >>> @register_converter(LengthUnit / TimeUnit)\n... class VelocityUnitConverter(CompositeUnitConverter): ...\n
    >>> VelocityUnitConverter.convert(100, LengthUnit.INCH/TimeUnit.SECOND, LengthUnit.CENTI_METER/TimeUnit.SECOND)\n254.0\n
    Source code in src/property_utils/units/converter_types.py
    @classmethod\ndef convert(\n    cls,\n    value: float,\n    from_descriptor: UnitDescriptor,\n    to_descriptor: UnitDescriptor,\n) -> float:\n    \"\"\"\n    Convert a value from a composite unit to another composite unit.\n\n    Raises `UnitConversionError` if `from_descriptor` or `to_descriptor` are not\n    an instance of the generic that is registered with the converter or if `value`\n    is not a numeric.\n\n    Raises `ConverterDependenciesError` if a converter for an invdividual unit has\n    not been defined/registered.\n\n    Raises `UnsupportedConverterError` if an individual unit is a relative unit.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit):\n        ...     CENTI_METER = \"cm\"\n        ...     INCH = \"in\"\n\n        >>> class TimeUnit(MeasurementUnit):\n        ...     SECOND = \"s\"\n        ...     MINUTE = \"min\"\n\n        >>> @register_converter(LengthUnit)\n        ... class LengthUnitConverter(AbsoluteUnitConverter):\n        ...     reference_unit = LengthUnit.INCH\n        ...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n\n        >>> @register_converter(TimeUnit)\n        ... class TimeUnitConverter(AbsoluteUnitConverter):\n        ...     reference_unit = TimeUnit.MINUTE\n        ...     conversion_map = {TimeUnit.MINUTE: 1, TimeUnit.SECOND: 60}\n\n        >>> @register_converter(LengthUnit / TimeUnit)\n        ... class VelocityUnitConverter(CompositeUnitConverter): ...\n\n        >>> VelocityUnitConverter.convert(100, LengthUnit.INCH/TimeUnit.SECOND, LengthUnit.CENTI_METER/TimeUnit.SECOND)\n        254.0\n    \"\"\"\n    if not isinstance(value, (float, int)):\n        raise UnitConversionError(f\"invalid 'value': {value}; expected numeric. \")\n    return value * cls.get_factor(from_descriptor, to_descriptor)\n
    "},{"location":"converter_types/#property_utils.units.converter_types.CompositeUnitConverter.get_factor","title":"get_factor(from_descriptor, to_descriptor) classmethod","text":"

    Get the multiplication factor for the conversion from from_descriptor to to_descriptor.

    Raises UnitConversionError if from_descriptor or to_descriptor are not an instance of the generic that is registered with the converter.

    Raises ConverterDependenciesError if a converter for an invdividual unit has not been defined/registered.

    Raises UnsupportedConverterError if an individual unit is a relative unit.

    Examples:

    >>> class LengthUnit(MeasurementUnit):\n...     CENTI_METER = \"cm\"\n...     INCH = \"in\"\n
    >>> class TimeUnit(MeasurementUnit):\n...     SECOND = \"s\"\n...     MINUTE = \"min\"\n
    >>> @register_converter(LengthUnit)\n... class LengthUnitConverter(AbsoluteUnitConverter):\n...     reference_unit = LengthUnit.INCH\n...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n
    >>> @register_converter(TimeUnit)\n... class TimeUnitConverter(AbsoluteUnitConverter):\n...     reference_unit = TimeUnit.MINUTE\n...     conversion_map = {TimeUnit.MINUTE: 1, TimeUnit.SECOND: 60}\n
    >>> @register_converter(LengthUnit / TimeUnit)\n... class VelocityUnitConverter(CompositeUnitConverter): ...\n
    >>> VelocityUnitConverter.get_factor(LengthUnit.INCH/TimeUnit.SECOND, LengthUnit.INCH/TimeUnit.MINUTE)\n60.0\n
    Source code in src/property_utils/units/converter_types.py
    @classmethod\ndef get_factor(\n    cls, from_descriptor: UnitDescriptor, to_descriptor: UnitDescriptor\n) -> float:\n    \"\"\"\n    Get the multiplication factor for the conversion from `from_descriptor` to\n    `to_descriptor`.\n\n    Raises `UnitConversionError` if `from_descriptor` or `to_descriptor` are not\n    an instance of the generic that is registered with the converter.\n\n    Raises `ConverterDependenciesError` if a converter for an invdividual unit has\n    not been defined/registered.\n\n    Raises `UnsupportedConverterError` if an individual unit is a relative unit.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit):\n        ...     CENTI_METER = \"cm\"\n        ...     INCH = \"in\"\n\n        >>> class TimeUnit(MeasurementUnit):\n        ...     SECOND = \"s\"\n        ...     MINUTE = \"min\"\n\n        >>> @register_converter(LengthUnit)\n        ... class LengthUnitConverter(AbsoluteUnitConverter):\n        ...     reference_unit = LengthUnit.INCH\n        ...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n\n        >>> @register_converter(TimeUnit)\n        ... class TimeUnitConverter(AbsoluteUnitConverter):\n        ...     reference_unit = TimeUnit.MINUTE\n        ...     conversion_map = {TimeUnit.MINUTE: 1, TimeUnit.SECOND: 60}\n\n        >>> @register_converter(LengthUnit / TimeUnit)\n        ... class VelocityUnitConverter(CompositeUnitConverter): ...\n\n        >>> VelocityUnitConverter.get_factor(LengthUnit.INCH/TimeUnit.SECOND, LengthUnit.INCH/TimeUnit.MINUTE)\n        60.0\n    \"\"\"\n    if not from_descriptor.isinstance_equivalent(cls.generic_unit_descriptor):\n        raise UnitConversionError(\n            f\"invalid 'from_descriptor; expected an instance-equivalent of {cls.generic_unit_descriptor}. \"\n        )\n    if not to_descriptor.isinstance_equivalent(cls.generic_unit_descriptor):\n        raise UnitConversionError(\n            f\"invalid 'to_descriptor'; expected an instance-equivalent of {cls.generic_unit_descriptor}. \"\n        )\n\n    from_dimension = CompositeDimension.from_descriptor(from_descriptor)\n\n    if not to_descriptor.isinstance(from_descriptor.to_generic()):\n\n        if cls._is_alias(from_dimension, to_descriptor) or (\n            cls._is_aliased(from_dimension)\n        ):\n            return cls._get_aliased_factor(from_dimension, to_descriptor)\n\n    to_dimension = CompositeDimension.from_descriptor(to_descriptor)\n    return cls._get_numerator_factor(\n        from_dimension, to_dimension\n    ) / cls._get_denominator_factor(from_dimension, to_dimension)\n
    "},{"location":"converter_types/#property_utils.units.converter_types.ExponentiatedUnitConverter","title":"ExponentiatedUnitConverter","text":"

    Base converter for exponentiated absolute measurement units.

    Use the register_converter decorator when subclassing. This converter requires the converter for the measurement unit that is exponentiated to be defined.

    Examples:

    >>> class LengthUnit(MeasurementUnit):\n...     CENTI_METER = \"cm\"\n...     INCH = \"in\"\n
    >>> @register_converter(LengthUnit)\n... class LengthUnitConverter(AbsoluteUnitConverter):\n...     reference_unit = LengthUnit.INCH\n...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n
    >>> @register_converter(LengthUnit**2)\n... class AreaUnitConverter(ExponentiatedUnitConverter): ...\n
    Source code in src/property_utils/units/converter_types.py
    class ExponentiatedUnitConverter(metaclass=ABCMeta):\n    \"\"\"\n    Base converter for exponentiated absolute measurement units.\n\n    Use the `register_converter` decorator when subclassing. This converter requires\n    the converter for the measurement unit that is exponentiated to be defined.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit):\n        ...     CENTI_METER = \"cm\"\n        ...     INCH = \"in\"\n\n        >>> @register_converter(LengthUnit)\n        ... class LengthUnitConverter(AbsoluteUnitConverter):\n        ...     reference_unit = LengthUnit.INCH\n        ...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n\n        >>> @register_converter(LengthUnit**2)\n        ... class AreaUnitConverter(ExponentiatedUnitConverter): ...\n    \"\"\"\n\n    generic_unit_descriptor: GenericDimension\n\n    @classmethod\n    def convert(\n        cls,\n        value: float,\n        from_descriptor: UnitDescriptor,\n        to_descriptor: UnitDescriptor,\n    ) -> float:\n        \"\"\"\n        Convert a value from an absolute exponentiated unit to another absolute\n        exponentiated unit. In order to use this converter a converter must exist for\n        the base unit.\n\n        Raises `UnitConversionError` if `from_descriptor` or `to_descriptor` are not\n        an instance of the generic that is registered with the converter or if `value`\n        is not a numeric.\n\n        Raises `ConverterDependenciesError` if a converter for the base unit has not\n        been defined/registered.\n\n        Raises `UnsupportedConverterError` if the base unit is a relative unit.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit):\n            ...     CENTI_METER = \"cm\"\n            ...     INCH = \"in\"\n\n            >>> @register_converter(LengthUnit)\n            ... class LengthUnitConverter(AbsoluteUnitConverter):\n            ...     reference_unit = LengthUnit.INCH\n            ...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n\n            >>> @register_converter(LengthUnit**2)\n            ... class AreaUnitConverter(ExponentiatedUnitConverter): ...\n\n            >>> AreaUnitConverter.convert(10, LengthUnit.INCH**2, LengthUnit.CENTI_METER**2)\n            64.516\n        \"\"\"\n        if not isinstance(value, (float, int)):\n            raise UnitConversionError(f\"invalid 'value': {value}; expected numeric. \")\n        return value * cls.get_factor(from_descriptor, to_descriptor)\n\n    @classmethod\n    def get_factor(\n        cls, from_descriptor: UnitDescriptor, to_descriptor: UnitDescriptor\n    ) -> float:\n        \"\"\"\n        Get the multiplication factor for the conversion from `from_descriptor` to\n        `to_descriptor`.\n\n        Raises `UnitConversionError` if `from_descriptor` or `to_descriptor` are not\n        an instance of the generic that is registered with the converter.\n\n        Raises `ConverterDependenciesError` if a converter for the base unit has not\n        been defined/registered.\n\n        Raises `UnsupportedConverterError` if the base unit is a relative unit.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit):\n            ...     CENTI_METER = \"cm\"\n            ...     INCH = \"in\"\n\n            >>> @register_converter(LengthUnit)\n            ... class LengthUnitConverter(AbsoluteUnitConverter):\n            ...     reference_unit = LengthUnit.INCH\n            ...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n\n            >>> @register_converter(LengthUnit**2)\n            ... class AreaUnitConverter(ExponentiatedUnitConverter): ...\n\n            >>> AreaUnitConverter.get_factor(LengthUnit.INCH**2, LengthUnit.CENTI_METER**2)\n            6.4516\n        \"\"\"\n        if not from_descriptor.isinstance_equivalent(cls.generic_unit_descriptor):\n            raise UnitConversionError(\n                f\"invalid 'from_descriptor; expected an instance-equivalent of {cls.generic_unit_descriptor}. \"\n            )\n        if not to_descriptor.isinstance_equivalent(cls.generic_unit_descriptor):\n            raise UnitConversionError(\n                f\"invalid 'to_descriptor'; expected an instance-equivalent of {cls.generic_unit_descriptor}. \"\n            )\n        from_dimension = Dimension.from_descriptor(from_descriptor)\n\n        if not to_descriptor.isinstance(from_descriptor.to_generic()):\n            if isinstance(to_descriptor, AliasMeasurementUnit):\n                return cls._get_aliased_factor(from_dimension, to_descriptor)\n\n        to_dimension = Dimension.from_descriptor(to_descriptor)\n\n        try:\n            converter = get_converter(cls.generic_unit_descriptor.unit_type)\n        except UndefinedConverterError:\n            raise ConverterDependenciesError(\n                f\"converter {cls.__name__} depends on a converter for \"\n                f\"{cls.generic_unit_descriptor.unit_type}. Did you forget to register \"\n                f\" a converter for {cls.generic_unit_descriptor.unit_type}? \"\n            ) from None\n        if not issubclass(converter, AbsoluteUnitConverter):\n            # NOTE: provide a link to documentation for the error.\n            raise UnsupportedConverterError(\n                f\"converter {cls.__name__} is not supported since \"\n                f\"{cls.generic_unit_descriptor.unit_type} is not an absolute unit;\"\n                \" conversion between exponentiated relative units is invalid. \"\n            )\n        factor = converter.get_factor(from_dimension.unit, to_dimension.unit)\n        return factor**to_dimension.power\n\n    @classmethod\n    def _get_aliased_factor(\n        cls, from_dimension: Dimension, to_descriptor: AliasMeasurementUnit\n    ) -> float:\n        \"\"\"\n        Returns the conversion factor from an alias unit to its aliased.\n\n        The conversion happens in three steps:\n\n        1. Convert from the alias unit to the SI unit.\n        2. Convert from the SI unit to the aliased SI units (this step is not\n        implemented in code, because the conversion factor is 1)\n        3. Convert from the aliased SI units to the target units.\n\n        e.g. if you want to convert from cm^3 to L:\n        1. cm^3 -> m^3\n        2. m^3 -> kL (conversion factor 1)\n        3. kL -> L\n        \"\"\"\n        step_1_factor = cls.get_factor(from_dimension, from_dimension.si())\n\n        converter = get_converter(to_descriptor.to_generic())\n\n        step_3_factor = converter.convert(\n            1, to_descriptor.to_generic().to_si(), to_descriptor\n        )\n\n        return step_1_factor * step_3_factor\n
    "},{"location":"converter_types/#property_utils.units.converter_types.ExponentiatedUnitConverter.convert","title":"convert(value, from_descriptor, to_descriptor) classmethod","text":"

    Convert a value from an absolute exponentiated unit to another absolute exponentiated unit. In order to use this converter a converter must exist for the base unit.

    Raises UnitConversionError if from_descriptor or to_descriptor are not an instance of the generic that is registered with the converter or if value is not a numeric.

    Raises ConverterDependenciesError if a converter for the base unit has not been defined/registered.

    Raises UnsupportedConverterError if the base unit is a relative unit.

    Examples:

    >>> class LengthUnit(MeasurementUnit):\n...     CENTI_METER = \"cm\"\n...     INCH = \"in\"\n
    >>> @register_converter(LengthUnit)\n... class LengthUnitConverter(AbsoluteUnitConverter):\n...     reference_unit = LengthUnit.INCH\n...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n
    >>> @register_converter(LengthUnit**2)\n... class AreaUnitConverter(ExponentiatedUnitConverter): ...\n
    >>> AreaUnitConverter.convert(10, LengthUnit.INCH**2, LengthUnit.CENTI_METER**2)\n64.516\n
    Source code in src/property_utils/units/converter_types.py
    @classmethod\ndef convert(\n    cls,\n    value: float,\n    from_descriptor: UnitDescriptor,\n    to_descriptor: UnitDescriptor,\n) -> float:\n    \"\"\"\n    Convert a value from an absolute exponentiated unit to another absolute\n    exponentiated unit. In order to use this converter a converter must exist for\n    the base unit.\n\n    Raises `UnitConversionError` if `from_descriptor` or `to_descriptor` are not\n    an instance of the generic that is registered with the converter or if `value`\n    is not a numeric.\n\n    Raises `ConverterDependenciesError` if a converter for the base unit has not\n    been defined/registered.\n\n    Raises `UnsupportedConverterError` if the base unit is a relative unit.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit):\n        ...     CENTI_METER = \"cm\"\n        ...     INCH = \"in\"\n\n        >>> @register_converter(LengthUnit)\n        ... class LengthUnitConverter(AbsoluteUnitConverter):\n        ...     reference_unit = LengthUnit.INCH\n        ...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n\n        >>> @register_converter(LengthUnit**2)\n        ... class AreaUnitConverter(ExponentiatedUnitConverter): ...\n\n        >>> AreaUnitConverter.convert(10, LengthUnit.INCH**2, LengthUnit.CENTI_METER**2)\n        64.516\n    \"\"\"\n    if not isinstance(value, (float, int)):\n        raise UnitConversionError(f\"invalid 'value': {value}; expected numeric. \")\n    return value * cls.get_factor(from_descriptor, to_descriptor)\n
    "},{"location":"converter_types/#property_utils.units.converter_types.ExponentiatedUnitConverter.get_factor","title":"get_factor(from_descriptor, to_descriptor) classmethod","text":"

    Get the multiplication factor for the conversion from from_descriptor to to_descriptor.

    Raises UnitConversionError if from_descriptor or to_descriptor are not an instance of the generic that is registered with the converter.

    Raises ConverterDependenciesError if a converter for the base unit has not been defined/registered.

    Raises UnsupportedConverterError if the base unit is a relative unit.

    Examples:

    >>> class LengthUnit(MeasurementUnit):\n...     CENTI_METER = \"cm\"\n...     INCH = \"in\"\n
    >>> @register_converter(LengthUnit)\n... class LengthUnitConverter(AbsoluteUnitConverter):\n...     reference_unit = LengthUnit.INCH\n...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n
    >>> @register_converter(LengthUnit**2)\n... class AreaUnitConverter(ExponentiatedUnitConverter): ...\n
    >>> AreaUnitConverter.get_factor(LengthUnit.INCH**2, LengthUnit.CENTI_METER**2)\n6.4516\n
    Source code in src/property_utils/units/converter_types.py
    @classmethod\ndef get_factor(\n    cls, from_descriptor: UnitDescriptor, to_descriptor: UnitDescriptor\n) -> float:\n    \"\"\"\n    Get the multiplication factor for the conversion from `from_descriptor` to\n    `to_descriptor`.\n\n    Raises `UnitConversionError` if `from_descriptor` or `to_descriptor` are not\n    an instance of the generic that is registered with the converter.\n\n    Raises `ConverterDependenciesError` if a converter for the base unit has not\n    been defined/registered.\n\n    Raises `UnsupportedConverterError` if the base unit is a relative unit.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit):\n        ...     CENTI_METER = \"cm\"\n        ...     INCH = \"in\"\n\n        >>> @register_converter(LengthUnit)\n        ... class LengthUnitConverter(AbsoluteUnitConverter):\n        ...     reference_unit = LengthUnit.INCH\n        ...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n\n        >>> @register_converter(LengthUnit**2)\n        ... class AreaUnitConverter(ExponentiatedUnitConverter): ...\n\n        >>> AreaUnitConverter.get_factor(LengthUnit.INCH**2, LengthUnit.CENTI_METER**2)\n        6.4516\n    \"\"\"\n    if not from_descriptor.isinstance_equivalent(cls.generic_unit_descriptor):\n        raise UnitConversionError(\n            f\"invalid 'from_descriptor; expected an instance-equivalent of {cls.generic_unit_descriptor}. \"\n        )\n    if not to_descriptor.isinstance_equivalent(cls.generic_unit_descriptor):\n        raise UnitConversionError(\n            f\"invalid 'to_descriptor'; expected an instance-equivalent of {cls.generic_unit_descriptor}. \"\n        )\n    from_dimension = Dimension.from_descriptor(from_descriptor)\n\n    if not to_descriptor.isinstance(from_descriptor.to_generic()):\n        if isinstance(to_descriptor, AliasMeasurementUnit):\n            return cls._get_aliased_factor(from_dimension, to_descriptor)\n\n    to_dimension = Dimension.from_descriptor(to_descriptor)\n\n    try:\n        converter = get_converter(cls.generic_unit_descriptor.unit_type)\n    except UndefinedConverterError:\n        raise ConverterDependenciesError(\n            f\"converter {cls.__name__} depends on a converter for \"\n            f\"{cls.generic_unit_descriptor.unit_type}. Did you forget to register \"\n            f\" a converter for {cls.generic_unit_descriptor.unit_type}? \"\n        ) from None\n    if not issubclass(converter, AbsoluteUnitConverter):\n        # NOTE: provide a link to documentation for the error.\n        raise UnsupportedConverterError(\n            f\"converter {cls.__name__} is not supported since \"\n            f\"{cls.generic_unit_descriptor.unit_type} is not an absolute unit;\"\n            \" conversion between exponentiated relative units is invalid. \"\n        )\n    factor = converter.get_factor(from_dimension.unit, to_dimension.unit)\n    return factor**to_dimension.power\n
    "},{"location":"converter_types/#property_utils.units.converter_types.RelativeUnitConverter","title":"RelativeUnitConverter","text":"

    Base converter class for measurement units that are relative.

    e.g. Temperature units are relative because conversion from one unit to another is not necessarily performed with multiplication with a single factor.

    Use the register_converter decorator when subclassing and define the reference_unit, conversion_map and reference_conversion_map attributes. It does not matter what unit you shall choose to be the reference; although you have to define the conversion map and reference conversion map accordingly. The conversion map is a dictionary that holds the conversion functions that convert other units to the reference unit. The reference conversion map is a dictionary that holds the conversion functions that convert the reference unit to other units.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     CELCIUS = \"\u00b0C\"\n...     FAHRENHEIT = \"\u00b0F\"\n
    >>> @register_converter(TemperatureUnit)\n... class TemperatureUnitConverter(RelativeUnitConverter):\n...     reference_unit = TemperatureUnit.CELCIUS\n...     conversion_map = {\n...             TemperatureUnit.CELCIUS: lambda t: t,\n...             TemperatureUnit.FAHRENHEIT: lambda t: (t - 32) / 1.8,\n...                 }\n...     reference_conversion_map = {\n...             TemperatureUnit.CELCIUS: lambda t: t,\n...             TemperatureUnit.FAHRENHEIT: lambda t: (t * 1.8) + 32,\n...                 }\n
    Source code in src/property_utils/units/converter_types.py
    class RelativeUnitConverter(\n    metaclass=ABCMeta\n):  # pylint: disable=too-few-public-methods\n    \"\"\"\n    Base converter class for measurement units that are relative.\n\n    e.g. Temperature units are relative because conversion from one unit to another\n    is not necessarily performed with multiplication with a single factor.\n\n    Use the `register_converter` decorator when subclassing and define the\n    `reference_unit`, `conversion_map` and `reference_conversion_map` attributes. It\n    does not matter what unit you shall choose to be the reference; although you have to\n    define the conversion map and reference conversion map accordingly. The conversion\n    map is a dictionary that holds the conversion functions that convert other units to\n    the reference unit. The reference conversion map is a dictionary that holds the\n    conversion functions that convert the reference unit to other units.\n\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     CELCIUS = \"\u00b0C\"\n        ...     FAHRENHEIT = \"\u00b0F\"\n\n        >>> @register_converter(TemperatureUnit)\n        ... class TemperatureUnitConverter(RelativeUnitConverter):\n        ...     reference_unit = TemperatureUnit.CELCIUS\n        ...     conversion_map = {\n        ...             TemperatureUnit.CELCIUS: lambda t: t,\n        ...             TemperatureUnit.FAHRENHEIT: lambda t: (t - 32) / 1.8,\n        ...                 }\n        ...     reference_conversion_map = {\n        ...             TemperatureUnit.CELCIUS: lambda t: t,\n        ...             TemperatureUnit.FAHRENHEIT: lambda t: (t * 1.8) + 32,\n        ...                 }\n    \"\"\"\n\n    generic_unit_descriptor: MeasurementUnitType\n    reference_unit: MeasurementUnit\n    reference_conversion_map: Dict[MeasurementUnit, Callable[[float], float]]\n    conversion_map: Dict[MeasurementUnit, Callable[[float], float]]\n\n    @classmethod\n    def convert(\n        cls,\n        value: float,\n        from_descriptor: UnitDescriptor,\n        to_descriptor: UnitDescriptor,\n    ) -> float:\n        \"\"\"\n        Convert a value from a relative unit to another relative unit.\n\n        Raises `UnitConversionError` if `from_descriptor` or `to_descriptor` are not\n        an instance of the generic that is registered with the converter or if `value`\n        is not a numeric.\n\n        Raises `ConversionFunctionError` if an error occurs when calling a function\n        provided in the conversion_map or reference_conversion_map.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     CELCIUS = \"\u00b0C\"\n            ...     FAHRENHEIT = \"\u00b0F\"\n\n            >>> @register_converter(TemperatureUnit)\n            ... class TemperatureUnitConverter(RelativeUnitConverter):\n            ...     reference_unit = TemperatureUnit.CELCIUS\n            ...     conversion_map = {\n            ...             TemperatureUnit.CELCIUS: lambda t: t,\n            ...             TemperatureUnit.FAHRENHEIT: lambda t: (t - 32) / 1.8,\n            ...                 }\n            ...     reference_conversion_map = {\n            ...             TemperatureUnit.CELCIUS: lambda t: t,\n            ...             TemperatureUnit.FAHRENHEIT: lambda t: (t * 1.8) + 32,\n            ...                 }\n\n            >>> TemperatureUnitConverter.convert(100, TemperatureUnit.CELCIUS, TemperatureUnit.FAHRENHEIT)\n            212.0\n        \"\"\"\n        if not isinstance(value, (float, int)):\n            raise UnitConversionError(f\"invalid 'value': {value}; expected numeric. \")\n        return cls._from_reference(\n            cls._to_reference(value, from_descriptor), to_descriptor\n        )\n\n    @classmethod\n    def _to_reference(cls, value: float, from_descriptor: UnitDescriptor) -> float:\n        if not from_descriptor.isinstance(cls.generic_unit_descriptor):\n            raise UnitConversionError(\n                f\"invalid 'from_descriptor; expected an instance of {cls.generic_unit_descriptor}. \"\n            )\n        from_unit = MeasurementUnit.from_descriptor(from_descriptor)\n        try:\n            conversion_func = cls.conversion_map[from_unit]\n        except KeyError:\n            raise UnitConversionError(\n                f\"cannot convert from {from_unit}; unit is not in {cls.__name__}'s conversion map. \",\n            ) from None\n        try:\n            return conversion_func(value)\n        except Exception as exc:\n            raise ConversionFunctionError(\n                f\"an error occured in a conversion function of {cls.__name__}. \", exc\n            ) from exc\n\n    @classmethod\n    def _from_reference(cls, value: float, to_descriptor: UnitDescriptor) -> float:\n        if not to_descriptor.isinstance(cls.generic_unit_descriptor):\n            raise UnitConversionError(\n                f\"invalid 'to_descriptor'; expected an instance of {cls.generic_unit_descriptor}. \"\n            )\n        to_unit = MeasurementUnit.from_descriptor(to_descriptor)\n        try:\n            conversion_func = cls.reference_conversion_map[to_unit]\n        except KeyError:\n            raise UnitConversionError(\n                f\"cannot convert to {to_unit}; unit is not registered in {cls.__name__}'s reference conversion map. \",\n            ) from None\n        try:\n            return conversion_func(value)\n        except Exception as exc:\n            raise ConversionFunctionError(\n                f\"an error occured in a conversion function of {cls.__name__}. \", exc\n            ) from exc\n
    "},{"location":"converter_types/#property_utils.units.converter_types.RelativeUnitConverter.convert","title":"convert(value, from_descriptor, to_descriptor) classmethod","text":"

    Convert a value from a relative unit to another relative unit.

    Raises UnitConversionError if from_descriptor or to_descriptor are not an instance of the generic that is registered with the converter or if value is not a numeric.

    Raises ConversionFunctionError if an error occurs when calling a function provided in the conversion_map or reference_conversion_map.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     CELCIUS = \"\u00b0C\"\n...     FAHRENHEIT = \"\u00b0F\"\n
    >>> @register_converter(TemperatureUnit)\n... class TemperatureUnitConverter(RelativeUnitConverter):\n...     reference_unit = TemperatureUnit.CELCIUS\n...     conversion_map = {\n...             TemperatureUnit.CELCIUS: lambda t: t,\n...             TemperatureUnit.FAHRENHEIT: lambda t: (t - 32) / 1.8,\n...                 }\n...     reference_conversion_map = {\n...             TemperatureUnit.CELCIUS: lambda t: t,\n...             TemperatureUnit.FAHRENHEIT: lambda t: (t * 1.8) + 32,\n...                 }\n
    >>> TemperatureUnitConverter.convert(100, TemperatureUnit.CELCIUS, TemperatureUnit.FAHRENHEIT)\n212.0\n
    Source code in src/property_utils/units/converter_types.py
    @classmethod\ndef convert(\n    cls,\n    value: float,\n    from_descriptor: UnitDescriptor,\n    to_descriptor: UnitDescriptor,\n) -> float:\n    \"\"\"\n    Convert a value from a relative unit to another relative unit.\n\n    Raises `UnitConversionError` if `from_descriptor` or `to_descriptor` are not\n    an instance of the generic that is registered with the converter or if `value`\n    is not a numeric.\n\n    Raises `ConversionFunctionError` if an error occurs when calling a function\n    provided in the conversion_map or reference_conversion_map.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     CELCIUS = \"\u00b0C\"\n        ...     FAHRENHEIT = \"\u00b0F\"\n\n        >>> @register_converter(TemperatureUnit)\n        ... class TemperatureUnitConverter(RelativeUnitConverter):\n        ...     reference_unit = TemperatureUnit.CELCIUS\n        ...     conversion_map = {\n        ...             TemperatureUnit.CELCIUS: lambda t: t,\n        ...             TemperatureUnit.FAHRENHEIT: lambda t: (t - 32) / 1.8,\n        ...                 }\n        ...     reference_conversion_map = {\n        ...             TemperatureUnit.CELCIUS: lambda t: t,\n        ...             TemperatureUnit.FAHRENHEIT: lambda t: (t * 1.8) + 32,\n        ...                 }\n\n        >>> TemperatureUnitConverter.convert(100, TemperatureUnit.CELCIUS, TemperatureUnit.FAHRENHEIT)\n        212.0\n    \"\"\"\n    if not isinstance(value, (float, int)):\n        raise UnitConversionError(f\"invalid 'value': {value}; expected numeric. \")\n    return cls._from_reference(\n        cls._to_reference(value, from_descriptor), to_descriptor\n    )\n
    "},{"location":"converter_types/#property_utils.units.converter_types.UnitConverter","title":"UnitConverter","text":"

    Bases: Protocol

    Protocol of classes that convert a value from one unit to another.

    Source code in src/property_utils/units/converter_types.py
    class UnitConverter(Protocol):  # pylint: disable=too-few-public-methods\n    \"\"\"Protocol of classes that convert a value from one unit to another.\"\"\"\n\n    generic_unit_descriptor: GenericUnitDescriptor\n\n    @classmethod\n    def convert(\n        cls,\n        value: float,\n        from_descriptor: UnitDescriptor,\n        to_descriptor: UnitDescriptor,\n    ) -> float:\n        \"\"\"\n        Convert a value from a unit descriptor to its' corresponding value in a\n        different unit descriptor.\n        \"\"\"\n
    "},{"location":"converter_types/#property_utils.units.converter_types.UnitConverter.convert","title":"convert(value, from_descriptor, to_descriptor) classmethod","text":"

    Convert a value from a unit descriptor to its' corresponding value in a different unit descriptor.

    Source code in src/property_utils/units/converter_types.py
    @classmethod\ndef convert(\n    cls,\n    value: float,\n    from_descriptor: UnitDescriptor,\n    to_descriptor: UnitDescriptor,\n) -> float:\n    \"\"\"\n    Convert a value from a unit descriptor to its' corresponding value in a\n    different unit descriptor.\n    \"\"\"\n
    "},{"location":"converter_types/#property_utils.units.converter_types.get_converter","title":"get_converter(generic)","text":"

    Get converter for given generic descriptor.

    Raises PropertyUtilsTypeError if argument is not a generic unit descriptor.

    Raises UndefinedConverterError if a converter has not been defined for the given generic.

    Source code in src/property_utils/units/converter_types.py
    def get_converter(generic: GenericUnitDescriptor) -> ConverterType:\n    \"\"\"\n    Get converter for given generic descriptor.\n\n    Raises `PropertyUtilsTypeError` if argument is not a generic unit descriptor.\n\n    Raises `UndefinedConverterError` if a converter has not been defined for the given generic.\n    \"\"\"\n    if not isinstance(\n        generic, (MeasurementUnitType, GenericDimension, GenericCompositeDimension)\n    ):\n        raise PropertyUtilsTypeError(\n            f\"cannot get converter; argument: {generic} is not a generic unit descriptor. \"\n        )\n    if isinstance(generic, GenericDimension) and generic.power == 1:\n        generic = generic.unit_type\n    elif isinstance(generic, GenericDimension) and generic not in _converters:\n        register_converter(generic)(\n            type(f\"{generic}_Converter\", (ExponentiatedUnitConverter,), {})\n        )\n    elif isinstance(generic, GenericCompositeDimension) and generic not in _converters:\n        register_converter(generic)(\n            type(f\"{generic}_Converter\", (CompositeUnitConverter,), {})\n        )\n    try:\n        return _converters[generic]\n    except KeyError:\n        raise UndefinedConverterError(\n            f\"a converter has not been defined for {generic}\"\n        ) from None\n
    "},{"location":"converter_types/#property_utils.units.converter_types.register_converter","title":"register_converter(generic)","text":"

    Decorate a converter class to register the generic descriptor of the units it operates on. This decorator also sets the 'generic_unit_descriptor' attribute of the decorated class.

    Raises PropertyUtilsTypeError if argument is not a generic unit descriptor.

    Raises PropertyUtilsValueError if generic has already a converter registered.

    Source code in src/property_utils/units/converter_types.py
    def register_converter(generic: GenericUnitDescriptor) -> Callable:\n    \"\"\"\n    Decorate a converter class to register the generic descriptor of the units it\n    operates on.\n    This decorator also sets the 'generic_unit_descriptor' attribute of the decorated\n    class.\n\n    Raises `PropertyUtilsTypeError` if argument is not a generic unit descriptor.\n\n    Raises `PropertyUtilsValueError` if generic has already a converter registered.\n    \"\"\"\n    if not isinstance(\n        generic, (MeasurementUnitType, GenericDimension, GenericCompositeDimension)\n    ):\n        raise PropertyUtilsTypeError(\n            f\"cannot get converter; argument: {generic} is not a generic unit descriptor. \"\n        )\n\n    if generic in _converters:\n        raise PropertyUtilsValueError(\n            f\"cannot register converter twice; {generic} has already got a converter. \"\n        )\n\n    def wrapper(cls: ConverterType) -> ConverterType:\n        _converters[generic] = cls\n        cls.generic_unit_descriptor = generic\n        return cls\n\n    return wrapper\n
    "},{"location":"converters/","title":"converters","text":"

    This module defines unit converters for the units in 'property_utils.units.units' as well as some converters for common exponentiated units (area and volume).

    "},{"location":"converters/#property_utils.units.converters.AbsoluteTemperatureUnitConverter","title":"AbsoluteTemperatureUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    Convert absolute temperature with this converter.

    Examples:

    >>> AbsoluteTemperatureUnitConverter.convert(10, AbsoluteTemperatureUnit.KELVIN, AbsoluteTemperatureUnit.RANKINE)\n18.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(AbsoluteTemperatureUnit)\nclass AbsoluteTemperatureUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    Convert absolute temperature with this converter.\n\n    Examples:\n        >>> AbsoluteTemperatureUnitConverter.convert(10, AbsoluteTemperatureUnit.KELVIN, AbsoluteTemperatureUnit.RANKINE)\n        18.0\n    \"\"\"\n\n    reference_unit = AbsoluteTemperatureUnit.KELVIN\n    conversion_map = {\n        AbsoluteTemperatureUnit.KELVIN: 1,\n        AbsoluteTemperatureUnit.RANKINE: 1.8,\n    }\n\n    @override\n    @classmethod\n    def convert(\n        cls,\n        value: float,\n        from_descriptor: UnitDescriptor,\n        to_descriptor: UnitDescriptor,\n    ) -> float:\n        if not isinstance(value, (float, int)):\n            raise UnitConversionError(f\"invalid 'value': {value}; expected numeric. \")\n        if from_descriptor.isinstance(\n            RelativeTemperatureUnit\n        ) or to_descriptor.isinstance(RelativeTemperatureUnit):\n            return RelativeTemperatureUnitConverter.convert(\n                value, from_descriptor, to_descriptor\n            )\n        return value * cls.get_factor(from_descriptor, to_descriptor)\n
    "},{"location":"converters/#property_utils.units.converters.AliasEnergyUnitConverter","title":"AliasEnergyUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    Convert energy units with this converter.

    Examples:

    >>> AliasEnergyUnitConverter.convert(2500, EnergyUnit.JOULE, EnergyUnit.KILO_JOULE)\n2.5\n
    Source code in src/property_utils/units/converters.py
    @register_converter(EnergyUnit)\nclass AliasEnergyUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    Convert energy units with this converter.\n\n    Examples:\n        >>> AliasEnergyUnitConverter.convert(2500, EnergyUnit.JOULE, EnergyUnit.KILO_JOULE)\n        2.5\n    \"\"\"\n\n    reference_unit = EnergyUnit.JOULE\n    conversion_map = {\n        EnergyUnit.JOULE: 1,\n        EnergyUnit.KILO_JOULE: UnitPrefix.KILO.inverse(),\n        EnergyUnit.MEGA_JOULE: UnitPrefix.MEGA.inverse(),\n        EnergyUnit.GIGA_JOULE: UnitPrefix.GIGA.inverse(),\n        EnergyUnit.CALORIE: 1 / 4.184,\n        EnergyUnit.KILO_CALORIE: (1 / 4.184) * UnitPrefix.KILO.inverse(),\n        EnergyUnit.BTU: 1 / 1055.0,\n        EnergyUnit.ELECTRONVOLT: 6.242e18,\n        EnergyUnit.WATTHOUR: 1 / 3600,\n        EnergyUnit.KILO_WATTHOUR: (1 / 3600) * UnitPrefix.KILO.inverse(),\n    }\n
    "},{"location":"converters/#property_utils.units.converters.AliasForceUnitConverter","title":"AliasForceUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    Convert force units with this converter.

    Examples:

    >>> AliasForceUnitConverter.convert(2, ForceUnit.NEWTON, ForceUnit.DYNE)\n200000.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(ForceUnit)\nclass AliasForceUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    Convert force units with this converter.\n\n    Examples:\n        >>> AliasForceUnitConverter.convert(2, ForceUnit.NEWTON, ForceUnit.DYNE)\n        200000.0\n    \"\"\"\n\n    reference_unit = ForceUnit.NEWTON\n    conversion_map = {ForceUnit.NEWTON: 1, ForceUnit.DYNE: 100_000}\n
    "},{"location":"converters/#property_utils.units.converters.AliasPowerUnitConverter","title":"AliasPowerUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    Convert power units with this converter.

    Examples:

    >>> AliasPowerUnitConverter.convert(5, PowerUnit.KILO_WATT, PowerUnit.WATT)\n5000.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(PowerUnit)\nclass AliasPowerUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    Convert power units with this converter.\n\n    Examples:\n        >>> AliasPowerUnitConverter.convert(5, PowerUnit.KILO_WATT, PowerUnit.WATT)\n        5000.0\n    \"\"\"\n\n    reference_unit = PowerUnit.WATT\n    conversion_map = {\n        PowerUnit.WATT: 1,\n        PowerUnit.KILO_WATT: UnitPrefix.KILO.inverse(),\n        PowerUnit.MEGA_WATT: UnitPrefix.MEGA.inverse(),\n        PowerUnit.GIGA_WATT: UnitPrefix.GIGA.inverse(),\n    }\n
    "},{"location":"converters/#property_utils.units.converters.AliasPressureUnitConverter","title":"AliasPressureUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    Convert pressure units with this converter.

    Examples:

    >>> AliasPressureUnitConverter.convert(2, PressureUnit.BAR, PressureUnit.KILO_PASCAL)\n200.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(PressureUnit)\nclass AliasPressureUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    Convert pressure units with this converter.\n\n    Examples:\n        >>> AliasPressureUnitConverter.convert(2, PressureUnit.BAR, PressureUnit.KILO_PASCAL)\n        200.0\n    \"\"\"\n\n    reference_unit = PressureUnit.BAR\n    conversion_map = {\n        PressureUnit.MILLI_BAR: UnitPrefix.MILLI.inverse(),\n        PressureUnit.BAR: 1,\n        PressureUnit.PSI: 14.5038,\n        PressureUnit.PASCAL: 100_000,\n        PressureUnit.KILO_PASCAL: 100,\n        PressureUnit.MEGA_PASCAL: 0.1,\n    }\n
    "},{"location":"converters/#property_utils.units.converters.AmountUnitConverter","title":"AmountUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    Convert amount units with this converter.

    Examples:

    >>> AmountUnitConverter.convert(2000, AmountUnit.MOL, AmountUnit.KILO_MOL)\n2.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(AmountUnit)\nclass AmountUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    Convert amount units with this converter.\n\n    Examples:\n        >>> AmountUnitConverter.convert(2000, AmountUnit.MOL, AmountUnit.KILO_MOL)\n        2.0\n    \"\"\"\n\n    reference_unit = AmountUnit.MOL\n    conversion_map = {AmountUnit.MOL: 1, AmountUnit.KILO_MOL: UnitPrefix.KILO.inverse()}\n
    "},{"location":"converters/#property_utils.units.converters.AreaUnitConverter","title":"AreaUnitConverter","text":"

    Bases: ExponentiatedUnitConverter

    Convert area units with this converter.

    Examples:

    >>> AreaUnitConverter.convert(1, LengthUnit.METER**2, LengthUnit.CENTI_METER**2)\n10000.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(LengthUnit**2)\nclass AreaUnitConverter(ExponentiatedUnitConverter):\n    \"\"\"\n    Convert area units with this converter.\n\n    Examples:\n        >>> AreaUnitConverter.convert(1, LengthUnit.METER**2, LengthUnit.CENTI_METER**2)\n        10000.0\n    \"\"\"\n
    "},{"location":"converters/#property_utils.units.converters.ElectricCurrentUnitConverter","title":"ElectricCurrentUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    Convert electric current units with this converter.

    Examples:

    >>> ElectricCurrentUnitConverter.convert(1000, ElectricCurrentUnit.MILLI_AMPERE, ElectricCurrentUnit.AMPERE)\n1.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(ElectricCurrentUnit)\nclass ElectricCurrentUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    Convert electric current units with this converter.\n\n    Examples:\n        >>> ElectricCurrentUnitConverter.convert(1000, ElectricCurrentUnit.MILLI_AMPERE, ElectricCurrentUnit.AMPERE)\n        1.0\n    \"\"\"\n\n    reference_unit = ElectricCurrentUnit.AMPERE\n    conversion_map = {\n        ElectricCurrentUnit.MILLI_AMPERE: UnitPrefix.MILLI.inverse(),\n        ElectricCurrentUnit.AMPERE: 1,\n        ElectricCurrentUnit.KILO_AMPERE: UnitPrefix.KILO.inverse(),\n    }\n
    "},{"location":"converters/#property_utils.units.converters.EnergyUnitConverter","title":"EnergyUnitConverter","text":"

    Bases: CompositeUnitConverter

    Convert energy units (mass * length^2 / time^2) with this converter.

    Examples:

    >>> from_unit = MassUnit.KILO_GRAM * (LengthUnit.METER**2) / (TimeUnit.MINUTE**2)\n>>> to_unit = MassUnit.METRIC_TONNE * (LengthUnit.CENTI_METER**2) / (TimeUnit.MINUTE**2)\n>>> EnergyUnitConverter.convert(25, from_unit, to_unit)\n250.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(EnergyUnit.aliased_generic_descriptor())\nclass EnergyUnitConverter(CompositeUnitConverter):\n    \"\"\"\n    Convert energy units (mass * length^2 / time^2) with this converter.\n\n    Examples:\n        >>> from_unit = MassUnit.KILO_GRAM * (LengthUnit.METER**2) / (TimeUnit.MINUTE**2)\n        >>> to_unit = MassUnit.METRIC_TONNE * (LengthUnit.CENTI_METER**2) / (TimeUnit.MINUTE**2)\n        >>> EnergyUnitConverter.convert(25, from_unit, to_unit)\n        250.0\n    \"\"\"\n
    "},{"location":"converters/#property_utils.units.converters.ForceUnitConverter","title":"ForceUnitConverter","text":"

    Bases: CompositeUnitConverter

    Convert force units (mass * length / time^2) with this converter.

    Examples:

    >>> from_unit = MassUnit.KILO_GRAM * LengthUnit.CENTI_METER / (TimeUnit.SECOND**2)\n>>> to_unit = MassUnit.GRAM * LengthUnit.METER / (TimeUnit.SECOND**2)\n>>> ForceUnitConverter.convert(100, from_unit, to_unit)\n1000.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(ForceUnit.aliased_generic_descriptor())\nclass ForceUnitConverter(CompositeUnitConverter):\n    \"\"\"\n    Convert force units (mass * length / time^2) with this converter.\n\n    Examples:\n        >>> from_unit = MassUnit.KILO_GRAM * LengthUnit.CENTI_METER / (TimeUnit.SECOND**2)\n        >>> to_unit = MassUnit.GRAM * LengthUnit.METER / (TimeUnit.SECOND**2)\n        >>> ForceUnitConverter.convert(100, from_unit, to_unit)\n        1000.0\n    \"\"\"\n
    "},{"location":"converters/#property_utils.units.converters.LengthUnitConverter","title":"LengthUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    Convert length units with this converter.

    Examples:

    >>> LengthUnitConverter.convert(2000, LengthUnit.MILLI_METER, LengthUnit.METER)\n2.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(LengthUnit)\nclass LengthUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    Convert length units with this converter.\n\n    Examples:\n        >>> LengthUnitConverter.convert(2000, LengthUnit.MILLI_METER, LengthUnit.METER)\n        2.0\n    \"\"\"\n\n    reference_unit = LengthUnit.METER\n    conversion_map = {\n        LengthUnit.MILLI_METER: UnitPrefix.MILLI.inverse(),\n        LengthUnit.CENTI_METER: UnitPrefix.CENTI.inverse(),\n        LengthUnit.METER: 1,\n        LengthUnit.KILO_METER: UnitPrefix.KILO.inverse(),\n        LengthUnit.INCH: 39.37,\n        LengthUnit.FOOT: 3.281,\n        LengthUnit.YARD: 1.094,\n        LengthUnit.MILE: 1 / 1609,\n        LengthUnit.NAUTICAL_MILE: 1 / 1852,\n    }\n
    "},{"location":"converters/#property_utils.units.converters.MassUnitConverter","title":"MassUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    Convert mass units with this converter.

    Examples:

    >>> MassUnitConverter.convert(10, MassUnit.KILO_GRAM, MassUnit.GRAM)\n10000.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(MassUnit)\nclass MassUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    Convert mass units with this converter.\n\n    Examples:\n        >>> MassUnitConverter.convert(10, MassUnit.KILO_GRAM, MassUnit.GRAM)\n        10000.0\n    \"\"\"\n\n    reference_unit = MassUnit.KILO_GRAM\n    conversion_map = {\n        MassUnit.MILLI_GRAM: UnitPrefix.KILO * UnitPrefix.MILLI.inverse(),\n        MassUnit.GRAM: UnitPrefix.KILO,\n        MassUnit.KILO_GRAM: 1,\n        MassUnit.METRIC_TONNE: 1 / 1_000.0,\n        MassUnit.POUND: 2.205,\n    }\n
    "},{"location":"converters/#property_utils.units.converters.PowerUnitConverter","title":"PowerUnitConverter","text":"

    Bases: CompositeUnitConverter

    Convert power units (mass * length^2 / time^3) with this converter.

    Examples:

    >>> from_unit = MassUnit.KILO_GRAM * (LengthUnit.METER**2) / (TimeUnit.MINUTE**3)\n>>> to_unit = MassUnit.METRIC_TONNE * (LengthUnit.CENTI_METER**2) / (TimeUnit.MINUTE**3)\n>>> PowerUnitConverter.convert(15, from_unit, to_unit)\n150.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(PowerUnit.aliased_generic_descriptor())\nclass PowerUnitConverter(CompositeUnitConverter):\n    \"\"\"\n    Convert power units (mass * length^2 / time^3) with this converter.\n\n    Examples:\n        >>> from_unit = MassUnit.KILO_GRAM * (LengthUnit.METER**2) / (TimeUnit.MINUTE**3)\n        >>> to_unit = MassUnit.METRIC_TONNE * (LengthUnit.CENTI_METER**2) / (TimeUnit.MINUTE**3)\n        >>> PowerUnitConverter.convert(15, from_unit, to_unit)\n        150.0\n    \"\"\"\n
    "},{"location":"converters/#property_utils.units.converters.PressureUnitConverter","title":"PressureUnitConverter","text":"

    Bases: CompositeUnitConverter

    Convert pressure units (mass / length / time^2) with this converter.

    Examples:

    >>> from_unit = MassUnit.GRAM / LengthUnit.CENTI_METER / (TimeUnit.HOUR**2)\n>>> to_unit = MassUnit.KILO_GRAM / LengthUnit.METER / (TimeUnit.HOUR**2)\n>>> PressureUnitConverter.convert(50, from_unit, to_unit)\n5.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(PressureUnit.aliased_generic_descriptor())\nclass PressureUnitConverter(CompositeUnitConverter):\n    \"\"\"\n    Convert pressure units (mass / length / time^2) with this converter.\n\n    Examples:\n        >>> from_unit = MassUnit.GRAM / LengthUnit.CENTI_METER / (TimeUnit.HOUR**2)\n        >>> to_unit = MassUnit.KILO_GRAM / LengthUnit.METER / (TimeUnit.HOUR**2)\n        >>> PressureUnitConverter.convert(50, from_unit, to_unit)\n        5.0\n    \"\"\"\n
    "},{"location":"converters/#property_utils.units.converters.RelativeTemperatureUnitConverter","title":"RelativeTemperatureUnitConverter","text":"

    Bases: RelativeUnitConverter

    Convert temperature units with this converter.

    Examples:

    >>> RelativeTemperatureUnitConverter.convert(100, RelativeTemperatureUnit.CELCIUS, RelativeTemperatureUnit.FAHRENHEIT)\n212.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(RelativeTemperatureUnit)\nclass RelativeTemperatureUnitConverter(\n    RelativeUnitConverter\n):  # pylint: disable=too-few-public-methods\n    \"\"\"\n    Convert temperature units with this converter.\n\n    Examples:\n        >>> RelativeTemperatureUnitConverter.convert(100, RelativeTemperatureUnit.CELCIUS, RelativeTemperatureUnit.FAHRENHEIT)\n        212.0\n    \"\"\"\n\n    reference_unit = RelativeTemperatureUnit.CELCIUS\n    conversion_map = {\n        RelativeTemperatureUnit.CELCIUS: lambda t: t,\n        AbsoluteTemperatureUnit.KELVIN: lambda t: t - 273.15,\n        RelativeTemperatureUnit.FAHRENHEIT: lambda t: (t - 32) / 1.8,\n        AbsoluteTemperatureUnit.RANKINE: lambda t: (t / 1.8) - 273.15,\n    }\n    reference_conversion_map = {\n        RelativeTemperatureUnit.CELCIUS: lambda t: t,\n        AbsoluteTemperatureUnit.KELVIN: lambda t: t + 273.15,\n        RelativeTemperatureUnit.FAHRENHEIT: lambda t: (t * 1.8) + 32,\n        AbsoluteTemperatureUnit.RANKINE: lambda t: (t + 273.15) * 1.8,\n    }\n
    "},{"location":"converters/#property_utils.units.converters.TimeUnitConverter","title":"TimeUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    Convert time units with this converter.

    Examples:

    >>> TimeUnitConverter.convert(1, TimeUnit.HOUR, TimeUnit.SECOND)\n3600.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(TimeUnit)\nclass TimeUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    Convert time units with this converter.\n\n    Examples:\n        >>> TimeUnitConverter.convert(1, TimeUnit.HOUR, TimeUnit.SECOND)\n        3600.0\n    \"\"\"\n\n    reference_unit = TimeUnit.SECOND\n    conversion_map = {\n        TimeUnit.MILLI_SECOND: UnitPrefix.MILLI.inverse(),\n        TimeUnit.SECOND: 1,\n        TimeUnit.MINUTE: 1 / 60.0,\n        TimeUnit.HOUR: 1 / 60.0 / 60.0,\n        TimeUnit.DAY: 1 / 60.0 / 60.0 / 24.0,\n        TimeUnit.WEEK: 1 / 60.0 / 60.0 / 24.0 / 7,\n        TimeUnit.MONTH: 1 / 60.0 / 60.0 / 24.0 / (365 / 12),\n        TimeUnit.YEAR: 1 / 60.0 / 60.0 / 24.0 / 365,\n    }\n
    "},{"location":"converters/#property_utils.units.converters.UnitPrefix","title":"UnitPrefix","text":"

    Bases: float, Enum

    Enumeration of unit prefixes. Handy when converting to and fro prefixed units.

    Examples:

    >>> centimeters = 225\n>>> meters = centimeters * UnitPrefix.CENTI\n>>> meters\n2.25\n
    Source code in src/property_utils/units/converters.py
    class UnitPrefix(float, Enum):\n    \"\"\"\n    Enumeration of unit prefixes.\n    Handy when converting to and fro prefixed units.\n\n    Examples:\n        >>> centimeters = 225\n        >>> meters = centimeters * UnitPrefix.CENTI\n        >>> meters\n        2.25\n    \"\"\"\n\n    PICO = 1e-12\n    NANO = 1e-9\n    MICRO = 1e-6\n    MILLI = 1e-3\n    CENTI = 1e-2\n    DECI = 1e-1\n    DECA = 1e1\n    HECTO = 1e2\n    KILO = 1e3\n    MEGA = 1e6\n    GIGA = 1e9\n    TERA = 1e12\n\n    def inverse(self) -> float:\n        \"\"\"\n        Return the inverse of the unit prefix. Use when prefixing a unit.\n\n        Examples:\n            >>> meters = 50.26\n            >>> centimeters = meters * UnitPrefix.CENTI.inverse()\n            >>> centimeters\n            5026.0\n        \"\"\"\n        return 1 / self.value\n
    "},{"location":"converters/#property_utils.units.converters.UnitPrefix.inverse","title":"inverse()","text":"

    Return the inverse of the unit prefix. Use when prefixing a unit.

    Examples:

    >>> meters = 50.26\n>>> centimeters = meters * UnitPrefix.CENTI.inverse()\n>>> centimeters\n5026.0\n
    Source code in src/property_utils/units/converters.py
    def inverse(self) -> float:\n    \"\"\"\n    Return the inverse of the unit prefix. Use when prefixing a unit.\n\n    Examples:\n        >>> meters = 50.26\n        >>> centimeters = meters * UnitPrefix.CENTI.inverse()\n        >>> centimeters\n        5026.0\n    \"\"\"\n    return 1 / self.value\n
    "},{"location":"converters/#property_utils.units.converters.VolumeUnitConverter","title":"VolumeUnitConverter","text":"

    Bases: ExponentiatedUnitConverter

    Convert volume units with this converter.

    Examples:

    >>> VolumeUnitConverter.convert(1, LengthUnit.METER**3, LengthUnit.CENTI_METER**3)\n1000000.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(LengthUnit**3)\nclass VolumeUnitConverter(ExponentiatedUnitConverter):\n    \"\"\"\n    Convert volume units with this converter.\n\n    Examples:\n        >>> VolumeUnitConverter.convert(1, LengthUnit.METER**3, LengthUnit.CENTI_METER**3)\n        1000000.0\n    \"\"\"\n
    "},{"location":"descriptors/","title":"descriptors","text":"

    This module includes definitions for generic unit descriptors and unit descriptors.

    A unit descriptor is an interface that describes a measurement unit. It can represent anything like \u00b0C, m^3, mol/m^3/s etc.

    A generic unit descriptor is an interface that describes a generic measurement unit. It can represent e.g. a temperature unit, a volume unit, a reaction rate unit etc.

    "},{"location":"descriptors/#property_utils.units.descriptors.AliasMeasurementUnit","title":"AliasMeasurementUnit","text":"

    Bases: MeasurementUnit

    Base class for common composite units of physical quantities.

    Subclasses of MeasurementUnit represent only primitive physical quantities. However, many common physical properties have composite units (e.g. pressure, force, energy, etc), thus subclasses of this class alias composite units as primitive ones.

    Only very common composite units should be aliased.

    e.g. you can create an alias for pressure units, instead of using mass * length / ( time^2) units.

    Examples:

    >>> class PressureUnit(AliasMeasurementUnit):\n...     BAR = \"bar\"\n...     PASCAL = \"Pa\"\n...     KILO_PASCAL = \"kPa\"\n...     PSI = \"psi\"\n
    Source code in src/property_utils/units/descriptors.py
    class AliasMeasurementUnit(MeasurementUnit):\n    \"\"\"\n    Base class for common composite units of physical quantities.\n\n    Subclasses of `MeasurementUnit` represent only primitive physical quantities.\n    However, many common physical properties have composite units (e.g. pressure, force,\n    energy, etc), thus subclasses of this class alias composite units as primitive ones.\n\n    Only very common composite units should be aliased.\n\n    e.g. you can create an alias for pressure units, instead of using mass * length / (\n        time^2) units.\n\n    Examples:\n        >>> class PressureUnit(AliasMeasurementUnit):\n        ...     BAR = \"bar\"\n        ...     PASCAL = \"Pa\"\n        ...     KILO_PASCAL = \"kPa\"\n        ...     PSI = \"psi\"\n    \"\"\"\n\n    @staticmethod\n    def from_descriptor(descriptor: UnitDescriptor) -> MeasurementUnit:\n        \"\"\"\n        Create an AliasMeasurementUnit from given descriptor.\n        If descriptor is already an AliasMeasurementUnit, it returns the same object.\n\n        This function does not serve as a constructor for AliasMeasurementUnit, rather\n        it is intended to be used to convert an unknown unit descriptor to an\n        AliasMeasurementUnit.\n\n        Subclasses should implement aliased_generic_descriptor and alias_mapping\n        methods.\n\n        Raises `UnitDescriptorTypeError` if given descriptor cannot be translated\n        to an AliasMeasurementUnit  instance.\n\n        Examples:\n            >>> class PressureUnit(AliasMeasurementUnit):\n            ...     BAR = \"bar\"\n\n            >>> bar = MeasurementUnit.from_descriptor(PressureUnit.BAR**(-1))\n            >>> bar\n            <PressureUnit: bar>\n        \"\"\"\n        if isinstance(descriptor, Dimension) and isinstance(\n            descriptor.unit, AliasMeasurementUnit\n        ):\n            return descriptor.unit\n        if isinstance(descriptor, AliasMeasurementUnit):\n            return descriptor\n        raise UnitDescriptorTypeError(\n            f\"cannot create AliasMeasurementUnit from descriptor {descriptor}\"\n        )\n\n    @classmethod\n    def aliased_generic_descriptor(cls) -> GenericUnitDescriptor:\n        \"\"\"\n        Implement this method by returning the generic of the unit descriptor that this\n        measurement unit aliases.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit): ...\n            >>> class AreaUnit(AliasMeasurementUnit):\n            ...     @classmethod\n            ...     def aliased_generic_descriptor(cls):\n            ...         return LengthUnit**2\n        \"\"\"\n        raise NotImplementedError\n
    "},{"location":"descriptors/#property_utils.units.descriptors.AliasMeasurementUnit.aliased_generic_descriptor","title":"aliased_generic_descriptor() classmethod","text":"

    Implement this method by returning the generic of the unit descriptor that this measurement unit aliases.

    Examples:

    >>> class LengthUnit(MeasurementUnit): ...\n>>> class AreaUnit(AliasMeasurementUnit):\n...     @classmethod\n...     def aliased_generic_descriptor(cls):\n...         return LengthUnit**2\n
    Source code in src/property_utils/units/descriptors.py
    @classmethod\ndef aliased_generic_descriptor(cls) -> GenericUnitDescriptor:\n    \"\"\"\n    Implement this method by returning the generic of the unit descriptor that this\n    measurement unit aliases.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit): ...\n        >>> class AreaUnit(AliasMeasurementUnit):\n        ...     @classmethod\n        ...     def aliased_generic_descriptor(cls):\n        ...         return LengthUnit**2\n    \"\"\"\n    raise NotImplementedError\n
    "},{"location":"descriptors/#property_utils.units.descriptors.AliasMeasurementUnit.from_descriptor","title":"from_descriptor(descriptor) staticmethod","text":"

    Create an AliasMeasurementUnit from given descriptor. If descriptor is already an AliasMeasurementUnit, it returns the same object.

    This function does not serve as a constructor for AliasMeasurementUnit, rather it is intended to be used to convert an unknown unit descriptor to an AliasMeasurementUnit.

    Subclasses should implement aliased_generic_descriptor and alias_mapping methods.

    Raises UnitDescriptorTypeError if given descriptor cannot be translated to an AliasMeasurementUnit instance.

    Examples:

    >>> class PressureUnit(AliasMeasurementUnit):\n...     BAR = \"bar\"\n
    >>> bar = MeasurementUnit.from_descriptor(PressureUnit.BAR**(-1))\n>>> bar\n<PressureUnit: bar>\n
    Source code in src/property_utils/units/descriptors.py
    @staticmethod\ndef from_descriptor(descriptor: UnitDescriptor) -> MeasurementUnit:\n    \"\"\"\n    Create an AliasMeasurementUnit from given descriptor.\n    If descriptor is already an AliasMeasurementUnit, it returns the same object.\n\n    This function does not serve as a constructor for AliasMeasurementUnit, rather\n    it is intended to be used to convert an unknown unit descriptor to an\n    AliasMeasurementUnit.\n\n    Subclasses should implement aliased_generic_descriptor and alias_mapping\n    methods.\n\n    Raises `UnitDescriptorTypeError` if given descriptor cannot be translated\n    to an AliasMeasurementUnit  instance.\n\n    Examples:\n        >>> class PressureUnit(AliasMeasurementUnit):\n        ...     BAR = \"bar\"\n\n        >>> bar = MeasurementUnit.from_descriptor(PressureUnit.BAR**(-1))\n        >>> bar\n        <PressureUnit: bar>\n    \"\"\"\n    if isinstance(descriptor, Dimension) and isinstance(\n        descriptor.unit, AliasMeasurementUnit\n    ):\n        return descriptor.unit\n    if isinstance(descriptor, AliasMeasurementUnit):\n        return descriptor\n    raise UnitDescriptorTypeError(\n        f\"cannot create AliasMeasurementUnit from descriptor {descriptor}\"\n    )\n
    "},{"location":"descriptors/#property_utils.units.descriptors.CompositeDimension","title":"CompositeDimension dataclass","text":"

    A CompositeDimension represents a measurement unit that is composed from other measurement units.

    Objects of this class can represent either multiplication or division between two Dimension objects.

    Create objects by multiplying and diving Dimension or MeasurementUnit objects.

    Examples:

    >>> class LengthUnit(MeasurementUnit):\n...     METER = \"m\"\n
    >>> class AmountUnit(MeasurementUnit):\n...     KILO_MOL = \"kmol\"\n
    >>> molal_volume_dimension = (LengthUnit.METER**3) / AmountUnit.KILO_MOL\n>>> molal_volume_dimension\n<CompositeDimension: (m^3) / kmol>\n
    Source code in src/property_utils/units/descriptors.py
    @dataclass\nclass CompositeDimension:\n    \"\"\"\n    A CompositeDimension represents a measurement unit that is composed from other\n    measurement units.\n\n    Objects of this class can represent either multiplication or division between two\n    Dimension objects.\n\n    Create objects by multiplying and diving Dimension or MeasurementUnit objects.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit):\n        ...     METER = \"m\"\n\n        >>> class AmountUnit(MeasurementUnit):\n        ...     KILO_MOL = \"kmol\"\n\n        >>> molal_volume_dimension = (LengthUnit.METER**3) / AmountUnit.KILO_MOL\n        >>> molal_volume_dimension\n        <CompositeDimension: (m^3) / kmol>\n    \"\"\"\n\n    Default = TypeVar(\"Default\")  # default return type for `get` functions.\n\n    numerator: List[Dimension] = field(default_factory=list)\n    denominator: List[Dimension] = field(default_factory=list)\n\n    @staticmethod\n    def from_descriptor(descriptor: UnitDescriptor) -> \"CompositeDimension\":\n        \"\"\"\n        Create a CompositeDimension from given descriptor.\n        If descriptor is already a CompositeDimension, it returns the same object.\n\n        This function does not serve as a constructor for CompositeDimension, rather it\n        is intended to be used to convert an unknown unit descriptor to a\n        CompositeDimension.\n\n        Raises `UnitDescriptorTypeError` if given descriptor cannot be translated\n        to a CompositeDimension instance.\n        \"\"\"\n        if not isinstance(descriptor, CompositeDimension):\n            raise UnitDescriptorTypeError(\n                f\"cannot create CompositeDimension from descriptor {descriptor}\"\n            )\n        return descriptor\n\n    def si(self) -> \"CompositeDimension\":\n        \"\"\"\n        Returns this composite dimension in SI units.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     KELVIN = \"K\"\n            ...     RANKINE = \"R\"\n            ...     @classmethod\n            ...     def si(cls): return cls.KELVIN\n\n            >>> class LengthUnit(MeasurementUnit):\n            ...     METER = \"m\"\n            ...     FOOT = \"ft\"\n            ...     @classmethod\n            ...     def si(cls): return cls.METER\n\n            >>> (TemperatureUnit.RANKINE / LengthUnit.FOOT**2).si()\n            <CompositeDimension: K / (m^2)>\n        \"\"\"\n        return CompositeDimension(\n            [n.si() for n in self.numerator], [d.si() for d in self.denominator]\n        )\n\n    def isinstance(self, generic: GenericUnitDescriptor) -> bool:\n        \"\"\"\n        Returns True if the CompositeDimension is an instance of the generic, False\n        otherwise.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     CELCIUS = \"C\"\n\n            >>> class LengthUnit(MeasurementUnit):\n            ...     METER = \"m\"\n\n            >>> (TemperatureUnit.CELCIUS / LengthUnit.METER).isinstance(TemperatureUnit / LengthUnit)\n            True\n\n            >>> (TemperatureUnit.CELCIUS * LengthUnit.METER).isinstance(TemperatureUnit**2)\n            False\n        \"\"\"\n        if not isinstance(generic, GenericCompositeDimension):\n            return False\n\n        return self.to_generic() == generic\n\n    def isinstance_equivalent(self, generic: GenericUnitDescriptor) -> bool:\n        \"\"\"\n        Returns True if the UnitDescriptor is an instance-equivalent of the generic,\n        False otherwise.\n\n        A unit descriptor is an instance-equivalent of a generic if the generic of the\n        unit descriptor is equivalent to the generic.\n\n        Equivalence between generics is checked with the `is_equivalent` method.\n\n        Examples:\n            >>> class MassUnit(MeasurementUnit):\n            ...     KILO_GRAM = \"kg\"\n            >>> class LengthUnit(MeasurementUnit):\n            ...     METER = \"m\"\n            >>> class TimeUnit(MeasurementUnit):\n            ...     SECOND = \"s\"\n\n            >>> class ForceUnit(AliasMeasurementUnit):\n            ...     NEWTON = \"N\"\n            ...     @classmethod\n            ...     def aliased_generic_descriptor(cls):\n            ...         return MassUnit * LengthUnit / (TimeUnit**2)\n\n            >>> (MassUnit.KILO_GRAM * LengthUnit.METER / (TimeUnit.SECOND**2)).isinstance_equivalent(ForceUnit)\n            True\n        \"\"\"\n        return self.to_generic().is_equivalent(generic)\n\n    def to_generic(self) -> GenericCompositeDimension:\n        \"\"\"\n        Create a generic descriptor from this CompositeDimension.\n\n        Examples:\n            >>> class AmountUnit(MeasurementUnit):\n            ...     MOL = \"mol\"\n\n            >>> class MassUnit(MeasurementUnit):\n            ...     KILO_GRAM = \"kg\"\n\n            >>> (AmountUnit.MOL / MassUnit.KILO_GRAM).to_generic()\n            <GenericCompositeDimension: AmountUnit / MassUnit>\n        \"\"\"\n        return GenericCompositeDimension(\n            numerator=[n.to_generic() for n in self.numerator],\n            denominator=[d.to_generic() for d in self.denominator],\n        )\n\n    def get_numerator(\n        self,\n        generic: Union[MeasurementUnitType, GenericDimension],\n        default: Optional[Default] = None,\n    ) -> Union[Dimension, Optional[Default]]:\n        \"\"\"\n        Get a dimension from the numerator. If the dimension is not found it returns\n        the default.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit):\n            ...     METER = \"m\"\n\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     KELVIN = \"K\"\n\n            >>> composite = TemperatureUnit.KELVIN / (LengthUnit.METER**3)\n            >>> composite.get_numerator(TemperatureUnit)\n            <Dimension: K>\n            >>> composite.get_numerator(LengthUnit, \"default\")\n            'default'\n        \"\"\"\n        for n in self.numerator:\n            if n.isinstance(generic):\n                return n\n        return default\n\n    def get_denominator(\n        self,\n        generic: Union[MeasurementUnitType, GenericDimension],\n        default: Optional[Default] = None,\n    ) -> Union[Dimension, Optional[Default]]:\n        \"\"\"\n        Get a dimension from the denominator. If the dimension is not found it returns\n        the default.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit):\n            ...     METER = \"m\"\n\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     KELVIN = \"K\"\n\n            >>> composite = TemperatureUnit.KELVIN / (LengthUnit.METER**3)\n            >>> composite.get_denominator(LengthUnit**3)\n            <Dimension: m^3>\n            >>> composite.get_denominator(LengthUnit, \"default\")\n            'default'\n        \"\"\"\n        for d in self.denominator:\n            if d.isinstance(generic):\n                return d\n        return default\n\n    def simplify(self) -> None:\n        \"\"\"\n        Simplify the composite by merging common dimensions.\n\n        Examples:\n            >>> class PressureUnit(AliasMeasurementUnit):\n            ...     BAR = \"bar\"\n            ...     PASCAL = \"Pa\"\n\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     KELVIN = \"K\"\n\n            >>> class LengthUnit(MeasurementUnit):\n            ...     METER = \"m\"\n\n            >>> class TimeUnit(MeasurementUnit):\n            ...     SECOND = \"s\"\n\n            >>> composite = (PressureUnit.BAR**(-2)) / (TemperatureUnit.KELVIN**(-1))\n            >>> composite\n            <CompositeDimension: (bar^-2) / (K^-1)>\n            >>> composite.simplify()\n            >>> composite\n            <CompositeDimension: K / (bar^2)>\n\n            >>> composite = PressureUnit.PASCAL * LengthUnit.METER * PressureUnit.PASCAL /TimeUnit.SECOND\n            >>> composite\n            <CompositeDimension: Pa * Pa * m / s>\n            >>> composite.simplify()\n            >>> composite\n            <CompositeDimension: (Pa^2) * m / s>\n        \"\"\"\n        exponents: Dict[MeasurementUnit, float] = {}\n        for n in self.numerator:\n            if n.unit in exponents:\n                exponents[n.unit] += n.power\n            else:\n                exponents[n.unit] = n.power\n\n        for d in self.denominator:\n            if d.unit in exponents:\n                exponents[d.unit] -= d.power\n            else:\n                exponents[d.unit] = 0 - d.power\n\n        numerator = []\n        denominator = []\n        for unit, exponent in exponents.items():\n            if exponent > 0:\n                numerator.append(Dimension(unit) ** exponent)\n            elif exponent < 0:\n                denominator.append(Dimension(unit) ** abs(exponent))\n\n        self.numerator = numerator\n        self.denominator = denominator\n\n    def simplified(self) -> \"CompositeDimension\":\n        \"\"\"\n        Returns a simplified version of this composite dimension as a new object.\n\n        Examples:\n            >>> class PressureUnit(AliasMeasurementUnit):\n            ...     BAR = \"bar\"\n            ...     PASCAL = \"Pa\"\n\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     KELVIN = \"K\"\n\n            >>> class LengthUnit(MeasurementUnit):\n            ...     METER = \"m\"\n\n            >>> class TimeUnit(MeasurementUnit):\n            ...     SECOND = \"s\"\n\n            >>> composite = (PressureUnit.BAR**(-2)) / (TemperatureUnit.KELVIN**(-1))\n            >>> composite\n            <CompositeDimension: (bar^-2) / (K^-1)>\n            >>> composite.simplified()\n            <CompositeDimension: K / (bar^2)>\n\n            >>> composite = PressureUnit.PASCAL * LengthUnit.METER * PressureUnit.PASCAL /TimeUnit.SECOND\n            >>> composite\n            <CompositeDimension: Pa * Pa * m / s>\n            >>> composite.simplified()\n            <CompositeDimension: (Pa^2) * m / s>\n        \"\"\"\n        copy = replace(self)\n        copy.simplify()\n        return copy\n\n    def inverse(self) -> \"CompositeDimension\":\n        \"\"\"\n        Create a composite with inverse units.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit):\n            ...     METER = \"m\"\n            >>> class TimeUnit(MeasurementUnit):\n            ...     SECOND = \"s\"\n\n            >>> (LengthUnit.METER / TimeUnit.SECOND).inverse()\n            <CompositeDimension: s / m>\n        \"\"\"\n        return CompositeDimension(self._denominator_copy(), self._numerator_copy())\n\n    def has_no_units(self) -> bool:\n        \"\"\"\n        Returns True if the composite dimension does not have any units, False otherwise.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit):\n            ...     METER = \"m\"\n\n            >>> CompositeDimension().has_no_units()\n            True\n            >>> CompositeDimension([LengthUnit.METER]).has_no_units()\n            False\n        \"\"\"\n        return len(self.denominator) == 0 and len(self.numerator) == 0\n\n    def _numerator_copy(self) -> List[Dimension]:\n        return [replace(n) for n in self.numerator]\n\n    def _denominator_copy(self) -> List[Dimension]:\n        return [replace(d) for d in self.denominator]\n\n    def __mul__(self, descriptor: \"UnitDescriptor\") -> \"CompositeDimension\":\n        \"\"\"\n        Defines multiplication between CompositeDimension(s) and other unit descriptors.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     CELCIUS = \"C\"\n            >>> class TimeUnit(MeasurementUnit):\n            ...     SECOND = \"s\"\n            >>> class LengthUnit(MeasurementUnit):\n            ...     CENTI_METER = \"cm\"\n            >>> (TemperatureUnit.CELCIUS / LengthUnit.CENTI_METER) * TimeUnit.SECOND\n            <CompositeDimension: C * s / cm>\n        \"\"\"\n        numerator = self.numerator.copy()\n        denominator = self.denominator.copy()\n        if isinstance(descriptor, CompositeDimension):\n            numerator.extend(descriptor.numerator)\n            denominator.extend(descriptor.denominator)\n            return CompositeDimension(numerator=numerator, denominator=denominator)\n        if isinstance(descriptor, Dimension):\n            numerator.append(descriptor)\n            return CompositeDimension(numerator=numerator, denominator=denominator)\n        if isinstance(descriptor, MeasurementUnit):\n            numerator.append(Dimension(descriptor))\n            return CompositeDimension(numerator=numerator, denominator=denominator)\n        raise DescriptorBinaryOperationError(\n            f\"cannot multiply {self} with {descriptor}. \"\n        )\n\n    def __truediv__(self, descriptor: \"UnitDescriptor\") -> \"CompositeDimension\":\n        \"\"\"\n        Defines multiplication between CompositeDimension(s) and other unit descriptors.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     CELCIUS = \"C\"\n            >>> class TimeUnit(MeasurementUnit):\n            ...     SECOND = \"s\"\n            >>> class LengthUnit(MeasurementUnit):\n            ...     CENTI_METER = \"cm\"\n            >>> (TemperatureUnit.CELCIUS * LengthUnit.CENTI_METER) / TimeUnit.SECOND\n            <CompositeDimension: C * cm / s>\n        \"\"\"\n        numerator = self.numerator.copy()\n        denominator = self.denominator.copy()\n        if isinstance(descriptor, CompositeDimension):\n            numerator.extend(descriptor.denominator)\n            denominator.extend(descriptor.numerator)\n            return CompositeDimension(numerator=numerator, denominator=denominator)\n        if isinstance(descriptor, Dimension):\n            denominator.append(descriptor)\n            return CompositeDimension(numerator=numerator, denominator=denominator)\n        if isinstance(descriptor, MeasurementUnit):\n            denominator.append(Dimension(descriptor))\n            return CompositeDimension(numerator=numerator, denominator=denominator)\n        raise DescriptorBinaryOperationError(\n            f\"cannot divide {self} with {descriptor}. \"\n        )\n\n    def __pow__(self, power: float) -> \"CompositeDimension\":\n        \"\"\"\n        Defines exponentiation for CompositeDimension(s).\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     CELCIUS = \"C\"\n            >>> class TimeUnit(MeasurementUnit):\n            ...     HOUR = \"hr\"\n\n            >>> (TemperatureUnit.CELCIUS / TimeUnit.HOUR)**2\n            <CompositeDimension: (C^2) / (hr^2)>\n        \"\"\"\n        if not isinstance(power, (float, int)):\n            raise DescriptorExponentError(\n                f\"invalid exponent: {{ value: {power}, type: {type(power)} }};\"\n                \" expected float or int. \"\n            )\n        numerator = [n**power for n in self._numerator_copy()]\n        denominator = [d**power for d in self._denominator_copy()]\n        return CompositeDimension(numerator, denominator)\n\n    def __eq__(self, dimension) -> bool:\n        \"\"\"\n        Defines equality for CompositeDimension(s).\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     CELCIUS = \"C\"\n            >>> class TimeUnit(MeasurementUnit):\n            ...     HOUR = \"hr\"\n            >>> (TemperatureUnit.CELCIUS / TimeUnit.HOUR) != (TimeUnit.HOUR / TemperatureUnit.CELCIUS)\n            True\n        \"\"\"\n        if not isinstance(dimension, CompositeDimension):\n            return False\n        return Counter(self.numerator) == Counter(dimension.numerator) and (\n            Counter(self.denominator) == Counter(dimension.denominator)\n        )\n\n    def __hash__(self) -> int:\n        return hash(str(self))\n\n    def __str__(self):\n        numerators = \" * \".join(sorted([str(n) for n in self.numerator]))\n        denominators = \" / \".join(sorted([str(d) for d in self.denominator]))\n        if len(denominators) > 0:\n            denominators = \" / \" + denominators\n        return numerators + denominators\n\n    def __repr__(self) -> str:\n        numerators = \" * \".join(sorted([str(n) for n in self.numerator]))\n        denominators = \" / \".join(sorted([str(d) for d in self.denominator]))\n        if len(denominators) > 0:\n            denominators = \" / \" + denominators\n        return f\"<CompositeDimension: {numerators + denominators}>\"\n
    "},{"location":"descriptors/#property_utils.units.descriptors.CompositeDimension.__eq__","title":"__eq__(dimension)","text":"

    Defines equality for CompositeDimension(s).

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     CELCIUS = \"C\"\n>>> class TimeUnit(MeasurementUnit):\n...     HOUR = \"hr\"\n>>> (TemperatureUnit.CELCIUS / TimeUnit.HOUR) != (TimeUnit.HOUR / TemperatureUnit.CELCIUS)\nTrue\n
    Source code in src/property_utils/units/descriptors.py
    def __eq__(self, dimension) -> bool:\n    \"\"\"\n    Defines equality for CompositeDimension(s).\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     CELCIUS = \"C\"\n        >>> class TimeUnit(MeasurementUnit):\n        ...     HOUR = \"hr\"\n        >>> (TemperatureUnit.CELCIUS / TimeUnit.HOUR) != (TimeUnit.HOUR / TemperatureUnit.CELCIUS)\n        True\n    \"\"\"\n    if not isinstance(dimension, CompositeDimension):\n        return False\n    return Counter(self.numerator) == Counter(dimension.numerator) and (\n        Counter(self.denominator) == Counter(dimension.denominator)\n    )\n
    "},{"location":"descriptors/#property_utils.units.descriptors.CompositeDimension.__mul__","title":"__mul__(descriptor)","text":"

    Defines multiplication between CompositeDimension(s) and other unit descriptors.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     CELCIUS = \"C\"\n>>> class TimeUnit(MeasurementUnit):\n...     SECOND = \"s\"\n>>> class LengthUnit(MeasurementUnit):\n...     CENTI_METER = \"cm\"\n>>> (TemperatureUnit.CELCIUS / LengthUnit.CENTI_METER) * TimeUnit.SECOND\n<CompositeDimension: C * s / cm>\n
    Source code in src/property_utils/units/descriptors.py
    def __mul__(self, descriptor: \"UnitDescriptor\") -> \"CompositeDimension\":\n    \"\"\"\n    Defines multiplication between CompositeDimension(s) and other unit descriptors.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     CELCIUS = \"C\"\n        >>> class TimeUnit(MeasurementUnit):\n        ...     SECOND = \"s\"\n        >>> class LengthUnit(MeasurementUnit):\n        ...     CENTI_METER = \"cm\"\n        >>> (TemperatureUnit.CELCIUS / LengthUnit.CENTI_METER) * TimeUnit.SECOND\n        <CompositeDimension: C * s / cm>\n    \"\"\"\n    numerator = self.numerator.copy()\n    denominator = self.denominator.copy()\n    if isinstance(descriptor, CompositeDimension):\n        numerator.extend(descriptor.numerator)\n        denominator.extend(descriptor.denominator)\n        return CompositeDimension(numerator=numerator, denominator=denominator)\n    if isinstance(descriptor, Dimension):\n        numerator.append(descriptor)\n        return CompositeDimension(numerator=numerator, denominator=denominator)\n    if isinstance(descriptor, MeasurementUnit):\n        numerator.append(Dimension(descriptor))\n        return CompositeDimension(numerator=numerator, denominator=denominator)\n    raise DescriptorBinaryOperationError(\n        f\"cannot multiply {self} with {descriptor}. \"\n    )\n
    "},{"location":"descriptors/#property_utils.units.descriptors.CompositeDimension.__pow__","title":"__pow__(power)","text":"

    Defines exponentiation for CompositeDimension(s).

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     CELCIUS = \"C\"\n>>> class TimeUnit(MeasurementUnit):\n...     HOUR = \"hr\"\n
    >>> (TemperatureUnit.CELCIUS / TimeUnit.HOUR)**2\n<CompositeDimension: (C^2) / (hr^2)>\n
    Source code in src/property_utils/units/descriptors.py
    def __pow__(self, power: float) -> \"CompositeDimension\":\n    \"\"\"\n    Defines exponentiation for CompositeDimension(s).\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     CELCIUS = \"C\"\n        >>> class TimeUnit(MeasurementUnit):\n        ...     HOUR = \"hr\"\n\n        >>> (TemperatureUnit.CELCIUS / TimeUnit.HOUR)**2\n        <CompositeDimension: (C^2) / (hr^2)>\n    \"\"\"\n    if not isinstance(power, (float, int)):\n        raise DescriptorExponentError(\n            f\"invalid exponent: {{ value: {power}, type: {type(power)} }};\"\n            \" expected float or int. \"\n        )\n    numerator = [n**power for n in self._numerator_copy()]\n    denominator = [d**power for d in self._denominator_copy()]\n    return CompositeDimension(numerator, denominator)\n
    "},{"location":"descriptors/#property_utils.units.descriptors.CompositeDimension.__truediv__","title":"__truediv__(descriptor)","text":"

    Defines multiplication between CompositeDimension(s) and other unit descriptors.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     CELCIUS = \"C\"\n>>> class TimeUnit(MeasurementUnit):\n...     SECOND = \"s\"\n>>> class LengthUnit(MeasurementUnit):\n...     CENTI_METER = \"cm\"\n>>> (TemperatureUnit.CELCIUS * LengthUnit.CENTI_METER) / TimeUnit.SECOND\n<CompositeDimension: C * cm / s>\n
    Source code in src/property_utils/units/descriptors.py
    def __truediv__(self, descriptor: \"UnitDescriptor\") -> \"CompositeDimension\":\n    \"\"\"\n    Defines multiplication between CompositeDimension(s) and other unit descriptors.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     CELCIUS = \"C\"\n        >>> class TimeUnit(MeasurementUnit):\n        ...     SECOND = \"s\"\n        >>> class LengthUnit(MeasurementUnit):\n        ...     CENTI_METER = \"cm\"\n        >>> (TemperatureUnit.CELCIUS * LengthUnit.CENTI_METER) / TimeUnit.SECOND\n        <CompositeDimension: C * cm / s>\n    \"\"\"\n    numerator = self.numerator.copy()\n    denominator = self.denominator.copy()\n    if isinstance(descriptor, CompositeDimension):\n        numerator.extend(descriptor.denominator)\n        denominator.extend(descriptor.numerator)\n        return CompositeDimension(numerator=numerator, denominator=denominator)\n    if isinstance(descriptor, Dimension):\n        denominator.append(descriptor)\n        return CompositeDimension(numerator=numerator, denominator=denominator)\n    if isinstance(descriptor, MeasurementUnit):\n        denominator.append(Dimension(descriptor))\n        return CompositeDimension(numerator=numerator, denominator=denominator)\n    raise DescriptorBinaryOperationError(\n        f\"cannot divide {self} with {descriptor}. \"\n    )\n
    "},{"location":"descriptors/#property_utils.units.descriptors.CompositeDimension.from_descriptor","title":"from_descriptor(descriptor) staticmethod","text":"

    Create a CompositeDimension from given descriptor. If descriptor is already a CompositeDimension, it returns the same object.

    This function does not serve as a constructor for CompositeDimension, rather it is intended to be used to convert an unknown unit descriptor to a CompositeDimension.

    Raises UnitDescriptorTypeError if given descriptor cannot be translated to a CompositeDimension instance.

    Source code in src/property_utils/units/descriptors.py
    @staticmethod\ndef from_descriptor(descriptor: UnitDescriptor) -> \"CompositeDimension\":\n    \"\"\"\n    Create a CompositeDimension from given descriptor.\n    If descriptor is already a CompositeDimension, it returns the same object.\n\n    This function does not serve as a constructor for CompositeDimension, rather it\n    is intended to be used to convert an unknown unit descriptor to a\n    CompositeDimension.\n\n    Raises `UnitDescriptorTypeError` if given descriptor cannot be translated\n    to a CompositeDimension instance.\n    \"\"\"\n    if not isinstance(descriptor, CompositeDimension):\n        raise UnitDescriptorTypeError(\n            f\"cannot create CompositeDimension from descriptor {descriptor}\"\n        )\n    return descriptor\n
    "},{"location":"descriptors/#property_utils.units.descriptors.CompositeDimension.get_denominator","title":"get_denominator(generic, default=None)","text":"

    Get a dimension from the denominator. If the dimension is not found it returns the default.

    Examples:

    >>> class LengthUnit(MeasurementUnit):\n...     METER = \"m\"\n
    >>> class TemperatureUnit(MeasurementUnit):\n...     KELVIN = \"K\"\n
    >>> composite = TemperatureUnit.KELVIN / (LengthUnit.METER**3)\n>>> composite.get_denominator(LengthUnit**3)\n<Dimension: m^3>\n>>> composite.get_denominator(LengthUnit, \"default\")\n'default'\n
    Source code in src/property_utils/units/descriptors.py
    def get_denominator(\n    self,\n    generic: Union[MeasurementUnitType, GenericDimension],\n    default: Optional[Default] = None,\n) -> Union[Dimension, Optional[Default]]:\n    \"\"\"\n    Get a dimension from the denominator. If the dimension is not found it returns\n    the default.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit):\n        ...     METER = \"m\"\n\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     KELVIN = \"K\"\n\n        >>> composite = TemperatureUnit.KELVIN / (LengthUnit.METER**3)\n        >>> composite.get_denominator(LengthUnit**3)\n        <Dimension: m^3>\n        >>> composite.get_denominator(LengthUnit, \"default\")\n        'default'\n    \"\"\"\n    for d in self.denominator:\n        if d.isinstance(generic):\n            return d\n    return default\n
    "},{"location":"descriptors/#property_utils.units.descriptors.CompositeDimension.get_numerator","title":"get_numerator(generic, default=None)","text":"

    Get a dimension from the numerator. If the dimension is not found it returns the default.

    Examples:

    >>> class LengthUnit(MeasurementUnit):\n...     METER = \"m\"\n
    >>> class TemperatureUnit(MeasurementUnit):\n...     KELVIN = \"K\"\n
    >>> composite = TemperatureUnit.KELVIN / (LengthUnit.METER**3)\n>>> composite.get_numerator(TemperatureUnit)\n<Dimension: K>\n>>> composite.get_numerator(LengthUnit, \"default\")\n'default'\n
    Source code in src/property_utils/units/descriptors.py
    def get_numerator(\n    self,\n    generic: Union[MeasurementUnitType, GenericDimension],\n    default: Optional[Default] = None,\n) -> Union[Dimension, Optional[Default]]:\n    \"\"\"\n    Get a dimension from the numerator. If the dimension is not found it returns\n    the default.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit):\n        ...     METER = \"m\"\n\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     KELVIN = \"K\"\n\n        >>> composite = TemperatureUnit.KELVIN / (LengthUnit.METER**3)\n        >>> composite.get_numerator(TemperatureUnit)\n        <Dimension: K>\n        >>> composite.get_numerator(LengthUnit, \"default\")\n        'default'\n    \"\"\"\n    for n in self.numerator:\n        if n.isinstance(generic):\n            return n\n    return default\n
    "},{"location":"descriptors/#property_utils.units.descriptors.CompositeDimension.has_no_units","title":"has_no_units()","text":"

    Returns True if the composite dimension does not have any units, False otherwise.

    Examples:

    >>> class LengthUnit(MeasurementUnit):\n...     METER = \"m\"\n
    >>> CompositeDimension().has_no_units()\nTrue\n>>> CompositeDimension([LengthUnit.METER]).has_no_units()\nFalse\n
    Source code in src/property_utils/units/descriptors.py
    def has_no_units(self) -> bool:\n    \"\"\"\n    Returns True if the composite dimension does not have any units, False otherwise.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit):\n        ...     METER = \"m\"\n\n        >>> CompositeDimension().has_no_units()\n        True\n        >>> CompositeDimension([LengthUnit.METER]).has_no_units()\n        False\n    \"\"\"\n    return len(self.denominator) == 0 and len(self.numerator) == 0\n
    "},{"location":"descriptors/#property_utils.units.descriptors.CompositeDimension.inverse","title":"inverse()","text":"

    Create a composite with inverse units.

    Examples:

    >>> class LengthUnit(MeasurementUnit):\n...     METER = \"m\"\n>>> class TimeUnit(MeasurementUnit):\n...     SECOND = \"s\"\n
    >>> (LengthUnit.METER / TimeUnit.SECOND).inverse()\n<CompositeDimension: s / m>\n
    Source code in src/property_utils/units/descriptors.py
    def inverse(self) -> \"CompositeDimension\":\n    \"\"\"\n    Create a composite with inverse units.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit):\n        ...     METER = \"m\"\n        >>> class TimeUnit(MeasurementUnit):\n        ...     SECOND = \"s\"\n\n        >>> (LengthUnit.METER / TimeUnit.SECOND).inverse()\n        <CompositeDimension: s / m>\n    \"\"\"\n    return CompositeDimension(self._denominator_copy(), self._numerator_copy())\n
    "},{"location":"descriptors/#property_utils.units.descriptors.CompositeDimension.isinstance","title":"isinstance(generic)","text":"

    Returns True if the CompositeDimension is an instance of the generic, False otherwise.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     CELCIUS = \"C\"\n
    >>> class LengthUnit(MeasurementUnit):\n...     METER = \"m\"\n
    >>> (TemperatureUnit.CELCIUS / LengthUnit.METER).isinstance(TemperatureUnit / LengthUnit)\nTrue\n
    >>> (TemperatureUnit.CELCIUS * LengthUnit.METER).isinstance(TemperatureUnit**2)\nFalse\n
    Source code in src/property_utils/units/descriptors.py
    def isinstance(self, generic: GenericUnitDescriptor) -> bool:\n    \"\"\"\n    Returns True if the CompositeDimension is an instance of the generic, False\n    otherwise.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     CELCIUS = \"C\"\n\n        >>> class LengthUnit(MeasurementUnit):\n        ...     METER = \"m\"\n\n        >>> (TemperatureUnit.CELCIUS / LengthUnit.METER).isinstance(TemperatureUnit / LengthUnit)\n        True\n\n        >>> (TemperatureUnit.CELCIUS * LengthUnit.METER).isinstance(TemperatureUnit**2)\n        False\n    \"\"\"\n    if not isinstance(generic, GenericCompositeDimension):\n        return False\n\n    return self.to_generic() == generic\n
    "},{"location":"descriptors/#property_utils.units.descriptors.CompositeDimension.isinstance_equivalent","title":"isinstance_equivalent(generic)","text":"

    Returns True if the UnitDescriptor is an instance-equivalent of the generic, False otherwise.

    A unit descriptor is an instance-equivalent of a generic if the generic of the unit descriptor is equivalent to the generic.

    Equivalence between generics is checked with the is_equivalent method.

    Examples:

    >>> class MassUnit(MeasurementUnit):\n...     KILO_GRAM = \"kg\"\n>>> class LengthUnit(MeasurementUnit):\n...     METER = \"m\"\n>>> class TimeUnit(MeasurementUnit):\n...     SECOND = \"s\"\n
    >>> class ForceUnit(AliasMeasurementUnit):\n...     NEWTON = \"N\"\n...     @classmethod\n...     def aliased_generic_descriptor(cls):\n...         return MassUnit * LengthUnit / (TimeUnit**2)\n
    >>> (MassUnit.KILO_GRAM * LengthUnit.METER / (TimeUnit.SECOND**2)).isinstance_equivalent(ForceUnit)\nTrue\n
    Source code in src/property_utils/units/descriptors.py
    def isinstance_equivalent(self, generic: GenericUnitDescriptor) -> bool:\n    \"\"\"\n    Returns True if the UnitDescriptor is an instance-equivalent of the generic,\n    False otherwise.\n\n    A unit descriptor is an instance-equivalent of a generic if the generic of the\n    unit descriptor is equivalent to the generic.\n\n    Equivalence between generics is checked with the `is_equivalent` method.\n\n    Examples:\n        >>> class MassUnit(MeasurementUnit):\n        ...     KILO_GRAM = \"kg\"\n        >>> class LengthUnit(MeasurementUnit):\n        ...     METER = \"m\"\n        >>> class TimeUnit(MeasurementUnit):\n        ...     SECOND = \"s\"\n\n        >>> class ForceUnit(AliasMeasurementUnit):\n        ...     NEWTON = \"N\"\n        ...     @classmethod\n        ...     def aliased_generic_descriptor(cls):\n        ...         return MassUnit * LengthUnit / (TimeUnit**2)\n\n        >>> (MassUnit.KILO_GRAM * LengthUnit.METER / (TimeUnit.SECOND**2)).isinstance_equivalent(ForceUnit)\n        True\n    \"\"\"\n    return self.to_generic().is_equivalent(generic)\n
    "},{"location":"descriptors/#property_utils.units.descriptors.CompositeDimension.si","title":"si()","text":"

    Returns this composite dimension in SI units.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     KELVIN = \"K\"\n...     RANKINE = \"R\"\n...     @classmethod\n...     def si(cls): return cls.KELVIN\n
    >>> class LengthUnit(MeasurementUnit):\n...     METER = \"m\"\n...     FOOT = \"ft\"\n...     @classmethod\n...     def si(cls): return cls.METER\n
    >>> (TemperatureUnit.RANKINE / LengthUnit.FOOT**2).si()\n<CompositeDimension: K / (m^2)>\n
    Source code in src/property_utils/units/descriptors.py
    def si(self) -> \"CompositeDimension\":\n    \"\"\"\n    Returns this composite dimension in SI units.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     KELVIN = \"K\"\n        ...     RANKINE = \"R\"\n        ...     @classmethod\n        ...     def si(cls): return cls.KELVIN\n\n        >>> class LengthUnit(MeasurementUnit):\n        ...     METER = \"m\"\n        ...     FOOT = \"ft\"\n        ...     @classmethod\n        ...     def si(cls): return cls.METER\n\n        >>> (TemperatureUnit.RANKINE / LengthUnit.FOOT**2).si()\n        <CompositeDimension: K / (m^2)>\n    \"\"\"\n    return CompositeDimension(\n        [n.si() for n in self.numerator], [d.si() for d in self.denominator]\n    )\n
    "},{"location":"descriptors/#property_utils.units.descriptors.CompositeDimension.simplified","title":"simplified()","text":"

    Returns a simplified version of this composite dimension as a new object.

    Examples:

    >>> class PressureUnit(AliasMeasurementUnit):\n...     BAR = \"bar\"\n...     PASCAL = \"Pa\"\n
    >>> class TemperatureUnit(MeasurementUnit):\n...     KELVIN = \"K\"\n
    >>> class LengthUnit(MeasurementUnit):\n...     METER = \"m\"\n
    >>> class TimeUnit(MeasurementUnit):\n...     SECOND = \"s\"\n
    >>> composite = (PressureUnit.BAR**(-2)) / (TemperatureUnit.KELVIN**(-1))\n>>> composite\n<CompositeDimension: (bar^-2) / (K^-1)>\n>>> composite.simplified()\n<CompositeDimension: K / (bar^2)>\n
    >>> composite = PressureUnit.PASCAL * LengthUnit.METER * PressureUnit.PASCAL /TimeUnit.SECOND\n>>> composite\n<CompositeDimension: Pa * Pa * m / s>\n>>> composite.simplified()\n<CompositeDimension: (Pa^2) * m / s>\n
    Source code in src/property_utils/units/descriptors.py
    def simplified(self) -> \"CompositeDimension\":\n    \"\"\"\n    Returns a simplified version of this composite dimension as a new object.\n\n    Examples:\n        >>> class PressureUnit(AliasMeasurementUnit):\n        ...     BAR = \"bar\"\n        ...     PASCAL = \"Pa\"\n\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     KELVIN = \"K\"\n\n        >>> class LengthUnit(MeasurementUnit):\n        ...     METER = \"m\"\n\n        >>> class TimeUnit(MeasurementUnit):\n        ...     SECOND = \"s\"\n\n        >>> composite = (PressureUnit.BAR**(-2)) / (TemperatureUnit.KELVIN**(-1))\n        >>> composite\n        <CompositeDimension: (bar^-2) / (K^-1)>\n        >>> composite.simplified()\n        <CompositeDimension: K / (bar^2)>\n\n        >>> composite = PressureUnit.PASCAL * LengthUnit.METER * PressureUnit.PASCAL /TimeUnit.SECOND\n        >>> composite\n        <CompositeDimension: Pa * Pa * m / s>\n        >>> composite.simplified()\n        <CompositeDimension: (Pa^2) * m / s>\n    \"\"\"\n    copy = replace(self)\n    copy.simplify()\n    return copy\n
    "},{"location":"descriptors/#property_utils.units.descriptors.CompositeDimension.simplify","title":"simplify()","text":"

    Simplify the composite by merging common dimensions.

    Examples:

    >>> class PressureUnit(AliasMeasurementUnit):\n...     BAR = \"bar\"\n...     PASCAL = \"Pa\"\n
    >>> class TemperatureUnit(MeasurementUnit):\n...     KELVIN = \"K\"\n
    >>> class LengthUnit(MeasurementUnit):\n...     METER = \"m\"\n
    >>> class TimeUnit(MeasurementUnit):\n...     SECOND = \"s\"\n
    >>> composite = (PressureUnit.BAR**(-2)) / (TemperatureUnit.KELVIN**(-1))\n>>> composite\n<CompositeDimension: (bar^-2) / (K^-1)>\n>>> composite.simplify()\n>>> composite\n<CompositeDimension: K / (bar^2)>\n
    >>> composite = PressureUnit.PASCAL * LengthUnit.METER * PressureUnit.PASCAL /TimeUnit.SECOND\n>>> composite\n<CompositeDimension: Pa * Pa * m / s>\n>>> composite.simplify()\n>>> composite\n<CompositeDimension: (Pa^2) * m / s>\n
    Source code in src/property_utils/units/descriptors.py
    def simplify(self) -> None:\n    \"\"\"\n    Simplify the composite by merging common dimensions.\n\n    Examples:\n        >>> class PressureUnit(AliasMeasurementUnit):\n        ...     BAR = \"bar\"\n        ...     PASCAL = \"Pa\"\n\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     KELVIN = \"K\"\n\n        >>> class LengthUnit(MeasurementUnit):\n        ...     METER = \"m\"\n\n        >>> class TimeUnit(MeasurementUnit):\n        ...     SECOND = \"s\"\n\n        >>> composite = (PressureUnit.BAR**(-2)) / (TemperatureUnit.KELVIN**(-1))\n        >>> composite\n        <CompositeDimension: (bar^-2) / (K^-1)>\n        >>> composite.simplify()\n        >>> composite\n        <CompositeDimension: K / (bar^2)>\n\n        >>> composite = PressureUnit.PASCAL * LengthUnit.METER * PressureUnit.PASCAL /TimeUnit.SECOND\n        >>> composite\n        <CompositeDimension: Pa * Pa * m / s>\n        >>> composite.simplify()\n        >>> composite\n        <CompositeDimension: (Pa^2) * m / s>\n    \"\"\"\n    exponents: Dict[MeasurementUnit, float] = {}\n    for n in self.numerator:\n        if n.unit in exponents:\n            exponents[n.unit] += n.power\n        else:\n            exponents[n.unit] = n.power\n\n    for d in self.denominator:\n        if d.unit in exponents:\n            exponents[d.unit] -= d.power\n        else:\n            exponents[d.unit] = 0 - d.power\n\n    numerator = []\n    denominator = []\n    for unit, exponent in exponents.items():\n        if exponent > 0:\n            numerator.append(Dimension(unit) ** exponent)\n        elif exponent < 0:\n            denominator.append(Dimension(unit) ** abs(exponent))\n\n    self.numerator = numerator\n    self.denominator = denominator\n
    "},{"location":"descriptors/#property_utils.units.descriptors.CompositeDimension.to_generic","title":"to_generic()","text":"

    Create a generic descriptor from this CompositeDimension.

    Examples:

    >>> class AmountUnit(MeasurementUnit):\n...     MOL = \"mol\"\n
    >>> class MassUnit(MeasurementUnit):\n...     KILO_GRAM = \"kg\"\n
    >>> (AmountUnit.MOL / MassUnit.KILO_GRAM).to_generic()\n<GenericCompositeDimension: AmountUnit / MassUnit>\n
    Source code in src/property_utils/units/descriptors.py
    def to_generic(self) -> GenericCompositeDimension:\n    \"\"\"\n    Create a generic descriptor from this CompositeDimension.\n\n    Examples:\n        >>> class AmountUnit(MeasurementUnit):\n        ...     MOL = \"mol\"\n\n        >>> class MassUnit(MeasurementUnit):\n        ...     KILO_GRAM = \"kg\"\n\n        >>> (AmountUnit.MOL / MassUnit.KILO_GRAM).to_generic()\n        <GenericCompositeDimension: AmountUnit / MassUnit>\n    \"\"\"\n    return GenericCompositeDimension(\n        numerator=[n.to_generic() for n in self.numerator],\n        denominator=[d.to_generic() for d in self.denominator],\n    )\n
    "},{"location":"descriptors/#property_utils.units.descriptors.Dimension","title":"Dimension dataclass","text":"

    A Dimension is a wrapper around MeasurementUnit.

    Objects of this class can represent either a simple MeasurementUnit or a MeasurementUnit to some power.

    Examples:

    >>> class TimeUnit(MeasurementUnit):\n...     SECOND = \"s\"\n
    >>> TimeUnit.SECOND**2\n<Dimension: s^2>\n
    Source code in src/property_utils/units/descriptors.py
    @dataclass\nclass Dimension:\n    \"\"\"\n    A Dimension is a wrapper around MeasurementUnit.\n\n    Objects of this class can represent either a simple MeasurementUnit or a\n    MeasurementUnit to some power.\n\n    Examples:\n        >>> class TimeUnit(MeasurementUnit):\n        ...     SECOND = \"s\"\n\n        >>> TimeUnit.SECOND**2\n        <Dimension: s^2>\n    \"\"\"\n\n    unit: MeasurementUnit\n    power: float = 1\n\n    def __init__(self, unit: MeasurementUnit, power: float = 1) -> None:\n        if not isinstance(power, (float, int)):\n            raise DescriptorExponentError(\n                f\"invalid exponent: {{ value: {power}, type: {type(power)} }};\"\n                \" expected float or int. \"\n            )\n        self.unit = unit\n        self.power = power\n\n    @staticmethod\n    def from_descriptor(descriptor: UnitDescriptor) -> \"Dimension\":\n        \"\"\"\n        Create a Dimension from given descriptor.\n        If descriptor is already a Dimension, it returns the same object.\n\n        This function does not serve as a constructor for Dimension, rather it\n        is intended to be used to convert an unknown unit descriptor to a Dimension.\n\n        Raises `UnitDescriptorTypeError` if given descriptor cannot be translated\n        to a Dimension instance.\n        \"\"\"\n        if isinstance(descriptor, Dimension):\n            return descriptor\n        if isinstance(descriptor, MeasurementUnit):\n            return Dimension(descriptor)\n        raise UnitDescriptorTypeError(\n            f\"cannot create Dimension from descriptor: {descriptor}\"\n        )\n\n    def si(self) -> \"Dimension\":\n        \"\"\"\n        Returns this dimension in SI units.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit):\n            ...     METER = \"m\"\n            ...     FOOT = \"ft\"\n            ...     @classmethod\n            ...     def si(cls): return cls.METER\n\n            >>> (LengthUnit.FOOT**2).si()\n            <Dimension: m^2>\n        \"\"\"\n        return Dimension(self.unit.si(), self.power)\n\n    def isinstance(self, generic: GenericUnitDescriptor) -> bool:\n        \"\"\"\n        Returns True if the Dimension is an instance of the generic, False\n        otherwise.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     CELCIUS = \"C\"\n\n            >>> Dimension(TemperatureUnit.CELCIUS).isinstance(TemperatureUnit)\n            True\n\n            >>> Dimension(TemperatureUnit.CELCIUS).isinstance(TemperatureUnit**2)\n            False\n        \"\"\"\n        if isinstance(generic, MeasurementUnitType):\n            generic = GenericDimension(generic)\n        if not isinstance(generic, GenericDimension):\n            return False\n\n        if isinstance(self.unit, generic.unit_type) and self.power == generic.power:\n            return True\n\n        return False\n\n    def isinstance_equivalent(self, generic: GenericUnitDescriptor) -> bool:\n        \"\"\"\n        Returns True if the UnitDescriptor is an instance-equivalent of the generic,\n        False otherwise.\n\n        A unit descriptor is an instance-equivalent of a generic if the generic of the\n        unit descriptor is equivalent to the generic.\n\n        Equivalence between generics is checked with the `is_equivalent` method.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit):\n            ...     METER = \"m\"\n            >>> class VolumeUnit(AliasMeasurementUnit):\n            ...     @classmethod\n            ...     def aliased_generic_descriptor(cls): return LengthUnit**3\n\n            >>> (LengthUnit.METER**3).isinstance_equivalent(VolumeUnit)\n            True\n        \"\"\"\n        return self.to_generic().is_equivalent(generic)\n\n    def to_generic(self) -> GenericDimension:\n        \"\"\"\n        Create a generic descriptor from this Dimension.\n\n        Examples:\n            >>> class AmountUnit(MeasurementUnit):\n            ...     MOL = \"mol\"\n\n            >>> (AmountUnit.MOL**3.56).to_generic()\n            <GenericDimension: AmountUnit^3.56>\n        \"\"\"\n        return GenericDimension(type(self.unit), self.power)\n\n    def inverse(self) -> \"CompositeDimension\":\n        \"\"\"\n        Create a composite with inverse units.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit):\n            ...     METER = \"m\"\n            >>> (LengthUnit.METER**2).inverse()\n            <CompositeDimension:  / (m^2)>\n        \"\"\"\n        return CompositeDimension([], [replace(self)])\n\n    def _isinstance_aliased(self, generic: GenericUnitDescriptor) -> bool:\n        \"\"\"\n        Returns True if the generic is the aliased unit descriptor of this Dimension,\n        False otherwise.\n\n        Only applicable if this Dimension's unit is of type AliasMeasurementUnit.\n        \"\"\"\n        return (\n            isinstance(self.unit, AliasMeasurementUnit)\n            and (self.unit.aliased_generic_descriptor() ** self.power) == generic\n        )\n\n    def _isinstance_alias(self, generic: GenericUnitDescriptor) -> bool:\n        \"\"\"\n        Returns True if this Dimension's unit is an instance of the aliased unit\n        descriptor of the generic, False otherwise.\n\n        Only applicable if generic is an AliasMeasurementUnit.\n        \"\"\"\n        if isinstance(generic, MeasurementUnitType):\n            generic = GenericDimension(generic)\n\n        if not isinstance(generic, GenericDimension):\n            return False\n\n        if not issubclass(generic.unit_type, AliasMeasurementUnit):\n            return False\n\n        if (\n            generic.unit_type.aliased_generic_descriptor() ** generic.power\n            == self.to_generic()\n        ):\n            return True\n\n        return False\n\n    def __mul__(self, descriptor: \"UnitDescriptor\") -> \"CompositeDimension\":\n        \"\"\"\n        Defines multiplication between Dimension(s) and other unit descriptors.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     CELCIUS = \"C\"\n            >>> class TimeUnit(MeasurementUnit):\n            ...     MINUTE = \"min\"\n            >>> (TemperatureUnit.CELCIUS**3) * TimeUnit.MINUTE\n            <CompositeDimension: (C^3) * min>\n        \"\"\"\n        if isinstance(descriptor, CompositeDimension):\n            numerator = descriptor.numerator.copy()\n            denominator = descriptor.denominator.copy()\n            numerator.append(self)\n            return CompositeDimension(numerator=numerator, denominator=denominator)\n        if isinstance(descriptor, Dimension):\n            return CompositeDimension(numerator=[self, descriptor])\n        if isinstance(descriptor, MeasurementUnit):\n            return CompositeDimension(numerator=[self, Dimension(descriptor)])\n        raise DescriptorBinaryOperationError(\n            f\"cannot multiply {self} with {descriptor}. \"\n        )\n\n    def __truediv__(self, descriptor: \"UnitDescriptor\") -> \"CompositeDimension\":\n        \"\"\"\n        Defines division between Dimension(s) and other unit descriptors.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     CELCIUS = \"C\"\n            >>> class TimeUnit(MeasurementUnit):\n            ...     MINUTE = \"min\"\n            >>> (TemperatureUnit.CELCIUS**3) / TimeUnit.MINUTE\n            <CompositeDimension: (C^3) / min>\n        \"\"\"\n        if isinstance(descriptor, CompositeDimension):\n            numerator = descriptor.denominator.copy()\n            denominator = descriptor.numerator.copy()\n            numerator.append(self)\n            return CompositeDimension(numerator=numerator, denominator=denominator)\n        if isinstance(descriptor, Dimension):\n            return CompositeDimension(numerator=[self], denominator=[descriptor])\n        if isinstance(descriptor, MeasurementUnit):\n            return CompositeDimension(\n                numerator=[self], denominator=[Dimension(descriptor)]\n            )\n        raise DescriptorBinaryOperationError(\n            f\"cannot divide {self} with  {descriptor}. \"\n        )\n\n    def __pow__(self, power: float) -> \"Dimension\":\n        \"\"\"\n        Defines exponentiation for Dimension(s).\n\n        Examples:\n            >>> class TimeUnit(MeasurementUnit):\n            ...     SECOND = \"s\"\n            >>> (TimeUnit.SECOND**2)**3\n            <Dimension: s^6>\n        \"\"\"\n        if not isinstance(power, (float, int)):\n            raise DescriptorExponentError(\n                f\"invalid exponent: {{ value: {power}, type: {type(power)} }};\"\n                \" expected float or int. \"\n            )\n        self.power *= power\n        return self\n\n    def __eq__(self, dimension) -> bool:\n        \"\"\"\n        Defines equality for Dimension(s).\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     KELVIN = \"K\"\n            >>> (TemperatureUnit.KELVIN**2) != TemperatureUnit.KELVIN\n            True\n        \"\"\"\n        if not isinstance(dimension, Dimension):\n            return False\n        return self.unit == dimension.unit and self.power == dimension.power\n\n    def __hash__(self) -> int:\n        return hash(str(self))\n\n    def __repr__(self) -> str:\n        if self.power != 1:\n            return f\"<Dimension: {self.unit.value}^{self.power}>\"\n        return f\"<Dimension: {self.unit.value}>\"\n\n    def __str__(self) -> str:\n        s = self.unit.value\n        if self.power != 1:\n            return f\"({s}^{self.power})\"\n        return s\n
    "},{"location":"descriptors/#property_utils.units.descriptors.Dimension.__eq__","title":"__eq__(dimension)","text":"

    Defines equality for Dimension(s).

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     KELVIN = \"K\"\n>>> (TemperatureUnit.KELVIN**2) != TemperatureUnit.KELVIN\nTrue\n
    Source code in src/property_utils/units/descriptors.py
    def __eq__(self, dimension) -> bool:\n    \"\"\"\n    Defines equality for Dimension(s).\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     KELVIN = \"K\"\n        >>> (TemperatureUnit.KELVIN**2) != TemperatureUnit.KELVIN\n        True\n    \"\"\"\n    if not isinstance(dimension, Dimension):\n        return False\n    return self.unit == dimension.unit and self.power == dimension.power\n
    "},{"location":"descriptors/#property_utils.units.descriptors.Dimension.__mul__","title":"__mul__(descriptor)","text":"

    Defines multiplication between Dimension(s) and other unit descriptors.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     CELCIUS = \"C\"\n>>> class TimeUnit(MeasurementUnit):\n...     MINUTE = \"min\"\n>>> (TemperatureUnit.CELCIUS**3) * TimeUnit.MINUTE\n<CompositeDimension: (C^3) * min>\n
    Source code in src/property_utils/units/descriptors.py
    def __mul__(self, descriptor: \"UnitDescriptor\") -> \"CompositeDimension\":\n    \"\"\"\n    Defines multiplication between Dimension(s) and other unit descriptors.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     CELCIUS = \"C\"\n        >>> class TimeUnit(MeasurementUnit):\n        ...     MINUTE = \"min\"\n        >>> (TemperatureUnit.CELCIUS**3) * TimeUnit.MINUTE\n        <CompositeDimension: (C^3) * min>\n    \"\"\"\n    if isinstance(descriptor, CompositeDimension):\n        numerator = descriptor.numerator.copy()\n        denominator = descriptor.denominator.copy()\n        numerator.append(self)\n        return CompositeDimension(numerator=numerator, denominator=denominator)\n    if isinstance(descriptor, Dimension):\n        return CompositeDimension(numerator=[self, descriptor])\n    if isinstance(descriptor, MeasurementUnit):\n        return CompositeDimension(numerator=[self, Dimension(descriptor)])\n    raise DescriptorBinaryOperationError(\n        f\"cannot multiply {self} with {descriptor}. \"\n    )\n
    "},{"location":"descriptors/#property_utils.units.descriptors.Dimension.__pow__","title":"__pow__(power)","text":"

    Defines exponentiation for Dimension(s).

    Examples:

    >>> class TimeUnit(MeasurementUnit):\n...     SECOND = \"s\"\n>>> (TimeUnit.SECOND**2)**3\n<Dimension: s^6>\n
    Source code in src/property_utils/units/descriptors.py
    def __pow__(self, power: float) -> \"Dimension\":\n    \"\"\"\n    Defines exponentiation for Dimension(s).\n\n    Examples:\n        >>> class TimeUnit(MeasurementUnit):\n        ...     SECOND = \"s\"\n        >>> (TimeUnit.SECOND**2)**3\n        <Dimension: s^6>\n    \"\"\"\n    if not isinstance(power, (float, int)):\n        raise DescriptorExponentError(\n            f\"invalid exponent: {{ value: {power}, type: {type(power)} }};\"\n            \" expected float or int. \"\n        )\n    self.power *= power\n    return self\n
    "},{"location":"descriptors/#property_utils.units.descriptors.Dimension.__truediv__","title":"__truediv__(descriptor)","text":"

    Defines division between Dimension(s) and other unit descriptors.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     CELCIUS = \"C\"\n>>> class TimeUnit(MeasurementUnit):\n...     MINUTE = \"min\"\n>>> (TemperatureUnit.CELCIUS**3) / TimeUnit.MINUTE\n<CompositeDimension: (C^3) / min>\n
    Source code in src/property_utils/units/descriptors.py
    def __truediv__(self, descriptor: \"UnitDescriptor\") -> \"CompositeDimension\":\n    \"\"\"\n    Defines division between Dimension(s) and other unit descriptors.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     CELCIUS = \"C\"\n        >>> class TimeUnit(MeasurementUnit):\n        ...     MINUTE = \"min\"\n        >>> (TemperatureUnit.CELCIUS**3) / TimeUnit.MINUTE\n        <CompositeDimension: (C^3) / min>\n    \"\"\"\n    if isinstance(descriptor, CompositeDimension):\n        numerator = descriptor.denominator.copy()\n        denominator = descriptor.numerator.copy()\n        numerator.append(self)\n        return CompositeDimension(numerator=numerator, denominator=denominator)\n    if isinstance(descriptor, Dimension):\n        return CompositeDimension(numerator=[self], denominator=[descriptor])\n    if isinstance(descriptor, MeasurementUnit):\n        return CompositeDimension(\n            numerator=[self], denominator=[Dimension(descriptor)]\n        )\n    raise DescriptorBinaryOperationError(\n        f\"cannot divide {self} with  {descriptor}. \"\n    )\n
    "},{"location":"descriptors/#property_utils.units.descriptors.Dimension.from_descriptor","title":"from_descriptor(descriptor) staticmethod","text":"

    Create a Dimension from given descriptor. If descriptor is already a Dimension, it returns the same object.

    This function does not serve as a constructor for Dimension, rather it is intended to be used to convert an unknown unit descriptor to a Dimension.

    Raises UnitDescriptorTypeError if given descriptor cannot be translated to a Dimension instance.

    Source code in src/property_utils/units/descriptors.py
    @staticmethod\ndef from_descriptor(descriptor: UnitDescriptor) -> \"Dimension\":\n    \"\"\"\n    Create a Dimension from given descriptor.\n    If descriptor is already a Dimension, it returns the same object.\n\n    This function does not serve as a constructor for Dimension, rather it\n    is intended to be used to convert an unknown unit descriptor to a Dimension.\n\n    Raises `UnitDescriptorTypeError` if given descriptor cannot be translated\n    to a Dimension instance.\n    \"\"\"\n    if isinstance(descriptor, Dimension):\n        return descriptor\n    if isinstance(descriptor, MeasurementUnit):\n        return Dimension(descriptor)\n    raise UnitDescriptorTypeError(\n        f\"cannot create Dimension from descriptor: {descriptor}\"\n    )\n
    "},{"location":"descriptors/#property_utils.units.descriptors.Dimension.inverse","title":"inverse()","text":"

    Create a composite with inverse units.

    Examples:

    >>> class LengthUnit(MeasurementUnit):\n...     METER = \"m\"\n>>> (LengthUnit.METER**2).inverse()\n<CompositeDimension:  / (m^2)>\n
    Source code in src/property_utils/units/descriptors.py
    def inverse(self) -> \"CompositeDimension\":\n    \"\"\"\n    Create a composite with inverse units.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit):\n        ...     METER = \"m\"\n        >>> (LengthUnit.METER**2).inverse()\n        <CompositeDimension:  / (m^2)>\n    \"\"\"\n    return CompositeDimension([], [replace(self)])\n
    "},{"location":"descriptors/#property_utils.units.descriptors.Dimension.isinstance","title":"isinstance(generic)","text":"

    Returns True if the Dimension is an instance of the generic, False otherwise.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     CELCIUS = \"C\"\n
    >>> Dimension(TemperatureUnit.CELCIUS).isinstance(TemperatureUnit)\nTrue\n
    >>> Dimension(TemperatureUnit.CELCIUS).isinstance(TemperatureUnit**2)\nFalse\n
    Source code in src/property_utils/units/descriptors.py
    def isinstance(self, generic: GenericUnitDescriptor) -> bool:\n    \"\"\"\n    Returns True if the Dimension is an instance of the generic, False\n    otherwise.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     CELCIUS = \"C\"\n\n        >>> Dimension(TemperatureUnit.CELCIUS).isinstance(TemperatureUnit)\n        True\n\n        >>> Dimension(TemperatureUnit.CELCIUS).isinstance(TemperatureUnit**2)\n        False\n    \"\"\"\n    if isinstance(generic, MeasurementUnitType):\n        generic = GenericDimension(generic)\n    if not isinstance(generic, GenericDimension):\n        return False\n\n    if isinstance(self.unit, generic.unit_type) and self.power == generic.power:\n        return True\n\n    return False\n
    "},{"location":"descriptors/#property_utils.units.descriptors.Dimension.isinstance_equivalent","title":"isinstance_equivalent(generic)","text":"

    Returns True if the UnitDescriptor is an instance-equivalent of the generic, False otherwise.

    A unit descriptor is an instance-equivalent of a generic if the generic of the unit descriptor is equivalent to the generic.

    Equivalence between generics is checked with the is_equivalent method.

    Examples:

    >>> class LengthUnit(MeasurementUnit):\n...     METER = \"m\"\n>>> class VolumeUnit(AliasMeasurementUnit):\n...     @classmethod\n...     def aliased_generic_descriptor(cls): return LengthUnit**3\n
    >>> (LengthUnit.METER**3).isinstance_equivalent(VolumeUnit)\nTrue\n
    Source code in src/property_utils/units/descriptors.py
    def isinstance_equivalent(self, generic: GenericUnitDescriptor) -> bool:\n    \"\"\"\n    Returns True if the UnitDescriptor is an instance-equivalent of the generic,\n    False otherwise.\n\n    A unit descriptor is an instance-equivalent of a generic if the generic of the\n    unit descriptor is equivalent to the generic.\n\n    Equivalence between generics is checked with the `is_equivalent` method.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit):\n        ...     METER = \"m\"\n        >>> class VolumeUnit(AliasMeasurementUnit):\n        ...     @classmethod\n        ...     def aliased_generic_descriptor(cls): return LengthUnit**3\n\n        >>> (LengthUnit.METER**3).isinstance_equivalent(VolumeUnit)\n        True\n    \"\"\"\n    return self.to_generic().is_equivalent(generic)\n
    "},{"location":"descriptors/#property_utils.units.descriptors.Dimension.si","title":"si()","text":"

    Returns this dimension in SI units.

    Examples:

    >>> class LengthUnit(MeasurementUnit):\n...     METER = \"m\"\n...     FOOT = \"ft\"\n...     @classmethod\n...     def si(cls): return cls.METER\n
    >>> (LengthUnit.FOOT**2).si()\n<Dimension: m^2>\n
    Source code in src/property_utils/units/descriptors.py
    def si(self) -> \"Dimension\":\n    \"\"\"\n    Returns this dimension in SI units.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit):\n        ...     METER = \"m\"\n        ...     FOOT = \"ft\"\n        ...     @classmethod\n        ...     def si(cls): return cls.METER\n\n        >>> (LengthUnit.FOOT**2).si()\n        <Dimension: m^2>\n    \"\"\"\n    return Dimension(self.unit.si(), self.power)\n
    "},{"location":"descriptors/#property_utils.units.descriptors.Dimension.to_generic","title":"to_generic()","text":"

    Create a generic descriptor from this Dimension.

    Examples:

    >>> class AmountUnit(MeasurementUnit):\n...     MOL = \"mol\"\n
    >>> (AmountUnit.MOL**3.56).to_generic()\n<GenericDimension: AmountUnit^3.56>\n
    Source code in src/property_utils/units/descriptors.py
    def to_generic(self) -> GenericDimension:\n    \"\"\"\n    Create a generic descriptor from this Dimension.\n\n    Examples:\n        >>> class AmountUnit(MeasurementUnit):\n        ...     MOL = \"mol\"\n\n        >>> (AmountUnit.MOL**3.56).to_generic()\n        <GenericDimension: AmountUnit^3.56>\n    \"\"\"\n    return GenericDimension(type(self.unit), self.power)\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericCompositeDimension","title":"GenericCompositeDimension dataclass","text":"

    A GenericCompositeDimension represents a generic measurement unit that is composed from other generic measurement units.

    Objects of this class can represent either multiplication or division between two GenericDimension objects.

    Create objects by multiplying and diving GenericDimension or MeasurementUnitMeta class objects:

    Examples:

    >>> class LengthUnit(MeasurementUnit): ...\n>>> class AmountUnit(MeasurementUnit): ...\n
    >>> generic_molal_volume_dimension = (LengthUnit**3) / AmountUnit\n>>> generic_molal_volume_dimension\n<GenericCompositeDimension: (LengthUnit^3) / AmountUnit>\n
    Source code in src/property_utils/units/descriptors.py
    @dataclass\nclass GenericCompositeDimension:\n    \"\"\"\n    A `GenericCompositeDimension` represents a generic measurement unit that is composed\n    from other generic measurement units.\n\n    Objects of this class can represent either multiplication or division between two\n    `GenericDimension` objects.\n\n    Create objects by multiplying and diving GenericDimension or MeasurementUnitMeta\n    class objects:\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit): ...\n        >>> class AmountUnit(MeasurementUnit): ...\n\n        >>> generic_molal_volume_dimension = (LengthUnit**3) / AmountUnit\n        >>> generic_molal_volume_dimension\n        <GenericCompositeDimension: (LengthUnit^3) / AmountUnit>\n    \"\"\"\n\n    numerator: List[GenericDimension] = field(default_factory=list)\n    denominator: List[GenericDimension] = field(default_factory=list)\n\n    def to_si(self) -> \"CompositeDimension\":\n        \"\"\"\n        Create a CompositeDimension with SI units.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     KELVIN = \"K\"\n            ...     @classmethod\n            ...     def si(cls): return cls.KELVIN\n            >>> class TimeUnit(MeasurementUnit):\n            ...     SECOND = \"s\"\n            ...     @classmethod\n            ...     def si(cls): return cls.SECOND\n            >>> class LengthUnit(MeasurementUnit):\n            ...     METER = \"m\"\n            ...     @classmethod\n            ...     def si(cls): return cls.METER\n            >>> (TemperatureUnit * LengthUnit / TimeUnit).to_si()\n            <CompositeDimension: K * m / s>\n        \"\"\"\n        return CompositeDimension(\n            [n.to_si() for n in self.numerator], [d.to_si() for d in self.denominator]\n        )\n\n    def simplify(self) -> None:\n        \"\"\"\n        Simplify the composite by merging common dimensions.\n\n        Examples:\n            >>> class PressureUnit(AliasMeasurementUnit): ...\n\n            >>> class TemperatureUnit(MeasurementUnit): ...\n\n            >>> class LengthUnit(MeasurementUnit): ...\n\n            >>> class TimeUnit(MeasurementUnit): ...\n\n            >>> composite = (PressureUnit**(-2)) / (TemperatureUnit**(-1))\n            >>> composite\n            <GenericCompositeDimension: (PressureUnit^-2) / (TemperatureUnit^-1)>\n            >>> composite.simplify()\n            >>> composite\n            <GenericCompositeDimension: TemperatureUnit / (PressureUnit^2)>\n\n            >>> composite = PressureUnit * LengthUnit * PressureUnit / TimeUnit\n            >>> composite\n            <GenericCompositeDimension: LengthUnit * PressureUnit * PressureUnit / TimeUnit>\n            >>> composite.simplify()\n            >>> composite\n            <GenericCompositeDimension: (PressureUnit^2) * LengthUnit / TimeUnit>\n        \"\"\"\n        exponents: Dict[MeasurementUnitType, float] = {}\n        for n in self.numerator:\n            if n.unit_type in exponents:\n                exponents[n.unit_type] += n.power\n            else:\n                exponents[n.unit_type] = n.power\n\n        for d in self.denominator:\n            if d.unit_type in exponents:\n                exponents[d.unit_type] -= d.power\n            else:\n                exponents[d.unit_type] = 0 - d.power\n\n        numerator = []\n        denominator = []\n        for unit_type, exponent in exponents.items():\n            if exponent > 0:\n                numerator.append(GenericDimension(unit_type) ** exponent)\n            elif exponent < 0:\n                denominator.append(GenericDimension(unit_type) ** abs(exponent))\n\n        self.numerator = numerator\n        self.denominator = denominator\n\n    def simplified(self) -> \"GenericCompositeDimension\":\n        \"\"\"\n        Returns a simplified version of this composite generic as a new object.\n\n        Examples:\n            >>> class PressureUnit(AliasMeasurementUnit): ...\n\n            >>> class TemperatureUnit(MeasurementUnit): ...\n\n            >>> class LengthUnit(MeasurementUnit): ...\n\n            >>> class TimeUnit(MeasurementUnit): ...\n\n            >>> composite = (PressureUnit**(-2)) / (TemperatureUnit**(-1))\n            >>> composite\n            <GenericCompositeDimension: (PressureUnit^-2) / (TemperatureUnit^-1)>\n            >>> composite.simplified()\n            <GenericCompositeDimension: TemperatureUnit / (PressureUnit^2)>\n\n            >>> composite = PressureUnit * LengthUnit * PressureUnit /TimeUnit\n            >>> composite\n            <GenericCompositeDimension: LengthUnit * PressureUnit * PressureUnit / TimeUnit>\n            >>> composite.simplified()\n            <GenericCompositeDimension: (PressureUnit^2) * LengthUnit / TimeUnit>\n        \"\"\"\n        copy = replace(self)\n        copy.simplify()\n        return copy\n\n    def analyse(self) -> None:\n        \"\"\"\n        Analyse this composite by replacing its alias units with their aliased units.\n\n        Examples:\n            >>> class MassUnit(MeasurementUnit): ...\n            >>> class LengthUnit(MeasurementUnit): ...\n            >>> class TimeUnit(MeasurementUnit): ...\n\n            >>> class PressureUnit(AliasMeasurementUnit):\n            ...     @classmethod\n            ...     def aliased_generic_descriptor(cls) -> GenericCompositeDimension:\n            ...         return MassUnit / LengthUnit / (TimeUnit**2)\n\n            >>> composite = PressureUnit / LengthUnit\n            >>> composite\n            <GenericCompositeDimension: PressureUnit / LengthUnit>\n\n            >>> composite.analyse()\n            >>> composite\n            <GenericCompositeDimension: MassUnit / (TimeUnit^2) / LengthUnit / LengthUnit>\n        \"\"\"\n        for n in self.numerator:\n            if issubclass(n.unit_type, AliasMeasurementUnit):\n                aliased = n.unit_type.aliased_generic_descriptor() ** n.power\n                if isinstance(aliased, GenericDimension):\n                    self.numerator.append(aliased)\n                elif isinstance(aliased, GenericCompositeDimension):\n                    self.numerator.extend(aliased.numerator)\n                    self.denominator.extend(aliased.denominator)\n\n                self.numerator.remove(n)\n\n        for d in self.denominator:\n            if issubclass(d.unit_type, AliasMeasurementUnit):\n                aliased = d.unit_type.aliased_generic_descriptor() ** d.power\n                if isinstance(aliased, GenericDimension):\n                    self.denominator.append(aliased)\n                elif isinstance(aliased, GenericCompositeDimension):\n                    self.denominator.extend(aliased.numerator)\n                    self.numerator.extend(aliased.denominator)\n\n                self.denominator.remove(d)\n\n    def analysed(self) -> \"GenericCompositeDimension\":\n        \"\"\"\n        Returns an analysed version of this composite generic as a new object.\n\n        Examples:\n            >>> class MassUnit(MeasurementUnit): ...\n            >>> class LengthUnit(MeasurementUnit): ...\n            >>> class TimeUnit(MeasurementUnit): ...\n\n            >>> class PressureUnit(AliasMeasurementUnit):\n            ...     @classmethod\n            ...     def aliased_generic_descriptor(cls) -> GenericCompositeDimension:\n            ...         return MassUnit / LengthUnit / (TimeUnit**2)\n\n            >>> composite = PressureUnit / LengthUnit\n            >>> composite\n            <GenericCompositeDimension: PressureUnit / LengthUnit>\n\n            >>> composite.analysed()\n            <GenericCompositeDimension: MassUnit / (TimeUnit^2) / LengthUnit / LengthUnit>\n        \"\"\"\n        copy = replace(self)\n        copy.analyse()\n        return copy\n\n    def inverse_generic(self):\n        \"\"\"\n        Create a generic composite with inverse units.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit): ...\n            >>> class TimeUnit(MeasurementUnit): ...\n\n            >>> (LengthUnit / TimeUnit).inverse_generic()\n            <GenericCompositeDimension: TimeUnit / LengthUnit>\n        \"\"\"\n        return GenericCompositeDimension(\n            self._denominator_copy(), self._numerator_copy()\n        )\n\n    def is_equivalent(self, other: GenericUnitDescriptor) -> bool:\n        \"\"\"\n        Returns True if this generic is equivalent to the given one, False otherwise.\n\n        A generic can be equivalent with another generic if the latter or the former\n        is an alias.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit): ...\n            >>> class MassUnit(MeasurementUnit): ...\n            >>> class TimeUnit(MeasurementUnit): ...\n            >>> class ForceUnit(AliasMeasurementUnit):\n            ...     @classmethod\n            ...     def aliased_generic_descriptor(cls):\n            ...         return MassUnit * LengthUnit / (TimeUnit**2)\n\n            >>> ForceUnit.is_equivalent(MassUnit * LengthUnit / (TimeUnit**2))\n            True\n\n            >>> class EnergyUnit(AliasMeasurementUnit):\n            ...     @classmethod\n            ...     def aliased_generic_descriptor(cls):\n            ...         return ForceUnit * LengthUnit\n\n            >>> EnergyUnit.is_equivalent(MassUnit * (LengthUnit**2) / (TimeUnit**2))\n            True\n        \"\"\"\n        if isinstance(other, MeasurementUnitType):\n            if (\n                self.denominator == []\n                and len(self.numerator) == 1\n                and self.numerator[0].is_equivalent(other)\n            ):\n                return True\n\n            if issubclass(other, AliasMeasurementUnit):\n                return other.aliased_generic_descriptor().is_equivalent(self)  # type: ignore[attr-defined]\n\n        elif isinstance(other, GenericDimension):\n            if (\n                self.denominator == []\n                and len(self.numerator) == 1\n                and self.numerator[0].is_equivalent(other)\n            ):\n                return True\n\n            if issubclass(other.unit_type, AliasMeasurementUnit):\n                return (\n                    other.unit_type.aliased_generic_descriptor() ** other.power\n                ).is_equivalent(self)\n\n        elif isinstance(other, GenericCompositeDimension):\n            _generic = other.analysed().simplified()\n            _self = self.analysed().simplified()\n\n            return Counter(_self.numerator) == Counter(_generic.numerator) and (\n                Counter(_self.denominator) == Counter(_generic.denominator)\n            )\n\n        return False\n\n    def has_no_units(self) -> bool:\n        \"\"\"\n        Returns True if the generic composite dimension does not have any units, False\n        otherwise.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit): ...\n\n            >>> GenericCompositeDimension().has_no_units()\n            True\n            >>> GenericCompositeDimension([LengthUnit]).has_no_units()\n            False\n        \"\"\"\n        return len(self.denominator) == 0 and len(self.numerator) == 0\n\n    def _numerator_copy(self) -> List[GenericDimension]:\n        return [replace(n) for n in self.numerator]\n\n    def _denominator_copy(self) -> List[GenericDimension]:\n        return [replace(d) for d in self.denominator]\n\n    def __mul__(self, generic: GenericUnitDescriptor) -> \"GenericCompositeDimension\":\n        \"\"\"\n        Defines multiplication between GenericCompositeDimension(s) and other generic\n        descriptors.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit): ...\n            >>> class TimeUnit(MeasurementUnit): ...\n            >>> class LengthUnit(MeasurementUnit): ...\n            >>> (TemperatureUnit / LengthUnit) * TimeUnit\n            <GenericCompositeDimension: TemperatureUnit * TimeUnit / LengthUnit>\n        \"\"\"\n        numerator = self.numerator.copy()\n        denominator = self.denominator.copy()\n        if isinstance(generic, GenericCompositeDimension):\n            numerator.extend(generic.numerator)\n            denominator.extend(generic.denominator)\n            return GenericCompositeDimension(\n                numerator=numerator, denominator=denominator\n            )\n\n        if isinstance(generic, GenericDimension):\n            numerator.append(generic)\n            return GenericCompositeDimension(\n                numerator=numerator, denominator=denominator\n            )\n\n        if isinstance(generic, MeasurementUnitType):\n            numerator.append(GenericDimension(generic))\n            return GenericCompositeDimension(\n                numerator=numerator, denominator=denominator\n            )\n        raise DescriptorBinaryOperationError(f\"cannot multiply {self} with {generic}. \")\n\n    def __truediv__(\n        self, generic: GenericUnitDescriptor\n    ) -> \"GenericCompositeDimension\":\n        \"\"\"\n        Defines division between GenericCompositeDimension(s) and other generic\n        descriptors.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit): ...\n            >>> class TimeUnit(MeasurementUnit): ...\n            >>> class LengthUnit(MeasurementUnit): ...\n            >>> (TemperatureUnit * LengthUnit) / TimeUnit\n            <GenericCompositeDimension: LengthUnit * TemperatureUnit / TimeUnit>\n        \"\"\"\n        numerator = self.numerator.copy()\n        denominator = self.denominator.copy()\n        if isinstance(generic, GenericCompositeDimension):\n            numerator.extend(generic.denominator)\n            denominator.extend(generic.numerator)\n            return GenericCompositeDimension(\n                numerator=numerator, denominator=denominator\n            )\n        if isinstance(generic, GenericDimension):\n            denominator.append(generic)\n            return GenericCompositeDimension(\n                numerator=numerator, denominator=denominator\n            )\n        if isinstance(generic, MeasurementUnitType):\n            denominator.append(GenericDimension(generic))\n            return GenericCompositeDimension(\n                numerator=numerator, denominator=denominator\n            )\n        raise DescriptorBinaryOperationError(f\"cannot divide {self} with {generic}. \")\n\n    def __pow__(self, power: float) -> \"GenericCompositeDimension\":\n        \"\"\"\n        Defines exponentiation for GenericCompositeDimension(s).\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit): ...\n            >>> class TimeUnit(MeasurementUnit): ...\n\n            >>> (TemperatureUnit / TimeUnit)**2\n            <GenericCompositeDimension: (TemperatureUnit^2) / (TimeUnit^2)>\n        \"\"\"\n        if not isinstance(power, (float, int)):\n            raise DescriptorExponentError(\n                f\"invalid exponent: {{ value: {power}, type: {type(power)} }};\"\n                \" expected float or int. \"\n            )\n        numerator = [n**power for n in self._numerator_copy()]\n        denominator = [d**power for d in self._denominator_copy()]\n        return GenericCompositeDimension(numerator, denominator)\n\n    def __eq__(self, generic) -> bool:\n        \"\"\"\n        Defines equality for GenericCompositeDimension(s).\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit): ...\n            >>> class TimeUnit(MeasurementUnit): ...\n            >>> (TemperatureUnit / TimeUnit) != (TimeUnit / TemperatureUnit)\n            True\n        \"\"\"\n        if not isinstance(generic, GenericCompositeDimension):\n            return False\n        return Counter(self.numerator) == Counter(generic.numerator) and (\n            Counter(self.denominator) == Counter(generic.denominator)\n        )\n\n    def __hash__(self) -> int:\n        return hash(str(self))\n\n    def __str__(self) -> str:\n        numerators = \" * \".join(sorted([str(n) for n in self.numerator]))\n        denominators = \" / \".join(sorted([str(d) for d in self.denominator]))\n        if len(denominators) > 0:\n            denominators = \" / \" + denominators\n        return numerators + denominators\n\n    def __repr__(self) -> str:\n        numerators = \" * \".join(sorted([str(n) for n in self.numerator]))\n        denominators = \" / \".join(sorted([str(d) for d in self.denominator]))\n        if len(denominators) > 0:\n            denominators = \" / \" + denominators\n        return f\"<GenericCompositeDimension: {numerators + denominators}>\"\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericCompositeDimension.__eq__","title":"__eq__(generic)","text":"

    Defines equality for GenericCompositeDimension(s).

    Examples:

    >>> class TemperatureUnit(MeasurementUnit): ...\n>>> class TimeUnit(MeasurementUnit): ...\n>>> (TemperatureUnit / TimeUnit) != (TimeUnit / TemperatureUnit)\nTrue\n
    Source code in src/property_utils/units/descriptors.py
    def __eq__(self, generic) -> bool:\n    \"\"\"\n    Defines equality for GenericCompositeDimension(s).\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit): ...\n        >>> class TimeUnit(MeasurementUnit): ...\n        >>> (TemperatureUnit / TimeUnit) != (TimeUnit / TemperatureUnit)\n        True\n    \"\"\"\n    if not isinstance(generic, GenericCompositeDimension):\n        return False\n    return Counter(self.numerator) == Counter(generic.numerator) and (\n        Counter(self.denominator) == Counter(generic.denominator)\n    )\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericCompositeDimension.__mul__","title":"__mul__(generic)","text":"

    Defines multiplication between GenericCompositeDimension(s) and other generic descriptors.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit): ...\n>>> class TimeUnit(MeasurementUnit): ...\n>>> class LengthUnit(MeasurementUnit): ...\n>>> (TemperatureUnit / LengthUnit) * TimeUnit\n<GenericCompositeDimension: TemperatureUnit * TimeUnit / LengthUnit>\n
    Source code in src/property_utils/units/descriptors.py
    def __mul__(self, generic: GenericUnitDescriptor) -> \"GenericCompositeDimension\":\n    \"\"\"\n    Defines multiplication between GenericCompositeDimension(s) and other generic\n    descriptors.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit): ...\n        >>> class TimeUnit(MeasurementUnit): ...\n        >>> class LengthUnit(MeasurementUnit): ...\n        >>> (TemperatureUnit / LengthUnit) * TimeUnit\n        <GenericCompositeDimension: TemperatureUnit * TimeUnit / LengthUnit>\n    \"\"\"\n    numerator = self.numerator.copy()\n    denominator = self.denominator.copy()\n    if isinstance(generic, GenericCompositeDimension):\n        numerator.extend(generic.numerator)\n        denominator.extend(generic.denominator)\n        return GenericCompositeDimension(\n            numerator=numerator, denominator=denominator\n        )\n\n    if isinstance(generic, GenericDimension):\n        numerator.append(generic)\n        return GenericCompositeDimension(\n            numerator=numerator, denominator=denominator\n        )\n\n    if isinstance(generic, MeasurementUnitType):\n        numerator.append(GenericDimension(generic))\n        return GenericCompositeDimension(\n            numerator=numerator, denominator=denominator\n        )\n    raise DescriptorBinaryOperationError(f\"cannot multiply {self} with {generic}. \")\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericCompositeDimension.__pow__","title":"__pow__(power)","text":"

    Defines exponentiation for GenericCompositeDimension(s).

    Examples:

    >>> class TemperatureUnit(MeasurementUnit): ...\n>>> class TimeUnit(MeasurementUnit): ...\n
    >>> (TemperatureUnit / TimeUnit)**2\n<GenericCompositeDimension: (TemperatureUnit^2) / (TimeUnit^2)>\n
    Source code in src/property_utils/units/descriptors.py
    def __pow__(self, power: float) -> \"GenericCompositeDimension\":\n    \"\"\"\n    Defines exponentiation for GenericCompositeDimension(s).\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit): ...\n        >>> class TimeUnit(MeasurementUnit): ...\n\n        >>> (TemperatureUnit / TimeUnit)**2\n        <GenericCompositeDimension: (TemperatureUnit^2) / (TimeUnit^2)>\n    \"\"\"\n    if not isinstance(power, (float, int)):\n        raise DescriptorExponentError(\n            f\"invalid exponent: {{ value: {power}, type: {type(power)} }};\"\n            \" expected float or int. \"\n        )\n    numerator = [n**power for n in self._numerator_copy()]\n    denominator = [d**power for d in self._denominator_copy()]\n    return GenericCompositeDimension(numerator, denominator)\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericCompositeDimension.__truediv__","title":"__truediv__(generic)","text":"

    Defines division between GenericCompositeDimension(s) and other generic descriptors.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit): ...\n>>> class TimeUnit(MeasurementUnit): ...\n>>> class LengthUnit(MeasurementUnit): ...\n>>> (TemperatureUnit * LengthUnit) / TimeUnit\n<GenericCompositeDimension: LengthUnit * TemperatureUnit / TimeUnit>\n
    Source code in src/property_utils/units/descriptors.py
    def __truediv__(\n    self, generic: GenericUnitDescriptor\n) -> \"GenericCompositeDimension\":\n    \"\"\"\n    Defines division between GenericCompositeDimension(s) and other generic\n    descriptors.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit): ...\n        >>> class TimeUnit(MeasurementUnit): ...\n        >>> class LengthUnit(MeasurementUnit): ...\n        >>> (TemperatureUnit * LengthUnit) / TimeUnit\n        <GenericCompositeDimension: LengthUnit * TemperatureUnit / TimeUnit>\n    \"\"\"\n    numerator = self.numerator.copy()\n    denominator = self.denominator.copy()\n    if isinstance(generic, GenericCompositeDimension):\n        numerator.extend(generic.denominator)\n        denominator.extend(generic.numerator)\n        return GenericCompositeDimension(\n            numerator=numerator, denominator=denominator\n        )\n    if isinstance(generic, GenericDimension):\n        denominator.append(generic)\n        return GenericCompositeDimension(\n            numerator=numerator, denominator=denominator\n        )\n    if isinstance(generic, MeasurementUnitType):\n        denominator.append(GenericDimension(generic))\n        return GenericCompositeDimension(\n            numerator=numerator, denominator=denominator\n        )\n    raise DescriptorBinaryOperationError(f\"cannot divide {self} with {generic}. \")\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericCompositeDimension.analyse","title":"analyse()","text":"

    Analyse this composite by replacing its alias units with their aliased units.

    Examples:

    >>> class MassUnit(MeasurementUnit): ...\n>>> class LengthUnit(MeasurementUnit): ...\n>>> class TimeUnit(MeasurementUnit): ...\n
    >>> class PressureUnit(AliasMeasurementUnit):\n...     @classmethod\n...     def aliased_generic_descriptor(cls) -> GenericCompositeDimension:\n...         return MassUnit / LengthUnit / (TimeUnit**2)\n
    >>> composite = PressureUnit / LengthUnit\n>>> composite\n<GenericCompositeDimension: PressureUnit / LengthUnit>\n
    >>> composite.analyse()\n>>> composite\n<GenericCompositeDimension: MassUnit / (TimeUnit^2) / LengthUnit / LengthUnit>\n
    Source code in src/property_utils/units/descriptors.py
    def analyse(self) -> None:\n    \"\"\"\n    Analyse this composite by replacing its alias units with their aliased units.\n\n    Examples:\n        >>> class MassUnit(MeasurementUnit): ...\n        >>> class LengthUnit(MeasurementUnit): ...\n        >>> class TimeUnit(MeasurementUnit): ...\n\n        >>> class PressureUnit(AliasMeasurementUnit):\n        ...     @classmethod\n        ...     def aliased_generic_descriptor(cls) -> GenericCompositeDimension:\n        ...         return MassUnit / LengthUnit / (TimeUnit**2)\n\n        >>> composite = PressureUnit / LengthUnit\n        >>> composite\n        <GenericCompositeDimension: PressureUnit / LengthUnit>\n\n        >>> composite.analyse()\n        >>> composite\n        <GenericCompositeDimension: MassUnit / (TimeUnit^2) / LengthUnit / LengthUnit>\n    \"\"\"\n    for n in self.numerator:\n        if issubclass(n.unit_type, AliasMeasurementUnit):\n            aliased = n.unit_type.aliased_generic_descriptor() ** n.power\n            if isinstance(aliased, GenericDimension):\n                self.numerator.append(aliased)\n            elif isinstance(aliased, GenericCompositeDimension):\n                self.numerator.extend(aliased.numerator)\n                self.denominator.extend(aliased.denominator)\n\n            self.numerator.remove(n)\n\n    for d in self.denominator:\n        if issubclass(d.unit_type, AliasMeasurementUnit):\n            aliased = d.unit_type.aliased_generic_descriptor() ** d.power\n            if isinstance(aliased, GenericDimension):\n                self.denominator.append(aliased)\n            elif isinstance(aliased, GenericCompositeDimension):\n                self.denominator.extend(aliased.numerator)\n                self.numerator.extend(aliased.denominator)\n\n            self.denominator.remove(d)\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericCompositeDimension.analysed","title":"analysed()","text":"

    Returns an analysed version of this composite generic as a new object.

    Examples:

    >>> class MassUnit(MeasurementUnit): ...\n>>> class LengthUnit(MeasurementUnit): ...\n>>> class TimeUnit(MeasurementUnit): ...\n
    >>> class PressureUnit(AliasMeasurementUnit):\n...     @classmethod\n...     def aliased_generic_descriptor(cls) -> GenericCompositeDimension:\n...         return MassUnit / LengthUnit / (TimeUnit**2)\n
    >>> composite = PressureUnit / LengthUnit\n>>> composite\n<GenericCompositeDimension: PressureUnit / LengthUnit>\n
    >>> composite.analysed()\n<GenericCompositeDimension: MassUnit / (TimeUnit^2) / LengthUnit / LengthUnit>\n
    Source code in src/property_utils/units/descriptors.py
    def analysed(self) -> \"GenericCompositeDimension\":\n    \"\"\"\n    Returns an analysed version of this composite generic as a new object.\n\n    Examples:\n        >>> class MassUnit(MeasurementUnit): ...\n        >>> class LengthUnit(MeasurementUnit): ...\n        >>> class TimeUnit(MeasurementUnit): ...\n\n        >>> class PressureUnit(AliasMeasurementUnit):\n        ...     @classmethod\n        ...     def aliased_generic_descriptor(cls) -> GenericCompositeDimension:\n        ...         return MassUnit / LengthUnit / (TimeUnit**2)\n\n        >>> composite = PressureUnit / LengthUnit\n        >>> composite\n        <GenericCompositeDimension: PressureUnit / LengthUnit>\n\n        >>> composite.analysed()\n        <GenericCompositeDimension: MassUnit / (TimeUnit^2) / LengthUnit / LengthUnit>\n    \"\"\"\n    copy = replace(self)\n    copy.analyse()\n    return copy\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericCompositeDimension.has_no_units","title":"has_no_units()","text":"

    Returns True if the generic composite dimension does not have any units, False otherwise.

    Examples:

    >>> class LengthUnit(MeasurementUnit): ...\n
    >>> GenericCompositeDimension().has_no_units()\nTrue\n>>> GenericCompositeDimension([LengthUnit]).has_no_units()\nFalse\n
    Source code in src/property_utils/units/descriptors.py
    def has_no_units(self) -> bool:\n    \"\"\"\n    Returns True if the generic composite dimension does not have any units, False\n    otherwise.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit): ...\n\n        >>> GenericCompositeDimension().has_no_units()\n        True\n        >>> GenericCompositeDimension([LengthUnit]).has_no_units()\n        False\n    \"\"\"\n    return len(self.denominator) == 0 and len(self.numerator) == 0\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericCompositeDimension.inverse_generic","title":"inverse_generic()","text":"

    Create a generic composite with inverse units.

    Examples:

    >>> class LengthUnit(MeasurementUnit): ...\n>>> class TimeUnit(MeasurementUnit): ...\n
    >>> (LengthUnit / TimeUnit).inverse_generic()\n<GenericCompositeDimension: TimeUnit / LengthUnit>\n
    Source code in src/property_utils/units/descriptors.py
    def inverse_generic(self):\n    \"\"\"\n    Create a generic composite with inverse units.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit): ...\n        >>> class TimeUnit(MeasurementUnit): ...\n\n        >>> (LengthUnit / TimeUnit).inverse_generic()\n        <GenericCompositeDimension: TimeUnit / LengthUnit>\n    \"\"\"\n    return GenericCompositeDimension(\n        self._denominator_copy(), self._numerator_copy()\n    )\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericCompositeDimension.is_equivalent","title":"is_equivalent(other)","text":"

    Returns True if this generic is equivalent to the given one, False otherwise.

    A generic can be equivalent with another generic if the latter or the former is an alias.

    Examples:

    >>> class LengthUnit(MeasurementUnit): ...\n>>> class MassUnit(MeasurementUnit): ...\n>>> class TimeUnit(MeasurementUnit): ...\n>>> class ForceUnit(AliasMeasurementUnit):\n...     @classmethod\n...     def aliased_generic_descriptor(cls):\n...         return MassUnit * LengthUnit / (TimeUnit**2)\n
    >>> ForceUnit.is_equivalent(MassUnit * LengthUnit / (TimeUnit**2))\nTrue\n
    >>> class EnergyUnit(AliasMeasurementUnit):\n...     @classmethod\n...     def aliased_generic_descriptor(cls):\n...         return ForceUnit * LengthUnit\n
    >>> EnergyUnit.is_equivalent(MassUnit * (LengthUnit**2) / (TimeUnit**2))\nTrue\n
    Source code in src/property_utils/units/descriptors.py
    def is_equivalent(self, other: GenericUnitDescriptor) -> bool:\n    \"\"\"\n    Returns True if this generic is equivalent to the given one, False otherwise.\n\n    A generic can be equivalent with another generic if the latter or the former\n    is an alias.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit): ...\n        >>> class MassUnit(MeasurementUnit): ...\n        >>> class TimeUnit(MeasurementUnit): ...\n        >>> class ForceUnit(AliasMeasurementUnit):\n        ...     @classmethod\n        ...     def aliased_generic_descriptor(cls):\n        ...         return MassUnit * LengthUnit / (TimeUnit**2)\n\n        >>> ForceUnit.is_equivalent(MassUnit * LengthUnit / (TimeUnit**2))\n        True\n\n        >>> class EnergyUnit(AliasMeasurementUnit):\n        ...     @classmethod\n        ...     def aliased_generic_descriptor(cls):\n        ...         return ForceUnit * LengthUnit\n\n        >>> EnergyUnit.is_equivalent(MassUnit * (LengthUnit**2) / (TimeUnit**2))\n        True\n    \"\"\"\n    if isinstance(other, MeasurementUnitType):\n        if (\n            self.denominator == []\n            and len(self.numerator) == 1\n            and self.numerator[0].is_equivalent(other)\n        ):\n            return True\n\n        if issubclass(other, AliasMeasurementUnit):\n            return other.aliased_generic_descriptor().is_equivalent(self)  # type: ignore[attr-defined]\n\n    elif isinstance(other, GenericDimension):\n        if (\n            self.denominator == []\n            and len(self.numerator) == 1\n            and self.numerator[0].is_equivalent(other)\n        ):\n            return True\n\n        if issubclass(other.unit_type, AliasMeasurementUnit):\n            return (\n                other.unit_type.aliased_generic_descriptor() ** other.power\n            ).is_equivalent(self)\n\n    elif isinstance(other, GenericCompositeDimension):\n        _generic = other.analysed().simplified()\n        _self = self.analysed().simplified()\n\n        return Counter(_self.numerator) == Counter(_generic.numerator) and (\n            Counter(_self.denominator) == Counter(_generic.denominator)\n        )\n\n    return False\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericCompositeDimension.simplified","title":"simplified()","text":"

    Returns a simplified version of this composite generic as a new object.

    Examples:

    >>> class PressureUnit(AliasMeasurementUnit): ...\n
    >>> class TemperatureUnit(MeasurementUnit): ...\n
    >>> class LengthUnit(MeasurementUnit): ...\n
    >>> class TimeUnit(MeasurementUnit): ...\n
    >>> composite = (PressureUnit**(-2)) / (TemperatureUnit**(-1))\n>>> composite\n<GenericCompositeDimension: (PressureUnit^-2) / (TemperatureUnit^-1)>\n>>> composite.simplified()\n<GenericCompositeDimension: TemperatureUnit / (PressureUnit^2)>\n
    >>> composite = PressureUnit * LengthUnit * PressureUnit /TimeUnit\n>>> composite\n<GenericCompositeDimension: LengthUnit * PressureUnit * PressureUnit / TimeUnit>\n>>> composite.simplified()\n<GenericCompositeDimension: (PressureUnit^2) * LengthUnit / TimeUnit>\n
    Source code in src/property_utils/units/descriptors.py
    def simplified(self) -> \"GenericCompositeDimension\":\n    \"\"\"\n    Returns a simplified version of this composite generic as a new object.\n\n    Examples:\n        >>> class PressureUnit(AliasMeasurementUnit): ...\n\n        >>> class TemperatureUnit(MeasurementUnit): ...\n\n        >>> class LengthUnit(MeasurementUnit): ...\n\n        >>> class TimeUnit(MeasurementUnit): ...\n\n        >>> composite = (PressureUnit**(-2)) / (TemperatureUnit**(-1))\n        >>> composite\n        <GenericCompositeDimension: (PressureUnit^-2) / (TemperatureUnit^-1)>\n        >>> composite.simplified()\n        <GenericCompositeDimension: TemperatureUnit / (PressureUnit^2)>\n\n        >>> composite = PressureUnit * LengthUnit * PressureUnit /TimeUnit\n        >>> composite\n        <GenericCompositeDimension: LengthUnit * PressureUnit * PressureUnit / TimeUnit>\n        >>> composite.simplified()\n        <GenericCompositeDimension: (PressureUnit^2) * LengthUnit / TimeUnit>\n    \"\"\"\n    copy = replace(self)\n    copy.simplify()\n    return copy\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericCompositeDimension.simplify","title":"simplify()","text":"

    Simplify the composite by merging common dimensions.

    Examples:

    >>> class PressureUnit(AliasMeasurementUnit): ...\n
    >>> class TemperatureUnit(MeasurementUnit): ...\n
    >>> class LengthUnit(MeasurementUnit): ...\n
    >>> class TimeUnit(MeasurementUnit): ...\n
    >>> composite = (PressureUnit**(-2)) / (TemperatureUnit**(-1))\n>>> composite\n<GenericCompositeDimension: (PressureUnit^-2) / (TemperatureUnit^-1)>\n>>> composite.simplify()\n>>> composite\n<GenericCompositeDimension: TemperatureUnit / (PressureUnit^2)>\n
    >>> composite = PressureUnit * LengthUnit * PressureUnit / TimeUnit\n>>> composite\n<GenericCompositeDimension: LengthUnit * PressureUnit * PressureUnit / TimeUnit>\n>>> composite.simplify()\n>>> composite\n<GenericCompositeDimension: (PressureUnit^2) * LengthUnit / TimeUnit>\n
    Source code in src/property_utils/units/descriptors.py
    def simplify(self) -> None:\n    \"\"\"\n    Simplify the composite by merging common dimensions.\n\n    Examples:\n        >>> class PressureUnit(AliasMeasurementUnit): ...\n\n        >>> class TemperatureUnit(MeasurementUnit): ...\n\n        >>> class LengthUnit(MeasurementUnit): ...\n\n        >>> class TimeUnit(MeasurementUnit): ...\n\n        >>> composite = (PressureUnit**(-2)) / (TemperatureUnit**(-1))\n        >>> composite\n        <GenericCompositeDimension: (PressureUnit^-2) / (TemperatureUnit^-1)>\n        >>> composite.simplify()\n        >>> composite\n        <GenericCompositeDimension: TemperatureUnit / (PressureUnit^2)>\n\n        >>> composite = PressureUnit * LengthUnit * PressureUnit / TimeUnit\n        >>> composite\n        <GenericCompositeDimension: LengthUnit * PressureUnit * PressureUnit / TimeUnit>\n        >>> composite.simplify()\n        >>> composite\n        <GenericCompositeDimension: (PressureUnit^2) * LengthUnit / TimeUnit>\n    \"\"\"\n    exponents: Dict[MeasurementUnitType, float] = {}\n    for n in self.numerator:\n        if n.unit_type in exponents:\n            exponents[n.unit_type] += n.power\n        else:\n            exponents[n.unit_type] = n.power\n\n    for d in self.denominator:\n        if d.unit_type in exponents:\n            exponents[d.unit_type] -= d.power\n        else:\n            exponents[d.unit_type] = 0 - d.power\n\n    numerator = []\n    denominator = []\n    for unit_type, exponent in exponents.items():\n        if exponent > 0:\n            numerator.append(GenericDimension(unit_type) ** exponent)\n        elif exponent < 0:\n            denominator.append(GenericDimension(unit_type) ** abs(exponent))\n\n    self.numerator = numerator\n    self.denominator = denominator\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericCompositeDimension.to_si","title":"to_si()","text":"

    Create a CompositeDimension with SI units.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     KELVIN = \"K\"\n...     @classmethod\n...     def si(cls): return cls.KELVIN\n>>> class TimeUnit(MeasurementUnit):\n...     SECOND = \"s\"\n...     @classmethod\n...     def si(cls): return cls.SECOND\n>>> class LengthUnit(MeasurementUnit):\n...     METER = \"m\"\n...     @classmethod\n...     def si(cls): return cls.METER\n>>> (TemperatureUnit * LengthUnit / TimeUnit).to_si()\n<CompositeDimension: K * m / s>\n
    Source code in src/property_utils/units/descriptors.py
    def to_si(self) -> \"CompositeDimension\":\n    \"\"\"\n    Create a CompositeDimension with SI units.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     KELVIN = \"K\"\n        ...     @classmethod\n        ...     def si(cls): return cls.KELVIN\n        >>> class TimeUnit(MeasurementUnit):\n        ...     SECOND = \"s\"\n        ...     @classmethod\n        ...     def si(cls): return cls.SECOND\n        >>> class LengthUnit(MeasurementUnit):\n        ...     METER = \"m\"\n        ...     @classmethod\n        ...     def si(cls): return cls.METER\n        >>> (TemperatureUnit * LengthUnit / TimeUnit).to_si()\n        <CompositeDimension: K * m / s>\n    \"\"\"\n    return CompositeDimension(\n        [n.to_si() for n in self.numerator], [d.to_si() for d in self.denominator]\n    )\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericDimension","title":"GenericDimension dataclass","text":"

    Represents a generic property unit or a generic property unit to some power.

    e.g. a generic dimension can be a temperature dimension or a volume dimension (length dimension to the 3rd power).

    Examples:

    >>> class MassUnit(MeasurementUnit): ...\n>>> MassUnit**2\n<GenericDimension: MassUnit^2>\n
    Source code in src/property_utils/units/descriptors.py
    @dataclass\nclass GenericDimension:\n    \"\"\"\n    Represents a generic property unit or a generic property unit to some power.\n\n    e.g. a generic dimension can be a temperature dimension or a volume dimension\n    (length dimension to the 3rd power).\n\n    Examples:\n        >>> class MassUnit(MeasurementUnit): ...\n        >>> MassUnit**2\n        <GenericDimension: MassUnit^2>\n    \"\"\"\n\n    unit_type: MeasurementUnitType\n    power: float = 1\n\n    def __init__(self, unit_type: MeasurementUnitType, power: float = 1) -> None:\n        if not isinstance(power, (float, int)):\n            raise DescriptorExponentError(\n                f\"invalid exponent: {{ value: {power}, type: {type(power)} }};\"\n                \" expected float or int. \"\n            )\n        self.unit_type = unit_type\n        self.power = power\n\n    def to_si(self) -> \"Dimension\":\n        \"\"\"\n        Create a Dimension with SI units.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     CELCIUS = \"C\"\n            ...     KELVIN = \"K\"\n            ...     @classmethod\n            ...     def si(cls): return cls.KELVIN\n            >>> (TemperatureUnit**2).to_si()\n            <Dimension: K^2>\n        \"\"\"\n        return Dimension(self.unit_type.to_si(), self.power)\n\n    def inverse_generic(self) -> \"GenericCompositeDimension\":\n        \"\"\"\n        Create a generic composite with inverse units.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit): ...\n            >>> (LengthUnit**2).inverse_generic()\n            <GenericCompositeDimension:  / (LengthUnit^2)>\n        \"\"\"\n        return GenericCompositeDimension([], [replace(self)])\n\n    # pylint: disable=too-many-return-statements\n    def is_equivalent(self, other: GenericUnitDescriptor) -> bool:\n        \"\"\"\n        Returns True if this generic is equivalent to the given one, False otherwise.\n\n        A generic can be equivalent with another generic if the latter or the former\n        is an alias.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit): ...\n            >>> class MassUnit(MeasurementUnit): ...\n            >>> class TimeUnit(MeasurementUnit): ...\n            >>> class ForceUnit(AliasMeasurementUnit):\n            ...     @classmethod\n            ...     def aliased_generic_descriptor(cls):\n            ...         return MassUnit * LengthUnit / (TimeUnit**2)\n\n            >>> ForceUnit.is_equivalent(MassUnit * LengthUnit / (TimeUnit**2))\n            True\n\n            >>> class EnergyUnit(AliasMeasurementUnit):\n            ...     @classmethod\n            ...     def aliased_generic_descriptor(cls):\n            ...         return ForceUnit * LengthUnit\n\n            >>> EnergyUnit.is_equivalent(MassUnit * (LengthUnit**2) / (TimeUnit**2))\n            True\n        \"\"\"\n        if isinstance(other, MeasurementUnitType):\n            if self.unit_type == other and self.power == 1:\n                return True\n\n            if issubclass(other, AliasMeasurementUnit):\n                return other.aliased_generic_descriptor().is_equivalent(self)  # type: ignore[attr-defined]\n\n        elif isinstance(other, GenericDimension):\n            if self.unit_type == other.unit_type and self.power == other.power:\n                return True\n\n            if issubclass(other.unit_type, AliasMeasurementUnit):\n                return (\n                    other.unit_type.aliased_generic_descriptor() ** other.power\n                ).is_equivalent(self)\n\n            if issubclass(self.unit_type, AliasMeasurementUnit):\n                return (\n                    self.unit_type.aliased_generic_descriptor() ** self.power\n                ).is_equivalent(other)\n\n        elif isinstance(other, GenericCompositeDimension):\n            if (\n                other.denominator == []\n                and len(other.numerator) == 1\n                and other.numerator[0].is_equivalent(self)\n            ):\n                return True\n\n            if issubclass(self.unit_type, AliasMeasurementUnit):\n                return (\n                    self.unit_type.aliased_generic_descriptor() ** self.power\n                ).is_equivalent(other)\n\n        return False\n\n    def __mul__(self, generic: GenericUnitDescriptor) -> \"GenericCompositeDimension\":\n        \"\"\"\n        Defines multiplication between GenericDimension(s) and other generic\n        descriptors.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit): ...\n            >>> class TimeUnit(MeasurementUnit): ...\n            >>> (TemperatureUnit**2) * TimeUnit\n            <GenericCompositeDimension: (TemperatureUnit^2) * TimeUnit>\n        \"\"\"\n        if isinstance(generic, GenericCompositeDimension):\n            numerator = generic.numerator.copy()\n            denominator = generic.denominator.copy()\n            numerator.append(self)\n            return GenericCompositeDimension(\n                numerator=numerator, denominator=denominator\n            )\n        if isinstance(generic, GenericDimension):\n            return GenericCompositeDimension(numerator=[self, generic])\n        if isinstance(generic, MeasurementUnitType):\n            return GenericCompositeDimension(\n                numerator=[self, GenericDimension(generic)]\n            )\n        raise DescriptorBinaryOperationError(f\"cannot multiply {self} with {generic}. \")\n\n    def __truediv__(\n        self, generic: GenericUnitDescriptor\n    ) -> \"GenericCompositeDimension\":\n        \"\"\"\n        Defines division between GenericDimension(s) and other generic descriptors.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit): ...\n            >>> class TimeUnit(MeasurementUnit): ...\n            >>> TemperatureUnit / (TimeUnit**2)\n            <GenericCompositeDimension: TemperatureUnit / (TimeUnit^2)>\n        \"\"\"\n        if isinstance(generic, GenericCompositeDimension):\n            numerator = generic.denominator.copy()\n            denominator = generic.numerator.copy()\n            numerator.append(self)\n            return GenericCompositeDimension(\n                numerator=numerator, denominator=denominator\n            )\n        if isinstance(generic, GenericDimension):\n            return GenericCompositeDimension(numerator=[self], denominator=[generic])\n        if isinstance(generic, MeasurementUnitType):\n            return GenericCompositeDimension(\n                numerator=[self], denominator=[GenericDimension(generic)]\n            )\n        raise DescriptorBinaryOperationError(f\"cannot divide {self} with {generic}. \")\n\n    def __pow__(self, power: float) -> \"GenericDimension\":\n        \"\"\"\n        Defines exponentiation of GenericDimension.\n\n        Examples:\n            >>> class TimeUnit(MeasurementUnit): ...\n            >>> (TimeUnit**2)**3\n            <GenericDimension: TimeUnit^6>\n        \"\"\"\n        if not isinstance(power, (float, int)):\n            raise DescriptorExponentError(\n                f\"invalid exponent: {{ value: {power}, type: {type(power)} }};\"\n                \" expected float or int. \"\n            )\n        self.power *= power\n        return self\n\n    def __eq__(self, generic) -> bool:\n        \"\"\"\n        Defines equality for GenericDimension(s).\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit): ...\n            >>> (TemperatureUnit**2) != TemperatureUnit\n            True\n        \"\"\"\n        if not isinstance(generic, GenericDimension):\n            return False\n        return self.unit_type == generic.unit_type and self.power == generic.power\n\n    def __hash__(self) -> int:\n        return hash(str(self))\n\n    def __str__(self) -> str:\n        s = self.unit_type.__name__\n        if self.power != 1:\n            return f\"({s}^{self.power})\"\n        return s\n\n    def __repr__(self) -> str:\n        if self.power != 1:\n            return f\"<GenericDimension: {self.unit_type.__name__}^{self.power}>\"\n        return f\"<GenericDimension: {self.unit_type.__name__}>\"\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericDimension.__eq__","title":"__eq__(generic)","text":"

    Defines equality for GenericDimension(s).

    Examples:

    >>> class TemperatureUnit(MeasurementUnit): ...\n>>> (TemperatureUnit**2) != TemperatureUnit\nTrue\n
    Source code in src/property_utils/units/descriptors.py
    def __eq__(self, generic) -> bool:\n    \"\"\"\n    Defines equality for GenericDimension(s).\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit): ...\n        >>> (TemperatureUnit**2) != TemperatureUnit\n        True\n    \"\"\"\n    if not isinstance(generic, GenericDimension):\n        return False\n    return self.unit_type == generic.unit_type and self.power == generic.power\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericDimension.__mul__","title":"__mul__(generic)","text":"

    Defines multiplication between GenericDimension(s) and other generic descriptors.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit): ...\n>>> class TimeUnit(MeasurementUnit): ...\n>>> (TemperatureUnit**2) * TimeUnit\n<GenericCompositeDimension: (TemperatureUnit^2) * TimeUnit>\n
    Source code in src/property_utils/units/descriptors.py
    def __mul__(self, generic: GenericUnitDescriptor) -> \"GenericCompositeDimension\":\n    \"\"\"\n    Defines multiplication between GenericDimension(s) and other generic\n    descriptors.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit): ...\n        >>> class TimeUnit(MeasurementUnit): ...\n        >>> (TemperatureUnit**2) * TimeUnit\n        <GenericCompositeDimension: (TemperatureUnit^2) * TimeUnit>\n    \"\"\"\n    if isinstance(generic, GenericCompositeDimension):\n        numerator = generic.numerator.copy()\n        denominator = generic.denominator.copy()\n        numerator.append(self)\n        return GenericCompositeDimension(\n            numerator=numerator, denominator=denominator\n        )\n    if isinstance(generic, GenericDimension):\n        return GenericCompositeDimension(numerator=[self, generic])\n    if isinstance(generic, MeasurementUnitType):\n        return GenericCompositeDimension(\n            numerator=[self, GenericDimension(generic)]\n        )\n    raise DescriptorBinaryOperationError(f\"cannot multiply {self} with {generic}. \")\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericDimension.__pow__","title":"__pow__(power)","text":"

    Defines exponentiation of GenericDimension.

    Examples:

    >>> class TimeUnit(MeasurementUnit): ...\n>>> (TimeUnit**2)**3\n<GenericDimension: TimeUnit^6>\n
    Source code in src/property_utils/units/descriptors.py
    def __pow__(self, power: float) -> \"GenericDimension\":\n    \"\"\"\n    Defines exponentiation of GenericDimension.\n\n    Examples:\n        >>> class TimeUnit(MeasurementUnit): ...\n        >>> (TimeUnit**2)**3\n        <GenericDimension: TimeUnit^6>\n    \"\"\"\n    if not isinstance(power, (float, int)):\n        raise DescriptorExponentError(\n            f\"invalid exponent: {{ value: {power}, type: {type(power)} }};\"\n            \" expected float or int. \"\n        )\n    self.power *= power\n    return self\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericDimension.__truediv__","title":"__truediv__(generic)","text":"

    Defines division between GenericDimension(s) and other generic descriptors.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit): ...\n>>> class TimeUnit(MeasurementUnit): ...\n>>> TemperatureUnit / (TimeUnit**2)\n<GenericCompositeDimension: TemperatureUnit / (TimeUnit^2)>\n
    Source code in src/property_utils/units/descriptors.py
    def __truediv__(\n    self, generic: GenericUnitDescriptor\n) -> \"GenericCompositeDimension\":\n    \"\"\"\n    Defines division between GenericDimension(s) and other generic descriptors.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit): ...\n        >>> class TimeUnit(MeasurementUnit): ...\n        >>> TemperatureUnit / (TimeUnit**2)\n        <GenericCompositeDimension: TemperatureUnit / (TimeUnit^2)>\n    \"\"\"\n    if isinstance(generic, GenericCompositeDimension):\n        numerator = generic.denominator.copy()\n        denominator = generic.numerator.copy()\n        numerator.append(self)\n        return GenericCompositeDimension(\n            numerator=numerator, denominator=denominator\n        )\n    if isinstance(generic, GenericDimension):\n        return GenericCompositeDimension(numerator=[self], denominator=[generic])\n    if isinstance(generic, MeasurementUnitType):\n        return GenericCompositeDimension(\n            numerator=[self], denominator=[GenericDimension(generic)]\n        )\n    raise DescriptorBinaryOperationError(f\"cannot divide {self} with {generic}. \")\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericDimension.inverse_generic","title":"inverse_generic()","text":"

    Create a generic composite with inverse units.

    Examples:

    >>> class LengthUnit(MeasurementUnit): ...\n>>> (LengthUnit**2).inverse_generic()\n<GenericCompositeDimension:  / (LengthUnit^2)>\n
    Source code in src/property_utils/units/descriptors.py
    def inverse_generic(self) -> \"GenericCompositeDimension\":\n    \"\"\"\n    Create a generic composite with inverse units.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit): ...\n        >>> (LengthUnit**2).inverse_generic()\n        <GenericCompositeDimension:  / (LengthUnit^2)>\n    \"\"\"\n    return GenericCompositeDimension([], [replace(self)])\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericDimension.is_equivalent","title":"is_equivalent(other)","text":"

    Returns True if this generic is equivalent to the given one, False otherwise.

    A generic can be equivalent with another generic if the latter or the former is an alias.

    Examples:

    >>> class LengthUnit(MeasurementUnit): ...\n>>> class MassUnit(MeasurementUnit): ...\n>>> class TimeUnit(MeasurementUnit): ...\n>>> class ForceUnit(AliasMeasurementUnit):\n...     @classmethod\n...     def aliased_generic_descriptor(cls):\n...         return MassUnit * LengthUnit / (TimeUnit**2)\n
    >>> ForceUnit.is_equivalent(MassUnit * LengthUnit / (TimeUnit**2))\nTrue\n
    >>> class EnergyUnit(AliasMeasurementUnit):\n...     @classmethod\n...     def aliased_generic_descriptor(cls):\n...         return ForceUnit * LengthUnit\n
    >>> EnergyUnit.is_equivalent(MassUnit * (LengthUnit**2) / (TimeUnit**2))\nTrue\n
    Source code in src/property_utils/units/descriptors.py
    def is_equivalent(self, other: GenericUnitDescriptor) -> bool:\n    \"\"\"\n    Returns True if this generic is equivalent to the given one, False otherwise.\n\n    A generic can be equivalent with another generic if the latter or the former\n    is an alias.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit): ...\n        >>> class MassUnit(MeasurementUnit): ...\n        >>> class TimeUnit(MeasurementUnit): ...\n        >>> class ForceUnit(AliasMeasurementUnit):\n        ...     @classmethod\n        ...     def aliased_generic_descriptor(cls):\n        ...         return MassUnit * LengthUnit / (TimeUnit**2)\n\n        >>> ForceUnit.is_equivalent(MassUnit * LengthUnit / (TimeUnit**2))\n        True\n\n        >>> class EnergyUnit(AliasMeasurementUnit):\n        ...     @classmethod\n        ...     def aliased_generic_descriptor(cls):\n        ...         return ForceUnit * LengthUnit\n\n        >>> EnergyUnit.is_equivalent(MassUnit * (LengthUnit**2) / (TimeUnit**2))\n        True\n    \"\"\"\n    if isinstance(other, MeasurementUnitType):\n        if self.unit_type == other and self.power == 1:\n            return True\n\n        if issubclass(other, AliasMeasurementUnit):\n            return other.aliased_generic_descriptor().is_equivalent(self)  # type: ignore[attr-defined]\n\n    elif isinstance(other, GenericDimension):\n        if self.unit_type == other.unit_type and self.power == other.power:\n            return True\n\n        if issubclass(other.unit_type, AliasMeasurementUnit):\n            return (\n                other.unit_type.aliased_generic_descriptor() ** other.power\n            ).is_equivalent(self)\n\n        if issubclass(self.unit_type, AliasMeasurementUnit):\n            return (\n                self.unit_type.aliased_generic_descriptor() ** self.power\n            ).is_equivalent(other)\n\n    elif isinstance(other, GenericCompositeDimension):\n        if (\n            other.denominator == []\n            and len(other.numerator) == 1\n            and other.numerator[0].is_equivalent(self)\n        ):\n            return True\n\n        if issubclass(self.unit_type, AliasMeasurementUnit):\n            return (\n                self.unit_type.aliased_generic_descriptor() ** self.power\n            ).is_equivalent(other)\n\n    return False\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericDimension.to_si","title":"to_si()","text":"

    Create a Dimension with SI units.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     CELCIUS = \"C\"\n...     KELVIN = \"K\"\n...     @classmethod\n...     def si(cls): return cls.KELVIN\n>>> (TemperatureUnit**2).to_si()\n<Dimension: K^2>\n
    Source code in src/property_utils/units/descriptors.py
    def to_si(self) -> \"Dimension\":\n    \"\"\"\n    Create a Dimension with SI units.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     CELCIUS = \"C\"\n        ...     KELVIN = \"K\"\n        ...     @classmethod\n        ...     def si(cls): return cls.KELVIN\n        >>> (TemperatureUnit**2).to_si()\n        <Dimension: K^2>\n    \"\"\"\n    return Dimension(self.unit_type.to_si(), self.power)\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericUnitDescriptor","title":"GenericUnitDescriptor","text":"

    Bases: Protocol

    Descriptor for a property unit that does not have a specific unit.

    e.g. a generic descriptor can represent a Temperature unit that does not have a specific value like Celcius or Fahrenheit.

    Source code in src/property_utils/units/descriptors.py
    class GenericUnitDescriptor(Protocol):\n    \"\"\"\n    Descriptor for a property unit that does not have a specific unit.\n\n    e.g. a  generic descriptor can represent a Temperature unit that does not have a\n    specific value like Celcius or Fahrenheit.\n    \"\"\"\n\n    def to_si(self) -> \"UnitDescriptor\":\n        \"\"\"\n        Create a unit descriptor with SI units.\n        \"\"\"\n\n    def inverse_generic(self) -> \"GenericCompositeDimension\":\n        \"\"\"\n        Create a generic composite with inverse units.\n        \"\"\"\n\n    def is_equivalent(self, other: \"GenericUnitDescriptor\") -> bool:\n        \"\"\"\n        Returns True if this generic is equivalent to the given one, False otherwise.\n\n        A generic can be equivalent with another generic if the latter or the former\n        is an alias.\n        \"\"\"\n\n    def __mul__(\n        self, generic: \"GenericUnitDescriptor\"\n    ) -> \"GenericCompositeDimension\": ...\n\n    def __truediv__(\n        self, generic: \"GenericUnitDescriptor\"\n    ) -> \"GenericCompositeDimension\": ...\n\n    def __pow__(self, power: float) -> \"GenericUnitDescriptor\": ...\n\n    def __eq__(self, generic) -> bool: ...\n\n    def __hash__(self) -> int: ...\n\n    def __str__(self) -> str: ...\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericUnitDescriptor.inverse_generic","title":"inverse_generic()","text":"

    Create a generic composite with inverse units.

    Source code in src/property_utils/units/descriptors.py
    def inverse_generic(self) -> \"GenericCompositeDimension\":\n    \"\"\"\n    Create a generic composite with inverse units.\n    \"\"\"\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericUnitDescriptor.is_equivalent","title":"is_equivalent(other)","text":"

    Returns True if this generic is equivalent to the given one, False otherwise.

    A generic can be equivalent with another generic if the latter or the former is an alias.

    Source code in src/property_utils/units/descriptors.py
    def is_equivalent(self, other: \"GenericUnitDescriptor\") -> bool:\n    \"\"\"\n    Returns True if this generic is equivalent to the given one, False otherwise.\n\n    A generic can be equivalent with another generic if the latter or the former\n    is an alias.\n    \"\"\"\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericUnitDescriptor.to_si","title":"to_si()","text":"

    Create a unit descriptor with SI units.

    Source code in src/property_utils/units/descriptors.py
    def to_si(self) -> \"UnitDescriptor\":\n    \"\"\"\n    Create a unit descriptor with SI units.\n    \"\"\"\n
    "},{"location":"descriptors/#property_utils.units.descriptors.MeasurementUnit","title":"MeasurementUnit","text":"

    Bases: Enum

    Base class for all measurement units of physical quantities.

    Each measurement-unit class is an enumeration of the available units for a quantity.

    Subclasses should only enumerate measurement units of primitive physical quantities, i.e. units that cannot be produced from other units. e.g. length is an acceptable quantity, but volume is not because its' units are produced from length units.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     CELCIUS = \"C\"\n...     KELVIN = \"K\"\n...     RANKINE = \"R\"\n...     FAHRENHEIT = \"F\"\n
    Source code in src/property_utils/units/descriptors.py
    class MeasurementUnit(Enum, metaclass=MeasurementUnitMeta):\n    \"\"\"\n    Base class for all measurement units of physical quantities.\n\n    Each measurement-unit class is an enumeration of the available units for a\n    quantity.\n\n    Subclasses should only enumerate measurement units of primitive physical\n    quantities, i.e. units that cannot be produced from other units.\n    e.g. length is an acceptable quantity, but volume is not because its' units are\n    produced from length units.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     CELCIUS = \"C\"\n        ...     KELVIN = \"K\"\n        ...     RANKINE = \"R\"\n        ...     FAHRENHEIT = \"F\"\n    \"\"\"\n\n    @classmethod\n    def si(cls) -> \"MeasurementUnit\":\n        \"\"\"\n        Returns the SI unit of this measurement unit.\n        \"\"\"\n        raise NotImplementedError\n\n    @staticmethod\n    def from_descriptor(descriptor: UnitDescriptor) -> \"MeasurementUnit\":\n        \"\"\"\n        Create a MeasurementUnit from given descriptor.\n        If descriptor is already a MeasurementUnit, it returns the same object.\n\n        This function does not serve as a constructor for MeasurementUnit, rather it\n        is intended to be used to convert an unknown unit descriptor to a\n        MeasurementUnit.\n\n        Raises `UnitDescriptorTypeError` if given descriptor cannot be translated\n        to a MeasurementUnit instance.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     CELCIUS = \"C\"\n\n            >>> celcius = MeasurementUnit.from_descriptor(TemperatureUnit.CELCIUS**2)\n            >>> celcius\n            <TemperatureUnit: C>\n        \"\"\"\n        if isinstance(descriptor, Dimension):\n            return descriptor.unit\n        if isinstance(descriptor, MeasurementUnit):\n            return descriptor\n        raise UnitDescriptorTypeError(\n            f\"cannot create MeasurementUnit from descriptor: {descriptor}\"\n        )\n\n    def isinstance(self, generic: GenericUnitDescriptor) -> bool:\n        \"\"\"\n        Returns True if the MeasurementUnit is an instance of the generic, False\n        otherwise.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     CELCIUS = \"C\"\n\n            >>> class LengthUnit(MeasurementUnit):\n            ...     METER = \"m\"\n\n            >>> TemperatureUnit.CELCIUS.isinstance(TemperatureUnit)\n            True\n\n            >>> TemperatureUnit.CELCIUS.isinstance(LengthUnit)\n            False\n        \"\"\"\n        return type(self) == generic  # pylint: disable=unidiomatic-typecheck\n\n    def isinstance_equivalent(self, generic: GenericUnitDescriptor) -> bool:\n        \"\"\"\n        Returns True if the UnitDescriptor is an instance-equivalent of the generic,\n        False otherwise.\n\n        A unit descriptor is an instance-equivalent of a generic if the generic of the\n        unit descriptor is equivalent to the generic.\n\n        Equivalence between generics is checked with the `is_equivalent` method.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit): ...\n            >>> class AreaUnit(AliasMeasurementUnit):\n            ...     HECTARE = \"ha\"\n            ...     @classmethod\n            ...     def aliased_generic_descriptor(cls): return LengthUnit**2\n\n            >>> AreaUnit.HECTARE.isinstance_equivalent(AreaUnit)\n            True\n            >>> AreaUnit.HECTARE.isinstance_equivalent(LengthUnit**2)\n            True\n        \"\"\"\n        return self.to_generic().is_equivalent(generic)\n\n    def to_generic(self) -> GenericUnitDescriptor:\n        \"\"\"\n        Create a generic descriptor from this MeasurementUnit.\n\n        Examples:\n            >>> class AmountUnit(MeasurementUnit):\n            ...     MOL = \"mol\"\n\n            >>> AmountUnit.MOL.to_generic()\n            <MeasurementUnit: AmountUnit>\n        \"\"\"\n        return self.__class__\n\n    def inverse(self) -> \"CompositeDimension\":\n        \"\"\"\n        Create a composite with inverse units.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     KELVIN = \"K\"\n            >>> TemperatureUnit.KELVIN.inverse()\n            <CompositeDimension:  / K>\n        \"\"\"\n        return CompositeDimension([], [Dimension(self)])\n\n    def __mul__(self, descriptor: UnitDescriptor) -> \"CompositeDimension\":\n        \"\"\"\n        Defines multiplication between MeasurementUnit objects and other unit descriptors.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     FAHRENHEIT = \"F\"\n            >>> class TimeUnit(MeasurementUnit):\n            ...     HOUR = \"hr\"\n            >>> TemperatureUnit.FAHRENHEIT * TimeUnit.HOUR\n            <CompositeDimension: F * hr>\n        \"\"\"\n        if isinstance(descriptor, MeasurementUnit):\n            return Dimension(self) * Dimension(descriptor)\n        if isinstance(descriptor, (Dimension, CompositeDimension)):\n            return Dimension(self) * descriptor\n        raise DescriptorBinaryOperationError(\n            f\"cannot multiply {self} with {descriptor}. \"\n        )\n\n    def __truediv__(self, descriptor: UnitDescriptor) -> \"CompositeDimension\":\n        \"\"\"\n        Defines division between MeasurementUnit objects and other unit descriptors.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     FAHRENHEIT = \"F\"\n            >>> class TimeUnit(MeasurementUnit):\n            ...     HOUR = \"hr\"\n            >>> TemperatureUnit.FAHRENHEIT / TimeUnit.HOUR\n            <CompositeDimension: F / hr>\n        \"\"\"\n        if isinstance(descriptor, MeasurementUnit):\n            return Dimension(self) / Dimension(descriptor)\n        if isinstance(descriptor, (Dimension, CompositeDimension)):\n            return Dimension(self) / descriptor\n        raise DescriptorBinaryOperationError(\n            f\"cannot divide {self} with {descriptor}. \"\n        )\n\n    def __pow__(self, power: float) -> \"Dimension\":\n        \"\"\"\n        Defines exponentiation of MeasurementUnit objects.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit):\n            ...     FEET = \"ft\"\n            >>> LengthUnit.FEET**3\n            <Dimension: ft^3>\n        \"\"\"\n        return Dimension(self, power)\n\n    def __hash__(self) -> int:\n        return hash(self.value)\n\n    def __repr__(self) -> str:\n        return f\"<{self.__class__.__name__}: {str(self)}>\"\n\n    def __str__(self) -> str:\n        return self.value\n
    "},{"location":"descriptors/#property_utils.units.descriptors.MeasurementUnit.__mul__","title":"__mul__(descriptor)","text":"

    Defines multiplication between MeasurementUnit objects and other unit descriptors.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     FAHRENHEIT = \"F\"\n>>> class TimeUnit(MeasurementUnit):\n...     HOUR = \"hr\"\n>>> TemperatureUnit.FAHRENHEIT * TimeUnit.HOUR\n<CompositeDimension: F * hr>\n
    Source code in src/property_utils/units/descriptors.py
    def __mul__(self, descriptor: UnitDescriptor) -> \"CompositeDimension\":\n    \"\"\"\n    Defines multiplication between MeasurementUnit objects and other unit descriptors.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     FAHRENHEIT = \"F\"\n        >>> class TimeUnit(MeasurementUnit):\n        ...     HOUR = \"hr\"\n        >>> TemperatureUnit.FAHRENHEIT * TimeUnit.HOUR\n        <CompositeDimension: F * hr>\n    \"\"\"\n    if isinstance(descriptor, MeasurementUnit):\n        return Dimension(self) * Dimension(descriptor)\n    if isinstance(descriptor, (Dimension, CompositeDimension)):\n        return Dimension(self) * descriptor\n    raise DescriptorBinaryOperationError(\n        f\"cannot multiply {self} with {descriptor}. \"\n    )\n
    "},{"location":"descriptors/#property_utils.units.descriptors.MeasurementUnit.__pow__","title":"__pow__(power)","text":"

    Defines exponentiation of MeasurementUnit objects.

    Examples:

    >>> class LengthUnit(MeasurementUnit):\n...     FEET = \"ft\"\n>>> LengthUnit.FEET**3\n<Dimension: ft^3>\n
    Source code in src/property_utils/units/descriptors.py
    def __pow__(self, power: float) -> \"Dimension\":\n    \"\"\"\n    Defines exponentiation of MeasurementUnit objects.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit):\n        ...     FEET = \"ft\"\n        >>> LengthUnit.FEET**3\n        <Dimension: ft^3>\n    \"\"\"\n    return Dimension(self, power)\n
    "},{"location":"descriptors/#property_utils.units.descriptors.MeasurementUnit.__truediv__","title":"__truediv__(descriptor)","text":"

    Defines division between MeasurementUnit objects and other unit descriptors.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     FAHRENHEIT = \"F\"\n>>> class TimeUnit(MeasurementUnit):\n...     HOUR = \"hr\"\n>>> TemperatureUnit.FAHRENHEIT / TimeUnit.HOUR\n<CompositeDimension: F / hr>\n
    Source code in src/property_utils/units/descriptors.py
    def __truediv__(self, descriptor: UnitDescriptor) -> \"CompositeDimension\":\n    \"\"\"\n    Defines division between MeasurementUnit objects and other unit descriptors.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     FAHRENHEIT = \"F\"\n        >>> class TimeUnit(MeasurementUnit):\n        ...     HOUR = \"hr\"\n        >>> TemperatureUnit.FAHRENHEIT / TimeUnit.HOUR\n        <CompositeDimension: F / hr>\n    \"\"\"\n    if isinstance(descriptor, MeasurementUnit):\n        return Dimension(self) / Dimension(descriptor)\n    if isinstance(descriptor, (Dimension, CompositeDimension)):\n        return Dimension(self) / descriptor\n    raise DescriptorBinaryOperationError(\n        f\"cannot divide {self} with {descriptor}. \"\n    )\n
    "},{"location":"descriptors/#property_utils.units.descriptors.MeasurementUnit.from_descriptor","title":"from_descriptor(descriptor) staticmethod","text":"

    Create a MeasurementUnit from given descriptor. If descriptor is already a MeasurementUnit, it returns the same object.

    This function does not serve as a constructor for MeasurementUnit, rather it is intended to be used to convert an unknown unit descriptor to a MeasurementUnit.

    Raises UnitDescriptorTypeError if given descriptor cannot be translated to a MeasurementUnit instance.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     CELCIUS = \"C\"\n
    >>> celcius = MeasurementUnit.from_descriptor(TemperatureUnit.CELCIUS**2)\n>>> celcius\n<TemperatureUnit: C>\n
    Source code in src/property_utils/units/descriptors.py
    @staticmethod\ndef from_descriptor(descriptor: UnitDescriptor) -> \"MeasurementUnit\":\n    \"\"\"\n    Create a MeasurementUnit from given descriptor.\n    If descriptor is already a MeasurementUnit, it returns the same object.\n\n    This function does not serve as a constructor for MeasurementUnit, rather it\n    is intended to be used to convert an unknown unit descriptor to a\n    MeasurementUnit.\n\n    Raises `UnitDescriptorTypeError` if given descriptor cannot be translated\n    to a MeasurementUnit instance.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     CELCIUS = \"C\"\n\n        >>> celcius = MeasurementUnit.from_descriptor(TemperatureUnit.CELCIUS**2)\n        >>> celcius\n        <TemperatureUnit: C>\n    \"\"\"\n    if isinstance(descriptor, Dimension):\n        return descriptor.unit\n    if isinstance(descriptor, MeasurementUnit):\n        return descriptor\n    raise UnitDescriptorTypeError(\n        f\"cannot create MeasurementUnit from descriptor: {descriptor}\"\n    )\n
    "},{"location":"descriptors/#property_utils.units.descriptors.MeasurementUnit.inverse","title":"inverse()","text":"

    Create a composite with inverse units.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     KELVIN = \"K\"\n>>> TemperatureUnit.KELVIN.inverse()\n<CompositeDimension:  / K>\n
    Source code in src/property_utils/units/descriptors.py
    def inverse(self) -> \"CompositeDimension\":\n    \"\"\"\n    Create a composite with inverse units.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     KELVIN = \"K\"\n        >>> TemperatureUnit.KELVIN.inverse()\n        <CompositeDimension:  / K>\n    \"\"\"\n    return CompositeDimension([], [Dimension(self)])\n
    "},{"location":"descriptors/#property_utils.units.descriptors.MeasurementUnit.isinstance","title":"isinstance(generic)","text":"

    Returns True if the MeasurementUnit is an instance of the generic, False otherwise.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     CELCIUS = \"C\"\n
    >>> class LengthUnit(MeasurementUnit):\n...     METER = \"m\"\n
    >>> TemperatureUnit.CELCIUS.isinstance(TemperatureUnit)\nTrue\n
    >>> TemperatureUnit.CELCIUS.isinstance(LengthUnit)\nFalse\n
    Source code in src/property_utils/units/descriptors.py
    def isinstance(self, generic: GenericUnitDescriptor) -> bool:\n    \"\"\"\n    Returns True if the MeasurementUnit is an instance of the generic, False\n    otherwise.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     CELCIUS = \"C\"\n\n        >>> class LengthUnit(MeasurementUnit):\n        ...     METER = \"m\"\n\n        >>> TemperatureUnit.CELCIUS.isinstance(TemperatureUnit)\n        True\n\n        >>> TemperatureUnit.CELCIUS.isinstance(LengthUnit)\n        False\n    \"\"\"\n    return type(self) == generic  # pylint: disable=unidiomatic-typecheck\n
    "},{"location":"descriptors/#property_utils.units.descriptors.MeasurementUnit.isinstance_equivalent","title":"isinstance_equivalent(generic)","text":"

    Returns True if the UnitDescriptor is an instance-equivalent of the generic, False otherwise.

    A unit descriptor is an instance-equivalent of a generic if the generic of the unit descriptor is equivalent to the generic.

    Equivalence between generics is checked with the is_equivalent method.

    Examples:

    >>> class LengthUnit(MeasurementUnit): ...\n>>> class AreaUnit(AliasMeasurementUnit):\n...     HECTARE = \"ha\"\n...     @classmethod\n...     def aliased_generic_descriptor(cls): return LengthUnit**2\n
    >>> AreaUnit.HECTARE.isinstance_equivalent(AreaUnit)\nTrue\n>>> AreaUnit.HECTARE.isinstance_equivalent(LengthUnit**2)\nTrue\n
    Source code in src/property_utils/units/descriptors.py
    def isinstance_equivalent(self, generic: GenericUnitDescriptor) -> bool:\n    \"\"\"\n    Returns True if the UnitDescriptor is an instance-equivalent of the generic,\n    False otherwise.\n\n    A unit descriptor is an instance-equivalent of a generic if the generic of the\n    unit descriptor is equivalent to the generic.\n\n    Equivalence between generics is checked with the `is_equivalent` method.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit): ...\n        >>> class AreaUnit(AliasMeasurementUnit):\n        ...     HECTARE = \"ha\"\n        ...     @classmethod\n        ...     def aliased_generic_descriptor(cls): return LengthUnit**2\n\n        >>> AreaUnit.HECTARE.isinstance_equivalent(AreaUnit)\n        True\n        >>> AreaUnit.HECTARE.isinstance_equivalent(LengthUnit**2)\n        True\n    \"\"\"\n    return self.to_generic().is_equivalent(generic)\n
    "},{"location":"descriptors/#property_utils.units.descriptors.MeasurementUnit.si","title":"si() classmethod","text":"

    Returns the SI unit of this measurement unit.

    Source code in src/property_utils/units/descriptors.py
    @classmethod\ndef si(cls) -> \"MeasurementUnit\":\n    \"\"\"\n    Returns the SI unit of this measurement unit.\n    \"\"\"\n    raise NotImplementedError\n
    "},{"location":"descriptors/#property_utils.units.descriptors.MeasurementUnit.to_generic","title":"to_generic()","text":"

    Create a generic descriptor from this MeasurementUnit.

    Examples:

    >>> class AmountUnit(MeasurementUnit):\n...     MOL = \"mol\"\n
    >>> AmountUnit.MOL.to_generic()\n<MeasurementUnit: AmountUnit>\n
    Source code in src/property_utils/units/descriptors.py
    def to_generic(self) -> GenericUnitDescriptor:\n    \"\"\"\n    Create a generic descriptor from this MeasurementUnit.\n\n    Examples:\n        >>> class AmountUnit(MeasurementUnit):\n        ...     MOL = \"mol\"\n\n        >>> AmountUnit.MOL.to_generic()\n        <MeasurementUnit: AmountUnit>\n    \"\"\"\n    return self.__class__\n
    "},{"location":"descriptors/#property_utils.units.descriptors.MeasurementUnitMeta","title":"MeasurementUnitMeta","text":"

    Bases: EnumMeta

    Metaclass for MeasurementUnit. Defines multiplication, division and exponent operations for MeasurementUnit class (and subclasses). These operations produce GenericUnitDescriptor(s).

    Source code in src/property_utils/units/descriptors.py
    class MeasurementUnitMeta(EnumMeta):\n    \"\"\"\n    Metaclass for MeasurementUnit. Defines multiplication, division and exponent\n    operations for MeasurementUnit class (and subclasses). These operations produce\n    GenericUnitDescriptor(s).\n    \"\"\"\n\n    def to_si(cls) -> \"MeasurementUnit\":\n        \"\"\"\n        Create a MeasurementUnit with SI units.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     CELCIUS = \"C\"\n            ...     KELVIN = \"K\"\n            ...     @classmethod\n            ...     def si(cls):\n            ...         return cls.KELVIN\n            >>> TemperatureUnit.to_si()\n            <TemperatureUnit: K>\n        \"\"\"\n        if hasattr(cls, \"si\"):\n            return cls.si()\n        raise NotImplementedError\n\n    def inverse_generic(cls) -> \"GenericCompositeDimension\":\n        \"\"\"\n        Create a generic composite with inverse units.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit): ...\n            >>> TemperatureUnit.inverse_generic()\n            <GenericCompositeDimension:  / TemperatureUnit>\n        \"\"\"\n        return GenericCompositeDimension([], [GenericDimension(cls)])\n\n    # pylint: disable=too-many-return-statements\n    def is_equivalent(cls, other: GenericUnitDescriptor) -> bool:\n        \"\"\"\n        Returns True if this generic is equivalent to the given one, False otherwise.\n\n        A generic can be equivalent with another generic if the latter or the former\n        is an alias.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit): ...\n            >>> class MassUnit(MeasurementUnit): ...\n            >>> class TimeUnit(MeasurementUnit): ...\n            >>> class ForceUnit(AliasMeasurementUnit):\n            ...     @classmethod\n            ...     def aliased_generic_descriptor(cls):\n            ...         return MassUnit * LengthUnit / (TimeUnit**2)\n\n            >>> ForceUnit.is_equivalent(MassUnit * LengthUnit / (TimeUnit**2))\n            True\n\n            >>> class EnergyUnit(AliasMeasurementUnit):\n            ...     @classmethod\n            ...     def aliased_generic_descriptor(cls):\n            ...         return ForceUnit * LengthUnit\n\n            >>> EnergyUnit.is_equivalent(MassUnit * (LengthUnit**2) / (TimeUnit**2))\n            True\n        \"\"\"\n        if isinstance(other, MeasurementUnitType):\n            return cls == other\n\n        if isinstance(other, GenericDimension):\n            if cls == other.unit_type and other.power == 1:\n                return True\n\n            if issubclass(other.unit_type, AliasMeasurementUnit):\n                return (\n                    other.unit_type.aliased_generic_descriptor() ** other.power\n                ).is_equivalent(cls)\n\n            if issubclass(cls, AliasMeasurementUnit):\n                return cls.aliased_generic_descriptor().is_equivalent(other)\n\n        elif isinstance(other, GenericCompositeDimension):\n            if (\n                other.denominator == []\n                and len(other.numerator) == 1\n                and other.numerator[0].is_equivalent(cls)\n            ):\n                return True\n\n            if issubclass(cls, AliasMeasurementUnit):\n                return cls.aliased_generic_descriptor().is_equivalent(other)\n\n        return False\n\n    def __mul__(cls, other: GenericUnitDescriptor) -> \"GenericCompositeDimension\":\n        \"\"\"\n        Defines multiplication between MeasurementUnit types and other generic\n        descriptors.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit): ...\n            >>> class TimeUnit(MeasurementUnit): ...\n            >>> TemperatureUnit * TimeUnit\n            <GenericCompositeDimension: TemperatureUnit * TimeUnit>\n        \"\"\"\n        if isinstance(other, GenericCompositeDimension):\n            numerator = other.numerator.copy()\n            denominator = other.denominator.copy()\n            numerator.append(GenericDimension(cls))\n            return GenericCompositeDimension(\n                numerator=numerator, denominator=denominator\n            )\n        if isinstance(other, GenericDimension):\n            return GenericCompositeDimension(numerator=[GenericDimension(cls), other])\n        if isinstance(other, MeasurementUnitType):\n            return GenericCompositeDimension(\n                numerator=[\n                    GenericDimension(cls),\n                    GenericDimension(other),\n                ]\n            )\n        raise DescriptorBinaryOperationError(f\"cannot multiply {cls} with {other}. \")\n\n    def __truediv__(cls, other: GenericUnitDescriptor) -> \"GenericCompositeDimension\":\n        \"\"\"\n        Defines division between MeasurementUnit types and other generic\n        descriptors.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit): ...\n            >>> class TimeUnit(MeasurementUnit): ...\n            >>> TemperatureUnit / TimeUnit\n            <GenericCompositeDimension: TemperatureUnit / TimeUnit>\n        \"\"\"\n        if isinstance(other, GenericCompositeDimension):\n            numerator = other.denominator.copy()\n            denominator = other.numerator.copy()\n            numerator.append(GenericDimension(cls))\n            return GenericCompositeDimension(\n                numerator=numerator, denominator=denominator\n            )\n        if isinstance(other, GenericDimension):\n            return GenericCompositeDimension(\n                numerator=[GenericDimension(cls)], denominator=[other]\n            )\n        if isinstance(other, MeasurementUnitType):\n            return GenericCompositeDimension(\n                numerator=[GenericDimension(cls)],\n                denominator=[GenericDimension(other)],\n            )\n        raise DescriptorBinaryOperationError(f\"cannot divide {cls} with {other}. \")\n\n    def __pow__(cls, power: float) -> \"GenericDimension\":\n        \"\"\"\n        Defines exponentiation of MeasurementUnit types.\n\n        Examples:\n            >>> class TimeUnit(MeasurementUnit): ...\n            >>> TimeUnit**3\n            <GenericDimension: TimeUnit^3>\n        \"\"\"\n        return GenericDimension(cls, power)\n\n    def __str__(cls) -> str:\n        return cls.__name__\n\n    def __repr__(cls) -> str:\n        return f\"<MeasurementUnit: {str(cls)}>\"\n
    "},{"location":"descriptors/#property_utils.units.descriptors.MeasurementUnitMeta.__mul__","title":"__mul__(other)","text":"

    Defines multiplication between MeasurementUnit types and other generic descriptors.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit): ...\n>>> class TimeUnit(MeasurementUnit): ...\n>>> TemperatureUnit * TimeUnit\n<GenericCompositeDimension: TemperatureUnit * TimeUnit>\n
    Source code in src/property_utils/units/descriptors.py
    def __mul__(cls, other: GenericUnitDescriptor) -> \"GenericCompositeDimension\":\n    \"\"\"\n    Defines multiplication between MeasurementUnit types and other generic\n    descriptors.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit): ...\n        >>> class TimeUnit(MeasurementUnit): ...\n        >>> TemperatureUnit * TimeUnit\n        <GenericCompositeDimension: TemperatureUnit * TimeUnit>\n    \"\"\"\n    if isinstance(other, GenericCompositeDimension):\n        numerator = other.numerator.copy()\n        denominator = other.denominator.copy()\n        numerator.append(GenericDimension(cls))\n        return GenericCompositeDimension(\n            numerator=numerator, denominator=denominator\n        )\n    if isinstance(other, GenericDimension):\n        return GenericCompositeDimension(numerator=[GenericDimension(cls), other])\n    if isinstance(other, MeasurementUnitType):\n        return GenericCompositeDimension(\n            numerator=[\n                GenericDimension(cls),\n                GenericDimension(other),\n            ]\n        )\n    raise DescriptorBinaryOperationError(f\"cannot multiply {cls} with {other}. \")\n
    "},{"location":"descriptors/#property_utils.units.descriptors.MeasurementUnitMeta.__pow__","title":"__pow__(power)","text":"

    Defines exponentiation of MeasurementUnit types.

    Examples:

    >>> class TimeUnit(MeasurementUnit): ...\n>>> TimeUnit**3\n<GenericDimension: TimeUnit^3>\n
    Source code in src/property_utils/units/descriptors.py
    def __pow__(cls, power: float) -> \"GenericDimension\":\n    \"\"\"\n    Defines exponentiation of MeasurementUnit types.\n\n    Examples:\n        >>> class TimeUnit(MeasurementUnit): ...\n        >>> TimeUnit**3\n        <GenericDimension: TimeUnit^3>\n    \"\"\"\n    return GenericDimension(cls, power)\n
    "},{"location":"descriptors/#property_utils.units.descriptors.MeasurementUnitMeta.__truediv__","title":"__truediv__(other)","text":"

    Defines division between MeasurementUnit types and other generic descriptors.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit): ...\n>>> class TimeUnit(MeasurementUnit): ...\n>>> TemperatureUnit / TimeUnit\n<GenericCompositeDimension: TemperatureUnit / TimeUnit>\n
    Source code in src/property_utils/units/descriptors.py
    def __truediv__(cls, other: GenericUnitDescriptor) -> \"GenericCompositeDimension\":\n    \"\"\"\n    Defines division between MeasurementUnit types and other generic\n    descriptors.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit): ...\n        >>> class TimeUnit(MeasurementUnit): ...\n        >>> TemperatureUnit / TimeUnit\n        <GenericCompositeDimension: TemperatureUnit / TimeUnit>\n    \"\"\"\n    if isinstance(other, GenericCompositeDimension):\n        numerator = other.denominator.copy()\n        denominator = other.numerator.copy()\n        numerator.append(GenericDimension(cls))\n        return GenericCompositeDimension(\n            numerator=numerator, denominator=denominator\n        )\n    if isinstance(other, GenericDimension):\n        return GenericCompositeDimension(\n            numerator=[GenericDimension(cls)], denominator=[other]\n        )\n    if isinstance(other, MeasurementUnitType):\n        return GenericCompositeDimension(\n            numerator=[GenericDimension(cls)],\n            denominator=[GenericDimension(other)],\n        )\n    raise DescriptorBinaryOperationError(f\"cannot divide {cls} with {other}. \")\n
    "},{"location":"descriptors/#property_utils.units.descriptors.MeasurementUnitMeta.inverse_generic","title":"inverse_generic()","text":"

    Create a generic composite with inverse units.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit): ...\n>>> TemperatureUnit.inverse_generic()\n<GenericCompositeDimension:  / TemperatureUnit>\n
    Source code in src/property_utils/units/descriptors.py
    def inverse_generic(cls) -> \"GenericCompositeDimension\":\n    \"\"\"\n    Create a generic composite with inverse units.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit): ...\n        >>> TemperatureUnit.inverse_generic()\n        <GenericCompositeDimension:  / TemperatureUnit>\n    \"\"\"\n    return GenericCompositeDimension([], [GenericDimension(cls)])\n
    "},{"location":"descriptors/#property_utils.units.descriptors.MeasurementUnitMeta.is_equivalent","title":"is_equivalent(other)","text":"

    Returns True if this generic is equivalent to the given one, False otherwise.

    A generic can be equivalent with another generic if the latter or the former is an alias.

    Examples:

    >>> class LengthUnit(MeasurementUnit): ...\n>>> class MassUnit(MeasurementUnit): ...\n>>> class TimeUnit(MeasurementUnit): ...\n>>> class ForceUnit(AliasMeasurementUnit):\n...     @classmethod\n...     def aliased_generic_descriptor(cls):\n...         return MassUnit * LengthUnit / (TimeUnit**2)\n
    >>> ForceUnit.is_equivalent(MassUnit * LengthUnit / (TimeUnit**2))\nTrue\n
    >>> class EnergyUnit(AliasMeasurementUnit):\n...     @classmethod\n...     def aliased_generic_descriptor(cls):\n...         return ForceUnit * LengthUnit\n
    >>> EnergyUnit.is_equivalent(MassUnit * (LengthUnit**2) / (TimeUnit**2))\nTrue\n
    Source code in src/property_utils/units/descriptors.py
    def is_equivalent(cls, other: GenericUnitDescriptor) -> bool:\n    \"\"\"\n    Returns True if this generic is equivalent to the given one, False otherwise.\n\n    A generic can be equivalent with another generic if the latter or the former\n    is an alias.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit): ...\n        >>> class MassUnit(MeasurementUnit): ...\n        >>> class TimeUnit(MeasurementUnit): ...\n        >>> class ForceUnit(AliasMeasurementUnit):\n        ...     @classmethod\n        ...     def aliased_generic_descriptor(cls):\n        ...         return MassUnit * LengthUnit / (TimeUnit**2)\n\n        >>> ForceUnit.is_equivalent(MassUnit * LengthUnit / (TimeUnit**2))\n        True\n\n        >>> class EnergyUnit(AliasMeasurementUnit):\n        ...     @classmethod\n        ...     def aliased_generic_descriptor(cls):\n        ...         return ForceUnit * LengthUnit\n\n        >>> EnergyUnit.is_equivalent(MassUnit * (LengthUnit**2) / (TimeUnit**2))\n        True\n    \"\"\"\n    if isinstance(other, MeasurementUnitType):\n        return cls == other\n\n    if isinstance(other, GenericDimension):\n        if cls == other.unit_type and other.power == 1:\n            return True\n\n        if issubclass(other.unit_type, AliasMeasurementUnit):\n            return (\n                other.unit_type.aliased_generic_descriptor() ** other.power\n            ).is_equivalent(cls)\n\n        if issubclass(cls, AliasMeasurementUnit):\n            return cls.aliased_generic_descriptor().is_equivalent(other)\n\n    elif isinstance(other, GenericCompositeDimension):\n        if (\n            other.denominator == []\n            and len(other.numerator) == 1\n            and other.numerator[0].is_equivalent(cls)\n        ):\n            return True\n\n        if issubclass(cls, AliasMeasurementUnit):\n            return cls.aliased_generic_descriptor().is_equivalent(other)\n\n    return False\n
    "},{"location":"descriptors/#property_utils.units.descriptors.MeasurementUnitMeta.to_si","title":"to_si()","text":"

    Create a MeasurementUnit with SI units.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     CELCIUS = \"C\"\n...     KELVIN = \"K\"\n...     @classmethod\n...     def si(cls):\n...         return cls.KELVIN\n>>> TemperatureUnit.to_si()\n<TemperatureUnit: K>\n
    Source code in src/property_utils/units/descriptors.py
    def to_si(cls) -> \"MeasurementUnit\":\n    \"\"\"\n    Create a MeasurementUnit with SI units.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     CELCIUS = \"C\"\n        ...     KELVIN = \"K\"\n        ...     @classmethod\n        ...     def si(cls):\n        ...         return cls.KELVIN\n        >>> TemperatureUnit.to_si()\n        <TemperatureUnit: K>\n    \"\"\"\n    if hasattr(cls, \"si\"):\n        return cls.si()\n    raise NotImplementedError\n
    "},{"location":"descriptors/#property_utils.units.descriptors.UnitDescriptor","title":"UnitDescriptor","text":"

    Bases: Protocol

    Descriptor for a property unit that has a specific unit, e.g. cm^2 or ft^2.

    Source code in src/property_utils/units/descriptors.py
    class UnitDescriptor(Protocol):\n    \"\"\"\n    Descriptor for a property unit that has a specific unit, e.g. cm^2 or ft^2.\n    \"\"\"\n\n    def si(self) -> \"UnitDescriptor\":\n        \"\"\"\n        Returns this descriptor with SI units.\n        \"\"\"\n\n    def isinstance(self, generic: GenericUnitDescriptor) -> bool:\n        \"\"\"\n        Returns True if the UnitDescriptor is an instance of the generic, False\n        otherwise.\n\n        A unit descriptor is an instance of a generic if the generic of the unit\n        descriptor is equal to the generic.\n\n        Equality between generics is checked with the `==` operator.\n        \"\"\"\n\n    def isinstance_equivalent(self, generic: GenericUnitDescriptor) -> bool:\n        \"\"\"\n        Returns True if the UnitDescriptor is an instance-equivalent of the generic,\n        False otherwise.\n\n        A unit descriptor is an instance-equivalent of a generic if the generic of the\n        unit descriptor is equivalent to the generic.\n\n        Equivalence between generics is checked with the `is_equivalent` method.\n        \"\"\"\n\n    def to_generic(self) -> GenericUnitDescriptor:\n        \"\"\"\n        Create a generic descriptor from this UnitDescriptor.\n        \"\"\"\n\n    def inverse(self) -> \"CompositeDimension\":\n        \"\"\"\n        Create a composite with inverse units.\n        \"\"\"\n\n    def __mul__(self, descriptor: \"UnitDescriptor\") -> \"CompositeDimension\": ...\n\n    def __truediv__(self, descriptor: \"UnitDescriptor\") -> \"CompositeDimension\": ...\n\n    def __pow__(self, power: float) -> \"UnitDescriptor\": ...\n\n    def __hash__(self) -> int: ...\n\n    def __str__(self) -> str: ...\n
    "},{"location":"descriptors/#property_utils.units.descriptors.UnitDescriptor.inverse","title":"inverse()","text":"

    Create a composite with inverse units.

    Source code in src/property_utils/units/descriptors.py
    def inverse(self) -> \"CompositeDimension\":\n    \"\"\"\n    Create a composite with inverse units.\n    \"\"\"\n
    "},{"location":"descriptors/#property_utils.units.descriptors.UnitDescriptor.isinstance","title":"isinstance(generic)","text":"

    Returns True if the UnitDescriptor is an instance of the generic, False otherwise.

    A unit descriptor is an instance of a generic if the generic of the unit descriptor is equal to the generic.

    Equality between generics is checked with the == operator.

    Source code in src/property_utils/units/descriptors.py
    def isinstance(self, generic: GenericUnitDescriptor) -> bool:\n    \"\"\"\n    Returns True if the UnitDescriptor is an instance of the generic, False\n    otherwise.\n\n    A unit descriptor is an instance of a generic if the generic of the unit\n    descriptor is equal to the generic.\n\n    Equality between generics is checked with the `==` operator.\n    \"\"\"\n
    "},{"location":"descriptors/#property_utils.units.descriptors.UnitDescriptor.isinstance_equivalent","title":"isinstance_equivalent(generic)","text":"

    Returns True if the UnitDescriptor is an instance-equivalent of the generic, False otherwise.

    A unit descriptor is an instance-equivalent of a generic if the generic of the unit descriptor is equivalent to the generic.

    Equivalence between generics is checked with the is_equivalent method.

    Source code in src/property_utils/units/descriptors.py
    def isinstance_equivalent(self, generic: GenericUnitDescriptor) -> bool:\n    \"\"\"\n    Returns True if the UnitDescriptor is an instance-equivalent of the generic,\n    False otherwise.\n\n    A unit descriptor is an instance-equivalent of a generic if the generic of the\n    unit descriptor is equivalent to the generic.\n\n    Equivalence between generics is checked with the `is_equivalent` method.\n    \"\"\"\n
    "},{"location":"descriptors/#property_utils.units.descriptors.UnitDescriptor.si","title":"si()","text":"

    Returns this descriptor with SI units.

    Source code in src/property_utils/units/descriptors.py
    def si(self) -> \"UnitDescriptor\":\n    \"\"\"\n    Returns this descriptor with SI units.\n    \"\"\"\n
    "},{"location":"descriptors/#property_utils.units.descriptors.UnitDescriptor.to_generic","title":"to_generic()","text":"

    Create a generic descriptor from this UnitDescriptor.

    Source code in src/property_utils/units/descriptors.py
    def to_generic(self) -> GenericUnitDescriptor:\n    \"\"\"\n    Create a generic descriptor from this UnitDescriptor.\n    \"\"\"\n
    "},{"location":"feedback/","title":"Feedback","text":""},{"location":"feedback/#got-bugs-or-an-idea-for-a-new-feature","title":"Got bugs or an idea for a new feature?","text":"

    Great! (well, not if you've got bugs) open up an issue in the project's repo: issues.

    "},{"location":"installation/","title":"Installation","text":"

    You'll need a Python version bigger or equal to 3.8. If you're new to programming this page could help with learning resources.

    Once you've got Python setup you can install property-utils from your IDE or via pip:

    pip install property-utils\n

    "},{"location":"installation/#dependencies","title":"Dependencies","text":"

    property-utils's only dependency is the typing-extensions library.

    "},{"location":"property/","title":"property","text":"

    This module defines the Property class and property arithmetics.

    "},{"location":"property/#property_utils.properties.property.AbsoluteTemperatureUnitConverter","title":"AbsoluteTemperatureUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    Convert absolute temperature with this converter.

    Examples:

    >>> AbsoluteTemperatureUnitConverter.convert(10, AbsoluteTemperatureUnit.KELVIN, AbsoluteTemperatureUnit.RANKINE)\n18.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(AbsoluteTemperatureUnit)\nclass AbsoluteTemperatureUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    Convert absolute temperature with this converter.\n\n    Examples:\n        >>> AbsoluteTemperatureUnitConverter.convert(10, AbsoluteTemperatureUnit.KELVIN, AbsoluteTemperatureUnit.RANKINE)\n        18.0\n    \"\"\"\n\n    reference_unit = AbsoluteTemperatureUnit.KELVIN\n    conversion_map = {\n        AbsoluteTemperatureUnit.KELVIN: 1,\n        AbsoluteTemperatureUnit.RANKINE: 1.8,\n    }\n\n    @override\n    @classmethod\n    def convert(\n        cls,\n        value: float,\n        from_descriptor: UnitDescriptor,\n        to_descriptor: UnitDescriptor,\n    ) -> float:\n        if not isinstance(value, (float, int)):\n            raise UnitConversionError(f\"invalid 'value': {value}; expected numeric. \")\n        if from_descriptor.isinstance(\n            RelativeTemperatureUnit\n        ) or to_descriptor.isinstance(RelativeTemperatureUnit):\n            return RelativeTemperatureUnitConverter.convert(\n                value, from_descriptor, to_descriptor\n            )\n        return value * cls.get_factor(from_descriptor, to_descriptor)\n
    "},{"location":"property/#property_utils.properties.property.AliasEnergyUnitConverter","title":"AliasEnergyUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    Convert energy units with this converter.

    Examples:

    >>> AliasEnergyUnitConverter.convert(2500, EnergyUnit.JOULE, EnergyUnit.KILO_JOULE)\n2.5\n
    Source code in src/property_utils/units/converters.py
    @register_converter(EnergyUnit)\nclass AliasEnergyUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    Convert energy units with this converter.\n\n    Examples:\n        >>> AliasEnergyUnitConverter.convert(2500, EnergyUnit.JOULE, EnergyUnit.KILO_JOULE)\n        2.5\n    \"\"\"\n\n    reference_unit = EnergyUnit.JOULE\n    conversion_map = {\n        EnergyUnit.JOULE: 1,\n        EnergyUnit.KILO_JOULE: UnitPrefix.KILO.inverse(),\n        EnergyUnit.MEGA_JOULE: UnitPrefix.MEGA.inverse(),\n        EnergyUnit.GIGA_JOULE: UnitPrefix.GIGA.inverse(),\n        EnergyUnit.CALORIE: 1 / 4.184,\n        EnergyUnit.KILO_CALORIE: (1 / 4.184) * UnitPrefix.KILO.inverse(),\n        EnergyUnit.BTU: 1 / 1055.0,\n        EnergyUnit.ELECTRONVOLT: 6.242e18,\n        EnergyUnit.WATTHOUR: 1 / 3600,\n        EnergyUnit.KILO_WATTHOUR: (1 / 3600) * UnitPrefix.KILO.inverse(),\n    }\n
    "},{"location":"property/#property_utils.properties.property.AliasForceUnitConverter","title":"AliasForceUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    Convert force units with this converter.

    Examples:

    >>> AliasForceUnitConverter.convert(2, ForceUnit.NEWTON, ForceUnit.DYNE)\n200000.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(ForceUnit)\nclass AliasForceUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    Convert force units with this converter.\n\n    Examples:\n        >>> AliasForceUnitConverter.convert(2, ForceUnit.NEWTON, ForceUnit.DYNE)\n        200000.0\n    \"\"\"\n\n    reference_unit = ForceUnit.NEWTON\n    conversion_map = {ForceUnit.NEWTON: 1, ForceUnit.DYNE: 100_000}\n
    "},{"location":"property/#property_utils.properties.property.AliasPowerUnitConverter","title":"AliasPowerUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    Convert power units with this converter.

    Examples:

    >>> AliasPowerUnitConverter.convert(5, PowerUnit.KILO_WATT, PowerUnit.WATT)\n5000.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(PowerUnit)\nclass AliasPowerUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    Convert power units with this converter.\n\n    Examples:\n        >>> AliasPowerUnitConverter.convert(5, PowerUnit.KILO_WATT, PowerUnit.WATT)\n        5000.0\n    \"\"\"\n\n    reference_unit = PowerUnit.WATT\n    conversion_map = {\n        PowerUnit.WATT: 1,\n        PowerUnit.KILO_WATT: UnitPrefix.KILO.inverse(),\n        PowerUnit.MEGA_WATT: UnitPrefix.MEGA.inverse(),\n        PowerUnit.GIGA_WATT: UnitPrefix.GIGA.inverse(),\n    }\n
    "},{"location":"property/#property_utils.properties.property.AliasPressureUnitConverter","title":"AliasPressureUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    Convert pressure units with this converter.

    Examples:

    >>> AliasPressureUnitConverter.convert(2, PressureUnit.BAR, PressureUnit.KILO_PASCAL)\n200.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(PressureUnit)\nclass AliasPressureUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    Convert pressure units with this converter.\n\n    Examples:\n        >>> AliasPressureUnitConverter.convert(2, PressureUnit.BAR, PressureUnit.KILO_PASCAL)\n        200.0\n    \"\"\"\n\n    reference_unit = PressureUnit.BAR\n    conversion_map = {\n        PressureUnit.MILLI_BAR: UnitPrefix.MILLI.inverse(),\n        PressureUnit.BAR: 1,\n        PressureUnit.PSI: 14.5038,\n        PressureUnit.PASCAL: 100_000,\n        PressureUnit.KILO_PASCAL: 100,\n        PressureUnit.MEGA_PASCAL: 0.1,\n    }\n
    "},{"location":"property/#property_utils.properties.property.AmountUnitConverter","title":"AmountUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    Convert amount units with this converter.

    Examples:

    >>> AmountUnitConverter.convert(2000, AmountUnit.MOL, AmountUnit.KILO_MOL)\n2.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(AmountUnit)\nclass AmountUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    Convert amount units with this converter.\n\n    Examples:\n        >>> AmountUnitConverter.convert(2000, AmountUnit.MOL, AmountUnit.KILO_MOL)\n        2.0\n    \"\"\"\n\n    reference_unit = AmountUnit.MOL\n    conversion_map = {AmountUnit.MOL: 1, AmountUnit.KILO_MOL: UnitPrefix.KILO.inverse()}\n
    "},{"location":"property/#property_utils.properties.property.AreaUnitConverter","title":"AreaUnitConverter","text":"

    Bases: ExponentiatedUnitConverter

    Convert area units with this converter.

    Examples:

    >>> AreaUnitConverter.convert(1, LengthUnit.METER**2, LengthUnit.CENTI_METER**2)\n10000.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(LengthUnit**2)\nclass AreaUnitConverter(ExponentiatedUnitConverter):\n    \"\"\"\n    Convert area units with this converter.\n\n    Examples:\n        >>> AreaUnitConverter.convert(1, LengthUnit.METER**2, LengthUnit.CENTI_METER**2)\n        10000.0\n    \"\"\"\n
    "},{"location":"property/#property_utils.properties.property.ElectricCurrentUnitConverter","title":"ElectricCurrentUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    Convert electric current units with this converter.

    Examples:

    >>> ElectricCurrentUnitConverter.convert(1000, ElectricCurrentUnit.MILLI_AMPERE, ElectricCurrentUnit.AMPERE)\n1.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(ElectricCurrentUnit)\nclass ElectricCurrentUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    Convert electric current units with this converter.\n\n    Examples:\n        >>> ElectricCurrentUnitConverter.convert(1000, ElectricCurrentUnit.MILLI_AMPERE, ElectricCurrentUnit.AMPERE)\n        1.0\n    \"\"\"\n\n    reference_unit = ElectricCurrentUnit.AMPERE\n    conversion_map = {\n        ElectricCurrentUnit.MILLI_AMPERE: UnitPrefix.MILLI.inverse(),\n        ElectricCurrentUnit.AMPERE: 1,\n        ElectricCurrentUnit.KILO_AMPERE: UnitPrefix.KILO.inverse(),\n    }\n
    "},{"location":"property/#property_utils.properties.property.EnergyUnitConverter","title":"EnergyUnitConverter","text":"

    Bases: CompositeUnitConverter

    Convert energy units (mass * length^2 / time^2) with this converter.

    Examples:

    >>> from_unit = MassUnit.KILO_GRAM * (LengthUnit.METER**2) / (TimeUnit.MINUTE**2)\n>>> to_unit = MassUnit.METRIC_TONNE * (LengthUnit.CENTI_METER**2) / (TimeUnit.MINUTE**2)\n>>> EnergyUnitConverter.convert(25, from_unit, to_unit)\n250.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(EnergyUnit.aliased_generic_descriptor())\nclass EnergyUnitConverter(CompositeUnitConverter):\n    \"\"\"\n    Convert energy units (mass * length^2 / time^2) with this converter.\n\n    Examples:\n        >>> from_unit = MassUnit.KILO_GRAM * (LengthUnit.METER**2) / (TimeUnit.MINUTE**2)\n        >>> to_unit = MassUnit.METRIC_TONNE * (LengthUnit.CENTI_METER**2) / (TimeUnit.MINUTE**2)\n        >>> EnergyUnitConverter.convert(25, from_unit, to_unit)\n        250.0\n    \"\"\"\n
    "},{"location":"property/#property_utils.properties.property.ForceUnitConverter","title":"ForceUnitConverter","text":"

    Bases: CompositeUnitConverter

    Convert force units (mass * length / time^2) with this converter.

    Examples:

    >>> from_unit = MassUnit.KILO_GRAM * LengthUnit.CENTI_METER / (TimeUnit.SECOND**2)\n>>> to_unit = MassUnit.GRAM * LengthUnit.METER / (TimeUnit.SECOND**2)\n>>> ForceUnitConverter.convert(100, from_unit, to_unit)\n1000.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(ForceUnit.aliased_generic_descriptor())\nclass ForceUnitConverter(CompositeUnitConverter):\n    \"\"\"\n    Convert force units (mass * length / time^2) with this converter.\n\n    Examples:\n        >>> from_unit = MassUnit.KILO_GRAM * LengthUnit.CENTI_METER / (TimeUnit.SECOND**2)\n        >>> to_unit = MassUnit.GRAM * LengthUnit.METER / (TimeUnit.SECOND**2)\n        >>> ForceUnitConverter.convert(100, from_unit, to_unit)\n        1000.0\n    \"\"\"\n
    "},{"location":"property/#property_utils.properties.property.LengthUnitConverter","title":"LengthUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    Convert length units with this converter.

    Examples:

    >>> LengthUnitConverter.convert(2000, LengthUnit.MILLI_METER, LengthUnit.METER)\n2.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(LengthUnit)\nclass LengthUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    Convert length units with this converter.\n\n    Examples:\n        >>> LengthUnitConverter.convert(2000, LengthUnit.MILLI_METER, LengthUnit.METER)\n        2.0\n    \"\"\"\n\n    reference_unit = LengthUnit.METER\n    conversion_map = {\n        LengthUnit.MILLI_METER: UnitPrefix.MILLI.inverse(),\n        LengthUnit.CENTI_METER: UnitPrefix.CENTI.inverse(),\n        LengthUnit.METER: 1,\n        LengthUnit.KILO_METER: UnitPrefix.KILO.inverse(),\n        LengthUnit.INCH: 39.37,\n        LengthUnit.FOOT: 3.281,\n        LengthUnit.YARD: 1.094,\n        LengthUnit.MILE: 1 / 1609,\n        LengthUnit.NAUTICAL_MILE: 1 / 1852,\n    }\n
    "},{"location":"property/#property_utils.properties.property.MassUnitConverter","title":"MassUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    Convert mass units with this converter.

    Examples:

    >>> MassUnitConverter.convert(10, MassUnit.KILO_GRAM, MassUnit.GRAM)\n10000.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(MassUnit)\nclass MassUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    Convert mass units with this converter.\n\n    Examples:\n        >>> MassUnitConverter.convert(10, MassUnit.KILO_GRAM, MassUnit.GRAM)\n        10000.0\n    \"\"\"\n\n    reference_unit = MassUnit.KILO_GRAM\n    conversion_map = {\n        MassUnit.MILLI_GRAM: UnitPrefix.KILO * UnitPrefix.MILLI.inverse(),\n        MassUnit.GRAM: UnitPrefix.KILO,\n        MassUnit.KILO_GRAM: 1,\n        MassUnit.METRIC_TONNE: 1 / 1_000.0,\n        MassUnit.POUND: 2.205,\n    }\n
    "},{"location":"property/#property_utils.properties.property.PowerUnitConverter","title":"PowerUnitConverter","text":"

    Bases: CompositeUnitConverter

    Convert power units (mass * length^2 / time^3) with this converter.

    Examples:

    >>> from_unit = MassUnit.KILO_GRAM * (LengthUnit.METER**2) / (TimeUnit.MINUTE**3)\n>>> to_unit = MassUnit.METRIC_TONNE * (LengthUnit.CENTI_METER**2) / (TimeUnit.MINUTE**3)\n>>> PowerUnitConverter.convert(15, from_unit, to_unit)\n150.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(PowerUnit.aliased_generic_descriptor())\nclass PowerUnitConverter(CompositeUnitConverter):\n    \"\"\"\n    Convert power units (mass * length^2 / time^3) with this converter.\n\n    Examples:\n        >>> from_unit = MassUnit.KILO_GRAM * (LengthUnit.METER**2) / (TimeUnit.MINUTE**3)\n        >>> to_unit = MassUnit.METRIC_TONNE * (LengthUnit.CENTI_METER**2) / (TimeUnit.MINUTE**3)\n        >>> PowerUnitConverter.convert(15, from_unit, to_unit)\n        150.0\n    \"\"\"\n
    "},{"location":"property/#property_utils.properties.property.PressureUnitConverter","title":"PressureUnitConverter","text":"

    Bases: CompositeUnitConverter

    Convert pressure units (mass / length / time^2) with this converter.

    Examples:

    >>> from_unit = MassUnit.GRAM / LengthUnit.CENTI_METER / (TimeUnit.HOUR**2)\n>>> to_unit = MassUnit.KILO_GRAM / LengthUnit.METER / (TimeUnit.HOUR**2)\n>>> PressureUnitConverter.convert(50, from_unit, to_unit)\n5.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(PressureUnit.aliased_generic_descriptor())\nclass PressureUnitConverter(CompositeUnitConverter):\n    \"\"\"\n    Convert pressure units (mass / length / time^2) with this converter.\n\n    Examples:\n        >>> from_unit = MassUnit.GRAM / LengthUnit.CENTI_METER / (TimeUnit.HOUR**2)\n        >>> to_unit = MassUnit.KILO_GRAM / LengthUnit.METER / (TimeUnit.HOUR**2)\n        >>> PressureUnitConverter.convert(50, from_unit, to_unit)\n        5.0\n    \"\"\"\n
    "},{"location":"property/#property_utils.properties.property.Property","title":"Property dataclass","text":"

    A Property describes a value with a unit of measurement.

    A Property can have any 'value' or 'unit'; validations are not applied to it. For example, a Property with length units and negative value is valid.

    Source code in src/property_utils/properties/property.py
    @dataclass\nclass Property:\n    \"\"\"\n    A Property describes a value with a unit of measurement.\n\n    A Property can have any 'value' or 'unit'; validations are not applied to it.\n    For example, a Property with length units and negative value is valid.\n    \"\"\"\n\n    value: float\n    unit: UnitDescriptor\n    unit_converter: Optional[Type[UnitConverter]] = None\n    default_units: ClassVar[Optional[UnitDescriptor]] = None\n\n    def __init__(self, value: float, unit: Optional[UnitDescriptor] = None) -> None:\n        if not isinstance(value, (float, int)):\n            raise PropertyValidationError(\n                f\"cannot create Property; invalid 'value': {value}; expected numeric. \"\n            )\n\n        if unit is None and self.default_units is not None:\n            unit = self.default_units\n\n        if not isinstance(unit, (MeasurementUnit, Dimension, CompositeDimension)):\n            raise PropertyValidationError(\n                f\"cannot create Property; invalid 'unit': {unit}. Expected an instance\"\n                \" of one of: MeasurementUnit, Dimension, CompositeDimension. \"\n            )\n\n        self.value = value\n        self.unit = unit\n\n    def eq(self, other: \"Property\", *, rel_tol=1e-9, abs_tol=0) -> bool:\n        \"\"\"\n        Perform equality comparison between this and some other Property. This method\n        of testing equality is preferable to the equality operator '==' because float\n        point tolerance is taken into account.\n\n        rel_tol is the maximum difference for being considered \"close\", relative\n        to the magnitude of the input values.\n        abs_tol is the maximum difference for being considered \"close\", regardless of\n        the magnitude of the input values.\n        For the values to be considered close, the difference between them must be\n        smaller than at least one of the tolerances.\n\n        Raises `PropertyBinaryOperationError` if an error occurs during conversion\n        of other's units.\n\n        Examples:\n            >>> from property_utils.units.units import AbsoluteTemperatureUnit, LengthUnit\n            >>> T1 = Property(33.333333, AbsoluteTemperatureUnit.KELVIN)\n            >>> T2 = Property(100/3, AbsoluteTemperatureUnit.KELVIN)\n            >>> T1 == T2\n            False\n            >>> T1.eq(T2)\n            False\n            >>> T1.eq(T2, rel_tol=0.1)\n            True\n        \"\"\"\n        if not isinstance(other, Property):\n            return False\n        if not self.unit.isinstance_equivalent(other.unit.to_generic()):\n            return False\n        try:\n            prop = other.to_unit(self.unit) if self.unit != other.unit else other\n        except PropertyUtilsException as exc:\n            raise PropertyBinaryOperationError(\n                f\"during conversion of {other} to ({self.unit}) units an error occured: \",\n                exc,\n            ) from None\n        return isclose(self.value, prop.value, rel_tol=rel_tol, abs_tol=abs_tol)\n\n    def to_si(self) -> Self:\n        \"\"\"\n        Create a new property with SI units.\n\n        Raises `ImpossiblePropertyUnitConverion` if there is no converter registered\n        for the unit.\n\n        Raises `InvalidUnitConversion` if any error occurs in the unit conversion.\n\n        Examples:\n            >>> from property_utils.units.units import RelativeTemperatureUnit\n            >>> T = Property(100, RelativeTemperatureUnit.CELCIUS)\n            >>> T.to_si()\n            <Property: 373.15 K>\n        \"\"\"\n        if isinstance(self.unit, MeasurementUnit):\n            return self.to_unit(self.unit.si())\n        if isinstance(self.unit, Dimension):\n            return self.to_unit(self.unit.unit.si() ** self.unit.power)\n        if isinstance(self.unit, CompositeDimension):\n            return self.to_unit(self.unit.to_generic().to_si())\n        raise PropertyValidationError(\n            f\"cannot convert Property to SI; 'unit' is invalid: {self.unit}. \"\n        )\n\n    def to_unit(self, unit: UnitDescriptor) -> Self:\n        \"\"\"\n        Create a new property with specified unit.\n\n        Raises `PropertyUnitConversionError` if the unit is not of the same type.\n\n        Raises `ImpossiblePropertyUnitConverion` if there is no converter registered\n        for the unit.\n\n        Raises `UnitConversionError` if any error occurs in the unit conversion.\n\n        Examples:\n            >>> from property_utils.units.units import RelativeTemperatureUnit\n            >>> T = Property(100, RelativeTemperatureUnit.CELCIUS)\n            >>> T.to_unit(RelativeTemperatureUnit.FAHRENHEIT)\n            <Property: 212.0 \u00b0F>\n        \"\"\"\n        if self.unit == unit:\n            return self.__class__(unit=self.unit, value=self.value)\n\n        if not unit.isinstance_equivalent(self.unit.to_generic()):\n            raise PropertyUnitConversionError(\n                f\"cannot convert {self} to ({unit}) units; 'unit' should be an instance\"\n                f\" of {self.unit.to_generic()}. \"\n            )\n        try:\n            converter = self._converter()\n        except UndefinedConverterError:\n            raise PropertyUnitConversionError(\n                f\"cannot convert property {self} to units: {unit}; no unit converter \"\n                f\" found for {unit.to_generic()}. \"\n                \"Did you forget to @register_converter? \"\n            ) from None\n        try:\n            value = converter.convert(self.value, self.unit, unit)\n        except UnitConversionError as exc:\n            raise exc from None\n        return self.__class__(value=value, unit=unit)\n\n    def __neg__(self) -> Self:\n        \"\"\"\n        Defines negation of properties.\n\n        Examples:\n            >>> from property_utils.units.units import RelativeTemperatureUnit\n            >>> T = Property(3, RelativeTemperatureUnit.CELCIUS)\n            >>> -T\n            <Property: -3 \u00b0C>\n        \"\"\"\n        return self.__class__(-self.value, self.unit)\n\n    def __mul__(self, other) -> \"Property\":\n        \"\"\"\n        Defines multiplication between properties and numerics.\n\n        Examples:\n            >>> from property_utils.units.units import AbsoluteTemperatureUnit, LengthUnit\n            >>> T = Property(300, AbsoluteTemperatureUnit.KELVIN)\n            >>> 2*T\n            <Property: 600 K>\n            >>> A = Property(10, LengthUnit.METER**2)\n            >>> T * A\n            <Property: 3000 (m^2) * K>\n        \"\"\"\n        if isinstance(other, (float, int)):\n            return self.__class__(self.value * other, self.unit)\n        if isinstance(other, Property):\n            _other = self._unit_preconversion(other)\n            return Property(\n                self.value * _other.value, self._simplify_units(self.unit * _other.unit)\n            )\n        raise PropertyBinaryOperationError(\n            f\"cannot multiply {self} with {other}; \"\n            \"second operand must be numeric or Property. \"\n        )\n\n    def __rmul__(self, other) -> \"Property\":\n        \"\"\"\n        Defines multiplication between properties and numerics.\n\n        Examples:\n            >>> from property_utils.units.units import AbsoluteTemperatureUnit, LengthUnit\n            >>> T = Property(300, AbsoluteTemperatureUnit.KELVIN)\n            >>> 2*T\n            <Property: 600 K>\n            >>> A = Property(10, LengthUnit.METER**2)\n            >>> T * A\n            <Property: 3000 (m^2) * K>\n        \"\"\"\n        return self.__mul__(other)\n\n    def __truediv__(self, other) -> \"Property\":\n        \"\"\"\n        Defines division between properties and numerics.\n\n        Examples:\n            >>> from property_utils.units.units import AbsoluteTemperatureUnit, LengthUnit\n            >>> T = Property(500, AbsoluteTemperatureUnit.KELVIN)\n            >>> T/2\n            <Property: 250.0 K>\n            >>> A = Property(10, LengthUnit.METER**2)\n            >>> T / A\n            <Property: 50.0 K / (m^2)>\n        \"\"\"\n        if isinstance(other, (float, int)):\n            try:\n                value = self.value / other\n            except ZeroDivisionError:\n                raise PropertyBinaryOperationError(\n                    f\"cannot divide {self} with {other}; denominator is zero. \"\n                ) from None\n            return Property(value, self.unit)\n        if isinstance(other, Property):\n            _other = self._unit_preconversion(other)\n            try:\n                value = self.value / _other.value\n            except ZeroDivisionError:\n                raise PropertyBinaryOperationError(\n                    f\"cannot divide {self} with {other}; denominator's value is zero. \"\n                ) from None\n            return Property(value, self._simplify_units(self.unit / _other.unit))\n        raise PropertyBinaryOperationError(\n            f\"cannot divide {self} with {other}; \"\n            \"denominator must be numeric or Property. \"\n        )\n\n    def __rtruediv__(self, other) -> \"Property\":\n        \"\"\"\n        Defines right division between properties and numerics.\n\n        Examples:\n            >>> from property_utils.units.units import AbsoluteTemperatureUnit\n            >>> T = Property(500, AbsoluteTemperatureUnit.KELVIN)\n            >>> 100/T\n            <Property: 0.2  / K>\n        \"\"\"\n        if isinstance(other, (float, int)):\n            try:\n                value = other / self.value\n            except ZeroDivisionError:\n                raise PropertyBinaryOperationError(\n                    f\"cannot divide {self} with {other}; denominator is zero. \"\n                ) from None\n            return Property(value, self.unit.inverse())\n        if isinstance(other, Property):\n            try:\n                value = other.value / self.value\n            except ZeroDivisionError:\n                raise PropertyBinaryOperationError(\n                    f\"cannot divide {self} with {other}; denominator's value is zero. \"\n                ) from None\n            return Property(value, self._simplify_units(other.unit / self.unit))\n        raise PropertyBinaryOperationError(\n            f\"cannot divide {self} with {other}; \"\n            \"numerator must be numeric or Property. \"\n        )\n\n    def __add__(self, other) -> Self:\n        \"\"\"\n        Defines addition between properties.\n\n        Examples:\n            >>> from property_utils.units.units import LengthUnit\n            >>> x1 = Property(15, LengthUnit.METER)\n            >>> x2 = Property(5, LengthUnit.METER)\n            >>> x1 + x2\n            <Property: 20 m>\n        \"\"\"\n        if not isinstance(other, Property):\n            raise PropertyBinaryOperationError(\n                f\"cannot add {other} to ({self}); {other} is not a Property; \"\n                \"only properties can be added to properties. \"\n            )\n        if not self.unit.isinstance_equivalent(other.unit.to_generic()):\n            raise PropertyBinaryOperationError(\n                f\"cannot add ({other}) to ({self}); \"\n                f\"({other}) must have ({self.unit.to_generic()}) units. \"\n            )\n        try:\n            prop = other.to_unit(self.unit) if self.unit != other.unit else other\n        except PropertyUnitConversionError:\n            raise PropertyBinaryOperationError(\n                f\"cannot add ({other}) to ({self}); ({other}) does not have the same \"\n                f\"units as ({self}) and there is no unit converter registered for \"\n                f\"({self.unit.to_generic()}). \"\n            ) from None\n        except UnitConversionError as exc:\n            raise PropertyBinaryOperationError(\n                f\"cannot add ({other}) to ({self});\", exc\n            ) from None\n        return self.__class__(self.value + prop.value, self.unit)\n\n    def __radd__(self, other) -> Self:\n        \"\"\"\n        Defines right addition between properties.\n\n        Examples:\n            >>> from property_utils.units.units import LengthUnit\n            >>> x1 = Property(15, LengthUnit.METER)\n            >>> x2 = Property(5, LengthUnit.METER)\n            >>> x1 + x2\n            <Property: 20 m>\n        \"\"\"\n        return self.__add__(other)\n\n    def __sub__(self, other) -> Self:\n        \"\"\"\n        Defines subtraction between properties.\n\n        Examples:\n            >>> from property_utils.units.units import TimeUnit\n            >>> t1 = Property(2, TimeUnit.MINUTE)\n            >>> t2 = Property(60, TimeUnit.SECOND)\n            >>> t1 - t2\n            <Property: 1.0 min>\n        \"\"\"\n        if not isinstance(other, Property):\n            raise PropertyBinaryOperationError(\n                f\"cannot subtract {other} from ({self}); {other} is not a \"\n                \"Property; only properties can be subtracted from properties. \"\n            )\n        if not self.unit.isinstance_equivalent(other.unit.to_generic()):\n            raise PropertyBinaryOperationError(\n                f\"cannot subtract ({other}) from ({self}); \"\n                f\"({other}) must have ({self.unit.to_generic()}) units. \"\n            )\n        try:\n            prop = other.to_unit(self.unit) if self.unit != other.unit else other\n        except PropertyUnitConversionError:\n            raise PropertyBinaryOperationError(\n                f\"cannot subtract ({other}) from ({self}); ({other}) does not have the \"\n                f\"same units as ({self}) and there is no unit converter registered for \"\n                f\"({self.unit.to_generic()}). \"\n            ) from None\n        except UnitConversionError as exc:\n            raise PropertyBinaryOperationError(\n                f\"cannot subtract ({other}) from ({self});\", exc\n            ) from None\n        return self.__class__(self.value - prop.value, self.unit)\n\n    def __rsub__(self, other) -> \"Property\":\n        \"\"\"\n        Defines right subtraction between properties.\n\n        Examples:\n            >>> from property_utils.units.units import TimeUnit\n            >>> t1 = Property(2, TimeUnit.MINUTE)\n            >>> t2 = Property(60, TimeUnit.SECOND)\n            >>> t1 - t2\n            <Property: 1.0 min>\n        \"\"\"\n        if not isinstance(other, Property):\n            raise PropertyBinaryOperationError(\n                f\"cannot subtract {self} from ({other}); {other} is not a \"\n                f\"{self.__class__}; only same properties can be subtracted from each \"\n                \"other. \"\n            )\n        if not self.unit.isinstance_equivalent(other.unit.to_generic()):\n            raise PropertyBinaryOperationError(\n                f\"cannot subtract ({self}) from ({other}); \"\n                f\"({other}) must have ({self.unit.to_generic()}) units. \"\n            )\n        return other.__add__(-self)\n\n    def __pow__(self, power) -> \"Property\":\n        \"\"\"\n        Defines exponentiation for properties.\n\n        Examples:\n            >>> from property_utils.units.units import LengthUnit\n            >>> L = Property(5, LengthUnit.METER)\n            >>> L**3\n            <Property: 125 (m^3)>\n        \"\"\"\n        if not isinstance(power, (float, int)):\n            raise PropertyExponentError(\n                f\"invalid exponent: {power}; expected numeric. \"\n            )\n        return Property(self.value**power, self.unit**power)\n\n    def __eq__(self, other) -> bool:\n        \"\"\"\n        Defines equality between properties.\n        Prefer Property.eq instead.The equality operator returns False even for very\n        small differences between floating point values.\n\n        Examples:\n            >>> from property_utils.units.units import LengthUnit\n            >>> L1 = Property(500, LengthUnit.CENTI_METER)\n            >>> L2 = Property(5, LengthUnit.METER)\n            >>> L1 == L2\n            True\n\n            >>> L3 = Property(6, LengthUnit.METER)\n            >>> L2 == L3\n            False\n        \"\"\"\n        if not isinstance(other, Property):\n            return False\n        if not self.unit.isinstance_equivalent(other.unit.to_generic()):\n            return False\n        try:\n            prop = other.to_unit(self.unit) if self.unit != other.unit else other\n        except PropertyUtilsException as exc:\n            raise PropertyBinaryOperationError(\n                f\"during conversion of {other} to ({self.unit}) units an error occured: \",\n                exc,\n            ) from None\n        return self.value == prop.value\n\n    def __ne__(self, other) -> bool:\n        \"\"\"\n        Defines inequality between properties.\n        Prefer Property.eq instead.The inequality operator returns True even for very\n        small differences between floating point values.\n\n        Examples:\n            >>> from property_utils.units.units import LengthUnit\n            >>> L1 = Property(500, LengthUnit.CENTI_METER)\n            >>> L2 = Property(5, LengthUnit.METER)\n            >>> L1 != L2\n            False\n\n            >>> L3 = Property(6, LengthUnit.METER)\n            >>> L2 != L3\n            True\n        \"\"\"\n        return not self.__eq__(other)\n\n    def __gt__(self, other) -> bool:\n        \"\"\"\n        Defines comparison between properties.\n\n        Examples:\n            >>> from property_utils.units.units import RelativeTemperatureUnit\n            >>> T1 = Property(100, RelativeTemperatureUnit.CELCIUS)\n            >>> T2 = Property(213, RelativeTemperatureUnit.FAHRENHEIT)\n            >>> T1 > T2\n            False\n        \"\"\"\n        self._validate_comparison_input(other)\n        try:\n            prop = other.to_unit(self.unit) if self.unit != other.unit else other\n        except PropertyUnitConversionError:\n            raise PropertyBinaryOperationError(\n                f\"cannot compare ({other}) to ({self}); ({other}) does not have the \"\n                f\"same units as ({self}) and there is no unit converter registered for \"\n                f\"({self.unit.to_generic()}). \"\n            ) from None\n        except UnitConversionError as exc:\n            raise PropertyBinaryOperationError(\n                f\"cannot compare ({other}) to ({self});\", exc\n            ) from None\n        return self.value > prop.value\n\n    def __ge__(self, other) -> bool:\n        \"\"\"\n        Defines comparison between properties.\n\n        Examples:\n            >>> from property_utils.units.units import RelativeTemperatureUnit\n            >>> T1 = Property(100, RelativeTemperatureUnit.CELCIUS)\n            >>> T2 = Property(212, RelativeTemperatureUnit.FAHRENHEIT)\n            >>> T1 >= T2\n            True\n        \"\"\"\n        self._validate_comparison_input(other)\n        try:\n            prop = other.to_unit(self.unit) if self.unit != other.unit else other\n        except PropertyUnitConversionError:\n            raise PropertyBinaryOperationError(\n                f\"cannot compare ({other}) to ({self}); ({other}) does not have the \"\n                f\"same units as ({self}) and there is no unit converter registered for \"\n                f\"({self.unit.to_generic()}). \"\n            ) from None\n        except UnitConversionError as exc:\n            raise PropertyBinaryOperationError(\n                f\"cannot compare ({other}) to ({self});\", exc\n            ) from None\n        return self.value >= prop.value\n\n    def __lt__(self, other) -> bool:\n        \"\"\"\n        Defines comparison between properties.\n\n        Examples:\n            >>> from property_utils.units.units import RelativeTemperatureUnit\n            >>> T1 = Property(100, RelativeTemperatureUnit.CELCIUS)\n            >>> T2 = Property(213, RelativeTemperatureUnit.FAHRENHEIT)\n            >>> T1 < T2\n            True\n        \"\"\"\n        self._validate_comparison_input(other)\n        try:\n            prop = other.to_unit(self.unit) if self.unit != other.unit else other\n        except PropertyUnitConversionError:\n            raise PropertyBinaryOperationError(\n                f\"cannot compare ({other}) to ({self}); ({other}) does not have the \"\n                f\"same units as ({self}) and there is no unit converter registered for \"\n                f\"({self.unit.to_generic()}). \"\n            ) from None\n        except UnitConversionError as exc:\n            raise PropertyBinaryOperationError(\n                f\"cannot compare ({other}) to ({self});\", exc\n            ) from None\n        return self.value < prop.value\n\n    def __le__(self, other) -> bool:\n        \"\"\"\n        Defines comparison between properties.\n\n        Examples:\n            >>> from property_utils.units.units import RelativeTemperatureUnit\n            >>> T1 = Property(100, RelativeTemperatureUnit.CELCIUS)\n            >>> T2 = Property(213, RelativeTemperatureUnit.FAHRENHEIT)\n            >>> T1 <= T2\n            True\n        \"\"\"\n        self._validate_comparison_input(other)\n        try:\n            prop = other.to_unit(self.unit) if self.unit != other.unit else other\n        except PropertyUnitConversionError:\n            raise PropertyBinaryOperationError(\n                f\"cannot compare ({other}) to ({self}); ({other}) does not have the \"\n                f\"same units as ({self}) and there is no unit converter registered for \"\n                f\"({self.unit.to_generic()}). \"\n            ) from None\n        except UnitConversionError as exc:\n            raise PropertyBinaryOperationError(\n                f\"cannot compare ({other}) to ({self});\", exc\n            ) from None\n        return self.value <= prop.value\n\n    def __str__(self) -> str:\n        return f\"{self.value} {self.unit}\"\n\n    def __repr__(self) -> str:\n        return f\"<Property: {str(self)}>\"\n\n    def _converter(self) -> Type[UnitConverter]:\n        \"\"\"\n        Raises `UndefinedConverter` if a converter is not defined.\n        \"\"\"\n        if self.unit_converter is None:\n            self.unit_converter = self._get_converter()\n        return self.unit_converter\n\n    def _get_converter(self) -> Type[UnitConverter]:\n        \"\"\"\n        Raises `UndefinedConverter` if a converter is not defined.\n        \"\"\"\n        return get_converter(self.unit.to_generic())\n\n    def _validate_comparison_input(self, other) -> None:\n        \"\"\"\n        Raises `PropertyBinaryOperationError` if other is not a Property or if it does\n        not have the same unit type as this Property.\n        \"\"\"\n        if not isinstance(other, Property):\n            raise PropertyBinaryOperationError(\n                f\"cannot compare {other} to ({self}); {other} is not a Property; \"\n                \"only properties can be compared to properties. \"\n            )\n        if not self.unit.isinstance_equivalent(other.unit.to_generic()):\n            raise PropertyBinaryOperationError(\n                f\"cannot compare ({other}) to ({self}); \"\n                f\"({other}) must have ({self.unit.to_generic()}) units. \"\n            )\n\n    def _unit_preconversion(self, prop: \"Property\") -> \"Property\":\n        \"\"\"\n        Applies a conversion to the given property's units before it is multiplied or\n        divided with this unit.\n\n        The preconversion is needed to produce simplified units from the multiplication/\n        division.\n        For example, if you multiply 5 cm with 2.02 m you don't want to get the result\n        in cm * m; in order to get the result in cm^2, 2.02 m (the right operand) is\n        converted to cm first.\n        \"\"\"\n        if isinstance(prop.unit, CompositeDimension):\n            return prop.to_unit(self._composite_unit_preconversion(prop.unit))\n\n        if isinstance(prop.unit, Dimension):\n            return prop.to_unit(self._dimension_unit_preconversion(prop.unit))\n\n        if isinstance(prop.unit, MeasurementUnit):\n            return prop.to_unit(self._simple_unit_preconversion(prop.unit))\n\n        return prop\n\n    # pylint: disable=too-many-branches\n    def _composite_unit_preconversion(\n        self, unit: CompositeDimension\n    ) -> CompositeDimension:\n        \"\"\"\n        Returns the composite dimension that the given dimension should be converted to\n        before multiplication or division with this property.\n        \"\"\"\n        other = replace(unit).simplified()\n\n        if isinstance(self.unit, CompositeDimension):\n            self.unit.simplify()\n\n            for i, num in enumerate(other.numerator):\n                _n = self.unit.get_numerator(num.to_generic(), None)\n                if _n is not None:\n                    other.numerator[i] = replace(_n)\n\n                d = self.unit.get_denominator(num.to_generic(), None)\n                if d is not None:\n                    other.numerator[i] = replace(d)\n\n            for i, d in enumerate(other.denominator):\n                _d = self.unit.get_denominator(d.to_generic(), None)\n                if _d is not None:\n                    other.denominator[i] = replace(_d)\n\n                n = self.unit.get_numerator(d.to_generic(), None)\n                if n is not None:\n                    other.denominator[i] = replace(n)\n\n            return other\n\n        _self: UnitDescriptor\n        if isinstance(self.unit, MeasurementUnit):\n            _self = self.unit**1\n        elif isinstance(self.unit, Dimension):\n            _self = replace(self.unit)\n        else:\n            _self = self.unit\n\n        if isinstance(_self, Dimension):\n            for i, n in enumerate(other.numerator):\n                if n.unit.isinstance(_self.unit.to_generic()):\n                    other.numerator[i] = _self.unit ** other.numerator[i].power\n                    return other\n\n            for i, d in enumerate(other.denominator):\n                if d.unit.isinstance(_self.unit.to_generic()):\n                    other.denominator[i] = _self.unit ** other.denominator[i].power\n                    return other\n\n        return unit\n\n    def _dimension_unit_preconversion(self, unit: Dimension) -> Dimension:\n        \"\"\"\n        Returns the dimension that the given dimension should be converted to before\n        multiplication or division with this property.\n        \"\"\"\n        if isinstance(self.unit, CompositeDimension):\n            self.unit.simplify()\n\n            for d in self.unit.denominator:\n                if d.unit.isinstance(unit.unit.to_generic()):\n                    return d.unit**unit.power\n\n            for n in self.unit.numerator:\n                if n.unit.isinstance(unit.unit.to_generic()):\n                    return n.unit**unit.power\n\n        _self: UnitDescriptor\n        if isinstance(self.unit, Dimension):\n            _self = self.unit.unit\n        else:\n            _self = self.unit\n\n        if isinstance(_self, MeasurementUnit):\n            if _self.isinstance(unit.unit.to_generic()):\n                return _self**unit.power\n\n        return unit\n\n    def _simple_unit_preconversion(self, unit: MeasurementUnit) -> MeasurementUnit:\n        \"\"\"\n        Returns the unit that the given unit should be converted to before\n        multiplication or division with this property.\n        \"\"\"\n        return self._dimension_unit_preconversion(unit**1).unit\n\n    def _simplify_units(self, unit: CompositeDimension) -> UnitDescriptor:\n        \"\"\"\n        Simplifies the composite dimension and returns NON_DIMENSIONAL if the simplified\n        composite does not have units.\n        \"\"\"\n        unit = unit.simplified()\n\n        if unit.has_no_units():\n            return NonDimensionalUnit.NON_DIMENSIONAL\n\n        return unit\n
    "},{"location":"property/#property_utils.properties.property.Property.__add__","title":"__add__(other)","text":"

    Defines addition between properties.

    Examples:

    >>> from property_utils.units.units import LengthUnit\n>>> x1 = Property(15, LengthUnit.METER)\n>>> x2 = Property(5, LengthUnit.METER)\n>>> x1 + x2\n<Property: 20 m>\n
    Source code in src/property_utils/properties/property.py
    def __add__(self, other) -> Self:\n    \"\"\"\n    Defines addition between properties.\n\n    Examples:\n        >>> from property_utils.units.units import LengthUnit\n        >>> x1 = Property(15, LengthUnit.METER)\n        >>> x2 = Property(5, LengthUnit.METER)\n        >>> x1 + x2\n        <Property: 20 m>\n    \"\"\"\n    if not isinstance(other, Property):\n        raise PropertyBinaryOperationError(\n            f\"cannot add {other} to ({self}); {other} is not a Property; \"\n            \"only properties can be added to properties. \"\n        )\n    if not self.unit.isinstance_equivalent(other.unit.to_generic()):\n        raise PropertyBinaryOperationError(\n            f\"cannot add ({other}) to ({self}); \"\n            f\"({other}) must have ({self.unit.to_generic()}) units. \"\n        )\n    try:\n        prop = other.to_unit(self.unit) if self.unit != other.unit else other\n    except PropertyUnitConversionError:\n        raise PropertyBinaryOperationError(\n            f\"cannot add ({other}) to ({self}); ({other}) does not have the same \"\n            f\"units as ({self}) and there is no unit converter registered for \"\n            f\"({self.unit.to_generic()}). \"\n        ) from None\n    except UnitConversionError as exc:\n        raise PropertyBinaryOperationError(\n            f\"cannot add ({other}) to ({self});\", exc\n        ) from None\n    return self.__class__(self.value + prop.value, self.unit)\n
    "},{"location":"property/#property_utils.properties.property.Property.__eq__","title":"__eq__(other)","text":"

    Defines equality between properties. Prefer Property.eq instead.The equality operator returns False even for very small differences between floating point values.

    Examples:

    >>> from property_utils.units.units import LengthUnit\n>>> L1 = Property(500, LengthUnit.CENTI_METER)\n>>> L2 = Property(5, LengthUnit.METER)\n>>> L1 == L2\nTrue\n
    >>> L3 = Property(6, LengthUnit.METER)\n>>> L2 == L3\nFalse\n
    Source code in src/property_utils/properties/property.py
    def __eq__(self, other) -> bool:\n    \"\"\"\n    Defines equality between properties.\n    Prefer Property.eq instead.The equality operator returns False even for very\n    small differences between floating point values.\n\n    Examples:\n        >>> from property_utils.units.units import LengthUnit\n        >>> L1 = Property(500, LengthUnit.CENTI_METER)\n        >>> L2 = Property(5, LengthUnit.METER)\n        >>> L1 == L2\n        True\n\n        >>> L3 = Property(6, LengthUnit.METER)\n        >>> L2 == L3\n        False\n    \"\"\"\n    if not isinstance(other, Property):\n        return False\n    if not self.unit.isinstance_equivalent(other.unit.to_generic()):\n        return False\n    try:\n        prop = other.to_unit(self.unit) if self.unit != other.unit else other\n    except PropertyUtilsException as exc:\n        raise PropertyBinaryOperationError(\n            f\"during conversion of {other} to ({self.unit}) units an error occured: \",\n            exc,\n        ) from None\n    return self.value == prop.value\n
    "},{"location":"property/#property_utils.properties.property.Property.__ge__","title":"__ge__(other)","text":"

    Defines comparison between properties.

    Examples:

    >>> from property_utils.units.units import RelativeTemperatureUnit\n>>> T1 = Property(100, RelativeTemperatureUnit.CELCIUS)\n>>> T2 = Property(212, RelativeTemperatureUnit.FAHRENHEIT)\n>>> T1 >= T2\nTrue\n
    Source code in src/property_utils/properties/property.py
    def __ge__(self, other) -> bool:\n    \"\"\"\n    Defines comparison between properties.\n\n    Examples:\n        >>> from property_utils.units.units import RelativeTemperatureUnit\n        >>> T1 = Property(100, RelativeTemperatureUnit.CELCIUS)\n        >>> T2 = Property(212, RelativeTemperatureUnit.FAHRENHEIT)\n        >>> T1 >= T2\n        True\n    \"\"\"\n    self._validate_comparison_input(other)\n    try:\n        prop = other.to_unit(self.unit) if self.unit != other.unit else other\n    except PropertyUnitConversionError:\n        raise PropertyBinaryOperationError(\n            f\"cannot compare ({other}) to ({self}); ({other}) does not have the \"\n            f\"same units as ({self}) and there is no unit converter registered for \"\n            f\"({self.unit.to_generic()}). \"\n        ) from None\n    except UnitConversionError as exc:\n        raise PropertyBinaryOperationError(\n            f\"cannot compare ({other}) to ({self});\", exc\n        ) from None\n    return self.value >= prop.value\n
    "},{"location":"property/#property_utils.properties.property.Property.__gt__","title":"__gt__(other)","text":"

    Defines comparison between properties.

    Examples:

    >>> from property_utils.units.units import RelativeTemperatureUnit\n>>> T1 = Property(100, RelativeTemperatureUnit.CELCIUS)\n>>> T2 = Property(213, RelativeTemperatureUnit.FAHRENHEIT)\n>>> T1 > T2\nFalse\n
    Source code in src/property_utils/properties/property.py
    def __gt__(self, other) -> bool:\n    \"\"\"\n    Defines comparison between properties.\n\n    Examples:\n        >>> from property_utils.units.units import RelativeTemperatureUnit\n        >>> T1 = Property(100, RelativeTemperatureUnit.CELCIUS)\n        >>> T2 = Property(213, RelativeTemperatureUnit.FAHRENHEIT)\n        >>> T1 > T2\n        False\n    \"\"\"\n    self._validate_comparison_input(other)\n    try:\n        prop = other.to_unit(self.unit) if self.unit != other.unit else other\n    except PropertyUnitConversionError:\n        raise PropertyBinaryOperationError(\n            f\"cannot compare ({other}) to ({self}); ({other}) does not have the \"\n            f\"same units as ({self}) and there is no unit converter registered for \"\n            f\"({self.unit.to_generic()}). \"\n        ) from None\n    except UnitConversionError as exc:\n        raise PropertyBinaryOperationError(\n            f\"cannot compare ({other}) to ({self});\", exc\n        ) from None\n    return self.value > prop.value\n
    "},{"location":"property/#property_utils.properties.property.Property.__le__","title":"__le__(other)","text":"

    Defines comparison between properties.

    Examples:

    >>> from property_utils.units.units import RelativeTemperatureUnit\n>>> T1 = Property(100, RelativeTemperatureUnit.CELCIUS)\n>>> T2 = Property(213, RelativeTemperatureUnit.FAHRENHEIT)\n>>> T1 <= T2\nTrue\n
    Source code in src/property_utils/properties/property.py
    def __le__(self, other) -> bool:\n    \"\"\"\n    Defines comparison between properties.\n\n    Examples:\n        >>> from property_utils.units.units import RelativeTemperatureUnit\n        >>> T1 = Property(100, RelativeTemperatureUnit.CELCIUS)\n        >>> T2 = Property(213, RelativeTemperatureUnit.FAHRENHEIT)\n        >>> T1 <= T2\n        True\n    \"\"\"\n    self._validate_comparison_input(other)\n    try:\n        prop = other.to_unit(self.unit) if self.unit != other.unit else other\n    except PropertyUnitConversionError:\n        raise PropertyBinaryOperationError(\n            f\"cannot compare ({other}) to ({self}); ({other}) does not have the \"\n            f\"same units as ({self}) and there is no unit converter registered for \"\n            f\"({self.unit.to_generic()}). \"\n        ) from None\n    except UnitConversionError as exc:\n        raise PropertyBinaryOperationError(\n            f\"cannot compare ({other}) to ({self});\", exc\n        ) from None\n    return self.value <= prop.value\n
    "},{"location":"property/#property_utils.properties.property.Property.__lt__","title":"__lt__(other)","text":"

    Defines comparison between properties.

    Examples:

    >>> from property_utils.units.units import RelativeTemperatureUnit\n>>> T1 = Property(100, RelativeTemperatureUnit.CELCIUS)\n>>> T2 = Property(213, RelativeTemperatureUnit.FAHRENHEIT)\n>>> T1 < T2\nTrue\n
    Source code in src/property_utils/properties/property.py
    def __lt__(self, other) -> bool:\n    \"\"\"\n    Defines comparison between properties.\n\n    Examples:\n        >>> from property_utils.units.units import RelativeTemperatureUnit\n        >>> T1 = Property(100, RelativeTemperatureUnit.CELCIUS)\n        >>> T2 = Property(213, RelativeTemperatureUnit.FAHRENHEIT)\n        >>> T1 < T2\n        True\n    \"\"\"\n    self._validate_comparison_input(other)\n    try:\n        prop = other.to_unit(self.unit) if self.unit != other.unit else other\n    except PropertyUnitConversionError:\n        raise PropertyBinaryOperationError(\n            f\"cannot compare ({other}) to ({self}); ({other}) does not have the \"\n            f\"same units as ({self}) and there is no unit converter registered for \"\n            f\"({self.unit.to_generic()}). \"\n        ) from None\n    except UnitConversionError as exc:\n        raise PropertyBinaryOperationError(\n            f\"cannot compare ({other}) to ({self});\", exc\n        ) from None\n    return self.value < prop.value\n
    "},{"location":"property/#property_utils.properties.property.Property.__mul__","title":"__mul__(other)","text":"

    Defines multiplication between properties and numerics.

    Examples:

    >>> from property_utils.units.units import AbsoluteTemperatureUnit, LengthUnit\n>>> T = Property(300, AbsoluteTemperatureUnit.KELVIN)\n>>> 2*T\n<Property: 600 K>\n>>> A = Property(10, LengthUnit.METER**2)\n>>> T * A\n<Property: 3000 (m^2) * K>\n
    Source code in src/property_utils/properties/property.py
    def __mul__(self, other) -> \"Property\":\n    \"\"\"\n    Defines multiplication between properties and numerics.\n\n    Examples:\n        >>> from property_utils.units.units import AbsoluteTemperatureUnit, LengthUnit\n        >>> T = Property(300, AbsoluteTemperatureUnit.KELVIN)\n        >>> 2*T\n        <Property: 600 K>\n        >>> A = Property(10, LengthUnit.METER**2)\n        >>> T * A\n        <Property: 3000 (m^2) * K>\n    \"\"\"\n    if isinstance(other, (float, int)):\n        return self.__class__(self.value * other, self.unit)\n    if isinstance(other, Property):\n        _other = self._unit_preconversion(other)\n        return Property(\n            self.value * _other.value, self._simplify_units(self.unit * _other.unit)\n        )\n    raise PropertyBinaryOperationError(\n        f\"cannot multiply {self} with {other}; \"\n        \"second operand must be numeric or Property. \"\n    )\n
    "},{"location":"property/#property_utils.properties.property.Property.__ne__","title":"__ne__(other)","text":"

    Defines inequality between properties. Prefer Property.eq instead.The inequality operator returns True even for very small differences between floating point values.

    Examples:

    >>> from property_utils.units.units import LengthUnit\n>>> L1 = Property(500, LengthUnit.CENTI_METER)\n>>> L2 = Property(5, LengthUnit.METER)\n>>> L1 != L2\nFalse\n
    >>> L3 = Property(6, LengthUnit.METER)\n>>> L2 != L3\nTrue\n
    Source code in src/property_utils/properties/property.py
    def __ne__(self, other) -> bool:\n    \"\"\"\n    Defines inequality between properties.\n    Prefer Property.eq instead.The inequality operator returns True even for very\n    small differences between floating point values.\n\n    Examples:\n        >>> from property_utils.units.units import LengthUnit\n        >>> L1 = Property(500, LengthUnit.CENTI_METER)\n        >>> L2 = Property(5, LengthUnit.METER)\n        >>> L1 != L2\n        False\n\n        >>> L3 = Property(6, LengthUnit.METER)\n        >>> L2 != L3\n        True\n    \"\"\"\n    return not self.__eq__(other)\n
    "},{"location":"property/#property_utils.properties.property.Property.__neg__","title":"__neg__()","text":"

    Defines negation of properties.

    Examples:

    >>> from property_utils.units.units import RelativeTemperatureUnit\n>>> T = Property(3, RelativeTemperatureUnit.CELCIUS)\n>>> -T\n<Property: -3 \u00b0C>\n
    Source code in src/property_utils/properties/property.py
    def __neg__(self) -> Self:\n    \"\"\"\n    Defines negation of properties.\n\n    Examples:\n        >>> from property_utils.units.units import RelativeTemperatureUnit\n        >>> T = Property(3, RelativeTemperatureUnit.CELCIUS)\n        >>> -T\n        <Property: -3 \u00b0C>\n    \"\"\"\n    return self.__class__(-self.value, self.unit)\n
    "},{"location":"property/#property_utils.properties.property.Property.__pow__","title":"__pow__(power)","text":"

    Defines exponentiation for properties.

    Examples:

    >>> from property_utils.units.units import LengthUnit\n>>> L = Property(5, LengthUnit.METER)\n>>> L**3\n<Property: 125 (m^3)>\n
    Source code in src/property_utils/properties/property.py
    def __pow__(self, power) -> \"Property\":\n    \"\"\"\n    Defines exponentiation for properties.\n\n    Examples:\n        >>> from property_utils.units.units import LengthUnit\n        >>> L = Property(5, LengthUnit.METER)\n        >>> L**3\n        <Property: 125 (m^3)>\n    \"\"\"\n    if not isinstance(power, (float, int)):\n        raise PropertyExponentError(\n            f\"invalid exponent: {power}; expected numeric. \"\n        )\n    return Property(self.value**power, self.unit**power)\n
    "},{"location":"property/#property_utils.properties.property.Property.__radd__","title":"__radd__(other)","text":"

    Defines right addition between properties.

    Examples:

    >>> from property_utils.units.units import LengthUnit\n>>> x1 = Property(15, LengthUnit.METER)\n>>> x2 = Property(5, LengthUnit.METER)\n>>> x1 + x2\n<Property: 20 m>\n
    Source code in src/property_utils/properties/property.py
    def __radd__(self, other) -> Self:\n    \"\"\"\n    Defines right addition between properties.\n\n    Examples:\n        >>> from property_utils.units.units import LengthUnit\n        >>> x1 = Property(15, LengthUnit.METER)\n        >>> x2 = Property(5, LengthUnit.METER)\n        >>> x1 + x2\n        <Property: 20 m>\n    \"\"\"\n    return self.__add__(other)\n
    "},{"location":"property/#property_utils.properties.property.Property.__rmul__","title":"__rmul__(other)","text":"

    Defines multiplication between properties and numerics.

    Examples:

    >>> from property_utils.units.units import AbsoluteTemperatureUnit, LengthUnit\n>>> T = Property(300, AbsoluteTemperatureUnit.KELVIN)\n>>> 2*T\n<Property: 600 K>\n>>> A = Property(10, LengthUnit.METER**2)\n>>> T * A\n<Property: 3000 (m^2) * K>\n
    Source code in src/property_utils/properties/property.py
    def __rmul__(self, other) -> \"Property\":\n    \"\"\"\n    Defines multiplication between properties and numerics.\n\n    Examples:\n        >>> from property_utils.units.units import AbsoluteTemperatureUnit, LengthUnit\n        >>> T = Property(300, AbsoluteTemperatureUnit.KELVIN)\n        >>> 2*T\n        <Property: 600 K>\n        >>> A = Property(10, LengthUnit.METER**2)\n        >>> T * A\n        <Property: 3000 (m^2) * K>\n    \"\"\"\n    return self.__mul__(other)\n
    "},{"location":"property/#property_utils.properties.property.Property.__rsub__","title":"__rsub__(other)","text":"

    Defines right subtraction between properties.

    Examples:

    >>> from property_utils.units.units import TimeUnit\n>>> t1 = Property(2, TimeUnit.MINUTE)\n>>> t2 = Property(60, TimeUnit.SECOND)\n>>> t1 - t2\n<Property: 1.0 min>\n
    Source code in src/property_utils/properties/property.py
    def __rsub__(self, other) -> \"Property\":\n    \"\"\"\n    Defines right subtraction between properties.\n\n    Examples:\n        >>> from property_utils.units.units import TimeUnit\n        >>> t1 = Property(2, TimeUnit.MINUTE)\n        >>> t2 = Property(60, TimeUnit.SECOND)\n        >>> t1 - t2\n        <Property: 1.0 min>\n    \"\"\"\n    if not isinstance(other, Property):\n        raise PropertyBinaryOperationError(\n            f\"cannot subtract {self} from ({other}); {other} is not a \"\n            f\"{self.__class__}; only same properties can be subtracted from each \"\n            \"other. \"\n        )\n    if not self.unit.isinstance_equivalent(other.unit.to_generic()):\n        raise PropertyBinaryOperationError(\n            f\"cannot subtract ({self}) from ({other}); \"\n            f\"({other}) must have ({self.unit.to_generic()}) units. \"\n        )\n    return other.__add__(-self)\n
    "},{"location":"property/#property_utils.properties.property.Property.__rtruediv__","title":"__rtruediv__(other)","text":"

    Defines right division between properties and numerics.

    Examples:

    >>> from property_utils.units.units import AbsoluteTemperatureUnit\n>>> T = Property(500, AbsoluteTemperatureUnit.KELVIN)\n>>> 100/T\n<Property: 0.2  / K>\n
    Source code in src/property_utils/properties/property.py
    def __rtruediv__(self, other) -> \"Property\":\n    \"\"\"\n    Defines right division between properties and numerics.\n\n    Examples:\n        >>> from property_utils.units.units import AbsoluteTemperatureUnit\n        >>> T = Property(500, AbsoluteTemperatureUnit.KELVIN)\n        >>> 100/T\n        <Property: 0.2  / K>\n    \"\"\"\n    if isinstance(other, (float, int)):\n        try:\n            value = other / self.value\n        except ZeroDivisionError:\n            raise PropertyBinaryOperationError(\n                f\"cannot divide {self} with {other}; denominator is zero. \"\n            ) from None\n        return Property(value, self.unit.inverse())\n    if isinstance(other, Property):\n        try:\n            value = other.value / self.value\n        except ZeroDivisionError:\n            raise PropertyBinaryOperationError(\n                f\"cannot divide {self} with {other}; denominator's value is zero. \"\n            ) from None\n        return Property(value, self._simplify_units(other.unit / self.unit))\n    raise PropertyBinaryOperationError(\n        f\"cannot divide {self} with {other}; \"\n        \"numerator must be numeric or Property. \"\n    )\n
    "},{"location":"property/#property_utils.properties.property.Property.__sub__","title":"__sub__(other)","text":"

    Defines subtraction between properties.

    Examples:

    >>> from property_utils.units.units import TimeUnit\n>>> t1 = Property(2, TimeUnit.MINUTE)\n>>> t2 = Property(60, TimeUnit.SECOND)\n>>> t1 - t2\n<Property: 1.0 min>\n
    Source code in src/property_utils/properties/property.py
    def __sub__(self, other) -> Self:\n    \"\"\"\n    Defines subtraction between properties.\n\n    Examples:\n        >>> from property_utils.units.units import TimeUnit\n        >>> t1 = Property(2, TimeUnit.MINUTE)\n        >>> t2 = Property(60, TimeUnit.SECOND)\n        >>> t1 - t2\n        <Property: 1.0 min>\n    \"\"\"\n    if not isinstance(other, Property):\n        raise PropertyBinaryOperationError(\n            f\"cannot subtract {other} from ({self}); {other} is not a \"\n            \"Property; only properties can be subtracted from properties. \"\n        )\n    if not self.unit.isinstance_equivalent(other.unit.to_generic()):\n        raise PropertyBinaryOperationError(\n            f\"cannot subtract ({other}) from ({self}); \"\n            f\"({other}) must have ({self.unit.to_generic()}) units. \"\n        )\n    try:\n        prop = other.to_unit(self.unit) if self.unit != other.unit else other\n    except PropertyUnitConversionError:\n        raise PropertyBinaryOperationError(\n            f\"cannot subtract ({other}) from ({self}); ({other}) does not have the \"\n            f\"same units as ({self}) and there is no unit converter registered for \"\n            f\"({self.unit.to_generic()}). \"\n        ) from None\n    except UnitConversionError as exc:\n        raise PropertyBinaryOperationError(\n            f\"cannot subtract ({other}) from ({self});\", exc\n        ) from None\n    return self.__class__(self.value - prop.value, self.unit)\n
    "},{"location":"property/#property_utils.properties.property.Property.__truediv__","title":"__truediv__(other)","text":"

    Defines division between properties and numerics.

    Examples:

    >>> from property_utils.units.units import AbsoluteTemperatureUnit, LengthUnit\n>>> T = Property(500, AbsoluteTemperatureUnit.KELVIN)\n>>> T/2\n<Property: 250.0 K>\n>>> A = Property(10, LengthUnit.METER**2)\n>>> T / A\n<Property: 50.0 K / (m^2)>\n
    Source code in src/property_utils/properties/property.py
    def __truediv__(self, other) -> \"Property\":\n    \"\"\"\n    Defines division between properties and numerics.\n\n    Examples:\n        >>> from property_utils.units.units import AbsoluteTemperatureUnit, LengthUnit\n        >>> T = Property(500, AbsoluteTemperatureUnit.KELVIN)\n        >>> T/2\n        <Property: 250.0 K>\n        >>> A = Property(10, LengthUnit.METER**2)\n        >>> T / A\n        <Property: 50.0 K / (m^2)>\n    \"\"\"\n    if isinstance(other, (float, int)):\n        try:\n            value = self.value / other\n        except ZeroDivisionError:\n            raise PropertyBinaryOperationError(\n                f\"cannot divide {self} with {other}; denominator is zero. \"\n            ) from None\n        return Property(value, self.unit)\n    if isinstance(other, Property):\n        _other = self._unit_preconversion(other)\n        try:\n            value = self.value / _other.value\n        except ZeroDivisionError:\n            raise PropertyBinaryOperationError(\n                f\"cannot divide {self} with {other}; denominator's value is zero. \"\n            ) from None\n        return Property(value, self._simplify_units(self.unit / _other.unit))\n    raise PropertyBinaryOperationError(\n        f\"cannot divide {self} with {other}; \"\n        \"denominator must be numeric or Property. \"\n    )\n
    "},{"location":"property/#property_utils.properties.property.Property.eq","title":"eq(other, *, rel_tol=1e-09, abs_tol=0)","text":"

    Perform equality comparison between this and some other Property. This method of testing equality is preferable to the equality operator '==' because float point tolerance is taken into account.

    rel_tol is the maximum difference for being considered \"close\", relative to the magnitude of the input values. abs_tol is the maximum difference for being considered \"close\", regardless of the magnitude of the input values. For the values to be considered close, the difference between them must be smaller than at least one of the tolerances.

    Raises PropertyBinaryOperationError if an error occurs during conversion of other's units.

    Examples:

    >>> from property_utils.units.units import AbsoluteTemperatureUnit, LengthUnit\n>>> T1 = Property(33.333333, AbsoluteTemperatureUnit.KELVIN)\n>>> T2 = Property(100/3, AbsoluteTemperatureUnit.KELVIN)\n>>> T1 == T2\nFalse\n>>> T1.eq(T2)\nFalse\n>>> T1.eq(T2, rel_tol=0.1)\nTrue\n
    Source code in src/property_utils/properties/property.py
    def eq(self, other: \"Property\", *, rel_tol=1e-9, abs_tol=0) -> bool:\n    \"\"\"\n    Perform equality comparison between this and some other Property. This method\n    of testing equality is preferable to the equality operator '==' because float\n    point tolerance is taken into account.\n\n    rel_tol is the maximum difference for being considered \"close\", relative\n    to the magnitude of the input values.\n    abs_tol is the maximum difference for being considered \"close\", regardless of\n    the magnitude of the input values.\n    For the values to be considered close, the difference between them must be\n    smaller than at least one of the tolerances.\n\n    Raises `PropertyBinaryOperationError` if an error occurs during conversion\n    of other's units.\n\n    Examples:\n        >>> from property_utils.units.units import AbsoluteTemperatureUnit, LengthUnit\n        >>> T1 = Property(33.333333, AbsoluteTemperatureUnit.KELVIN)\n        >>> T2 = Property(100/3, AbsoluteTemperatureUnit.KELVIN)\n        >>> T1 == T2\n        False\n        >>> T1.eq(T2)\n        False\n        >>> T1.eq(T2, rel_tol=0.1)\n        True\n    \"\"\"\n    if not isinstance(other, Property):\n        return False\n    if not self.unit.isinstance_equivalent(other.unit.to_generic()):\n        return False\n    try:\n        prop = other.to_unit(self.unit) if self.unit != other.unit else other\n    except PropertyUtilsException as exc:\n        raise PropertyBinaryOperationError(\n            f\"during conversion of {other} to ({self.unit}) units an error occured: \",\n            exc,\n        ) from None\n    return isclose(self.value, prop.value, rel_tol=rel_tol, abs_tol=abs_tol)\n
    "},{"location":"property/#property_utils.properties.property.Property.to_si","title":"to_si()","text":"

    Create a new property with SI units.

    Raises ImpossiblePropertyUnitConverion if there is no converter registered for the unit.

    Raises InvalidUnitConversion if any error occurs in the unit conversion.

    Examples:

    >>> from property_utils.units.units import RelativeTemperatureUnit\n>>> T = Property(100, RelativeTemperatureUnit.CELCIUS)\n>>> T.to_si()\n<Property: 373.15 K>\n
    Source code in src/property_utils/properties/property.py
    def to_si(self) -> Self:\n    \"\"\"\n    Create a new property with SI units.\n\n    Raises `ImpossiblePropertyUnitConverion` if there is no converter registered\n    for the unit.\n\n    Raises `InvalidUnitConversion` if any error occurs in the unit conversion.\n\n    Examples:\n        >>> from property_utils.units.units import RelativeTemperatureUnit\n        >>> T = Property(100, RelativeTemperatureUnit.CELCIUS)\n        >>> T.to_si()\n        <Property: 373.15 K>\n    \"\"\"\n    if isinstance(self.unit, MeasurementUnit):\n        return self.to_unit(self.unit.si())\n    if isinstance(self.unit, Dimension):\n        return self.to_unit(self.unit.unit.si() ** self.unit.power)\n    if isinstance(self.unit, CompositeDimension):\n        return self.to_unit(self.unit.to_generic().to_si())\n    raise PropertyValidationError(\n        f\"cannot convert Property to SI; 'unit' is invalid: {self.unit}. \"\n    )\n
    "},{"location":"property/#property_utils.properties.property.Property.to_unit","title":"to_unit(unit)","text":"

    Create a new property with specified unit.

    Raises PropertyUnitConversionError if the unit is not of the same type.

    Raises ImpossiblePropertyUnitConverion if there is no converter registered for the unit.

    Raises UnitConversionError if any error occurs in the unit conversion.

    Examples:

    >>> from property_utils.units.units import RelativeTemperatureUnit\n>>> T = Property(100, RelativeTemperatureUnit.CELCIUS)\n>>> T.to_unit(RelativeTemperatureUnit.FAHRENHEIT)\n<Property: 212.0 \u00b0F>\n
    Source code in src/property_utils/properties/property.py
    def to_unit(self, unit: UnitDescriptor) -> Self:\n    \"\"\"\n    Create a new property with specified unit.\n\n    Raises `PropertyUnitConversionError` if the unit is not of the same type.\n\n    Raises `ImpossiblePropertyUnitConverion` if there is no converter registered\n    for the unit.\n\n    Raises `UnitConversionError` if any error occurs in the unit conversion.\n\n    Examples:\n        >>> from property_utils.units.units import RelativeTemperatureUnit\n        >>> T = Property(100, RelativeTemperatureUnit.CELCIUS)\n        >>> T.to_unit(RelativeTemperatureUnit.FAHRENHEIT)\n        <Property: 212.0 \u00b0F>\n    \"\"\"\n    if self.unit == unit:\n        return self.__class__(unit=self.unit, value=self.value)\n\n    if not unit.isinstance_equivalent(self.unit.to_generic()):\n        raise PropertyUnitConversionError(\n            f\"cannot convert {self} to ({unit}) units; 'unit' should be an instance\"\n            f\" of {self.unit.to_generic()}. \"\n        )\n    try:\n        converter = self._converter()\n    except UndefinedConverterError:\n        raise PropertyUnitConversionError(\n            f\"cannot convert property {self} to units: {unit}; no unit converter \"\n            f\" found for {unit.to_generic()}. \"\n            \"Did you forget to @register_converter? \"\n        ) from None\n    try:\n        value = converter.convert(self.value, self.unit, unit)\n    except UnitConversionError as exc:\n        raise exc from None\n    return self.__class__(value=value, unit=unit)\n
    "},{"location":"property/#property_utils.properties.property.RelativeTemperatureUnitConverter","title":"RelativeTemperatureUnitConverter","text":"

    Bases: RelativeUnitConverter

    Convert temperature units with this converter.

    Examples:

    >>> RelativeTemperatureUnitConverter.convert(100, RelativeTemperatureUnit.CELCIUS, RelativeTemperatureUnit.FAHRENHEIT)\n212.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(RelativeTemperatureUnit)\nclass RelativeTemperatureUnitConverter(\n    RelativeUnitConverter\n):  # pylint: disable=too-few-public-methods\n    \"\"\"\n    Convert temperature units with this converter.\n\n    Examples:\n        >>> RelativeTemperatureUnitConverter.convert(100, RelativeTemperatureUnit.CELCIUS, RelativeTemperatureUnit.FAHRENHEIT)\n        212.0\n    \"\"\"\n\n    reference_unit = RelativeTemperatureUnit.CELCIUS\n    conversion_map = {\n        RelativeTemperatureUnit.CELCIUS: lambda t: t,\n        AbsoluteTemperatureUnit.KELVIN: lambda t: t - 273.15,\n        RelativeTemperatureUnit.FAHRENHEIT: lambda t: (t - 32) / 1.8,\n        AbsoluteTemperatureUnit.RANKINE: lambda t: (t / 1.8) - 273.15,\n    }\n    reference_conversion_map = {\n        RelativeTemperatureUnit.CELCIUS: lambda t: t,\n        AbsoluteTemperatureUnit.KELVIN: lambda t: t + 273.15,\n        RelativeTemperatureUnit.FAHRENHEIT: lambda t: (t * 1.8) + 32,\n        AbsoluteTemperatureUnit.RANKINE: lambda t: (t + 273.15) * 1.8,\n    }\n
    "},{"location":"property/#property_utils.properties.property.TimeUnitConverter","title":"TimeUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    Convert time units with this converter.

    Examples:

    >>> TimeUnitConverter.convert(1, TimeUnit.HOUR, TimeUnit.SECOND)\n3600.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(TimeUnit)\nclass TimeUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    Convert time units with this converter.\n\n    Examples:\n        >>> TimeUnitConverter.convert(1, TimeUnit.HOUR, TimeUnit.SECOND)\n        3600.0\n    \"\"\"\n\n    reference_unit = TimeUnit.SECOND\n    conversion_map = {\n        TimeUnit.MILLI_SECOND: UnitPrefix.MILLI.inverse(),\n        TimeUnit.SECOND: 1,\n        TimeUnit.MINUTE: 1 / 60.0,\n        TimeUnit.HOUR: 1 / 60.0 / 60.0,\n        TimeUnit.DAY: 1 / 60.0 / 60.0 / 24.0,\n        TimeUnit.WEEK: 1 / 60.0 / 60.0 / 24.0 / 7,\n        TimeUnit.MONTH: 1 / 60.0 / 60.0 / 24.0 / (365 / 12),\n        TimeUnit.YEAR: 1 / 60.0 / 60.0 / 24.0 / 365,\n    }\n
    "},{"location":"property/#property_utils.properties.property.UnitPrefix","title":"UnitPrefix","text":"

    Bases: float, Enum

    Enumeration of unit prefixes. Handy when converting to and fro prefixed units.

    Examples:

    >>> centimeters = 225\n>>> meters = centimeters * UnitPrefix.CENTI\n>>> meters\n2.25\n
    Source code in src/property_utils/units/converters.py
    class UnitPrefix(float, Enum):\n    \"\"\"\n    Enumeration of unit prefixes.\n    Handy when converting to and fro prefixed units.\n\n    Examples:\n        >>> centimeters = 225\n        >>> meters = centimeters * UnitPrefix.CENTI\n        >>> meters\n        2.25\n    \"\"\"\n\n    PICO = 1e-12\n    NANO = 1e-9\n    MICRO = 1e-6\n    MILLI = 1e-3\n    CENTI = 1e-2\n    DECI = 1e-1\n    DECA = 1e1\n    HECTO = 1e2\n    KILO = 1e3\n    MEGA = 1e6\n    GIGA = 1e9\n    TERA = 1e12\n\n    def inverse(self) -> float:\n        \"\"\"\n        Return the inverse of the unit prefix. Use when prefixing a unit.\n\n        Examples:\n            >>> meters = 50.26\n            >>> centimeters = meters * UnitPrefix.CENTI.inverse()\n            >>> centimeters\n            5026.0\n        \"\"\"\n        return 1 / self.value\n
    "},{"location":"property/#property_utils.properties.property.UnitPrefix.inverse","title":"inverse()","text":"

    Return the inverse of the unit prefix. Use when prefixing a unit.

    Examples:

    >>> meters = 50.26\n>>> centimeters = meters * UnitPrefix.CENTI.inverse()\n>>> centimeters\n5026.0\n
    Source code in src/property_utils/units/converters.py
    def inverse(self) -> float:\n    \"\"\"\n    Return the inverse of the unit prefix. Use when prefixing a unit.\n\n    Examples:\n        >>> meters = 50.26\n        >>> centimeters = meters * UnitPrefix.CENTI.inverse()\n        >>> centimeters\n        5026.0\n    \"\"\"\n    return 1 / self.value\n
    "},{"location":"property/#property_utils.properties.property.VolumeUnitConverter","title":"VolumeUnitConverter","text":"

    Bases: ExponentiatedUnitConverter

    Convert volume units with this converter.

    Examples:

    >>> VolumeUnitConverter.convert(1, LengthUnit.METER**3, LengthUnit.CENTI_METER**3)\n1000000.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(LengthUnit**3)\nclass VolumeUnitConverter(ExponentiatedUnitConverter):\n    \"\"\"\n    Convert volume units with this converter.\n\n    Examples:\n        >>> VolumeUnitConverter.convert(1, LengthUnit.METER**3, LengthUnit.CENTI_METER**3)\n        1000000.0\n    \"\"\"\n
    "},{"location":"property/#property_utils.properties.property.p","title":"p(value, unit=NonDimensionalUnit.NON_DIMENSIONAL)","text":"

    Create a property with a value and a unit. Default unit is non-dimensional, i.e. no unit.

    Examples:

    >>> from property_utils.units import KELVIN\n>>> p(350, KELVIN)\n<Property: 350 K>\n
    >>> p(20.23)\n<Property: 20.23 >\n
    Source code in src/property_utils/properties/property.py
    def p(\n    value: float, unit: UnitDescriptor = NonDimensionalUnit.NON_DIMENSIONAL\n) -> \"Property\":\n    \"\"\"\n    Create a property with a value and a unit.\n    Default unit is non-dimensional, i.e. no unit.\n\n    Examples:\n        >>> from property_utils.units import KELVIN\n        >>> p(350, KELVIN)\n        <Property: 350 K>\n\n        >>> p(20.23)\n        <Property: 20.23 >\n    \"\"\"\n    return Property(value, unit)\n
    "},{"location":"terminology/","title":"Terminology","text":""},{"location":"terminology/#unit-descriptors-or-just-units","title":"Unit descriptors (or just units)","text":"

    Throughout property-utils the term unit descriptor is used to denote a specific measurement unit of a physical property; it can, for example, refer to Celcius (\u00b0C) but not to temperature units in general.

    "},{"location":"terminology/#generic-unit-descriptors-or-just-generics","title":"Generic unit descriptors (or just generics)","text":"

    Throughout property-utils the term generic descriptor is used to denote a type of measurement units; it can, for example, refer to length units but not to meters, inches, etc.

    "},{"location":"usage/","title":"Usage","text":"

    This sections assumes the reader is acquainted with the terms in Terminology.

    "},{"location":"usage/#unit-arithmetics","title":"Unit arithmetics","text":""},{"location":"usage/#create-composite-units","title":"Create composite units","text":"

    Units can be created by multiplying and dividing base units:

    from property_utils.units import JOULE, MOL, KELVIN, METER\n\nthermal_capacity_units = JOULE / MOL / KELVIN\nmolar_volume_units = MOL / METER**3\nprint(\"thermal_capacity_units =\", thermal_capacity_units)\nprint(\"molar_volume_units =\", molar_volume_units)\n

    Result:

    thermal_capacity_units = J / K / mol\nmolar_volume_units = mol / (m^3)\n
    "},{"location":"usage/#compare-units","title":"Compare units","text":"

    Units can be compared with other units. The isinstance method checks if a unit belongs to some specific unit type.

    from property_utils.units import WATT, PowerUnit, EnergyUnit\n\nprint(WATT.isinstance(PowerUnit))\nprint(WATT.isinstance(EnergyUnit))\n

    Result:

    True\nFalse\n

    The isinstance_equivalent method checks if a unit is equivalent to some other generic unit.

    from property_utils.units import (\n    WATT,\n    PowerUnit,\n    EnergyUnit,\n    TimeUnit,\n    ForceUnit,\n    LengthUnit,\n    MassUnit,\n)\n\nprint(WATT.isinstance_equivalent(PowerUnit))\nprint(WATT.isinstance_equivalent(EnergyUnit / TimeUnit))\nprint(WATT.isinstance_equivalent(ForceUnit * LengthUnit / TimeUnit))\nprint(WATT.isinstance_equivalent(MassUnit * LengthUnit**2 / TimeUnit**3))\n

    Result:

    True\nTrue\nTrue\nTrue\n
    "},{"location":"usage/#si-units","title":"SI units","text":"

    Any unit can be converted to si units with the si method.

    from property_utils.units import BTU, RANKINE, FOOT, CENTI_METER, KILO_CALORIE\n\nprint((BTU / FOOT**2 / RANKINE).si())\nprint((CENTI_METER**3).si())\nprint(KILO_CALORIE.si())\n

    Result:

    J / (m^2) / K\n(m^3)\nJ\n
    "},{"location":"usage/#simplify-composite-units","title":"Simplify composite units","text":"

    Composite units may contain same units in the numerator and denominator. The simplified method removes common units from the numerator and denominator.

    from property_utils.units import METER, SECOND\n\nvelocity_units = METER / SECOND\nacceleration_units = velocity_units / SECOND\n\nprint(\"acceleration_units =\", acceleration_units)\nprint(\"acceleration_units simplified =\", acceleration_units.simplified())\n

    Result:

    acceleration_units = m / s / s\nacceleration_units simplified = m / (s^2)\n

    The simplified method also merges common units.

    from property_utils.units import METER\n\nlength_units = METER\narea_units = length_units * length_units\n\nprint(\"area_units =\", area_units)\nprint(\"area_units simplified =\", area_units.simplified())\n

    Result:

    area_units = m * m\narea_units simplified = (m^2)\n
    "},{"location":"usage/#unit-conversions","title":"Unit conversions","text":"

    Any property can be converted to chosen units with to_unit:

    from property_utils.properties import p\nfrom property_utils.units import WATT, METER, KELVIN, BTU, FOOT, RANKINE, HOUR\n\nheat_transfer_coeff = p(50, WATT / METER**2 / KELVIN)\nprint(\n    \"heat_transfer_coeff =\",\n    heat_transfer_coeff.to_unit(BTU / HOUR / FOOT**2 / RANKINE),\n)\n

    Result:

    heat_transfer_coeff = 8.805115955164156 Btu / (ft^2) / hr / \u00b0R\n

    Converting to SI units is easier with to_si:

    from property_utils.properties import p\nfrom property_utils.units import GRAM, CENTI_METER\n\narea_density = p(12, GRAM / CENTI_METER**2)\n\nprint(\"area_density =\", area_density)\nprint(\"area_density (SI) =\", area_density.to_si())\n

    Result:

    area_density = 12 g / (cm^2)\narea_density (SI) = 120.0 kg / (m^2)\n
    "},{"location":"usage/#property-arithmetics","title":"Property arithmetics","text":""},{"location":"usage/#addition-subtraction","title":"Addition - Subtraction","text":"

    Properties can be added and subtracted to and from each other:

    from property_utils.properties import p\nfrom property_utils.units import BAR\n\npressure_1 = p(15, BAR)\npressure_2 = p(2, BAR)\nprint(\"pressure_1 + pressure_2 =\", pressure_1 + pressure_2)\nprint(\"pressure_1 - pressure_2 =\", pressure_1 - pressure_2)\n

    Result:

    pressure_1 + pressure_2 = 17 bar\npressure_1 - pressure_2 = 13 bar\n

    Properties with different units can be added to each other. The result is always calculated in the units of the left operand.

    from property_utils.properties import p\nfrom property_utils.units import BAR, PSI\n\npressure_1 = p(5, BAR)\npressure_2 = p(30, PSI)\nprint(\"pressure_1 + pressure_2 =\", pressure_1 + pressure_2)\nprint(\"pressure_2 + pressure_1 =\", pressure_2 + pressure_1)\n

    Result:

    pressure_1 + pressure_2 = 7.068423447648202 bar\npressure_2 + pressure_1 = 102.519 psi\n
    "},{"location":"usage/#multiplication-division","title":"Multiplication - Division","text":"

    Properties can be multiplied and divided by numerics:

    from property_utils.properties import p\nfrom property_utils.units import KELVIN\n\ntemperature = p(773.15, KELVIN)\nprint(\"2*temperature =\", 2*temperature)\nprint(\"temperature/2 =\", temperature/2)\n

    Result:

    2*temperature = 1546.3 K\ntemperature/2 = 386.575 K\n

    Properties can also be multiplied and divided with each other:

    from property_utils.properties import p\nfrom property_utils.units import KELVIN, JOULE, KILO_GRAM\n\nthermal_capacity = p(4200, JOULE/KELVIN/KILO_GRAM)\ntemperature_diff = p(57, KELVIN)\nenthalpy = thermal_capacity * temperature_diff\nprint(\"enthalpy =\", thermal_capacity*temperature_diff)\n

    Result:

    enthalpy = 239400 J / kg\n
    "},{"location":"validated_property/","title":"validated property","text":""},{"location":"validated_property/#property_utils.properties.validated_property.ValidatedProperty","title":"ValidatedProperty dataclass","text":"

    Bases: Property

    A ValidatedProperty applies custom validations on its' value.

    Inherit from this class and implement the validate_value method to apply a validation to the property's value.

    You should also define the generic_unit_descriptor class variable. A validation is applied upon initialization for the type of the unit; if its' generic type does not match the generic_unit_descriptor a PropertyValidationError` is raised.

    default_units class variable is the default units with which properties will be created; if it is not defined the default it to use SI units.

    Examples:

    >>> from property_utils.units.units import LengthUnit, AbsoluteTemperatureUnit\n>>> class Distance(ValidatedProperty):\n...     generic_unit_descriptor = LengthUnit\n
    >>> class NauticalDistance(Distance):\n...     default_units = LengthUnit.NAUTICAL_MILE\n
    >>> Distance(5) # defaults to SI units\n<Distance: 5 m>\n>>> NauticalDistance(45.2)\n<NauticalDistance: 45.2 NM>\n
    Source code in src/property_utils/properties/validated_property.py
    @dataclass\nclass ValidatedProperty(Property):\n    \"\"\"\n    A ValidatedProperty applies custom validations on its' value.\n\n    Inherit from this class and implement the `validate_value` method to apply a\n    validation to the property's value.\n\n    You should also define the `generic_unit_descriptor` class variable. A validation\n    is applied upon initialization for the type of the unit; if its' generic type\n    does not match the `generic_unit_descriptor` a PropertyValidationError` is raised.\n\n    `default_units` class variable is the default units with which properties will be\n    created; if it is not defined the default it to use SI units.\n\n    Examples:\n        >>> from property_utils.units.units import LengthUnit, AbsoluteTemperatureUnit\n        >>> class Distance(ValidatedProperty):\n        ...     generic_unit_descriptor = LengthUnit\n\n        >>> class NauticalDistance(Distance):\n        ...     default_units = LengthUnit.NAUTICAL_MILE\n\n        >>> Distance(5) # defaults to SI units\n        <Distance: 5 m>\n        >>> NauticalDistance(45.2)\n        <NauticalDistance: 45.2 NM>\n    \"\"\"\n\n    generic_unit_descriptor: ClassVar[GenericUnitDescriptor]\n    default_units: ClassVar[Optional[UnitDescriptor]] = None\n\n    def __init__(self, value: float, unit: Optional[UnitDescriptor] = None) -> None:\n        if unit is None:\n            unit = self.default_units if self.default_units is not None else unit\n            unit = self.generic_unit_descriptor.to_si() if unit is None else unit\n\n        super().__init__(value, unit)\n        if not unit.isinstance(self.generic_unit_descriptor):\n            raise PropertyValidationError(\n                f\"cannot create {self.__class__.__name__} with {unit} units; \"\n                f\"expected {self.generic_unit_descriptor} units. \"\n            )\n\n        self.__post_init__()\n\n    def __post_init__(self) -> None:\n        self.validate_value(self.value)\n\n    @abstractmethod\n    def validate_value(self, value: float) -> None:\n        \"\"\"\n        Validate the `value` for this property. This validation takes place after\n        initialization; hence all initialized attributes are available.\n\n        The only exception this method should raise is `PropertyValidationError`.\n        \"\"\"\n\n    def __repr__(self) -> str:\n        return f\"<{self.__class__.__name__}: {self.value} {self.unit}>\"\n
    "},{"location":"validated_property/#property_utils.properties.validated_property.ValidatedProperty.validate_value","title":"validate_value(value) abstractmethod","text":"

    Validate the value for this property. This validation takes place after initialization; hence all initialized attributes are available.

    The only exception this method should raise is PropertyValidationError.

    Source code in src/property_utils/properties/validated_property.py
    @abstractmethod\ndef validate_value(self, value: float) -> None:\n    \"\"\"\n    Validate the `value` for this property. This validation takes place after\n    initialization; hence all initialized attributes are available.\n\n    The only exception this method should raise is `PropertyValidationError`.\n    \"\"\"\n
    "}]} \ No newline at end of file +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"What is property-utils?","text":"

    property-utils is a python library that aims at making programming with physical properties easier. It was created to be used by scientists and engineers with little programming experience.

    What is provided by property-utils?

    "},{"location":"#unit-arithmetics","title":"Unit arithmetics","text":"

    You can divide and multiply units to create new units. For example you can create velocity units by dividing length units with time units.

    "},{"location":"#unit-conversions","title":"Unit conversions","text":"

    You can easily convert a property from one unit to another by calling a method.

    "},{"location":"#property-arithmetics","title":"Property arithmetics","text":"

    You can add, subtract, divide and multiply properties to create new properties. For example, you can create a density property by dividing a mass property with a volume property.

    If you're not sure what all the above mean, head to Usage to see examples of how they're used.

    "},{"location":"converter_types/","title":"converter types","text":"

    This module defines: Functions to fetch and register unit converters Unit converter protocol Base abstract classes for different types of unit converters

    Converters implement a 2-step process to convert 'from_unit' to 'to_unit'. 1. Convert the 'from_unit' to a reference unit. 2. Convert the reference unit to the 'to_unit'.

    "},{"location":"converter_types/#property_utils.units.converter_types.AbsoluteUnitConverter","title":"AbsoluteUnitConverter","text":"

    Base converter class for measurement units that are absolute, i.e. not relative.

    e.g. Pressure units are absolute because the following applies: unit_i = unit_j * constant, where unit_i and unit_j can be any pressure units.

    Temperature units are not absolute because the above equation does not apply when converting from a relative temperature to an absolute temperature (e.g. from Celcius to Kelvin, or Fahrenheit to Rankine).

    Use the register_converter decorator when subclassing and define the reference_unit and conversion_map attributes. It does not matter what unit you shall choose to be the reference; although you have to define the conversion map accordingly. The conversion map is a dictionary that holds the conversion factors from the reference unit to other units. e.g. in the below example: 1 in = 2.54 cm

    Examples:

    >>> class LengthUnit(MeasurementUnit):\n...     CENTI_METER = \"cm\"\n...     INCH = \"in\"\n
    >>> @register_converter(LengthUnit)\n... class LengthUnitConverter(AbsoluteUnitConverter):\n...     reference_unit = LengthUnit.INCH\n...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n
    Source code in src/property_utils/units/converter_types.py
    class AbsoluteUnitConverter(metaclass=ABCMeta):\n    \"\"\"\n    Base converter class for measurement units that are absolute, i.e. not relative.\n\n    e.g.\n    Pressure units are absolute because the following applies:\n    unit_i = unit_j * constant,\n    where unit_i and unit_j can be any pressure units.\n\n    Temperature units are not absolute because the above equation does not apply when\n    converting from a relative temperature to an absolute temperature (e.g. from Celcius\n    to Kelvin, or Fahrenheit to Rankine).\n\n    Use the `register_converter` decorator when subclassing and define the\n    `reference_unit` and `conversion_map` attributes. It does not matter what unit you\n    shall choose to be the reference; although you have to define the conversion map\n    accordingly. The conversion map is a dictionary that holds the conversion factors\n    from the reference unit to other units. e.g. in the below example: 1 in = 2.54 cm\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit):\n        ...     CENTI_METER = \"cm\"\n        ...     INCH = \"in\"\n\n        >>> @register_converter(LengthUnit)\n        ... class LengthUnitConverter(AbsoluteUnitConverter):\n        ...     reference_unit = LengthUnit.INCH\n        ...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n    \"\"\"\n\n    generic_unit_descriptor: MeasurementUnitType\n    reference_unit: MeasurementUnit\n    conversion_map: Dict[MeasurementUnit, float]\n\n    @classmethod\n    def convert(\n        cls,\n        value: float,\n        from_descriptor: UnitDescriptor,\n        to_descriptor: UnitDescriptor,\n    ) -> float:\n        \"\"\"\n        Convert a value from an absolute unit to another absolute unit.\n        Raises `UnitConversionError` if `from_descriptor` or `to_descriptor` are not\n        an instance of the generic that is registered with the converter or if `value`\n        is not a numeric.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit):\n            ...     CENTI_METER = \"cm\"\n            ...     INCH = \"in\"\n\n            >>> @register_converter(LengthUnit)\n            ... class LengthUnitConverter(AbsoluteUnitConverter):\n            ...     reference_unit = LengthUnit.INCH\n            ...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n\n            >>> LengthUnitConverter.convert(2, LengthUnit.INCH, LengthUnit.CENTI_METER)\n            5.08\n        \"\"\"\n        if not isinstance(value, (float, int)):\n            raise UnitConversionError(f\"invalid 'value': {value}; expected numeric. \")\n        return value * cls.get_factor(from_descriptor, to_descriptor)\n\n    @classmethod\n    def get_factor(\n        cls, from_descriptor: UnitDescriptor, to_descriptor: UnitDescriptor\n    ) -> float:\n        \"\"\"\n        Get the multiplication factor for the conversion from `from_descriptor` to\n        `to_descriptor`.\n        Raises `UnitConversionError` if `from_descriptor` or `to_descriptor` are not\n        an instance of the generic that is registered with the converter.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit):\n            ...     CENTI_METER = \"cm\"\n            ...     INCH = \"in\"\n\n            >>> @register_converter(LengthUnit)\n            ... class LengthUnitConverter(AbsoluteUnitConverter):\n            ...     reference_unit = LengthUnit.INCH\n            ...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n\n            >>> LengthUnitConverter.get_factor(LengthUnit.INCH, LengthUnit.CENTI_METER)\n            2.54\n        \"\"\"\n        if not from_descriptor.isinstance_equivalent(cls.generic_unit_descriptor):\n            raise UnitConversionError(\n                f\"invalid 'from_descriptor; expected an instance-equivalent of {cls.generic_unit_descriptor}. \"\n            )\n        if not to_descriptor.isinstance_equivalent(cls.generic_unit_descriptor):\n            raise UnitConversionError(\n                f\"invalid 'to_descriptor'; expected an instance-equivalent of {cls.generic_unit_descriptor}. \"\n            )\n        from_unit = MeasurementUnit.from_descriptor(from_descriptor)\n\n        if isinstance(from_unit, AliasMeasurementUnit) and not isinstance(\n            to_descriptor, AliasMeasurementUnit\n        ):\n            return cls._get_aliased_factor(from_unit, to_descriptor)\n\n        to_unit = MeasurementUnit.from_descriptor(to_descriptor)\n        try:\n            return cls._to_reference(from_unit) * cls.conversion_map[to_unit]\n        except KeyError:\n            raise UnitConversionError(\n                f\"cannot convert to {to_unit}; unit is not registered in {cls.__name__}'s conversion map. \",\n            ) from None\n\n    @classmethod\n    def _to_reference(cls, from_unit: MeasurementUnit) -> float:\n        try:\n            return 1 / cls.conversion_map[from_unit]\n        except KeyError:\n            raise UnitConversionError(\n                f\"cannot convert from {from_unit}; unit is not registered in {cls.__name__}'s conversion map. \",\n            ) from None\n\n    @classmethod\n    def _get_aliased_factor(\n        cls, from_unit: AliasMeasurementUnit, to_descriptor: UnitDescriptor\n    ) -> float:\n        \"\"\"\n        Returns the conversion factor from an alias unit to its aliased.\n\n        The conversion happens in four steps:\n\n        1. Convert from the alias unit to the SI unit.\n        2. Convert from the SI unit to the aliased SI units (this step is not\n        implemented in code, because the conversion factor is 1)\n        3. Convert from the SI units to the target units.\n\n        e.g. if you want to convert from bar to kN/m^2:\n        1. bar -> Pa\n        2. Pa -> N/m^2 (conversion factor 1)\n        3. N/m^2 -> kN/m^2\n        \"\"\"\n        step_1_factor = cls.get_factor(from_unit, from_unit.si())\n\n        converter = get_converter(to_descriptor.to_generic())\n\n        step_3_factor = converter.convert(\n            1, to_descriptor.to_generic().to_si(), to_descriptor\n        )\n\n        return step_1_factor * step_3_factor\n
    "},{"location":"converter_types/#property_utils.units.converter_types.AbsoluteUnitConverter.convert","title":"convert(value, from_descriptor, to_descriptor) classmethod","text":"

    Convert a value from an absolute unit to another absolute unit. Raises UnitConversionError if from_descriptor or to_descriptor are not an instance of the generic that is registered with the converter or if value is not a numeric.

    Examples:

    >>> class LengthUnit(MeasurementUnit):\n...     CENTI_METER = \"cm\"\n...     INCH = \"in\"\n
    >>> @register_converter(LengthUnit)\n... class LengthUnitConverter(AbsoluteUnitConverter):\n...     reference_unit = LengthUnit.INCH\n...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n
    >>> LengthUnitConverter.convert(2, LengthUnit.INCH, LengthUnit.CENTI_METER)\n5.08\n
    Source code in src/property_utils/units/converter_types.py
    @classmethod\ndef convert(\n    cls,\n    value: float,\n    from_descriptor: UnitDescriptor,\n    to_descriptor: UnitDescriptor,\n) -> float:\n    \"\"\"\n    Convert a value from an absolute unit to another absolute unit.\n    Raises `UnitConversionError` if `from_descriptor` or `to_descriptor` are not\n    an instance of the generic that is registered with the converter or if `value`\n    is not a numeric.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit):\n        ...     CENTI_METER = \"cm\"\n        ...     INCH = \"in\"\n\n        >>> @register_converter(LengthUnit)\n        ... class LengthUnitConverter(AbsoluteUnitConverter):\n        ...     reference_unit = LengthUnit.INCH\n        ...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n\n        >>> LengthUnitConverter.convert(2, LengthUnit.INCH, LengthUnit.CENTI_METER)\n        5.08\n    \"\"\"\n    if not isinstance(value, (float, int)):\n        raise UnitConversionError(f\"invalid 'value': {value}; expected numeric. \")\n    return value * cls.get_factor(from_descriptor, to_descriptor)\n
    "},{"location":"converter_types/#property_utils.units.converter_types.AbsoluteUnitConverter.get_factor","title":"get_factor(from_descriptor, to_descriptor) classmethod","text":"

    Get the multiplication factor for the conversion from from_descriptor to to_descriptor. Raises UnitConversionError if from_descriptor or to_descriptor are not an instance of the generic that is registered with the converter.

    Examples:

    >>> class LengthUnit(MeasurementUnit):\n...     CENTI_METER = \"cm\"\n...     INCH = \"in\"\n
    >>> @register_converter(LengthUnit)\n... class LengthUnitConverter(AbsoluteUnitConverter):\n...     reference_unit = LengthUnit.INCH\n...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n
    >>> LengthUnitConverter.get_factor(LengthUnit.INCH, LengthUnit.CENTI_METER)\n2.54\n
    Source code in src/property_utils/units/converter_types.py
    @classmethod\ndef get_factor(\n    cls, from_descriptor: UnitDescriptor, to_descriptor: UnitDescriptor\n) -> float:\n    \"\"\"\n    Get the multiplication factor for the conversion from `from_descriptor` to\n    `to_descriptor`.\n    Raises `UnitConversionError` if `from_descriptor` or `to_descriptor` are not\n    an instance of the generic that is registered with the converter.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit):\n        ...     CENTI_METER = \"cm\"\n        ...     INCH = \"in\"\n\n        >>> @register_converter(LengthUnit)\n        ... class LengthUnitConverter(AbsoluteUnitConverter):\n        ...     reference_unit = LengthUnit.INCH\n        ...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n\n        >>> LengthUnitConverter.get_factor(LengthUnit.INCH, LengthUnit.CENTI_METER)\n        2.54\n    \"\"\"\n    if not from_descriptor.isinstance_equivalent(cls.generic_unit_descriptor):\n        raise UnitConversionError(\n            f\"invalid 'from_descriptor; expected an instance-equivalent of {cls.generic_unit_descriptor}. \"\n        )\n    if not to_descriptor.isinstance_equivalent(cls.generic_unit_descriptor):\n        raise UnitConversionError(\n            f\"invalid 'to_descriptor'; expected an instance-equivalent of {cls.generic_unit_descriptor}. \"\n        )\n    from_unit = MeasurementUnit.from_descriptor(from_descriptor)\n\n    if isinstance(from_unit, AliasMeasurementUnit) and not isinstance(\n        to_descriptor, AliasMeasurementUnit\n    ):\n        return cls._get_aliased_factor(from_unit, to_descriptor)\n\n    to_unit = MeasurementUnit.from_descriptor(to_descriptor)\n    try:\n        return cls._to_reference(from_unit) * cls.conversion_map[to_unit]\n    except KeyError:\n        raise UnitConversionError(\n            f\"cannot convert to {to_unit}; unit is not registered in {cls.__name__}'s conversion map. \",\n        ) from None\n
    "},{"location":"converter_types/#property_utils.units.converter_types.CompositeUnitConverter","title":"CompositeUnitConverter","text":"

    Base converter for composite units.

    Use the register_converter decorator when subclassing. This converter requires the converters for the individual measurement units to be defined.

    Examples:

    >>> class LengthUnit(MeasurementUnit):\n...     CENTI_METER = \"cm\"\n...     INCH = \"in\"\n
    >>> class TimeUnit(MeasurementUnit):\n...     SECOND = \"s\"\n...     MINUTE = \"min\"\n
    >>> @register_converter(LengthUnit)\n... class LengthUnitConverter(AbsoluteUnitConverter):\n...     reference_unit = LengthUnit.INCH\n...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n
    >>> @register_converter(TimeUnit)\n... class TimeUnitConverter(AbsoluteUnitConverter):\n...     reference_unit = TimeUnit.MINUTE\n...     conversion_map = {TimeUnit.MINUTE: 1, TimeUnit.SECOND: 60}\n
    >>> @register_converter(LengthUnit / TimeUnit)\n... class VelocityUnitConverter(CompositeUnitConverter): ...\n
    Source code in src/property_utils/units/converter_types.py
    class CompositeUnitConverter(metaclass=ABCMeta):\n    \"\"\"\n    Base converter for composite units.\n\n    Use the `register_converter` decorator when subclassing. This converter requires\n    the converters for the individual measurement units to be defined.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit):\n        ...     CENTI_METER = \"cm\"\n        ...     INCH = \"in\"\n\n        >>> class TimeUnit(MeasurementUnit):\n        ...     SECOND = \"s\"\n        ...     MINUTE = \"min\"\n\n        >>> @register_converter(LengthUnit)\n        ... class LengthUnitConverter(AbsoluteUnitConverter):\n        ...     reference_unit = LengthUnit.INCH\n        ...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n\n        >>> @register_converter(TimeUnit)\n        ... class TimeUnitConverter(AbsoluteUnitConverter):\n        ...     reference_unit = TimeUnit.MINUTE\n        ...     conversion_map = {TimeUnit.MINUTE: 1, TimeUnit.SECOND: 60}\n\n        >>> @register_converter(LengthUnit / TimeUnit)\n        ... class VelocityUnitConverter(CompositeUnitConverter): ...\n    \"\"\"\n\n    generic_unit_descriptor: GenericUnitDescriptor\n\n    @classmethod\n    def convert(\n        cls,\n        value: float,\n        from_descriptor: UnitDescriptor,\n        to_descriptor: UnitDescriptor,\n    ) -> float:\n        \"\"\"\n        Convert a value from a composite unit to another composite unit.\n\n        Raises `UnitConversionError` if `from_descriptor` or `to_descriptor` are not\n        an instance of the generic that is registered with the converter or if `value`\n        is not a numeric.\n\n        Raises `ConverterDependenciesError` if a converter for an invdividual unit has\n        not been defined/registered.\n\n        Raises `UnsupportedConverterError` if an individual unit is a relative unit.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit):\n            ...     CENTI_METER = \"cm\"\n            ...     INCH = \"in\"\n\n            >>> class TimeUnit(MeasurementUnit):\n            ...     SECOND = \"s\"\n            ...     MINUTE = \"min\"\n\n            >>> @register_converter(LengthUnit)\n            ... class LengthUnitConverter(AbsoluteUnitConverter):\n            ...     reference_unit = LengthUnit.INCH\n            ...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n\n            >>> @register_converter(TimeUnit)\n            ... class TimeUnitConverter(AbsoluteUnitConverter):\n            ...     reference_unit = TimeUnit.MINUTE\n            ...     conversion_map = {TimeUnit.MINUTE: 1, TimeUnit.SECOND: 60}\n\n            >>> @register_converter(LengthUnit / TimeUnit)\n            ... class VelocityUnitConverter(CompositeUnitConverter): ...\n\n            >>> VelocityUnitConverter.convert(100, LengthUnit.INCH/TimeUnit.SECOND, LengthUnit.CENTI_METER/TimeUnit.SECOND)\n            254.0\n        \"\"\"\n        if not isinstance(value, (float, int)):\n            raise UnitConversionError(f\"invalid 'value': {value}; expected numeric. \")\n        return value * cls.get_factor(from_descriptor, to_descriptor)\n\n    @classmethod\n    def get_factor(\n        cls, from_descriptor: UnitDescriptor, to_descriptor: UnitDescriptor\n    ) -> float:\n        \"\"\"\n        Get the multiplication factor for the conversion from `from_descriptor` to\n        `to_descriptor`.\n\n        Raises `UnitConversionError` if `from_descriptor` or `to_descriptor` are not\n        an instance of the generic that is registered with the converter.\n\n        Raises `ConverterDependenciesError` if a converter for an invdividual unit has\n        not been defined/registered.\n\n        Raises `UnsupportedConverterError` if an individual unit is a relative unit.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit):\n            ...     CENTI_METER = \"cm\"\n            ...     INCH = \"in\"\n\n            >>> class TimeUnit(MeasurementUnit):\n            ...     SECOND = \"s\"\n            ...     MINUTE = \"min\"\n\n            >>> @register_converter(LengthUnit)\n            ... class LengthUnitConverter(AbsoluteUnitConverter):\n            ...     reference_unit = LengthUnit.INCH\n            ...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n\n            >>> @register_converter(TimeUnit)\n            ... class TimeUnitConverter(AbsoluteUnitConverter):\n            ...     reference_unit = TimeUnit.MINUTE\n            ...     conversion_map = {TimeUnit.MINUTE: 1, TimeUnit.SECOND: 60}\n\n            >>> @register_converter(LengthUnit / TimeUnit)\n            ... class VelocityUnitConverter(CompositeUnitConverter): ...\n\n            >>> VelocityUnitConverter.get_factor(LengthUnit.INCH/TimeUnit.SECOND, LengthUnit.INCH/TimeUnit.MINUTE)\n            60.0\n        \"\"\"\n        if not from_descriptor.isinstance_equivalent(cls.generic_unit_descriptor):\n            raise UnitConversionError(\n                f\"invalid 'from_descriptor; expected an instance-equivalent of {cls.generic_unit_descriptor}. \"\n            )\n        if not to_descriptor.isinstance_equivalent(cls.generic_unit_descriptor):\n            raise UnitConversionError(\n                f\"invalid 'to_descriptor'; expected an instance-equivalent of {cls.generic_unit_descriptor}. \"\n            )\n\n        from_dimension = CompositeDimension.from_descriptor(from_descriptor)\n\n        if not to_descriptor.isinstance(from_descriptor.to_generic()):\n\n            if cls._is_alias(from_dimension, to_descriptor) or (\n                cls._is_aliased(from_dimension)\n            ):\n                return cls._get_aliased_factor(from_dimension, to_descriptor)\n\n        to_dimension = CompositeDimension.from_descriptor(to_descriptor)\n        return cls._get_numerator_factor(\n            from_dimension, to_dimension\n        ) / cls._get_denominator_factor(from_dimension, to_dimension)\n\n    @classmethod\n    def _get_numerator_factor(\n        cls, from_dimension: CompositeDimension, to_dimension: CompositeDimension\n    ) -> float:\n        numerator_factor = 1.0\n        for from_d in from_dimension.numerator:\n            to_d = to_dimension.get_numerator(from_d.to_generic())\n            if to_d is None:\n                raise UnitConversionError(\n                    f\"cannot convert from {from_dimension} to {to_dimension}\"\n                )\n            try:\n                converter = get_converter(type(from_d.unit))\n            except UndefinedConverterError:\n                raise ConverterDependenciesError(\n                    f\"converter {cls.__name__} depends on a converter for \"\n                    f\"{type(from_d.unit)}. Did you forget to register \"\n                    f\" a converter for {type(from_d.unit)}? \"\n                ) from None\n            if not issubclass(converter, AbsoluteUnitConverter):\n                # NOTE: provide a link to documentation for the error.\n                raise UnsupportedConverterError(\n                    f\"converter {cls.__name__} is not supported since \"\n                    f\"{type(from_d.unit)} is not an absolute unit;\"\n                    \" conversion between composite relative units is invalid. \"\n                )\n            factor = (converter.get_factor(from_d.unit, to_d.unit)) ** from_d.power\n            numerator_factor *= factor\n        return numerator_factor\n\n    @classmethod\n    def _get_denominator_factor(\n        cls, from_dimension: CompositeDimension, to_dimension: CompositeDimension\n    ) -> float:\n        denominator_factor = 1.0\n\n        for from_d in from_dimension.denominator:\n            to_d = to_dimension.get_denominator(from_d.to_generic())\n            if to_d is None:\n                raise UnitConversionError(\n                    f\"cannot convert from {from_dimension} to {to_dimension}\"\n                )\n            try:\n                converter = get_converter(type(from_d.unit))\n            except UndefinedConverterError:\n                raise ConverterDependenciesError(\n                    f\"converter {cls.__name__} depends on a converter for \"\n                    f\"{type(from_d.unit)}. Did you forget to register \"\n                    f\" a converter for {type(from_d.unit)}? \"\n                ) from None\n            if not issubclass(converter, AbsoluteUnitConverter):\n                # NOTE: provide a link to documentation for the error.\n                raise UnsupportedConverterError(\n                    f\"converter {cls.__name__} is not supported since \"\n                    f\"{type(from_d.unit)} is not an absolute unit;\"\n                    \" conversion between composite relative units is invalid. \"\n                )\n            factor = (converter.get_factor(from_d.unit, to_d.unit)) ** from_d.power\n            denominator_factor *= factor\n        return denominator_factor\n\n    @staticmethod\n    def _is_alias(\n        from_dimension: CompositeDimension, descriptor: UnitDescriptor\n    ) -> bool:\n        \"\"\"\n        Returns True if the descriptor is an alias of the from_dimension.\n\n        Assumes that from_dimension and descriptor are both an instance of the\n        converter's generic unit descriptor.\n        \"\"\"\n        if isinstance(descriptor, AliasMeasurementUnit):\n            return True\n\n        if isinstance(descriptor, Dimension):\n            if isinstance(descriptor.unit, AliasMeasurementUnit):\n                return True\n\n            return False\n\n        if isinstance(descriptor, CompositeDimension):\n            for n in descriptor.numerator:\n                if from_dimension.get_numerator(n.to_generic(), None) is None:\n                    return True\n\n            for d in descriptor.denominator:\n                if from_dimension.get_denominator(d.to_generic(), None) is None:\n                    return True\n\n        return False\n\n    @staticmethod\n    def _is_aliased(dimension: CompositeDimension) -> bool:\n        \"\"\"\n        Returns True if the dimension contains an alias, False otherwise.\n        \"\"\"\n        for n in dimension.numerator:\n            if isinstance(n.unit, AliasMeasurementUnit):\n                return True\n\n        for d in dimension.denominator:\n            if isinstance(d.unit, AliasMeasurementUnit):\n                return True\n\n        return False\n\n    @classmethod\n    def _get_aliased_factor(\n        cls, from_dimension: CompositeDimension, to_descriptor: UnitDescriptor\n    ) -> float:\n        \"\"\"\n        Returns the conversion factor from an alias unit to its aliased.\n\n        The conversion happens in three steps:\n\n        1. Convert from the alias unit to the SI unit.\n        2. Convert from the SI unit to the aliased SI units (this step is not\n        implemented in code, because the conversion factor is 1)\n        3. Convert from the SI units to the target units.\n\n        e.g. if you want to convert from cal/K/s to kW/K:\n        1. cal/K/s -> J/K/s\n        2. J/K/s -> W/K (conversion factor 1)\n        3. W/K -> kW/K\n        \"\"\"\n        step_1_factor = cls.get_factor(from_dimension, from_dimension.si())\n\n        converter = get_converter(to_descriptor.to_generic())\n\n        step_3_factor = converter.convert(\n            1, to_descriptor.to_generic().to_si(), to_descriptor\n        )\n\n        return step_1_factor * step_3_factor\n
    "},{"location":"converter_types/#property_utils.units.converter_types.CompositeUnitConverter.convert","title":"convert(value, from_descriptor, to_descriptor) classmethod","text":"

    Convert a value from a composite unit to another composite unit.

    Raises UnitConversionError if from_descriptor or to_descriptor are not an instance of the generic that is registered with the converter or if value is not a numeric.

    Raises ConverterDependenciesError if a converter for an invdividual unit has not been defined/registered.

    Raises UnsupportedConverterError if an individual unit is a relative unit.

    Examples:

    >>> class LengthUnit(MeasurementUnit):\n...     CENTI_METER = \"cm\"\n...     INCH = \"in\"\n
    >>> class TimeUnit(MeasurementUnit):\n...     SECOND = \"s\"\n...     MINUTE = \"min\"\n
    >>> @register_converter(LengthUnit)\n... class LengthUnitConverter(AbsoluteUnitConverter):\n...     reference_unit = LengthUnit.INCH\n...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n
    >>> @register_converter(TimeUnit)\n... class TimeUnitConverter(AbsoluteUnitConverter):\n...     reference_unit = TimeUnit.MINUTE\n...     conversion_map = {TimeUnit.MINUTE: 1, TimeUnit.SECOND: 60}\n
    >>> @register_converter(LengthUnit / TimeUnit)\n... class VelocityUnitConverter(CompositeUnitConverter): ...\n
    >>> VelocityUnitConverter.convert(100, LengthUnit.INCH/TimeUnit.SECOND, LengthUnit.CENTI_METER/TimeUnit.SECOND)\n254.0\n
    Source code in src/property_utils/units/converter_types.py
    @classmethod\ndef convert(\n    cls,\n    value: float,\n    from_descriptor: UnitDescriptor,\n    to_descriptor: UnitDescriptor,\n) -> float:\n    \"\"\"\n    Convert a value from a composite unit to another composite unit.\n\n    Raises `UnitConversionError` if `from_descriptor` or `to_descriptor` are not\n    an instance of the generic that is registered with the converter or if `value`\n    is not a numeric.\n\n    Raises `ConverterDependenciesError` if a converter for an invdividual unit has\n    not been defined/registered.\n\n    Raises `UnsupportedConverterError` if an individual unit is a relative unit.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit):\n        ...     CENTI_METER = \"cm\"\n        ...     INCH = \"in\"\n\n        >>> class TimeUnit(MeasurementUnit):\n        ...     SECOND = \"s\"\n        ...     MINUTE = \"min\"\n\n        >>> @register_converter(LengthUnit)\n        ... class LengthUnitConverter(AbsoluteUnitConverter):\n        ...     reference_unit = LengthUnit.INCH\n        ...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n\n        >>> @register_converter(TimeUnit)\n        ... class TimeUnitConverter(AbsoluteUnitConverter):\n        ...     reference_unit = TimeUnit.MINUTE\n        ...     conversion_map = {TimeUnit.MINUTE: 1, TimeUnit.SECOND: 60}\n\n        >>> @register_converter(LengthUnit / TimeUnit)\n        ... class VelocityUnitConverter(CompositeUnitConverter): ...\n\n        >>> VelocityUnitConverter.convert(100, LengthUnit.INCH/TimeUnit.SECOND, LengthUnit.CENTI_METER/TimeUnit.SECOND)\n        254.0\n    \"\"\"\n    if not isinstance(value, (float, int)):\n        raise UnitConversionError(f\"invalid 'value': {value}; expected numeric. \")\n    return value * cls.get_factor(from_descriptor, to_descriptor)\n
    "},{"location":"converter_types/#property_utils.units.converter_types.CompositeUnitConverter.get_factor","title":"get_factor(from_descriptor, to_descriptor) classmethod","text":"

    Get the multiplication factor for the conversion from from_descriptor to to_descriptor.

    Raises UnitConversionError if from_descriptor or to_descriptor are not an instance of the generic that is registered with the converter.

    Raises ConverterDependenciesError if a converter for an invdividual unit has not been defined/registered.

    Raises UnsupportedConverterError if an individual unit is a relative unit.

    Examples:

    >>> class LengthUnit(MeasurementUnit):\n...     CENTI_METER = \"cm\"\n...     INCH = \"in\"\n
    >>> class TimeUnit(MeasurementUnit):\n...     SECOND = \"s\"\n...     MINUTE = \"min\"\n
    >>> @register_converter(LengthUnit)\n... class LengthUnitConverter(AbsoluteUnitConverter):\n...     reference_unit = LengthUnit.INCH\n...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n
    >>> @register_converter(TimeUnit)\n... class TimeUnitConverter(AbsoluteUnitConverter):\n...     reference_unit = TimeUnit.MINUTE\n...     conversion_map = {TimeUnit.MINUTE: 1, TimeUnit.SECOND: 60}\n
    >>> @register_converter(LengthUnit / TimeUnit)\n... class VelocityUnitConverter(CompositeUnitConverter): ...\n
    >>> VelocityUnitConverter.get_factor(LengthUnit.INCH/TimeUnit.SECOND, LengthUnit.INCH/TimeUnit.MINUTE)\n60.0\n
    Source code in src/property_utils/units/converter_types.py
    @classmethod\ndef get_factor(\n    cls, from_descriptor: UnitDescriptor, to_descriptor: UnitDescriptor\n) -> float:\n    \"\"\"\n    Get the multiplication factor for the conversion from `from_descriptor` to\n    `to_descriptor`.\n\n    Raises `UnitConversionError` if `from_descriptor` or `to_descriptor` are not\n    an instance of the generic that is registered with the converter.\n\n    Raises `ConverterDependenciesError` if a converter for an invdividual unit has\n    not been defined/registered.\n\n    Raises `UnsupportedConverterError` if an individual unit is a relative unit.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit):\n        ...     CENTI_METER = \"cm\"\n        ...     INCH = \"in\"\n\n        >>> class TimeUnit(MeasurementUnit):\n        ...     SECOND = \"s\"\n        ...     MINUTE = \"min\"\n\n        >>> @register_converter(LengthUnit)\n        ... class LengthUnitConverter(AbsoluteUnitConverter):\n        ...     reference_unit = LengthUnit.INCH\n        ...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n\n        >>> @register_converter(TimeUnit)\n        ... class TimeUnitConverter(AbsoluteUnitConverter):\n        ...     reference_unit = TimeUnit.MINUTE\n        ...     conversion_map = {TimeUnit.MINUTE: 1, TimeUnit.SECOND: 60}\n\n        >>> @register_converter(LengthUnit / TimeUnit)\n        ... class VelocityUnitConverter(CompositeUnitConverter): ...\n\n        >>> VelocityUnitConverter.get_factor(LengthUnit.INCH/TimeUnit.SECOND, LengthUnit.INCH/TimeUnit.MINUTE)\n        60.0\n    \"\"\"\n    if not from_descriptor.isinstance_equivalent(cls.generic_unit_descriptor):\n        raise UnitConversionError(\n            f\"invalid 'from_descriptor; expected an instance-equivalent of {cls.generic_unit_descriptor}. \"\n        )\n    if not to_descriptor.isinstance_equivalent(cls.generic_unit_descriptor):\n        raise UnitConversionError(\n            f\"invalid 'to_descriptor'; expected an instance-equivalent of {cls.generic_unit_descriptor}. \"\n        )\n\n    from_dimension = CompositeDimension.from_descriptor(from_descriptor)\n\n    if not to_descriptor.isinstance(from_descriptor.to_generic()):\n\n        if cls._is_alias(from_dimension, to_descriptor) or (\n            cls._is_aliased(from_dimension)\n        ):\n            return cls._get_aliased_factor(from_dimension, to_descriptor)\n\n    to_dimension = CompositeDimension.from_descriptor(to_descriptor)\n    return cls._get_numerator_factor(\n        from_dimension, to_dimension\n    ) / cls._get_denominator_factor(from_dimension, to_dimension)\n
    "},{"location":"converter_types/#property_utils.units.converter_types.ExponentiatedUnitConverter","title":"ExponentiatedUnitConverter","text":"

    Base converter for exponentiated absolute measurement units.

    Use the register_converter decorator when subclassing. This converter requires the converter for the measurement unit that is exponentiated to be defined.

    Examples:

    >>> class LengthUnit(MeasurementUnit):\n...     CENTI_METER = \"cm\"\n...     INCH = \"in\"\n
    >>> @register_converter(LengthUnit)\n... class LengthUnitConverter(AbsoluteUnitConverter):\n...     reference_unit = LengthUnit.INCH\n...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n
    >>> @register_converter(LengthUnit**2)\n... class AreaUnitConverter(ExponentiatedUnitConverter): ...\n
    Source code in src/property_utils/units/converter_types.py
    class ExponentiatedUnitConverter(metaclass=ABCMeta):\n    \"\"\"\n    Base converter for exponentiated absolute measurement units.\n\n    Use the `register_converter` decorator when subclassing. This converter requires\n    the converter for the measurement unit that is exponentiated to be defined.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit):\n        ...     CENTI_METER = \"cm\"\n        ...     INCH = \"in\"\n\n        >>> @register_converter(LengthUnit)\n        ... class LengthUnitConverter(AbsoluteUnitConverter):\n        ...     reference_unit = LengthUnit.INCH\n        ...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n\n        >>> @register_converter(LengthUnit**2)\n        ... class AreaUnitConverter(ExponentiatedUnitConverter): ...\n    \"\"\"\n\n    generic_unit_descriptor: GenericDimension\n\n    @classmethod\n    def convert(\n        cls,\n        value: float,\n        from_descriptor: UnitDescriptor,\n        to_descriptor: UnitDescriptor,\n    ) -> float:\n        \"\"\"\n        Convert a value from an absolute exponentiated unit to another absolute\n        exponentiated unit. In order to use this converter a converter must exist for\n        the base unit.\n\n        Raises `UnitConversionError` if `from_descriptor` or `to_descriptor` are not\n        an instance of the generic that is registered with the converter or if `value`\n        is not a numeric.\n\n        Raises `ConverterDependenciesError` if a converter for the base unit has not\n        been defined/registered.\n\n        Raises `UnsupportedConverterError` if the base unit is a relative unit.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit):\n            ...     CENTI_METER = \"cm\"\n            ...     INCH = \"in\"\n\n            >>> @register_converter(LengthUnit)\n            ... class LengthUnitConverter(AbsoluteUnitConverter):\n            ...     reference_unit = LengthUnit.INCH\n            ...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n\n            >>> @register_converter(LengthUnit**2)\n            ... class AreaUnitConverter(ExponentiatedUnitConverter): ...\n\n            >>> AreaUnitConverter.convert(10, LengthUnit.INCH**2, LengthUnit.CENTI_METER**2)\n            64.516\n        \"\"\"\n        if not isinstance(value, (float, int)):\n            raise UnitConversionError(f\"invalid 'value': {value}; expected numeric. \")\n        return value * cls.get_factor(from_descriptor, to_descriptor)\n\n    @classmethod\n    def get_factor(\n        cls, from_descriptor: UnitDescriptor, to_descriptor: UnitDescriptor\n    ) -> float:\n        \"\"\"\n        Get the multiplication factor for the conversion from `from_descriptor` to\n        `to_descriptor`.\n\n        Raises `UnitConversionError` if `from_descriptor` or `to_descriptor` are not\n        an instance of the generic that is registered with the converter.\n\n        Raises `ConverterDependenciesError` if a converter for the base unit has not\n        been defined/registered.\n\n        Raises `UnsupportedConverterError` if the base unit is a relative unit.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit):\n            ...     CENTI_METER = \"cm\"\n            ...     INCH = \"in\"\n\n            >>> @register_converter(LengthUnit)\n            ... class LengthUnitConverter(AbsoluteUnitConverter):\n            ...     reference_unit = LengthUnit.INCH\n            ...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n\n            >>> @register_converter(LengthUnit**2)\n            ... class AreaUnitConverter(ExponentiatedUnitConverter): ...\n\n            >>> AreaUnitConverter.get_factor(LengthUnit.INCH**2, LengthUnit.CENTI_METER**2)\n            6.4516\n        \"\"\"\n        if not from_descriptor.isinstance_equivalent(cls.generic_unit_descriptor):\n            raise UnitConversionError(\n                f\"invalid 'from_descriptor; expected an instance-equivalent of {cls.generic_unit_descriptor}. \"\n            )\n        if not to_descriptor.isinstance_equivalent(cls.generic_unit_descriptor):\n            raise UnitConversionError(\n                f\"invalid 'to_descriptor'; expected an instance-equivalent of {cls.generic_unit_descriptor}. \"\n            )\n        from_dimension = Dimension.from_descriptor(from_descriptor)\n\n        if not to_descriptor.isinstance(from_descriptor.to_generic()):\n            if isinstance(to_descriptor, AliasMeasurementUnit):\n                return cls._get_aliased_factor(from_dimension, to_descriptor)\n\n        to_dimension = Dimension.from_descriptor(to_descriptor)\n\n        try:\n            converter = get_converter(cls.generic_unit_descriptor.unit_type)\n        except UndefinedConverterError:\n            raise ConverterDependenciesError(\n                f\"converter {cls.__name__} depends on a converter for \"\n                f\"{cls.generic_unit_descriptor.unit_type}. Did you forget to register \"\n                f\" a converter for {cls.generic_unit_descriptor.unit_type}? \"\n            ) from None\n        if not issubclass(converter, AbsoluteUnitConverter):\n            # NOTE: provide a link to documentation for the error.\n            raise UnsupportedConverterError(\n                f\"converter {cls.__name__} is not supported since \"\n                f\"{cls.generic_unit_descriptor.unit_type} is not an absolute unit;\"\n                \" conversion between exponentiated relative units is invalid. \"\n            )\n        factor = converter.get_factor(from_dimension.unit, to_dimension.unit)\n        return factor**to_dimension.power\n\n    @classmethod\n    def _get_aliased_factor(\n        cls, from_dimension: Dimension, to_descriptor: AliasMeasurementUnit\n    ) -> float:\n        \"\"\"\n        Returns the conversion factor from an alias unit to its aliased.\n\n        The conversion happens in three steps:\n\n        1. Convert from the alias unit to the SI unit.\n        2. Convert from the SI unit to the aliased SI units (this step is not\n        implemented in code, because the conversion factor is 1)\n        3. Convert from the aliased SI units to the target units.\n\n        e.g. if you want to convert from cm^3 to L:\n        1. cm^3 -> m^3\n        2. m^3 -> kL (conversion factor 1)\n        3. kL -> L\n        \"\"\"\n        step_1_factor = cls.get_factor(from_dimension, from_dimension.si())\n\n        converter = get_converter(to_descriptor.to_generic())\n\n        step_3_factor = converter.convert(\n            1, to_descriptor.to_generic().to_si(), to_descriptor\n        )\n\n        return step_1_factor * step_3_factor\n
    "},{"location":"converter_types/#property_utils.units.converter_types.ExponentiatedUnitConverter.convert","title":"convert(value, from_descriptor, to_descriptor) classmethod","text":"

    Convert a value from an absolute exponentiated unit to another absolute exponentiated unit. In order to use this converter a converter must exist for the base unit.

    Raises UnitConversionError if from_descriptor or to_descriptor are not an instance of the generic that is registered with the converter or if value is not a numeric.

    Raises ConverterDependenciesError if a converter for the base unit has not been defined/registered.

    Raises UnsupportedConverterError if the base unit is a relative unit.

    Examples:

    >>> class LengthUnit(MeasurementUnit):\n...     CENTI_METER = \"cm\"\n...     INCH = \"in\"\n
    >>> @register_converter(LengthUnit)\n... class LengthUnitConverter(AbsoluteUnitConverter):\n...     reference_unit = LengthUnit.INCH\n...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n
    >>> @register_converter(LengthUnit**2)\n... class AreaUnitConverter(ExponentiatedUnitConverter): ...\n
    >>> AreaUnitConverter.convert(10, LengthUnit.INCH**2, LengthUnit.CENTI_METER**2)\n64.516\n
    Source code in src/property_utils/units/converter_types.py
    @classmethod\ndef convert(\n    cls,\n    value: float,\n    from_descriptor: UnitDescriptor,\n    to_descriptor: UnitDescriptor,\n) -> float:\n    \"\"\"\n    Convert a value from an absolute exponentiated unit to another absolute\n    exponentiated unit. In order to use this converter a converter must exist for\n    the base unit.\n\n    Raises `UnitConversionError` if `from_descriptor` or `to_descriptor` are not\n    an instance of the generic that is registered with the converter or if `value`\n    is not a numeric.\n\n    Raises `ConverterDependenciesError` if a converter for the base unit has not\n    been defined/registered.\n\n    Raises `UnsupportedConverterError` if the base unit is a relative unit.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit):\n        ...     CENTI_METER = \"cm\"\n        ...     INCH = \"in\"\n\n        >>> @register_converter(LengthUnit)\n        ... class LengthUnitConverter(AbsoluteUnitConverter):\n        ...     reference_unit = LengthUnit.INCH\n        ...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n\n        >>> @register_converter(LengthUnit**2)\n        ... class AreaUnitConverter(ExponentiatedUnitConverter): ...\n\n        >>> AreaUnitConverter.convert(10, LengthUnit.INCH**2, LengthUnit.CENTI_METER**2)\n        64.516\n    \"\"\"\n    if not isinstance(value, (float, int)):\n        raise UnitConversionError(f\"invalid 'value': {value}; expected numeric. \")\n    return value * cls.get_factor(from_descriptor, to_descriptor)\n
    "},{"location":"converter_types/#property_utils.units.converter_types.ExponentiatedUnitConverter.get_factor","title":"get_factor(from_descriptor, to_descriptor) classmethod","text":"

    Get the multiplication factor for the conversion from from_descriptor to to_descriptor.

    Raises UnitConversionError if from_descriptor or to_descriptor are not an instance of the generic that is registered with the converter.

    Raises ConverterDependenciesError if a converter for the base unit has not been defined/registered.

    Raises UnsupportedConverterError if the base unit is a relative unit.

    Examples:

    >>> class LengthUnit(MeasurementUnit):\n...     CENTI_METER = \"cm\"\n...     INCH = \"in\"\n
    >>> @register_converter(LengthUnit)\n... class LengthUnitConverter(AbsoluteUnitConverter):\n...     reference_unit = LengthUnit.INCH\n...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n
    >>> @register_converter(LengthUnit**2)\n... class AreaUnitConverter(ExponentiatedUnitConverter): ...\n
    >>> AreaUnitConverter.get_factor(LengthUnit.INCH**2, LengthUnit.CENTI_METER**2)\n6.4516\n
    Source code in src/property_utils/units/converter_types.py
    @classmethod\ndef get_factor(\n    cls, from_descriptor: UnitDescriptor, to_descriptor: UnitDescriptor\n) -> float:\n    \"\"\"\n    Get the multiplication factor for the conversion from `from_descriptor` to\n    `to_descriptor`.\n\n    Raises `UnitConversionError` if `from_descriptor` or `to_descriptor` are not\n    an instance of the generic that is registered with the converter.\n\n    Raises `ConverterDependenciesError` if a converter for the base unit has not\n    been defined/registered.\n\n    Raises `UnsupportedConverterError` if the base unit is a relative unit.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit):\n        ...     CENTI_METER = \"cm\"\n        ...     INCH = \"in\"\n\n        >>> @register_converter(LengthUnit)\n        ... class LengthUnitConverter(AbsoluteUnitConverter):\n        ...     reference_unit = LengthUnit.INCH\n        ...     conversion_map = {LengthUnit.INCH: 1, LengthUnit.CENTI_METER: 2.54}\n\n        >>> @register_converter(LengthUnit**2)\n        ... class AreaUnitConverter(ExponentiatedUnitConverter): ...\n\n        >>> AreaUnitConverter.get_factor(LengthUnit.INCH**2, LengthUnit.CENTI_METER**2)\n        6.4516\n    \"\"\"\n    if not from_descriptor.isinstance_equivalent(cls.generic_unit_descriptor):\n        raise UnitConversionError(\n            f\"invalid 'from_descriptor; expected an instance-equivalent of {cls.generic_unit_descriptor}. \"\n        )\n    if not to_descriptor.isinstance_equivalent(cls.generic_unit_descriptor):\n        raise UnitConversionError(\n            f\"invalid 'to_descriptor'; expected an instance-equivalent of {cls.generic_unit_descriptor}. \"\n        )\n    from_dimension = Dimension.from_descriptor(from_descriptor)\n\n    if not to_descriptor.isinstance(from_descriptor.to_generic()):\n        if isinstance(to_descriptor, AliasMeasurementUnit):\n            return cls._get_aliased_factor(from_dimension, to_descriptor)\n\n    to_dimension = Dimension.from_descriptor(to_descriptor)\n\n    try:\n        converter = get_converter(cls.generic_unit_descriptor.unit_type)\n    except UndefinedConverterError:\n        raise ConverterDependenciesError(\n            f\"converter {cls.__name__} depends on a converter for \"\n            f\"{cls.generic_unit_descriptor.unit_type}. Did you forget to register \"\n            f\" a converter for {cls.generic_unit_descriptor.unit_type}? \"\n        ) from None\n    if not issubclass(converter, AbsoluteUnitConverter):\n        # NOTE: provide a link to documentation for the error.\n        raise UnsupportedConverterError(\n            f\"converter {cls.__name__} is not supported since \"\n            f\"{cls.generic_unit_descriptor.unit_type} is not an absolute unit;\"\n            \" conversion between exponentiated relative units is invalid. \"\n        )\n    factor = converter.get_factor(from_dimension.unit, to_dimension.unit)\n    return factor**to_dimension.power\n
    "},{"location":"converter_types/#property_utils.units.converter_types.RelativeUnitConverter","title":"RelativeUnitConverter","text":"

    Base converter class for measurement units that are relative.

    e.g. Temperature units are relative because conversion from one unit to another is not necessarily performed with multiplication with a single factor.

    Use the register_converter decorator when subclassing and define the reference_unit, conversion_map and reference_conversion_map attributes. It does not matter what unit you shall choose to be the reference; although you have to define the conversion map and reference conversion map accordingly. The conversion map is a dictionary that holds the conversion functions that convert other units to the reference unit. The reference conversion map is a dictionary that holds the conversion functions that convert the reference unit to other units.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     CELCIUS = \"\u00b0C\"\n...     FAHRENHEIT = \"\u00b0F\"\n
    >>> @register_converter(TemperatureUnit)\n... class TemperatureUnitConverter(RelativeUnitConverter):\n...     reference_unit = TemperatureUnit.CELCIUS\n...     conversion_map = {\n...             TemperatureUnit.CELCIUS: lambda t: t,\n...             TemperatureUnit.FAHRENHEIT: lambda t: (t - 32) / 1.8,\n...                 }\n...     reference_conversion_map = {\n...             TemperatureUnit.CELCIUS: lambda t: t,\n...             TemperatureUnit.FAHRENHEIT: lambda t: (t * 1.8) + 32,\n...                 }\n
    Source code in src/property_utils/units/converter_types.py
    class RelativeUnitConverter(\n    metaclass=ABCMeta\n):  # pylint: disable=too-few-public-methods\n    \"\"\"\n    Base converter class for measurement units that are relative.\n\n    e.g. Temperature units are relative because conversion from one unit to another\n    is not necessarily performed with multiplication with a single factor.\n\n    Use the `register_converter` decorator when subclassing and define the\n    `reference_unit`, `conversion_map` and `reference_conversion_map` attributes. It\n    does not matter what unit you shall choose to be the reference; although you have to\n    define the conversion map and reference conversion map accordingly. The conversion\n    map is a dictionary that holds the conversion functions that convert other units to\n    the reference unit. The reference conversion map is a dictionary that holds the\n    conversion functions that convert the reference unit to other units.\n\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     CELCIUS = \"\u00b0C\"\n        ...     FAHRENHEIT = \"\u00b0F\"\n\n        >>> @register_converter(TemperatureUnit)\n        ... class TemperatureUnitConverter(RelativeUnitConverter):\n        ...     reference_unit = TemperatureUnit.CELCIUS\n        ...     conversion_map = {\n        ...             TemperatureUnit.CELCIUS: lambda t: t,\n        ...             TemperatureUnit.FAHRENHEIT: lambda t: (t - 32) / 1.8,\n        ...                 }\n        ...     reference_conversion_map = {\n        ...             TemperatureUnit.CELCIUS: lambda t: t,\n        ...             TemperatureUnit.FAHRENHEIT: lambda t: (t * 1.8) + 32,\n        ...                 }\n    \"\"\"\n\n    generic_unit_descriptor: MeasurementUnitType\n    reference_unit: MeasurementUnit\n    reference_conversion_map: Dict[MeasurementUnit, Callable[[float], float]]\n    conversion_map: Dict[MeasurementUnit, Callable[[float], float]]\n\n    @classmethod\n    def convert(\n        cls,\n        value: float,\n        from_descriptor: UnitDescriptor,\n        to_descriptor: UnitDescriptor,\n    ) -> float:\n        \"\"\"\n        Convert a value from a relative unit to another relative unit.\n\n        Raises `UnitConversionError` if `from_descriptor` or `to_descriptor` are not\n        an instance of the generic that is registered with the converter or if `value`\n        is not a numeric.\n\n        Raises `ConversionFunctionError` if an error occurs when calling a function\n        provided in the conversion_map or reference_conversion_map.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     CELCIUS = \"\u00b0C\"\n            ...     FAHRENHEIT = \"\u00b0F\"\n\n            >>> @register_converter(TemperatureUnit)\n            ... class TemperatureUnitConverter(RelativeUnitConverter):\n            ...     reference_unit = TemperatureUnit.CELCIUS\n            ...     conversion_map = {\n            ...             TemperatureUnit.CELCIUS: lambda t: t,\n            ...             TemperatureUnit.FAHRENHEIT: lambda t: (t - 32) / 1.8,\n            ...                 }\n            ...     reference_conversion_map = {\n            ...             TemperatureUnit.CELCIUS: lambda t: t,\n            ...             TemperatureUnit.FAHRENHEIT: lambda t: (t * 1.8) + 32,\n            ...                 }\n\n            >>> TemperatureUnitConverter.convert(100, TemperatureUnit.CELCIUS, TemperatureUnit.FAHRENHEIT)\n            212.0\n        \"\"\"\n        if not isinstance(value, (float, int)):\n            raise UnitConversionError(f\"invalid 'value': {value}; expected numeric. \")\n        return cls._from_reference(\n            cls._to_reference(value, from_descriptor), to_descriptor\n        )\n\n    @classmethod\n    def _to_reference(cls, value: float, from_descriptor: UnitDescriptor) -> float:\n        if not from_descriptor.isinstance(cls.generic_unit_descriptor):\n            raise UnitConversionError(\n                f\"invalid 'from_descriptor; expected an instance of {cls.generic_unit_descriptor}. \"\n            )\n        from_unit = MeasurementUnit.from_descriptor(from_descriptor)\n        try:\n            conversion_func = cls.conversion_map[from_unit]\n        except KeyError:\n            raise UnitConversionError(\n                f\"cannot convert from {from_unit}; unit is not in {cls.__name__}'s conversion map. \",\n            ) from None\n        try:\n            return conversion_func(value)\n        except Exception as exc:\n            raise ConversionFunctionError(\n                f\"an error occured in a conversion function of {cls.__name__}. \", exc\n            ) from exc\n\n    @classmethod\n    def _from_reference(cls, value: float, to_descriptor: UnitDescriptor) -> float:\n        if not to_descriptor.isinstance(cls.generic_unit_descriptor):\n            raise UnitConversionError(\n                f\"invalid 'to_descriptor'; expected an instance of {cls.generic_unit_descriptor}. \"\n            )\n        to_unit = MeasurementUnit.from_descriptor(to_descriptor)\n        try:\n            conversion_func = cls.reference_conversion_map[to_unit]\n        except KeyError:\n            raise UnitConversionError(\n                f\"cannot convert to {to_unit}; unit is not registered in {cls.__name__}'s reference conversion map. \",\n            ) from None\n        try:\n            return conversion_func(value)\n        except Exception as exc:\n            raise ConversionFunctionError(\n                f\"an error occured in a conversion function of {cls.__name__}. \", exc\n            ) from exc\n
    "},{"location":"converter_types/#property_utils.units.converter_types.RelativeUnitConverter.convert","title":"convert(value, from_descriptor, to_descriptor) classmethod","text":"

    Convert a value from a relative unit to another relative unit.

    Raises UnitConversionError if from_descriptor or to_descriptor are not an instance of the generic that is registered with the converter or if value is not a numeric.

    Raises ConversionFunctionError if an error occurs when calling a function provided in the conversion_map or reference_conversion_map.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     CELCIUS = \"\u00b0C\"\n...     FAHRENHEIT = \"\u00b0F\"\n
    >>> @register_converter(TemperatureUnit)\n... class TemperatureUnitConverter(RelativeUnitConverter):\n...     reference_unit = TemperatureUnit.CELCIUS\n...     conversion_map = {\n...             TemperatureUnit.CELCIUS: lambda t: t,\n...             TemperatureUnit.FAHRENHEIT: lambda t: (t - 32) / 1.8,\n...                 }\n...     reference_conversion_map = {\n...             TemperatureUnit.CELCIUS: lambda t: t,\n...             TemperatureUnit.FAHRENHEIT: lambda t: (t * 1.8) + 32,\n...                 }\n
    >>> TemperatureUnitConverter.convert(100, TemperatureUnit.CELCIUS, TemperatureUnit.FAHRENHEIT)\n212.0\n
    Source code in src/property_utils/units/converter_types.py
    @classmethod\ndef convert(\n    cls,\n    value: float,\n    from_descriptor: UnitDescriptor,\n    to_descriptor: UnitDescriptor,\n) -> float:\n    \"\"\"\n    Convert a value from a relative unit to another relative unit.\n\n    Raises `UnitConversionError` if `from_descriptor` or `to_descriptor` are not\n    an instance of the generic that is registered with the converter or if `value`\n    is not a numeric.\n\n    Raises `ConversionFunctionError` if an error occurs when calling a function\n    provided in the conversion_map or reference_conversion_map.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     CELCIUS = \"\u00b0C\"\n        ...     FAHRENHEIT = \"\u00b0F\"\n\n        >>> @register_converter(TemperatureUnit)\n        ... class TemperatureUnitConverter(RelativeUnitConverter):\n        ...     reference_unit = TemperatureUnit.CELCIUS\n        ...     conversion_map = {\n        ...             TemperatureUnit.CELCIUS: lambda t: t,\n        ...             TemperatureUnit.FAHRENHEIT: lambda t: (t - 32) / 1.8,\n        ...                 }\n        ...     reference_conversion_map = {\n        ...             TemperatureUnit.CELCIUS: lambda t: t,\n        ...             TemperatureUnit.FAHRENHEIT: lambda t: (t * 1.8) + 32,\n        ...                 }\n\n        >>> TemperatureUnitConverter.convert(100, TemperatureUnit.CELCIUS, TemperatureUnit.FAHRENHEIT)\n        212.0\n    \"\"\"\n    if not isinstance(value, (float, int)):\n        raise UnitConversionError(f\"invalid 'value': {value}; expected numeric. \")\n    return cls._from_reference(\n        cls._to_reference(value, from_descriptor), to_descriptor\n    )\n
    "},{"location":"converter_types/#property_utils.units.converter_types.UnitConverter","title":"UnitConverter","text":"

    Bases: Protocol

    Protocol of classes that convert a value from one unit to another.

    Source code in src/property_utils/units/converter_types.py
    class UnitConverter(Protocol):  # pylint: disable=too-few-public-methods\n    \"\"\"Protocol of classes that convert a value from one unit to another.\"\"\"\n\n    generic_unit_descriptor: GenericUnitDescriptor\n\n    @classmethod\n    def convert(\n        cls,\n        value: float,\n        from_descriptor: UnitDescriptor,\n        to_descriptor: UnitDescriptor,\n    ) -> float:\n        \"\"\"\n        Convert a value from a unit descriptor to its' corresponding value in a\n        different unit descriptor.\n        \"\"\"\n
    "},{"location":"converter_types/#property_utils.units.converter_types.UnitConverter.convert","title":"convert(value, from_descriptor, to_descriptor) classmethod","text":"

    Convert a value from a unit descriptor to its' corresponding value in a different unit descriptor.

    Source code in src/property_utils/units/converter_types.py
    @classmethod\ndef convert(\n    cls,\n    value: float,\n    from_descriptor: UnitDescriptor,\n    to_descriptor: UnitDescriptor,\n) -> float:\n    \"\"\"\n    Convert a value from a unit descriptor to its' corresponding value in a\n    different unit descriptor.\n    \"\"\"\n
    "},{"location":"converter_types/#property_utils.units.converter_types.get_converter","title":"get_converter(generic)","text":"

    Get converter for given generic descriptor.

    Raises PropertyUtilsTypeError if argument is not a generic unit descriptor.

    Raises UndefinedConverterError if a converter has not been defined for the given generic.

    Source code in src/property_utils/units/converter_types.py
    def get_converter(generic: GenericUnitDescriptor) -> ConverterType:\n    \"\"\"\n    Get converter for given generic descriptor.\n\n    Raises `PropertyUtilsTypeError` if argument is not a generic unit descriptor.\n\n    Raises `UndefinedConverterError` if a converter has not been defined for the given generic.\n    \"\"\"\n    if not isinstance(\n        generic, (MeasurementUnitType, GenericDimension, GenericCompositeDimension)\n    ):\n        raise PropertyUtilsTypeError(\n            f\"cannot get converter; argument: {generic} is not a generic unit descriptor. \"\n        )\n    if isinstance(generic, GenericDimension) and generic.power == 1:\n        generic = generic.unit_type\n    elif isinstance(generic, GenericDimension) and generic not in _converters:\n        register_converter(generic)(\n            type(f\"{generic}_Converter\", (ExponentiatedUnitConverter,), {})\n        )\n    elif isinstance(generic, GenericCompositeDimension) and generic not in _converters:\n        register_converter(generic)(\n            type(f\"{generic}_Converter\", (CompositeUnitConverter,), {})\n        )\n    try:\n        return _converters[generic]\n    except KeyError:\n        raise UndefinedConverterError(\n            f\"a converter has not been defined for {generic}\"\n        ) from None\n
    "},{"location":"converter_types/#property_utils.units.converter_types.register_converter","title":"register_converter(generic)","text":"

    Decorate a converter class to register the generic descriptor of the units it operates on. This decorator also sets the 'generic_unit_descriptor' attribute of the decorated class.

    Raises PropertyUtilsTypeError if argument is not a generic unit descriptor.

    Raises PropertyUtilsValueError if generic has already a converter registered.

    Source code in src/property_utils/units/converter_types.py
    def register_converter(generic: GenericUnitDescriptor) -> Callable:\n    \"\"\"\n    Decorate a converter class to register the generic descriptor of the units it\n    operates on.\n    This decorator also sets the 'generic_unit_descriptor' attribute of the decorated\n    class.\n\n    Raises `PropertyUtilsTypeError` if argument is not a generic unit descriptor.\n\n    Raises `PropertyUtilsValueError` if generic has already a converter registered.\n    \"\"\"\n    if not isinstance(\n        generic, (MeasurementUnitType, GenericDimension, GenericCompositeDimension)\n    ):\n        raise PropertyUtilsTypeError(\n            f\"cannot get converter; argument: {generic} is not a generic unit descriptor. \"\n        )\n\n    if generic in _converters:\n        raise PropertyUtilsValueError(\n            f\"cannot register converter twice; {generic} has already got a converter. \"\n        )\n\n    def wrapper(cls: ConverterType) -> ConverterType:\n        _converters[generic] = cls\n        cls.generic_unit_descriptor = generic\n        return cls\n\n    return wrapper\n
    "},{"location":"converters/","title":"converters","text":"

    This module defines unit converters for the units in 'property_utils.units.units' as well as some converters for common exponentiated units (area and volume).

    "},{"location":"converters/#property_utils.units.converters.AbsoluteTemperatureUnitConverter","title":"AbsoluteTemperatureUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    Convert absolute temperature with this converter.

    Examples:

    >>> AbsoluteTemperatureUnitConverter.convert(10, AbsoluteTemperatureUnit.KELVIN, AbsoluteTemperatureUnit.RANKINE)\n18.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(AbsoluteTemperatureUnit)\nclass AbsoluteTemperatureUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    Convert absolute temperature with this converter.\n\n    Examples:\n        >>> AbsoluteTemperatureUnitConverter.convert(10, AbsoluteTemperatureUnit.KELVIN, AbsoluteTemperatureUnit.RANKINE)\n        18.0\n    \"\"\"\n\n    reference_unit = AbsoluteTemperatureUnit.KELVIN\n    conversion_map = {\n        AbsoluteTemperatureUnit.KELVIN: 1,\n        AbsoluteTemperatureUnit.RANKINE: 1.8,\n    }\n\n    @override\n    @classmethod\n    def convert(\n        cls,\n        value: float,\n        from_descriptor: UnitDescriptor,\n        to_descriptor: UnitDescriptor,\n    ) -> float:\n        if not isinstance(value, (float, int)):\n            raise UnitConversionError(f\"invalid 'value': {value}; expected numeric. \")\n        if from_descriptor.isinstance(\n            RelativeTemperatureUnit\n        ) or to_descriptor.isinstance(RelativeTemperatureUnit):\n            return RelativeTemperatureUnitConverter.convert(\n                value, from_descriptor, to_descriptor\n            )\n        return value * cls.get_factor(from_descriptor, to_descriptor)\n
    "},{"location":"converters/#property_utils.units.converters.AliasEnergyUnitConverter","title":"AliasEnergyUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    Convert energy units with this converter.

    Examples:

    >>> AliasEnergyUnitConverter.convert(2500, EnergyUnit.JOULE, EnergyUnit.KILO_JOULE)\n2.5\n
    Source code in src/property_utils/units/converters.py
    @register_converter(EnergyUnit)\nclass AliasEnergyUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    Convert energy units with this converter.\n\n    Examples:\n        >>> AliasEnergyUnitConverter.convert(2500, EnergyUnit.JOULE, EnergyUnit.KILO_JOULE)\n        2.5\n    \"\"\"\n\n    reference_unit = EnergyUnit.JOULE\n    conversion_map = {\n        EnergyUnit.JOULE: 1,\n        EnergyUnit.KILO_JOULE: UnitPrefix.KILO.inverse(),\n        EnergyUnit.MEGA_JOULE: UnitPrefix.MEGA.inverse(),\n        EnergyUnit.GIGA_JOULE: UnitPrefix.GIGA.inverse(),\n        EnergyUnit.CALORIE: 1 / 4.184,\n        EnergyUnit.KILO_CALORIE: (1 / 4.184) * UnitPrefix.KILO.inverse(),\n        EnergyUnit.BTU: 1 / 1055.0,\n        EnergyUnit.ELECTRONVOLT: 6.242e18,\n        EnergyUnit.WATTHOUR: 1 / 3600,\n        EnergyUnit.KILO_WATTHOUR: (1 / 3600) * UnitPrefix.KILO.inverse(),\n    }\n
    "},{"location":"converters/#property_utils.units.converters.AliasForceUnitConverter","title":"AliasForceUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    Convert force units with this converter.

    Examples:

    >>> AliasForceUnitConverter.convert(2, ForceUnit.NEWTON, ForceUnit.DYNE)\n200000.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(ForceUnit)\nclass AliasForceUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    Convert force units with this converter.\n\n    Examples:\n        >>> AliasForceUnitConverter.convert(2, ForceUnit.NEWTON, ForceUnit.DYNE)\n        200000.0\n    \"\"\"\n\n    reference_unit = ForceUnit.NEWTON\n    conversion_map = {ForceUnit.NEWTON: 1, ForceUnit.DYNE: 100_000}\n
    "},{"location":"converters/#property_utils.units.converters.AliasPowerUnitConverter","title":"AliasPowerUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    Convert power units with this converter.

    Examples:

    >>> AliasPowerUnitConverter.convert(5, PowerUnit.KILO_WATT, PowerUnit.WATT)\n5000.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(PowerUnit)\nclass AliasPowerUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    Convert power units with this converter.\n\n    Examples:\n        >>> AliasPowerUnitConverter.convert(5, PowerUnit.KILO_WATT, PowerUnit.WATT)\n        5000.0\n    \"\"\"\n\n    reference_unit = PowerUnit.WATT\n    conversion_map = {\n        PowerUnit.WATT: 1,\n        PowerUnit.KILO_WATT: UnitPrefix.KILO.inverse(),\n        PowerUnit.MEGA_WATT: UnitPrefix.MEGA.inverse(),\n        PowerUnit.GIGA_WATT: UnitPrefix.GIGA.inverse(),\n    }\n
    "},{"location":"converters/#property_utils.units.converters.AliasPressureUnitConverter","title":"AliasPressureUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    Convert pressure units with this converter.

    Examples:

    >>> AliasPressureUnitConverter.convert(2, PressureUnit.BAR, PressureUnit.KILO_PASCAL)\n200.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(PressureUnit)\nclass AliasPressureUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    Convert pressure units with this converter.\n\n    Examples:\n        >>> AliasPressureUnitConverter.convert(2, PressureUnit.BAR, PressureUnit.KILO_PASCAL)\n        200.0\n    \"\"\"\n\n    reference_unit = PressureUnit.BAR\n    conversion_map = {\n        PressureUnit.MILLI_BAR: UnitPrefix.MILLI.inverse(),\n        PressureUnit.BAR: 1,\n        PressureUnit.PSI: 14.5038,\n        PressureUnit.PASCAL: 100_000,\n        PressureUnit.KILO_PASCAL: 100,\n        PressureUnit.MEGA_PASCAL: 0.1,\n    }\n
    "},{"location":"converters/#property_utils.units.converters.AmountUnitConverter","title":"AmountUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    Convert amount units with this converter.

    Examples:

    >>> AmountUnitConverter.convert(2000, AmountUnit.MOL, AmountUnit.KILO_MOL)\n2.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(AmountUnit)\nclass AmountUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    Convert amount units with this converter.\n\n    Examples:\n        >>> AmountUnitConverter.convert(2000, AmountUnit.MOL, AmountUnit.KILO_MOL)\n        2.0\n    \"\"\"\n\n    reference_unit = AmountUnit.MOL\n    conversion_map = {AmountUnit.MOL: 1, AmountUnit.KILO_MOL: UnitPrefix.KILO.inverse()}\n
    "},{"location":"converters/#property_utils.units.converters.AreaUnitConverter","title":"AreaUnitConverter","text":"

    Bases: ExponentiatedUnitConverter

    Convert area units with this converter.

    Examples:

    >>> AreaUnitConverter.convert(1, LengthUnit.METER**2, LengthUnit.CENTI_METER**2)\n10000.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(LengthUnit**2)\nclass AreaUnitConverter(ExponentiatedUnitConverter):\n    \"\"\"\n    Convert area units with this converter.\n\n    Examples:\n        >>> AreaUnitConverter.convert(1, LengthUnit.METER**2, LengthUnit.CENTI_METER**2)\n        10000.0\n    \"\"\"\n
    "},{"location":"converters/#property_utils.units.converters.ElectricCurrentUnitConverter","title":"ElectricCurrentUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    Convert electric current units with this converter.

    Examples:

    >>> ElectricCurrentUnitConverter.convert(1000, ElectricCurrentUnit.MILLI_AMPERE, ElectricCurrentUnit.AMPERE)\n1.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(ElectricCurrentUnit)\nclass ElectricCurrentUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    Convert electric current units with this converter.\n\n    Examples:\n        >>> ElectricCurrentUnitConverter.convert(1000, ElectricCurrentUnit.MILLI_AMPERE, ElectricCurrentUnit.AMPERE)\n        1.0\n    \"\"\"\n\n    reference_unit = ElectricCurrentUnit.AMPERE\n    conversion_map = {\n        ElectricCurrentUnit.MILLI_AMPERE: UnitPrefix.MILLI.inverse(),\n        ElectricCurrentUnit.AMPERE: 1,\n        ElectricCurrentUnit.KILO_AMPERE: UnitPrefix.KILO.inverse(),\n    }\n
    "},{"location":"converters/#property_utils.units.converters.EnergyUnitConverter","title":"EnergyUnitConverter","text":"

    Bases: CompositeUnitConverter

    Convert energy units (mass * length^2 / time^2) with this converter.

    Examples:

    >>> from_unit = MassUnit.KILO_GRAM * (LengthUnit.METER**2) / (TimeUnit.MINUTE**2)\n>>> to_unit = MassUnit.METRIC_TONNE * (LengthUnit.CENTI_METER**2) / (TimeUnit.MINUTE**2)\n>>> EnergyUnitConverter.convert(25, from_unit, to_unit)\n250.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(EnergyUnit.aliased_generic_descriptor())\nclass EnergyUnitConverter(CompositeUnitConverter):\n    \"\"\"\n    Convert energy units (mass * length^2 / time^2) with this converter.\n\n    Examples:\n        >>> from_unit = MassUnit.KILO_GRAM * (LengthUnit.METER**2) / (TimeUnit.MINUTE**2)\n        >>> to_unit = MassUnit.METRIC_TONNE * (LengthUnit.CENTI_METER**2) / (TimeUnit.MINUTE**2)\n        >>> EnergyUnitConverter.convert(25, from_unit, to_unit)\n        250.0\n    \"\"\"\n
    "},{"location":"converters/#property_utils.units.converters.ForceUnitConverter","title":"ForceUnitConverter","text":"

    Bases: CompositeUnitConverter

    Convert force units (mass * length / time^2) with this converter.

    Examples:

    >>> from_unit = MassUnit.KILO_GRAM * LengthUnit.CENTI_METER / (TimeUnit.SECOND**2)\n>>> to_unit = MassUnit.GRAM * LengthUnit.METER / (TimeUnit.SECOND**2)\n>>> ForceUnitConverter.convert(100, from_unit, to_unit)\n1000.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(ForceUnit.aliased_generic_descriptor())\nclass ForceUnitConverter(CompositeUnitConverter):\n    \"\"\"\n    Convert force units (mass * length / time^2) with this converter.\n\n    Examples:\n        >>> from_unit = MassUnit.KILO_GRAM * LengthUnit.CENTI_METER / (TimeUnit.SECOND**2)\n        >>> to_unit = MassUnit.GRAM * LengthUnit.METER / (TimeUnit.SECOND**2)\n        >>> ForceUnitConverter.convert(100, from_unit, to_unit)\n        1000.0\n    \"\"\"\n
    "},{"location":"converters/#property_utils.units.converters.LengthUnitConverter","title":"LengthUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    Convert length units with this converter.

    Examples:

    >>> LengthUnitConverter.convert(2000, LengthUnit.MILLI_METER, LengthUnit.METER)\n2.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(LengthUnit)\nclass LengthUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    Convert length units with this converter.\n\n    Examples:\n        >>> LengthUnitConverter.convert(2000, LengthUnit.MILLI_METER, LengthUnit.METER)\n        2.0\n    \"\"\"\n\n    reference_unit = LengthUnit.METER\n    conversion_map = {\n        LengthUnit.MILLI_METER: UnitPrefix.MILLI.inverse(),\n        LengthUnit.CENTI_METER: UnitPrefix.CENTI.inverse(),\n        LengthUnit.METER: 1,\n        LengthUnit.KILO_METER: UnitPrefix.KILO.inverse(),\n        LengthUnit.INCH: 39.37,\n        LengthUnit.FOOT: 3.281,\n        LengthUnit.YARD: 1.094,\n        LengthUnit.MILE: 1 / 1609,\n        LengthUnit.NAUTICAL_MILE: 1 / 1852,\n    }\n
    "},{"location":"converters/#property_utils.units.converters.MassUnitConverter","title":"MassUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    Convert mass units with this converter.

    Examples:

    >>> MassUnitConverter.convert(10, MassUnit.KILO_GRAM, MassUnit.GRAM)\n10000.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(MassUnit)\nclass MassUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    Convert mass units with this converter.\n\n    Examples:\n        >>> MassUnitConverter.convert(10, MassUnit.KILO_GRAM, MassUnit.GRAM)\n        10000.0\n    \"\"\"\n\n    reference_unit = MassUnit.KILO_GRAM\n    conversion_map = {\n        MassUnit.MILLI_GRAM: UnitPrefix.KILO * UnitPrefix.MILLI.inverse(),\n        MassUnit.GRAM: UnitPrefix.KILO,\n        MassUnit.KILO_GRAM: 1,\n        MassUnit.METRIC_TONNE: 1 / 1_000.0,\n        MassUnit.POUND: 2.205,\n    }\n
    "},{"location":"converters/#property_utils.units.converters.NonDimensionalUnitConverter","title":"NonDimensionalUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    This converter is needed for compatibility, i.e. for conversions to work from non-dimensional units to non-dimensional dimensions.

    Source code in src/property_utils/units/converters.py
    @register_converter(NonDimensionalUnit)\nclass NonDimensionalUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    This converter is needed for compatibility, i.e. for conversions to work from\n    non-dimensional units to non-dimensional dimensions.\n    \"\"\"\n\n    reference_unit = NonDimensionalUnit.NON_DIMENSIONAL\n    conversion_map = {NonDimensionalUnit.NON_DIMENSIONAL: 1}\n
    "},{"location":"converters/#property_utils.units.converters.PowerUnitConverter","title":"PowerUnitConverter","text":"

    Bases: CompositeUnitConverter

    Convert power units (mass * length^2 / time^3) with this converter.

    Examples:

    >>> from_unit = MassUnit.KILO_GRAM * (LengthUnit.METER**2) / (TimeUnit.MINUTE**3)\n>>> to_unit = MassUnit.METRIC_TONNE * (LengthUnit.CENTI_METER**2) / (TimeUnit.MINUTE**3)\n>>> PowerUnitConverter.convert(15, from_unit, to_unit)\n150.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(PowerUnit.aliased_generic_descriptor())\nclass PowerUnitConverter(CompositeUnitConverter):\n    \"\"\"\n    Convert power units (mass * length^2 / time^3) with this converter.\n\n    Examples:\n        >>> from_unit = MassUnit.KILO_GRAM * (LengthUnit.METER**2) / (TimeUnit.MINUTE**3)\n        >>> to_unit = MassUnit.METRIC_TONNE * (LengthUnit.CENTI_METER**2) / (TimeUnit.MINUTE**3)\n        >>> PowerUnitConverter.convert(15, from_unit, to_unit)\n        150.0\n    \"\"\"\n
    "},{"location":"converters/#property_utils.units.converters.PressureUnitConverter","title":"PressureUnitConverter","text":"

    Bases: CompositeUnitConverter

    Convert pressure units (mass / length / time^2) with this converter.

    Examples:

    >>> from_unit = MassUnit.GRAM / LengthUnit.CENTI_METER / (TimeUnit.HOUR**2)\n>>> to_unit = MassUnit.KILO_GRAM / LengthUnit.METER / (TimeUnit.HOUR**2)\n>>> PressureUnitConverter.convert(50, from_unit, to_unit)\n5.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(PressureUnit.aliased_generic_descriptor())\nclass PressureUnitConverter(CompositeUnitConverter):\n    \"\"\"\n    Convert pressure units (mass / length / time^2) with this converter.\n\n    Examples:\n        >>> from_unit = MassUnit.GRAM / LengthUnit.CENTI_METER / (TimeUnit.HOUR**2)\n        >>> to_unit = MassUnit.KILO_GRAM / LengthUnit.METER / (TimeUnit.HOUR**2)\n        >>> PressureUnitConverter.convert(50, from_unit, to_unit)\n        5.0\n    \"\"\"\n
    "},{"location":"converters/#property_utils.units.converters.RelativeTemperatureUnitConverter","title":"RelativeTemperatureUnitConverter","text":"

    Bases: RelativeUnitConverter

    Convert temperature units with this converter.

    Examples:

    >>> RelativeTemperatureUnitConverter.convert(100, RelativeTemperatureUnit.CELCIUS, RelativeTemperatureUnit.FAHRENHEIT)\n212.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(RelativeTemperatureUnit)\nclass RelativeTemperatureUnitConverter(RelativeUnitConverter):  # pylint: disable=too-few-public-methods\n    \"\"\"\n    Convert temperature units with this converter.\n\n    Examples:\n        >>> RelativeTemperatureUnitConverter.convert(100, RelativeTemperatureUnit.CELCIUS, RelativeTemperatureUnit.FAHRENHEIT)\n        212.0\n    \"\"\"\n\n    reference_unit = RelativeTemperatureUnit.CELCIUS\n    conversion_map = {\n        RelativeTemperatureUnit.CELCIUS: lambda t: t,\n        AbsoluteTemperatureUnit.KELVIN: lambda t: t - 273.15,\n        RelativeTemperatureUnit.FAHRENHEIT: lambda t: (t - 32) / 1.8,\n        AbsoluteTemperatureUnit.RANKINE: lambda t: (t / 1.8) - 273.15,\n    }\n    reference_conversion_map = {\n        RelativeTemperatureUnit.CELCIUS: lambda t: t,\n        AbsoluteTemperatureUnit.KELVIN: lambda t: t + 273.15,\n        RelativeTemperatureUnit.FAHRENHEIT: lambda t: (t * 1.8) + 32,\n        AbsoluteTemperatureUnit.RANKINE: lambda t: (t + 273.15) * 1.8,\n    }\n
    "},{"location":"converters/#property_utils.units.converters.TimeUnitConverter","title":"TimeUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    Convert time units with this converter.

    Examples:

    >>> TimeUnitConverter.convert(1, TimeUnit.HOUR, TimeUnit.SECOND)\n3600.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(TimeUnit)\nclass TimeUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    Convert time units with this converter.\n\n    Examples:\n        >>> TimeUnitConverter.convert(1, TimeUnit.HOUR, TimeUnit.SECOND)\n        3600.0\n    \"\"\"\n\n    reference_unit = TimeUnit.SECOND\n    conversion_map = {\n        TimeUnit.MILLI_SECOND: UnitPrefix.MILLI.inverse(),\n        TimeUnit.SECOND: 1,\n        TimeUnit.MINUTE: 1 / 60.0,\n        TimeUnit.HOUR: 1 / 60.0 / 60.0,\n        TimeUnit.DAY: 1 / 60.0 / 60.0 / 24.0,\n        TimeUnit.WEEK: 1 / 60.0 / 60.0 / 24.0 / 7,\n        TimeUnit.MONTH: 1 / 60.0 / 60.0 / 24.0 / (365 / 12),\n        TimeUnit.YEAR: 1 / 60.0 / 60.0 / 24.0 / 365,\n    }\n
    "},{"location":"converters/#property_utils.units.converters.UnitPrefix","title":"UnitPrefix","text":"

    Bases: float, Enum

    Enumeration of unit prefixes. Handy when converting to and fro prefixed units.

    Examples:

    >>> centimeters = 225\n>>> meters = centimeters * UnitPrefix.CENTI\n>>> meters\n2.25\n
    Source code in src/property_utils/units/converters.py
    class UnitPrefix(float, Enum):\n    \"\"\"\n    Enumeration of unit prefixes.\n    Handy when converting to and fro prefixed units.\n\n    Examples:\n        >>> centimeters = 225\n        >>> meters = centimeters * UnitPrefix.CENTI\n        >>> meters\n        2.25\n    \"\"\"\n\n    PICO = 1e-12\n    NANO = 1e-9\n    MICRO = 1e-6\n    MILLI = 1e-3\n    CENTI = 1e-2\n    DECI = 1e-1\n    DECA = 1e1\n    HECTO = 1e2\n    KILO = 1e3\n    MEGA = 1e6\n    GIGA = 1e9\n    TERA = 1e12\n\n    def inverse(self) -> float:\n        \"\"\"\n        Return the inverse of the unit prefix. Use when prefixing a unit.\n\n        Examples:\n            >>> meters = 50.26\n            >>> centimeters = meters * UnitPrefix.CENTI.inverse()\n            >>> centimeters\n            5026.0\n        \"\"\"\n        return 1 / self.value\n
    "},{"location":"converters/#property_utils.units.converters.UnitPrefix.inverse","title":"inverse()","text":"

    Return the inverse of the unit prefix. Use when prefixing a unit.

    Examples:

    >>> meters = 50.26\n>>> centimeters = meters * UnitPrefix.CENTI.inverse()\n>>> centimeters\n5026.0\n
    Source code in src/property_utils/units/converters.py
    def inverse(self) -> float:\n    \"\"\"\n    Return the inverse of the unit prefix. Use when prefixing a unit.\n\n    Examples:\n        >>> meters = 50.26\n        >>> centimeters = meters * UnitPrefix.CENTI.inverse()\n        >>> centimeters\n        5026.0\n    \"\"\"\n    return 1 / self.value\n
    "},{"location":"converters/#property_utils.units.converters.VolumeUnitConverter","title":"VolumeUnitConverter","text":"

    Bases: ExponentiatedUnitConverter

    Convert volume units with this converter.

    Examples:

    >>> VolumeUnitConverter.convert(1, LengthUnit.METER**3, LengthUnit.CENTI_METER**3)\n1000000.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(LengthUnit**3)\nclass VolumeUnitConverter(ExponentiatedUnitConverter):\n    \"\"\"\n    Convert volume units with this converter.\n\n    Examples:\n        >>> VolumeUnitConverter.convert(1, LengthUnit.METER**3, LengthUnit.CENTI_METER**3)\n        1000000.0\n    \"\"\"\n
    "},{"location":"descriptors/","title":"descriptors","text":"

    This module includes definitions for generic unit descriptors and unit descriptors.

    A unit descriptor is an interface that describes a measurement unit. It can represent anything like \u00b0C, m^3, mol/m^3/s etc.

    A generic unit descriptor is an interface that describes a generic measurement unit. It can represent e.g. a temperature unit, a volume unit, a reaction rate unit etc.

    "},{"location":"descriptors/#property_utils.units.descriptors.AliasMeasurementUnit","title":"AliasMeasurementUnit","text":"

    Bases: MeasurementUnit

    Base class for common composite units of physical quantities.

    Subclasses of MeasurementUnit represent only primitive physical quantities. However, many common physical properties have composite units (e.g. pressure, force, energy, etc), thus subclasses of this class alias composite units as primitive ones.

    Only very common composite units should be aliased.

    e.g. you can create an alias for pressure units, instead of using mass * length / ( time^2) units.

    Examples:

    >>> class PressureUnit(AliasMeasurementUnit):\n...     BAR = \"bar\"\n...     PASCAL = \"Pa\"\n...     KILO_PASCAL = \"kPa\"\n...     PSI = \"psi\"\n
    Source code in src/property_utils/units/descriptors.py
    class AliasMeasurementUnit(MeasurementUnit):\n    \"\"\"\n    Base class for common composite units of physical quantities.\n\n    Subclasses of `MeasurementUnit` represent only primitive physical quantities.\n    However, many common physical properties have composite units (e.g. pressure, force,\n    energy, etc), thus subclasses of this class alias composite units as primitive ones.\n\n    Only very common composite units should be aliased.\n\n    e.g. you can create an alias for pressure units, instead of using mass * length / (\n        time^2) units.\n\n    Examples:\n        >>> class PressureUnit(AliasMeasurementUnit):\n        ...     BAR = \"bar\"\n        ...     PASCAL = \"Pa\"\n        ...     KILO_PASCAL = \"kPa\"\n        ...     PSI = \"psi\"\n    \"\"\"\n\n    @staticmethod\n    def from_descriptor(descriptor: UnitDescriptor) -> MeasurementUnit:\n        \"\"\"\n        Create an AliasMeasurementUnit from given descriptor.\n        If descriptor is already an AliasMeasurementUnit, it returns the same object.\n\n        This function does not serve as a constructor for AliasMeasurementUnit, rather\n        it is intended to be used to convert an unknown unit descriptor to an\n        AliasMeasurementUnit.\n\n        Subclasses should implement aliased_generic_descriptor and alias_mapping\n        methods.\n\n        Raises `UnitDescriptorTypeError` if given descriptor cannot be translated\n        to an AliasMeasurementUnit  instance.\n\n        Examples:\n            >>> class PressureUnit(AliasMeasurementUnit):\n            ...     BAR = \"bar\"\n\n            >>> bar = MeasurementUnit.from_descriptor(PressureUnit.BAR**(-1))\n            >>> bar\n            <PressureUnit: bar>\n        \"\"\"\n        if isinstance(descriptor, Dimension) and isinstance(\n            descriptor.unit, AliasMeasurementUnit\n        ):\n            return descriptor.unit\n        if isinstance(descriptor, AliasMeasurementUnit):\n            return descriptor\n        raise UnitDescriptorTypeError(\n            f\"cannot create AliasMeasurementUnit from descriptor {descriptor}\"\n        )\n\n    @classmethod\n    def aliased_generic_descriptor(cls) -> GenericUnitDescriptor:\n        \"\"\"\n        Implement this method by returning the generic of the unit descriptor that this\n        measurement unit aliases.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit): ...\n            >>> class AreaUnit(AliasMeasurementUnit):\n            ...     @classmethod\n            ...     def aliased_generic_descriptor(cls):\n            ...         return LengthUnit**2\n        \"\"\"\n        raise NotImplementedError\n
    "},{"location":"descriptors/#property_utils.units.descriptors.AliasMeasurementUnit.aliased_generic_descriptor","title":"aliased_generic_descriptor() classmethod","text":"

    Implement this method by returning the generic of the unit descriptor that this measurement unit aliases.

    Examples:

    >>> class LengthUnit(MeasurementUnit): ...\n>>> class AreaUnit(AliasMeasurementUnit):\n...     @classmethod\n...     def aliased_generic_descriptor(cls):\n...         return LengthUnit**2\n
    Source code in src/property_utils/units/descriptors.py
    @classmethod\ndef aliased_generic_descriptor(cls) -> GenericUnitDescriptor:\n    \"\"\"\n    Implement this method by returning the generic of the unit descriptor that this\n    measurement unit aliases.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit): ...\n        >>> class AreaUnit(AliasMeasurementUnit):\n        ...     @classmethod\n        ...     def aliased_generic_descriptor(cls):\n        ...         return LengthUnit**2\n    \"\"\"\n    raise NotImplementedError\n
    "},{"location":"descriptors/#property_utils.units.descriptors.AliasMeasurementUnit.from_descriptor","title":"from_descriptor(descriptor) staticmethod","text":"

    Create an AliasMeasurementUnit from given descriptor. If descriptor is already an AliasMeasurementUnit, it returns the same object.

    This function does not serve as a constructor for AliasMeasurementUnit, rather it is intended to be used to convert an unknown unit descriptor to an AliasMeasurementUnit.

    Subclasses should implement aliased_generic_descriptor and alias_mapping methods.

    Raises UnitDescriptorTypeError if given descriptor cannot be translated to an AliasMeasurementUnit instance.

    Examples:

    >>> class PressureUnit(AliasMeasurementUnit):\n...     BAR = \"bar\"\n
    >>> bar = MeasurementUnit.from_descriptor(PressureUnit.BAR**(-1))\n>>> bar\n<PressureUnit: bar>\n
    Source code in src/property_utils/units/descriptors.py
    @staticmethod\ndef from_descriptor(descriptor: UnitDescriptor) -> MeasurementUnit:\n    \"\"\"\n    Create an AliasMeasurementUnit from given descriptor.\n    If descriptor is already an AliasMeasurementUnit, it returns the same object.\n\n    This function does not serve as a constructor for AliasMeasurementUnit, rather\n    it is intended to be used to convert an unknown unit descriptor to an\n    AliasMeasurementUnit.\n\n    Subclasses should implement aliased_generic_descriptor and alias_mapping\n    methods.\n\n    Raises `UnitDescriptorTypeError` if given descriptor cannot be translated\n    to an AliasMeasurementUnit  instance.\n\n    Examples:\n        >>> class PressureUnit(AliasMeasurementUnit):\n        ...     BAR = \"bar\"\n\n        >>> bar = MeasurementUnit.from_descriptor(PressureUnit.BAR**(-1))\n        >>> bar\n        <PressureUnit: bar>\n    \"\"\"\n    if isinstance(descriptor, Dimension) and isinstance(\n        descriptor.unit, AliasMeasurementUnit\n    ):\n        return descriptor.unit\n    if isinstance(descriptor, AliasMeasurementUnit):\n        return descriptor\n    raise UnitDescriptorTypeError(\n        f\"cannot create AliasMeasurementUnit from descriptor {descriptor}\"\n    )\n
    "},{"location":"descriptors/#property_utils.units.descriptors.CompositeDimension","title":"CompositeDimension dataclass","text":"

    A CompositeDimension represents a measurement unit that is composed from other measurement units.

    Objects of this class can represent either multiplication or division between two Dimension objects.

    Create objects by multiplying and diving Dimension or MeasurementUnit objects.

    Examples:

    >>> class LengthUnit(MeasurementUnit):\n...     METER = \"m\"\n
    >>> class AmountUnit(MeasurementUnit):\n...     KILO_MOL = \"kmol\"\n
    >>> molal_volume_dimension = (LengthUnit.METER**3) / AmountUnit.KILO_MOL\n>>> molal_volume_dimension\n<CompositeDimension: (m^3) / kmol>\n
    Source code in src/property_utils/units/descriptors.py
    @dataclass\nclass CompositeDimension:\n    \"\"\"\n    A CompositeDimension represents a measurement unit that is composed from other\n    measurement units.\n\n    Objects of this class can represent either multiplication or division between two\n    Dimension objects.\n\n    Create objects by multiplying and diving Dimension or MeasurementUnit objects.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit):\n        ...     METER = \"m\"\n\n        >>> class AmountUnit(MeasurementUnit):\n        ...     KILO_MOL = \"kmol\"\n\n        >>> molal_volume_dimension = (LengthUnit.METER**3) / AmountUnit.KILO_MOL\n        >>> molal_volume_dimension\n        <CompositeDimension: (m^3) / kmol>\n    \"\"\"\n\n    Default = TypeVar(\"Default\")  # default return type for `get` functions.\n\n    numerator: List[Dimension] = field(default_factory=list)\n    denominator: List[Dimension] = field(default_factory=list)\n\n    @staticmethod\n    def from_descriptor(descriptor: UnitDescriptor) -> \"CompositeDimension\":\n        \"\"\"\n        Create a CompositeDimension from given descriptor.\n        If descriptor is already a CompositeDimension, it returns the same object.\n\n        This function does not serve as a constructor for CompositeDimension, rather it\n        is intended to be used to convert an unknown unit descriptor to a\n        CompositeDimension.\n\n        Raises `UnitDescriptorTypeError` if given descriptor cannot be translated\n        to a CompositeDimension instance.\n        \"\"\"\n        if not isinstance(descriptor, CompositeDimension):\n            raise UnitDescriptorTypeError(\n                f\"cannot create CompositeDimension from descriptor {descriptor}\"\n            )\n        return descriptor\n\n    def si(self) -> \"CompositeDimension\":\n        \"\"\"\n        Returns this composite dimension in SI units.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     KELVIN = \"K\"\n            ...     RANKINE = \"R\"\n            ...     @classmethod\n            ...     def si(cls): return cls.KELVIN\n\n            >>> class LengthUnit(MeasurementUnit):\n            ...     METER = \"m\"\n            ...     FOOT = \"ft\"\n            ...     @classmethod\n            ...     def si(cls): return cls.METER\n\n            >>> (TemperatureUnit.RANKINE / LengthUnit.FOOT**2).si()\n            <CompositeDimension: K / (m^2)>\n        \"\"\"\n        return CompositeDimension(\n            [n.si() for n in self.numerator], [d.si() for d in self.denominator]\n        )\n\n    def isinstance(self, generic: GenericUnitDescriptor) -> bool:\n        \"\"\"\n        Returns True if the CompositeDimension is an instance of the generic, False\n        otherwise.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     CELCIUS = \"C\"\n\n            >>> class LengthUnit(MeasurementUnit):\n            ...     METER = \"m\"\n\n            >>> (TemperatureUnit.CELCIUS / LengthUnit.METER).isinstance(TemperatureUnit / LengthUnit)\n            True\n\n            >>> (TemperatureUnit.CELCIUS * LengthUnit.METER).isinstance(TemperatureUnit**2)\n            False\n        \"\"\"\n        if not isinstance(generic, GenericCompositeDimension):\n            return False\n\n        return self.to_generic() == generic\n\n    def isinstance_equivalent(self, generic: GenericUnitDescriptor) -> bool:\n        \"\"\"\n        Returns True if the UnitDescriptor is an instance-equivalent of the generic,\n        False otherwise.\n\n        A unit descriptor is an instance-equivalent of a generic if the generic of the\n        unit descriptor is equivalent to the generic.\n\n        Equivalence between generics is checked with the `is_equivalent` method.\n\n        Examples:\n            >>> class MassUnit(MeasurementUnit):\n            ...     KILO_GRAM = \"kg\"\n            >>> class LengthUnit(MeasurementUnit):\n            ...     METER = \"m\"\n            >>> class TimeUnit(MeasurementUnit):\n            ...     SECOND = \"s\"\n\n            >>> class ForceUnit(AliasMeasurementUnit):\n            ...     NEWTON = \"N\"\n            ...     @classmethod\n            ...     def aliased_generic_descriptor(cls):\n            ...         return MassUnit * LengthUnit / (TimeUnit**2)\n\n            >>> (MassUnit.KILO_GRAM * LengthUnit.METER / (TimeUnit.SECOND**2)).isinstance_equivalent(ForceUnit)\n            True\n        \"\"\"\n        return self.to_generic().is_equivalent(generic)\n\n    def to_generic(self) -> GenericCompositeDimension:\n        \"\"\"\n        Create a generic descriptor from this CompositeDimension.\n\n        Examples:\n            >>> class AmountUnit(MeasurementUnit):\n            ...     MOL = \"mol\"\n\n            >>> class MassUnit(MeasurementUnit):\n            ...     KILO_GRAM = \"kg\"\n\n            >>> (AmountUnit.MOL / MassUnit.KILO_GRAM).to_generic()\n            <GenericCompositeDimension: AmountUnit / MassUnit>\n        \"\"\"\n        return GenericCompositeDimension(\n            numerator=[n.to_generic() for n in self.numerator],\n            denominator=[d.to_generic() for d in self.denominator],\n        )\n\n    def get_numerator(\n        self,\n        generic: Union[MeasurementUnitType, GenericDimension],\n        default: Optional[Default] = None,\n    ) -> Union[Dimension, Optional[Default]]:\n        \"\"\"\n        Get a dimension from the numerator. If the dimension is not found it returns\n        the default.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit):\n            ...     METER = \"m\"\n\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     KELVIN = \"K\"\n\n            >>> composite = TemperatureUnit.KELVIN / (LengthUnit.METER**3)\n            >>> composite.get_numerator(TemperatureUnit)\n            <Dimension: K>\n            >>> composite.get_numerator(LengthUnit, \"default\")\n            'default'\n        \"\"\"\n        for n in self.numerator:\n            if n.isinstance(generic):\n                return n\n        return default\n\n    def get_denominator(\n        self,\n        generic: Union[MeasurementUnitType, GenericDimension],\n        default: Optional[Default] = None,\n    ) -> Union[Dimension, Optional[Default]]:\n        \"\"\"\n        Get a dimension from the denominator. If the dimension is not found it returns\n        the default.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit):\n            ...     METER = \"m\"\n\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     KELVIN = \"K\"\n\n            >>> composite = TemperatureUnit.KELVIN / (LengthUnit.METER**3)\n            >>> composite.get_denominator(LengthUnit**3)\n            <Dimension: m^3>\n            >>> composite.get_denominator(LengthUnit, \"default\")\n            'default'\n        \"\"\"\n        for d in self.denominator:\n            if d.isinstance(generic):\n                return d\n        return default\n\n    def simplify(self) -> None:\n        \"\"\"\n        Simplify the composite by merging common dimensions.\n\n        Examples:\n            >>> class PressureUnit(AliasMeasurementUnit):\n            ...     BAR = \"bar\"\n            ...     PASCAL = \"Pa\"\n\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     KELVIN = \"K\"\n\n            >>> class LengthUnit(MeasurementUnit):\n            ...     METER = \"m\"\n\n            >>> class TimeUnit(MeasurementUnit):\n            ...     SECOND = \"s\"\n\n            >>> composite = (PressureUnit.BAR**(-2)) / (TemperatureUnit.KELVIN**(-1))\n            >>> composite\n            <CompositeDimension: (bar^-2) / (K^-1)>\n            >>> composite.simplify()\n            >>> composite\n            <CompositeDimension: K / (bar^2)>\n\n            >>> composite = PressureUnit.PASCAL * LengthUnit.METER * PressureUnit.PASCAL /TimeUnit.SECOND\n            >>> composite\n            <CompositeDimension: Pa * Pa * m / s>\n            >>> composite.simplify()\n            >>> composite\n            <CompositeDimension: (Pa^2) * m / s>\n        \"\"\"\n        exponents: Dict[MeasurementUnit, float] = {}\n        for n in self.numerator:\n            if n.unit in exponents:\n                exponents[n.unit] += n.power\n            else:\n                exponents[n.unit] = n.power\n\n        for d in self.denominator:\n            if d.unit in exponents:\n                exponents[d.unit] -= d.power\n            else:\n                exponents[d.unit] = 0 - d.power\n\n        numerator = []\n        denominator = []\n        for unit, exponent in exponents.items():\n            if unit.is_non_dimensional():\n                continue  # do not add non dimensional units to the simplified composite\n\n            if exponent > 0:\n                numerator.append(Dimension(unit) ** exponent)\n            elif exponent < 0:\n                denominator.append(Dimension(unit) ** abs(exponent))\n\n        self.numerator = numerator\n        self.denominator = denominator\n\n    def simplified(self) -> \"CompositeDimension\":\n        \"\"\"\n        Returns a simplified version of this composite dimension as a new object.\n\n        Examples:\n            >>> class PressureUnit(AliasMeasurementUnit):\n            ...     BAR = \"bar\"\n            ...     PASCAL = \"Pa\"\n\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     KELVIN = \"K\"\n\n            >>> class LengthUnit(MeasurementUnit):\n            ...     METER = \"m\"\n\n            >>> class TimeUnit(MeasurementUnit):\n            ...     SECOND = \"s\"\n\n            >>> composite = (PressureUnit.BAR**(-2)) / (TemperatureUnit.KELVIN**(-1))\n            >>> composite\n            <CompositeDimension: (bar^-2) / (K^-1)>\n            >>> composite.simplified()\n            <CompositeDimension: K / (bar^2)>\n\n            >>> composite = PressureUnit.PASCAL * LengthUnit.METER * PressureUnit.PASCAL /TimeUnit.SECOND\n            >>> composite\n            <CompositeDimension: Pa * Pa * m / s>\n            >>> composite.simplified()\n            <CompositeDimension: (Pa^2) * m / s>\n        \"\"\"\n        copy = replace(self)\n        copy.simplify()\n        return copy\n\n    def inverse(self) -> \"CompositeDimension\":\n        \"\"\"\n        Create a composite with inverse units.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit):\n            ...     METER = \"m\"\n            >>> class TimeUnit(MeasurementUnit):\n            ...     SECOND = \"s\"\n\n            >>> (LengthUnit.METER / TimeUnit.SECOND).inverse()\n            <CompositeDimension: s / m>\n        \"\"\"\n        return CompositeDimension(self._denominator_copy(), self._numerator_copy())\n\n    def has_no_units(self) -> bool:\n        \"\"\"\n        Returns True if the composite dimension does not have any units, False otherwise.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit):\n            ...     METER = \"m\"\n\n            >>> CompositeDimension().has_no_units()\n            True\n            >>> CompositeDimension([LengthUnit.METER]).has_no_units()\n            False\n        \"\"\"\n        return len(self.denominator) == 0 and len(self.numerator) == 0\n\n    def _numerator_copy(self) -> List[Dimension]:\n        return [replace(n) for n in self.numerator]\n\n    def _denominator_copy(self) -> List[Dimension]:\n        return [replace(d) for d in self.denominator]\n\n    def __mul__(self, descriptor: \"UnitDescriptor\") -> \"CompositeDimension\":\n        \"\"\"\n        Defines multiplication between CompositeDimension(s) and other unit descriptors.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     CELCIUS = \"C\"\n            >>> class TimeUnit(MeasurementUnit):\n            ...     SECOND = \"s\"\n            >>> class LengthUnit(MeasurementUnit):\n            ...     CENTI_METER = \"cm\"\n            >>> (TemperatureUnit.CELCIUS / LengthUnit.CENTI_METER) * TimeUnit.SECOND\n            <CompositeDimension: C * s / cm>\n        \"\"\"\n        numerator = self.numerator.copy()\n        denominator = self.denominator.copy()\n        if isinstance(descriptor, CompositeDimension):\n            numerator.extend(descriptor.numerator)\n            denominator.extend(descriptor.denominator)\n            return CompositeDimension(numerator=numerator, denominator=denominator)\n        if isinstance(descriptor, Dimension):\n            numerator.append(descriptor)\n            return CompositeDimension(numerator=numerator, denominator=denominator)\n        if isinstance(descriptor, MeasurementUnit):\n            numerator.append(Dimension(descriptor))\n            return CompositeDimension(numerator=numerator, denominator=denominator)\n        raise DescriptorBinaryOperationError(\n            f\"cannot multiply {self} with {descriptor}. \"\n        )\n\n    def __truediv__(self, descriptor: \"UnitDescriptor\") -> \"CompositeDimension\":\n        \"\"\"\n        Defines multiplication between CompositeDimension(s) and other unit descriptors.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     CELCIUS = \"C\"\n            >>> class TimeUnit(MeasurementUnit):\n            ...     SECOND = \"s\"\n            >>> class LengthUnit(MeasurementUnit):\n            ...     CENTI_METER = \"cm\"\n            >>> (TemperatureUnit.CELCIUS * LengthUnit.CENTI_METER) / TimeUnit.SECOND\n            <CompositeDimension: C * cm / s>\n        \"\"\"\n        numerator = self.numerator.copy()\n        denominator = self.denominator.copy()\n        if isinstance(descriptor, CompositeDimension):\n            numerator.extend(descriptor.denominator)\n            denominator.extend(descriptor.numerator)\n            return CompositeDimension(numerator=numerator, denominator=denominator)\n        if isinstance(descriptor, Dimension):\n            denominator.append(descriptor)\n            return CompositeDimension(numerator=numerator, denominator=denominator)\n        if isinstance(descriptor, MeasurementUnit):\n            denominator.append(Dimension(descriptor))\n            return CompositeDimension(numerator=numerator, denominator=denominator)\n        raise DescriptorBinaryOperationError(\n            f\"cannot divide {self} with {descriptor}. \"\n        )\n\n    def __pow__(self, power: float) -> \"CompositeDimension\":\n        \"\"\"\n        Defines exponentiation for CompositeDimension(s).\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     CELCIUS = \"C\"\n            >>> class TimeUnit(MeasurementUnit):\n            ...     HOUR = \"hr\"\n\n            >>> (TemperatureUnit.CELCIUS / TimeUnit.HOUR)**2\n            <CompositeDimension: (C^2) / (hr^2)>\n        \"\"\"\n        if not isinstance(power, (float, int)):\n            raise DescriptorExponentError(\n                f\"invalid exponent: {{ value: {power}, type: {type(power)} }};\"\n                \" expected float or int. \"\n            )\n        numerator = [n**power for n in self._numerator_copy()]\n        denominator = [d**power for d in self._denominator_copy()]\n        return CompositeDimension(numerator, denominator)\n\n    def __eq__(self, dimension) -> bool:\n        \"\"\"\n        Defines equality for CompositeDimension(s).\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     CELCIUS = \"C\"\n            >>> class TimeUnit(MeasurementUnit):\n            ...     HOUR = \"hr\"\n            >>> (TemperatureUnit.CELCIUS / TimeUnit.HOUR) != (TimeUnit.HOUR / TemperatureUnit.CELCIUS)\n            True\n        \"\"\"\n        if not isinstance(dimension, CompositeDimension):\n            return False\n        return Counter(self.numerator) == Counter(dimension.numerator) and (\n            Counter(self.denominator) == Counter(dimension.denominator)\n        )\n\n    def __hash__(self) -> int:\n        return hash(str(self))\n\n    def __str__(self):\n        numerators = \" * \".join(sorted([str(n) for n in self.numerator]))\n        denominators = \" / \".join(sorted([str(d) for d in self.denominator]))\n        if len(denominators) > 0:\n            denominators = \" / \" + denominators\n        return numerators + denominators\n\n    def __repr__(self) -> str:\n        numerators = \" * \".join(sorted([str(n) for n in self.numerator]))\n        denominators = \" / \".join(sorted([str(d) for d in self.denominator]))\n        if len(denominators) > 0:\n            denominators = \" / \" + denominators\n        return f\"<CompositeDimension: {numerators + denominators}>\"\n
    "},{"location":"descriptors/#property_utils.units.descriptors.CompositeDimension.__eq__","title":"__eq__(dimension)","text":"

    Defines equality for CompositeDimension(s).

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     CELCIUS = \"C\"\n>>> class TimeUnit(MeasurementUnit):\n...     HOUR = \"hr\"\n>>> (TemperatureUnit.CELCIUS / TimeUnit.HOUR) != (TimeUnit.HOUR / TemperatureUnit.CELCIUS)\nTrue\n
    Source code in src/property_utils/units/descriptors.py
    def __eq__(self, dimension) -> bool:\n    \"\"\"\n    Defines equality for CompositeDimension(s).\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     CELCIUS = \"C\"\n        >>> class TimeUnit(MeasurementUnit):\n        ...     HOUR = \"hr\"\n        >>> (TemperatureUnit.CELCIUS / TimeUnit.HOUR) != (TimeUnit.HOUR / TemperatureUnit.CELCIUS)\n        True\n    \"\"\"\n    if not isinstance(dimension, CompositeDimension):\n        return False\n    return Counter(self.numerator) == Counter(dimension.numerator) and (\n        Counter(self.denominator) == Counter(dimension.denominator)\n    )\n
    "},{"location":"descriptors/#property_utils.units.descriptors.CompositeDimension.__mul__","title":"__mul__(descriptor)","text":"

    Defines multiplication between CompositeDimension(s) and other unit descriptors.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     CELCIUS = \"C\"\n>>> class TimeUnit(MeasurementUnit):\n...     SECOND = \"s\"\n>>> class LengthUnit(MeasurementUnit):\n...     CENTI_METER = \"cm\"\n>>> (TemperatureUnit.CELCIUS / LengthUnit.CENTI_METER) * TimeUnit.SECOND\n<CompositeDimension: C * s / cm>\n
    Source code in src/property_utils/units/descriptors.py
    def __mul__(self, descriptor: \"UnitDescriptor\") -> \"CompositeDimension\":\n    \"\"\"\n    Defines multiplication between CompositeDimension(s) and other unit descriptors.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     CELCIUS = \"C\"\n        >>> class TimeUnit(MeasurementUnit):\n        ...     SECOND = \"s\"\n        >>> class LengthUnit(MeasurementUnit):\n        ...     CENTI_METER = \"cm\"\n        >>> (TemperatureUnit.CELCIUS / LengthUnit.CENTI_METER) * TimeUnit.SECOND\n        <CompositeDimension: C * s / cm>\n    \"\"\"\n    numerator = self.numerator.copy()\n    denominator = self.denominator.copy()\n    if isinstance(descriptor, CompositeDimension):\n        numerator.extend(descriptor.numerator)\n        denominator.extend(descriptor.denominator)\n        return CompositeDimension(numerator=numerator, denominator=denominator)\n    if isinstance(descriptor, Dimension):\n        numerator.append(descriptor)\n        return CompositeDimension(numerator=numerator, denominator=denominator)\n    if isinstance(descriptor, MeasurementUnit):\n        numerator.append(Dimension(descriptor))\n        return CompositeDimension(numerator=numerator, denominator=denominator)\n    raise DescriptorBinaryOperationError(\n        f\"cannot multiply {self} with {descriptor}. \"\n    )\n
    "},{"location":"descriptors/#property_utils.units.descriptors.CompositeDimension.__pow__","title":"__pow__(power)","text":"

    Defines exponentiation for CompositeDimension(s).

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     CELCIUS = \"C\"\n>>> class TimeUnit(MeasurementUnit):\n...     HOUR = \"hr\"\n
    >>> (TemperatureUnit.CELCIUS / TimeUnit.HOUR)**2\n<CompositeDimension: (C^2) / (hr^2)>\n
    Source code in src/property_utils/units/descriptors.py
    def __pow__(self, power: float) -> \"CompositeDimension\":\n    \"\"\"\n    Defines exponentiation for CompositeDimension(s).\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     CELCIUS = \"C\"\n        >>> class TimeUnit(MeasurementUnit):\n        ...     HOUR = \"hr\"\n\n        >>> (TemperatureUnit.CELCIUS / TimeUnit.HOUR)**2\n        <CompositeDimension: (C^2) / (hr^2)>\n    \"\"\"\n    if not isinstance(power, (float, int)):\n        raise DescriptorExponentError(\n            f\"invalid exponent: {{ value: {power}, type: {type(power)} }};\"\n            \" expected float or int. \"\n        )\n    numerator = [n**power for n in self._numerator_copy()]\n    denominator = [d**power for d in self._denominator_copy()]\n    return CompositeDimension(numerator, denominator)\n
    "},{"location":"descriptors/#property_utils.units.descriptors.CompositeDimension.__truediv__","title":"__truediv__(descriptor)","text":"

    Defines multiplication between CompositeDimension(s) and other unit descriptors.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     CELCIUS = \"C\"\n>>> class TimeUnit(MeasurementUnit):\n...     SECOND = \"s\"\n>>> class LengthUnit(MeasurementUnit):\n...     CENTI_METER = \"cm\"\n>>> (TemperatureUnit.CELCIUS * LengthUnit.CENTI_METER) / TimeUnit.SECOND\n<CompositeDimension: C * cm / s>\n
    Source code in src/property_utils/units/descriptors.py
    def __truediv__(self, descriptor: \"UnitDescriptor\") -> \"CompositeDimension\":\n    \"\"\"\n    Defines multiplication between CompositeDimension(s) and other unit descriptors.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     CELCIUS = \"C\"\n        >>> class TimeUnit(MeasurementUnit):\n        ...     SECOND = \"s\"\n        >>> class LengthUnit(MeasurementUnit):\n        ...     CENTI_METER = \"cm\"\n        >>> (TemperatureUnit.CELCIUS * LengthUnit.CENTI_METER) / TimeUnit.SECOND\n        <CompositeDimension: C * cm / s>\n    \"\"\"\n    numerator = self.numerator.copy()\n    denominator = self.denominator.copy()\n    if isinstance(descriptor, CompositeDimension):\n        numerator.extend(descriptor.denominator)\n        denominator.extend(descriptor.numerator)\n        return CompositeDimension(numerator=numerator, denominator=denominator)\n    if isinstance(descriptor, Dimension):\n        denominator.append(descriptor)\n        return CompositeDimension(numerator=numerator, denominator=denominator)\n    if isinstance(descriptor, MeasurementUnit):\n        denominator.append(Dimension(descriptor))\n        return CompositeDimension(numerator=numerator, denominator=denominator)\n    raise DescriptorBinaryOperationError(\n        f\"cannot divide {self} with {descriptor}. \"\n    )\n
    "},{"location":"descriptors/#property_utils.units.descriptors.CompositeDimension.from_descriptor","title":"from_descriptor(descriptor) staticmethod","text":"

    Create a CompositeDimension from given descriptor. If descriptor is already a CompositeDimension, it returns the same object.

    This function does not serve as a constructor for CompositeDimension, rather it is intended to be used to convert an unknown unit descriptor to a CompositeDimension.

    Raises UnitDescriptorTypeError if given descriptor cannot be translated to a CompositeDimension instance.

    Source code in src/property_utils/units/descriptors.py
    @staticmethod\ndef from_descriptor(descriptor: UnitDescriptor) -> \"CompositeDimension\":\n    \"\"\"\n    Create a CompositeDimension from given descriptor.\n    If descriptor is already a CompositeDimension, it returns the same object.\n\n    This function does not serve as a constructor for CompositeDimension, rather it\n    is intended to be used to convert an unknown unit descriptor to a\n    CompositeDimension.\n\n    Raises `UnitDescriptorTypeError` if given descriptor cannot be translated\n    to a CompositeDimension instance.\n    \"\"\"\n    if not isinstance(descriptor, CompositeDimension):\n        raise UnitDescriptorTypeError(\n            f\"cannot create CompositeDimension from descriptor {descriptor}\"\n        )\n    return descriptor\n
    "},{"location":"descriptors/#property_utils.units.descriptors.CompositeDimension.get_denominator","title":"get_denominator(generic, default=None)","text":"

    Get a dimension from the denominator. If the dimension is not found it returns the default.

    Examples:

    >>> class LengthUnit(MeasurementUnit):\n...     METER = \"m\"\n
    >>> class TemperatureUnit(MeasurementUnit):\n...     KELVIN = \"K\"\n
    >>> composite = TemperatureUnit.KELVIN / (LengthUnit.METER**3)\n>>> composite.get_denominator(LengthUnit**3)\n<Dimension: m^3>\n>>> composite.get_denominator(LengthUnit, \"default\")\n'default'\n
    Source code in src/property_utils/units/descriptors.py
    def get_denominator(\n    self,\n    generic: Union[MeasurementUnitType, GenericDimension],\n    default: Optional[Default] = None,\n) -> Union[Dimension, Optional[Default]]:\n    \"\"\"\n    Get a dimension from the denominator. If the dimension is not found it returns\n    the default.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit):\n        ...     METER = \"m\"\n\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     KELVIN = \"K\"\n\n        >>> composite = TemperatureUnit.KELVIN / (LengthUnit.METER**3)\n        >>> composite.get_denominator(LengthUnit**3)\n        <Dimension: m^3>\n        >>> composite.get_denominator(LengthUnit, \"default\")\n        'default'\n    \"\"\"\n    for d in self.denominator:\n        if d.isinstance(generic):\n            return d\n    return default\n
    "},{"location":"descriptors/#property_utils.units.descriptors.CompositeDimension.get_numerator","title":"get_numerator(generic, default=None)","text":"

    Get a dimension from the numerator. If the dimension is not found it returns the default.

    Examples:

    >>> class LengthUnit(MeasurementUnit):\n...     METER = \"m\"\n
    >>> class TemperatureUnit(MeasurementUnit):\n...     KELVIN = \"K\"\n
    >>> composite = TemperatureUnit.KELVIN / (LengthUnit.METER**3)\n>>> composite.get_numerator(TemperatureUnit)\n<Dimension: K>\n>>> composite.get_numerator(LengthUnit, \"default\")\n'default'\n
    Source code in src/property_utils/units/descriptors.py
    def get_numerator(\n    self,\n    generic: Union[MeasurementUnitType, GenericDimension],\n    default: Optional[Default] = None,\n) -> Union[Dimension, Optional[Default]]:\n    \"\"\"\n    Get a dimension from the numerator. If the dimension is not found it returns\n    the default.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit):\n        ...     METER = \"m\"\n\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     KELVIN = \"K\"\n\n        >>> composite = TemperatureUnit.KELVIN / (LengthUnit.METER**3)\n        >>> composite.get_numerator(TemperatureUnit)\n        <Dimension: K>\n        >>> composite.get_numerator(LengthUnit, \"default\")\n        'default'\n    \"\"\"\n    for n in self.numerator:\n        if n.isinstance(generic):\n            return n\n    return default\n
    "},{"location":"descriptors/#property_utils.units.descriptors.CompositeDimension.has_no_units","title":"has_no_units()","text":"

    Returns True if the composite dimension does not have any units, False otherwise.

    Examples:

    >>> class LengthUnit(MeasurementUnit):\n...     METER = \"m\"\n
    >>> CompositeDimension().has_no_units()\nTrue\n>>> CompositeDimension([LengthUnit.METER]).has_no_units()\nFalse\n
    Source code in src/property_utils/units/descriptors.py
    def has_no_units(self) -> bool:\n    \"\"\"\n    Returns True if the composite dimension does not have any units, False otherwise.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit):\n        ...     METER = \"m\"\n\n        >>> CompositeDimension().has_no_units()\n        True\n        >>> CompositeDimension([LengthUnit.METER]).has_no_units()\n        False\n    \"\"\"\n    return len(self.denominator) == 0 and len(self.numerator) == 0\n
    "},{"location":"descriptors/#property_utils.units.descriptors.CompositeDimension.inverse","title":"inverse()","text":"

    Create a composite with inverse units.

    Examples:

    >>> class LengthUnit(MeasurementUnit):\n...     METER = \"m\"\n>>> class TimeUnit(MeasurementUnit):\n...     SECOND = \"s\"\n
    >>> (LengthUnit.METER / TimeUnit.SECOND).inverse()\n<CompositeDimension: s / m>\n
    Source code in src/property_utils/units/descriptors.py
    def inverse(self) -> \"CompositeDimension\":\n    \"\"\"\n    Create a composite with inverse units.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit):\n        ...     METER = \"m\"\n        >>> class TimeUnit(MeasurementUnit):\n        ...     SECOND = \"s\"\n\n        >>> (LengthUnit.METER / TimeUnit.SECOND).inverse()\n        <CompositeDimension: s / m>\n    \"\"\"\n    return CompositeDimension(self._denominator_copy(), self._numerator_copy())\n
    "},{"location":"descriptors/#property_utils.units.descriptors.CompositeDimension.isinstance","title":"isinstance(generic)","text":"

    Returns True if the CompositeDimension is an instance of the generic, False otherwise.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     CELCIUS = \"C\"\n
    >>> class LengthUnit(MeasurementUnit):\n...     METER = \"m\"\n
    >>> (TemperatureUnit.CELCIUS / LengthUnit.METER).isinstance(TemperatureUnit / LengthUnit)\nTrue\n
    >>> (TemperatureUnit.CELCIUS * LengthUnit.METER).isinstance(TemperatureUnit**2)\nFalse\n
    Source code in src/property_utils/units/descriptors.py
    def isinstance(self, generic: GenericUnitDescriptor) -> bool:\n    \"\"\"\n    Returns True if the CompositeDimension is an instance of the generic, False\n    otherwise.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     CELCIUS = \"C\"\n\n        >>> class LengthUnit(MeasurementUnit):\n        ...     METER = \"m\"\n\n        >>> (TemperatureUnit.CELCIUS / LengthUnit.METER).isinstance(TemperatureUnit / LengthUnit)\n        True\n\n        >>> (TemperatureUnit.CELCIUS * LengthUnit.METER).isinstance(TemperatureUnit**2)\n        False\n    \"\"\"\n    if not isinstance(generic, GenericCompositeDimension):\n        return False\n\n    return self.to_generic() == generic\n
    "},{"location":"descriptors/#property_utils.units.descriptors.CompositeDimension.isinstance_equivalent","title":"isinstance_equivalent(generic)","text":"

    Returns True if the UnitDescriptor is an instance-equivalent of the generic, False otherwise.

    A unit descriptor is an instance-equivalent of a generic if the generic of the unit descriptor is equivalent to the generic.

    Equivalence between generics is checked with the is_equivalent method.

    Examples:

    >>> class MassUnit(MeasurementUnit):\n...     KILO_GRAM = \"kg\"\n>>> class LengthUnit(MeasurementUnit):\n...     METER = \"m\"\n>>> class TimeUnit(MeasurementUnit):\n...     SECOND = \"s\"\n
    >>> class ForceUnit(AliasMeasurementUnit):\n...     NEWTON = \"N\"\n...     @classmethod\n...     def aliased_generic_descriptor(cls):\n...         return MassUnit * LengthUnit / (TimeUnit**2)\n
    >>> (MassUnit.KILO_GRAM * LengthUnit.METER / (TimeUnit.SECOND**2)).isinstance_equivalent(ForceUnit)\nTrue\n
    Source code in src/property_utils/units/descriptors.py
    def isinstance_equivalent(self, generic: GenericUnitDescriptor) -> bool:\n    \"\"\"\n    Returns True if the UnitDescriptor is an instance-equivalent of the generic,\n    False otherwise.\n\n    A unit descriptor is an instance-equivalent of a generic if the generic of the\n    unit descriptor is equivalent to the generic.\n\n    Equivalence between generics is checked with the `is_equivalent` method.\n\n    Examples:\n        >>> class MassUnit(MeasurementUnit):\n        ...     KILO_GRAM = \"kg\"\n        >>> class LengthUnit(MeasurementUnit):\n        ...     METER = \"m\"\n        >>> class TimeUnit(MeasurementUnit):\n        ...     SECOND = \"s\"\n\n        >>> class ForceUnit(AliasMeasurementUnit):\n        ...     NEWTON = \"N\"\n        ...     @classmethod\n        ...     def aliased_generic_descriptor(cls):\n        ...         return MassUnit * LengthUnit / (TimeUnit**2)\n\n        >>> (MassUnit.KILO_GRAM * LengthUnit.METER / (TimeUnit.SECOND**2)).isinstance_equivalent(ForceUnit)\n        True\n    \"\"\"\n    return self.to_generic().is_equivalent(generic)\n
    "},{"location":"descriptors/#property_utils.units.descriptors.CompositeDimension.si","title":"si()","text":"

    Returns this composite dimension in SI units.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     KELVIN = \"K\"\n...     RANKINE = \"R\"\n...     @classmethod\n...     def si(cls): return cls.KELVIN\n
    >>> class LengthUnit(MeasurementUnit):\n...     METER = \"m\"\n...     FOOT = \"ft\"\n...     @classmethod\n...     def si(cls): return cls.METER\n
    >>> (TemperatureUnit.RANKINE / LengthUnit.FOOT**2).si()\n<CompositeDimension: K / (m^2)>\n
    Source code in src/property_utils/units/descriptors.py
    def si(self) -> \"CompositeDimension\":\n    \"\"\"\n    Returns this composite dimension in SI units.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     KELVIN = \"K\"\n        ...     RANKINE = \"R\"\n        ...     @classmethod\n        ...     def si(cls): return cls.KELVIN\n\n        >>> class LengthUnit(MeasurementUnit):\n        ...     METER = \"m\"\n        ...     FOOT = \"ft\"\n        ...     @classmethod\n        ...     def si(cls): return cls.METER\n\n        >>> (TemperatureUnit.RANKINE / LengthUnit.FOOT**2).si()\n        <CompositeDimension: K / (m^2)>\n    \"\"\"\n    return CompositeDimension(\n        [n.si() for n in self.numerator], [d.si() for d in self.denominator]\n    )\n
    "},{"location":"descriptors/#property_utils.units.descriptors.CompositeDimension.simplified","title":"simplified()","text":"

    Returns a simplified version of this composite dimension as a new object.

    Examples:

    >>> class PressureUnit(AliasMeasurementUnit):\n...     BAR = \"bar\"\n...     PASCAL = \"Pa\"\n
    >>> class TemperatureUnit(MeasurementUnit):\n...     KELVIN = \"K\"\n
    >>> class LengthUnit(MeasurementUnit):\n...     METER = \"m\"\n
    >>> class TimeUnit(MeasurementUnit):\n...     SECOND = \"s\"\n
    >>> composite = (PressureUnit.BAR**(-2)) / (TemperatureUnit.KELVIN**(-1))\n>>> composite\n<CompositeDimension: (bar^-2) / (K^-1)>\n>>> composite.simplified()\n<CompositeDimension: K / (bar^2)>\n
    >>> composite = PressureUnit.PASCAL * LengthUnit.METER * PressureUnit.PASCAL /TimeUnit.SECOND\n>>> composite\n<CompositeDimension: Pa * Pa * m / s>\n>>> composite.simplified()\n<CompositeDimension: (Pa^2) * m / s>\n
    Source code in src/property_utils/units/descriptors.py
    def simplified(self) -> \"CompositeDimension\":\n    \"\"\"\n    Returns a simplified version of this composite dimension as a new object.\n\n    Examples:\n        >>> class PressureUnit(AliasMeasurementUnit):\n        ...     BAR = \"bar\"\n        ...     PASCAL = \"Pa\"\n\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     KELVIN = \"K\"\n\n        >>> class LengthUnit(MeasurementUnit):\n        ...     METER = \"m\"\n\n        >>> class TimeUnit(MeasurementUnit):\n        ...     SECOND = \"s\"\n\n        >>> composite = (PressureUnit.BAR**(-2)) / (TemperatureUnit.KELVIN**(-1))\n        >>> composite\n        <CompositeDimension: (bar^-2) / (K^-1)>\n        >>> composite.simplified()\n        <CompositeDimension: K / (bar^2)>\n\n        >>> composite = PressureUnit.PASCAL * LengthUnit.METER * PressureUnit.PASCAL /TimeUnit.SECOND\n        >>> composite\n        <CompositeDimension: Pa * Pa * m / s>\n        >>> composite.simplified()\n        <CompositeDimension: (Pa^2) * m / s>\n    \"\"\"\n    copy = replace(self)\n    copy.simplify()\n    return copy\n
    "},{"location":"descriptors/#property_utils.units.descriptors.CompositeDimension.simplify","title":"simplify()","text":"

    Simplify the composite by merging common dimensions.

    Examples:

    >>> class PressureUnit(AliasMeasurementUnit):\n...     BAR = \"bar\"\n...     PASCAL = \"Pa\"\n
    >>> class TemperatureUnit(MeasurementUnit):\n...     KELVIN = \"K\"\n
    >>> class LengthUnit(MeasurementUnit):\n...     METER = \"m\"\n
    >>> class TimeUnit(MeasurementUnit):\n...     SECOND = \"s\"\n
    >>> composite = (PressureUnit.BAR**(-2)) / (TemperatureUnit.KELVIN**(-1))\n>>> composite\n<CompositeDimension: (bar^-2) / (K^-1)>\n>>> composite.simplify()\n>>> composite\n<CompositeDimension: K / (bar^2)>\n
    >>> composite = PressureUnit.PASCAL * LengthUnit.METER * PressureUnit.PASCAL /TimeUnit.SECOND\n>>> composite\n<CompositeDimension: Pa * Pa * m / s>\n>>> composite.simplify()\n>>> composite\n<CompositeDimension: (Pa^2) * m / s>\n
    Source code in src/property_utils/units/descriptors.py
    def simplify(self) -> None:\n    \"\"\"\n    Simplify the composite by merging common dimensions.\n\n    Examples:\n        >>> class PressureUnit(AliasMeasurementUnit):\n        ...     BAR = \"bar\"\n        ...     PASCAL = \"Pa\"\n\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     KELVIN = \"K\"\n\n        >>> class LengthUnit(MeasurementUnit):\n        ...     METER = \"m\"\n\n        >>> class TimeUnit(MeasurementUnit):\n        ...     SECOND = \"s\"\n\n        >>> composite = (PressureUnit.BAR**(-2)) / (TemperatureUnit.KELVIN**(-1))\n        >>> composite\n        <CompositeDimension: (bar^-2) / (K^-1)>\n        >>> composite.simplify()\n        >>> composite\n        <CompositeDimension: K / (bar^2)>\n\n        >>> composite = PressureUnit.PASCAL * LengthUnit.METER * PressureUnit.PASCAL /TimeUnit.SECOND\n        >>> composite\n        <CompositeDimension: Pa * Pa * m / s>\n        >>> composite.simplify()\n        >>> composite\n        <CompositeDimension: (Pa^2) * m / s>\n    \"\"\"\n    exponents: Dict[MeasurementUnit, float] = {}\n    for n in self.numerator:\n        if n.unit in exponents:\n            exponents[n.unit] += n.power\n        else:\n            exponents[n.unit] = n.power\n\n    for d in self.denominator:\n        if d.unit in exponents:\n            exponents[d.unit] -= d.power\n        else:\n            exponents[d.unit] = 0 - d.power\n\n    numerator = []\n    denominator = []\n    for unit, exponent in exponents.items():\n        if unit.is_non_dimensional():\n            continue  # do not add non dimensional units to the simplified composite\n\n        if exponent > 0:\n            numerator.append(Dimension(unit) ** exponent)\n        elif exponent < 0:\n            denominator.append(Dimension(unit) ** abs(exponent))\n\n    self.numerator = numerator\n    self.denominator = denominator\n
    "},{"location":"descriptors/#property_utils.units.descriptors.CompositeDimension.to_generic","title":"to_generic()","text":"

    Create a generic descriptor from this CompositeDimension.

    Examples:

    >>> class AmountUnit(MeasurementUnit):\n...     MOL = \"mol\"\n
    >>> class MassUnit(MeasurementUnit):\n...     KILO_GRAM = \"kg\"\n
    >>> (AmountUnit.MOL / MassUnit.KILO_GRAM).to_generic()\n<GenericCompositeDimension: AmountUnit / MassUnit>\n
    Source code in src/property_utils/units/descriptors.py
    def to_generic(self) -> GenericCompositeDimension:\n    \"\"\"\n    Create a generic descriptor from this CompositeDimension.\n\n    Examples:\n        >>> class AmountUnit(MeasurementUnit):\n        ...     MOL = \"mol\"\n\n        >>> class MassUnit(MeasurementUnit):\n        ...     KILO_GRAM = \"kg\"\n\n        >>> (AmountUnit.MOL / MassUnit.KILO_GRAM).to_generic()\n        <GenericCompositeDimension: AmountUnit / MassUnit>\n    \"\"\"\n    return GenericCompositeDimension(\n        numerator=[n.to_generic() for n in self.numerator],\n        denominator=[d.to_generic() for d in self.denominator],\n    )\n
    "},{"location":"descriptors/#property_utils.units.descriptors.Dimension","title":"Dimension dataclass","text":"

    A Dimension is a wrapper around MeasurementUnit.

    Objects of this class can represent either a simple MeasurementUnit or a MeasurementUnit to some power.

    Examples:

    >>> class TimeUnit(MeasurementUnit):\n...     SECOND = \"s\"\n
    >>> TimeUnit.SECOND**2\n<Dimension: s^2>\n
    Source code in src/property_utils/units/descriptors.py
    @dataclass\nclass Dimension:\n    \"\"\"\n    A Dimension is a wrapper around MeasurementUnit.\n\n    Objects of this class can represent either a simple MeasurementUnit or a\n    MeasurementUnit to some power.\n\n    Examples:\n        >>> class TimeUnit(MeasurementUnit):\n        ...     SECOND = \"s\"\n\n        >>> TimeUnit.SECOND**2\n        <Dimension: s^2>\n    \"\"\"\n\n    unit: MeasurementUnit\n    power: float = 1\n\n    def __init__(self, unit: MeasurementUnit, power: float = 1) -> None:\n        if not isinstance(power, (float, int)):\n            raise DescriptorExponentError(\n                f\"invalid exponent: {{ value: {power}, type: {type(power)} }};\"\n                \" expected float or int. \"\n            )\n        self.unit = unit\n        self.power = power\n\n    @staticmethod\n    def from_descriptor(descriptor: UnitDescriptor) -> \"Dimension\":\n        \"\"\"\n        Create a Dimension from given descriptor.\n        If descriptor is already a Dimension, it returns the same object.\n\n        This function does not serve as a constructor for Dimension, rather it\n        is intended to be used to convert an unknown unit descriptor to a Dimension.\n\n        Raises `UnitDescriptorTypeError` if given descriptor cannot be translated\n        to a Dimension instance.\n        \"\"\"\n        if isinstance(descriptor, Dimension):\n            return descriptor\n        if isinstance(descriptor, MeasurementUnit):\n            return Dimension(descriptor)\n        raise UnitDescriptorTypeError(\n            f\"cannot create Dimension from descriptor: {descriptor}\"\n        )\n\n    def si(self) -> \"Dimension\":\n        \"\"\"\n        Returns this dimension in SI units.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit):\n            ...     METER = \"m\"\n            ...     FOOT = \"ft\"\n            ...     @classmethod\n            ...     def si(cls): return cls.METER\n\n            >>> (LengthUnit.FOOT**2).si()\n            <Dimension: m^2>\n        \"\"\"\n        return Dimension(self.unit.si(), self.power)\n\n    def isinstance(self, generic: GenericUnitDescriptor) -> bool:\n        \"\"\"\n        Returns True if the Dimension is an instance of the generic, False\n        otherwise.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     CELCIUS = \"C\"\n\n            >>> Dimension(TemperatureUnit.CELCIUS).isinstance(TemperatureUnit)\n            True\n\n            >>> Dimension(TemperatureUnit.CELCIUS).isinstance(TemperatureUnit**2)\n            False\n        \"\"\"\n        if isinstance(generic, MeasurementUnitType):\n            generic = GenericDimension(generic)\n        if not isinstance(generic, GenericDimension):\n            return False\n\n        if isinstance(self.unit, generic.unit_type) and self.power == generic.power:\n            return True\n\n        return False\n\n    def isinstance_equivalent(self, generic: GenericUnitDescriptor) -> bool:\n        \"\"\"\n        Returns True if the UnitDescriptor is an instance-equivalent of the generic,\n        False otherwise.\n\n        A unit descriptor is an instance-equivalent of a generic if the generic of the\n        unit descriptor is equivalent to the generic.\n\n        Equivalence between generics is checked with the `is_equivalent` method.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit):\n            ...     METER = \"m\"\n            >>> class VolumeUnit(AliasMeasurementUnit):\n            ...     @classmethod\n            ...     def aliased_generic_descriptor(cls): return LengthUnit**3\n\n            >>> (LengthUnit.METER**3).isinstance_equivalent(VolumeUnit)\n            True\n        \"\"\"\n        return self.to_generic().is_equivalent(generic)\n\n    def to_generic(self) -> GenericDimension:\n        \"\"\"\n        Create a generic descriptor from this Dimension.\n\n        Examples:\n            >>> class AmountUnit(MeasurementUnit):\n            ...     MOL = \"mol\"\n\n            >>> (AmountUnit.MOL**3.56).to_generic()\n            <GenericDimension: AmountUnit^3.56>\n        \"\"\"\n        return GenericDimension(type(self.unit), self.power)\n\n    def inverse(self) -> \"CompositeDimension\":\n        \"\"\"\n        Create a composite with inverse units.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit):\n            ...     METER = \"m\"\n            >>> (LengthUnit.METER**2).inverse()\n            <CompositeDimension:  / (m^2)>\n        \"\"\"\n        return CompositeDimension([], [replace(self)])\n\n    def _isinstance_aliased(self, generic: GenericUnitDescriptor) -> bool:\n        \"\"\"\n        Returns True if the generic is the aliased unit descriptor of this Dimension,\n        False otherwise.\n\n        Only applicable if this Dimension's unit is of type AliasMeasurementUnit.\n        \"\"\"\n        return (\n            isinstance(self.unit, AliasMeasurementUnit)\n            and (self.unit.aliased_generic_descriptor() ** self.power) == generic\n        )\n\n    def _isinstance_alias(self, generic: GenericUnitDescriptor) -> bool:\n        \"\"\"\n        Returns True if this Dimension's unit is an instance of the aliased unit\n        descriptor of the generic, False otherwise.\n\n        Only applicable if generic is an AliasMeasurementUnit.\n        \"\"\"\n        if isinstance(generic, MeasurementUnitType):\n            generic = GenericDimension(generic)\n\n        if not isinstance(generic, GenericDimension):\n            return False\n\n        if not issubclass(generic.unit_type, AliasMeasurementUnit):\n            return False\n\n        if (\n            generic.unit_type.aliased_generic_descriptor() ** generic.power\n            == self.to_generic()\n        ):\n            return True\n\n        return False\n\n    def __mul__(self, descriptor: \"UnitDescriptor\") -> \"CompositeDimension\":\n        \"\"\"\n        Defines multiplication between Dimension(s) and other unit descriptors.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     CELCIUS = \"C\"\n            >>> class TimeUnit(MeasurementUnit):\n            ...     MINUTE = \"min\"\n            >>> (TemperatureUnit.CELCIUS**3) * TimeUnit.MINUTE\n            <CompositeDimension: (C^3) * min>\n        \"\"\"\n        if isinstance(descriptor, CompositeDimension):\n            numerator = descriptor.numerator.copy()\n            denominator = descriptor.denominator.copy()\n            numerator.append(self)\n            return CompositeDimension(numerator=numerator, denominator=denominator)\n        if isinstance(descriptor, Dimension):\n            return CompositeDimension(numerator=[self, descriptor])\n        if isinstance(descriptor, MeasurementUnit):\n            return CompositeDimension(numerator=[self, Dimension(descriptor)])\n        raise DescriptorBinaryOperationError(\n            f\"cannot multiply {self} with {descriptor}. \"\n        )\n\n    def __truediv__(self, descriptor: \"UnitDescriptor\") -> \"CompositeDimension\":\n        \"\"\"\n        Defines division between Dimension(s) and other unit descriptors.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     CELCIUS = \"C\"\n            >>> class TimeUnit(MeasurementUnit):\n            ...     MINUTE = \"min\"\n            >>> (TemperatureUnit.CELCIUS**3) / TimeUnit.MINUTE\n            <CompositeDimension: (C^3) / min>\n        \"\"\"\n        if isinstance(descriptor, CompositeDimension):\n            numerator = descriptor.denominator.copy()\n            denominator = descriptor.numerator.copy()\n            numerator.append(self)\n            return CompositeDimension(numerator=numerator, denominator=denominator)\n        if isinstance(descriptor, Dimension):\n            return CompositeDimension(numerator=[self], denominator=[descriptor])\n        if isinstance(descriptor, MeasurementUnit):\n            return CompositeDimension(\n                numerator=[self], denominator=[Dimension(descriptor)]\n            )\n        raise DescriptorBinaryOperationError(\n            f\"cannot divide {self} with  {descriptor}. \"\n        )\n\n    def __pow__(self, power: float) -> \"Dimension\":\n        \"\"\"\n        Defines exponentiation for Dimension(s).\n\n        Examples:\n            >>> class TimeUnit(MeasurementUnit):\n            ...     SECOND = \"s\"\n            >>> (TimeUnit.SECOND**2)**3\n            <Dimension: s^6>\n        \"\"\"\n        if not isinstance(power, (float, int)):\n            raise DescriptorExponentError(\n                f\"invalid exponent: {{ value: {power}, type: {type(power)} }};\"\n                \" expected float or int. \"\n            )\n        if self.unit.is_non_dimensional():\n            self.power = 1\n        else:\n            self.power *= power\n        return self\n\n    def __eq__(self, dimension) -> bool:\n        \"\"\"\n        Defines equality for Dimension(s).\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     KELVIN = \"K\"\n            >>> (TemperatureUnit.KELVIN**2) != TemperatureUnit.KELVIN\n            True\n        \"\"\"\n        if not isinstance(dimension, Dimension):\n            return False\n        return self.unit == dimension.unit and self.power == dimension.power\n\n    def __hash__(self) -> int:\n        return hash(str(self))\n\n    def __repr__(self) -> str:\n        if self.power != 1:\n            return f\"<Dimension: {self.unit.value}^{self.power}>\"\n        return f\"<Dimension: {self.unit.value}>\"\n\n    def __str__(self) -> str:\n        s = self.unit.value\n        if self.power != 1:\n            return f\"({s}^{self.power})\"\n        return s\n
    "},{"location":"descriptors/#property_utils.units.descriptors.Dimension.__eq__","title":"__eq__(dimension)","text":"

    Defines equality for Dimension(s).

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     KELVIN = \"K\"\n>>> (TemperatureUnit.KELVIN**2) != TemperatureUnit.KELVIN\nTrue\n
    Source code in src/property_utils/units/descriptors.py
    def __eq__(self, dimension) -> bool:\n    \"\"\"\n    Defines equality for Dimension(s).\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     KELVIN = \"K\"\n        >>> (TemperatureUnit.KELVIN**2) != TemperatureUnit.KELVIN\n        True\n    \"\"\"\n    if not isinstance(dimension, Dimension):\n        return False\n    return self.unit == dimension.unit and self.power == dimension.power\n
    "},{"location":"descriptors/#property_utils.units.descriptors.Dimension.__mul__","title":"__mul__(descriptor)","text":"

    Defines multiplication between Dimension(s) and other unit descriptors.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     CELCIUS = \"C\"\n>>> class TimeUnit(MeasurementUnit):\n...     MINUTE = \"min\"\n>>> (TemperatureUnit.CELCIUS**3) * TimeUnit.MINUTE\n<CompositeDimension: (C^3) * min>\n
    Source code in src/property_utils/units/descriptors.py
    def __mul__(self, descriptor: \"UnitDescriptor\") -> \"CompositeDimension\":\n    \"\"\"\n    Defines multiplication between Dimension(s) and other unit descriptors.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     CELCIUS = \"C\"\n        >>> class TimeUnit(MeasurementUnit):\n        ...     MINUTE = \"min\"\n        >>> (TemperatureUnit.CELCIUS**3) * TimeUnit.MINUTE\n        <CompositeDimension: (C^3) * min>\n    \"\"\"\n    if isinstance(descriptor, CompositeDimension):\n        numerator = descriptor.numerator.copy()\n        denominator = descriptor.denominator.copy()\n        numerator.append(self)\n        return CompositeDimension(numerator=numerator, denominator=denominator)\n    if isinstance(descriptor, Dimension):\n        return CompositeDimension(numerator=[self, descriptor])\n    if isinstance(descriptor, MeasurementUnit):\n        return CompositeDimension(numerator=[self, Dimension(descriptor)])\n    raise DescriptorBinaryOperationError(\n        f\"cannot multiply {self} with {descriptor}. \"\n    )\n
    "},{"location":"descriptors/#property_utils.units.descriptors.Dimension.__pow__","title":"__pow__(power)","text":"

    Defines exponentiation for Dimension(s).

    Examples:

    >>> class TimeUnit(MeasurementUnit):\n...     SECOND = \"s\"\n>>> (TimeUnit.SECOND**2)**3\n<Dimension: s^6>\n
    Source code in src/property_utils/units/descriptors.py
    def __pow__(self, power: float) -> \"Dimension\":\n    \"\"\"\n    Defines exponentiation for Dimension(s).\n\n    Examples:\n        >>> class TimeUnit(MeasurementUnit):\n        ...     SECOND = \"s\"\n        >>> (TimeUnit.SECOND**2)**3\n        <Dimension: s^6>\n    \"\"\"\n    if not isinstance(power, (float, int)):\n        raise DescriptorExponentError(\n            f\"invalid exponent: {{ value: {power}, type: {type(power)} }};\"\n            \" expected float or int. \"\n        )\n    if self.unit.is_non_dimensional():\n        self.power = 1\n    else:\n        self.power *= power\n    return self\n
    "},{"location":"descriptors/#property_utils.units.descriptors.Dimension.__truediv__","title":"__truediv__(descriptor)","text":"

    Defines division between Dimension(s) and other unit descriptors.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     CELCIUS = \"C\"\n>>> class TimeUnit(MeasurementUnit):\n...     MINUTE = \"min\"\n>>> (TemperatureUnit.CELCIUS**3) / TimeUnit.MINUTE\n<CompositeDimension: (C^3) / min>\n
    Source code in src/property_utils/units/descriptors.py
    def __truediv__(self, descriptor: \"UnitDescriptor\") -> \"CompositeDimension\":\n    \"\"\"\n    Defines division between Dimension(s) and other unit descriptors.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     CELCIUS = \"C\"\n        >>> class TimeUnit(MeasurementUnit):\n        ...     MINUTE = \"min\"\n        >>> (TemperatureUnit.CELCIUS**3) / TimeUnit.MINUTE\n        <CompositeDimension: (C^3) / min>\n    \"\"\"\n    if isinstance(descriptor, CompositeDimension):\n        numerator = descriptor.denominator.copy()\n        denominator = descriptor.numerator.copy()\n        numerator.append(self)\n        return CompositeDimension(numerator=numerator, denominator=denominator)\n    if isinstance(descriptor, Dimension):\n        return CompositeDimension(numerator=[self], denominator=[descriptor])\n    if isinstance(descriptor, MeasurementUnit):\n        return CompositeDimension(\n            numerator=[self], denominator=[Dimension(descriptor)]\n        )\n    raise DescriptorBinaryOperationError(\n        f\"cannot divide {self} with  {descriptor}. \"\n    )\n
    "},{"location":"descriptors/#property_utils.units.descriptors.Dimension.from_descriptor","title":"from_descriptor(descriptor) staticmethod","text":"

    Create a Dimension from given descriptor. If descriptor is already a Dimension, it returns the same object.

    This function does not serve as a constructor for Dimension, rather it is intended to be used to convert an unknown unit descriptor to a Dimension.

    Raises UnitDescriptorTypeError if given descriptor cannot be translated to a Dimension instance.

    Source code in src/property_utils/units/descriptors.py
    @staticmethod\ndef from_descriptor(descriptor: UnitDescriptor) -> \"Dimension\":\n    \"\"\"\n    Create a Dimension from given descriptor.\n    If descriptor is already a Dimension, it returns the same object.\n\n    This function does not serve as a constructor for Dimension, rather it\n    is intended to be used to convert an unknown unit descriptor to a Dimension.\n\n    Raises `UnitDescriptorTypeError` if given descriptor cannot be translated\n    to a Dimension instance.\n    \"\"\"\n    if isinstance(descriptor, Dimension):\n        return descriptor\n    if isinstance(descriptor, MeasurementUnit):\n        return Dimension(descriptor)\n    raise UnitDescriptorTypeError(\n        f\"cannot create Dimension from descriptor: {descriptor}\"\n    )\n
    "},{"location":"descriptors/#property_utils.units.descriptors.Dimension.inverse","title":"inverse()","text":"

    Create a composite with inverse units.

    Examples:

    >>> class LengthUnit(MeasurementUnit):\n...     METER = \"m\"\n>>> (LengthUnit.METER**2).inverse()\n<CompositeDimension:  / (m^2)>\n
    Source code in src/property_utils/units/descriptors.py
    def inverse(self) -> \"CompositeDimension\":\n    \"\"\"\n    Create a composite with inverse units.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit):\n        ...     METER = \"m\"\n        >>> (LengthUnit.METER**2).inverse()\n        <CompositeDimension:  / (m^2)>\n    \"\"\"\n    return CompositeDimension([], [replace(self)])\n
    "},{"location":"descriptors/#property_utils.units.descriptors.Dimension.isinstance","title":"isinstance(generic)","text":"

    Returns True if the Dimension is an instance of the generic, False otherwise.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     CELCIUS = \"C\"\n
    >>> Dimension(TemperatureUnit.CELCIUS).isinstance(TemperatureUnit)\nTrue\n
    >>> Dimension(TemperatureUnit.CELCIUS).isinstance(TemperatureUnit**2)\nFalse\n
    Source code in src/property_utils/units/descriptors.py
    def isinstance(self, generic: GenericUnitDescriptor) -> bool:\n    \"\"\"\n    Returns True if the Dimension is an instance of the generic, False\n    otherwise.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     CELCIUS = \"C\"\n\n        >>> Dimension(TemperatureUnit.CELCIUS).isinstance(TemperatureUnit)\n        True\n\n        >>> Dimension(TemperatureUnit.CELCIUS).isinstance(TemperatureUnit**2)\n        False\n    \"\"\"\n    if isinstance(generic, MeasurementUnitType):\n        generic = GenericDimension(generic)\n    if not isinstance(generic, GenericDimension):\n        return False\n\n    if isinstance(self.unit, generic.unit_type) and self.power == generic.power:\n        return True\n\n    return False\n
    "},{"location":"descriptors/#property_utils.units.descriptors.Dimension.isinstance_equivalent","title":"isinstance_equivalent(generic)","text":"

    Returns True if the UnitDescriptor is an instance-equivalent of the generic, False otherwise.

    A unit descriptor is an instance-equivalent of a generic if the generic of the unit descriptor is equivalent to the generic.

    Equivalence between generics is checked with the is_equivalent method.

    Examples:

    >>> class LengthUnit(MeasurementUnit):\n...     METER = \"m\"\n>>> class VolumeUnit(AliasMeasurementUnit):\n...     @classmethod\n...     def aliased_generic_descriptor(cls): return LengthUnit**3\n
    >>> (LengthUnit.METER**3).isinstance_equivalent(VolumeUnit)\nTrue\n
    Source code in src/property_utils/units/descriptors.py
    def isinstance_equivalent(self, generic: GenericUnitDescriptor) -> bool:\n    \"\"\"\n    Returns True if the UnitDescriptor is an instance-equivalent of the generic,\n    False otherwise.\n\n    A unit descriptor is an instance-equivalent of a generic if the generic of the\n    unit descriptor is equivalent to the generic.\n\n    Equivalence between generics is checked with the `is_equivalent` method.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit):\n        ...     METER = \"m\"\n        >>> class VolumeUnit(AliasMeasurementUnit):\n        ...     @classmethod\n        ...     def aliased_generic_descriptor(cls): return LengthUnit**3\n\n        >>> (LengthUnit.METER**3).isinstance_equivalent(VolumeUnit)\n        True\n    \"\"\"\n    return self.to_generic().is_equivalent(generic)\n
    "},{"location":"descriptors/#property_utils.units.descriptors.Dimension.si","title":"si()","text":"

    Returns this dimension in SI units.

    Examples:

    >>> class LengthUnit(MeasurementUnit):\n...     METER = \"m\"\n...     FOOT = \"ft\"\n...     @classmethod\n...     def si(cls): return cls.METER\n
    >>> (LengthUnit.FOOT**2).si()\n<Dimension: m^2>\n
    Source code in src/property_utils/units/descriptors.py
    def si(self) -> \"Dimension\":\n    \"\"\"\n    Returns this dimension in SI units.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit):\n        ...     METER = \"m\"\n        ...     FOOT = \"ft\"\n        ...     @classmethod\n        ...     def si(cls): return cls.METER\n\n        >>> (LengthUnit.FOOT**2).si()\n        <Dimension: m^2>\n    \"\"\"\n    return Dimension(self.unit.si(), self.power)\n
    "},{"location":"descriptors/#property_utils.units.descriptors.Dimension.to_generic","title":"to_generic()","text":"

    Create a generic descriptor from this Dimension.

    Examples:

    >>> class AmountUnit(MeasurementUnit):\n...     MOL = \"mol\"\n
    >>> (AmountUnit.MOL**3.56).to_generic()\n<GenericDimension: AmountUnit^3.56>\n
    Source code in src/property_utils/units/descriptors.py
    def to_generic(self) -> GenericDimension:\n    \"\"\"\n    Create a generic descriptor from this Dimension.\n\n    Examples:\n        >>> class AmountUnit(MeasurementUnit):\n        ...     MOL = \"mol\"\n\n        >>> (AmountUnit.MOL**3.56).to_generic()\n        <GenericDimension: AmountUnit^3.56>\n    \"\"\"\n    return GenericDimension(type(self.unit), self.power)\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericCompositeDimension","title":"GenericCompositeDimension dataclass","text":"

    A GenericCompositeDimension represents a generic measurement unit that is composed from other generic measurement units.

    Objects of this class can represent either multiplication or division between two GenericDimension objects.

    Create objects by multiplying and diving GenericDimension or MeasurementUnitMeta class objects:

    Examples:

    >>> class LengthUnit(MeasurementUnit): ...\n>>> class AmountUnit(MeasurementUnit): ...\n
    >>> generic_molal_volume_dimension = (LengthUnit**3) / AmountUnit\n>>> generic_molal_volume_dimension\n<GenericCompositeDimension: (LengthUnit^3) / AmountUnit>\n
    Source code in src/property_utils/units/descriptors.py
    @dataclass\nclass GenericCompositeDimension:\n    \"\"\"\n    A `GenericCompositeDimension` represents a generic measurement unit that is composed\n    from other generic measurement units.\n\n    Objects of this class can represent either multiplication or division between two\n    `GenericDimension` objects.\n\n    Create objects by multiplying and diving GenericDimension or MeasurementUnitMeta\n    class objects:\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit): ...\n        >>> class AmountUnit(MeasurementUnit): ...\n\n        >>> generic_molal_volume_dimension = (LengthUnit**3) / AmountUnit\n        >>> generic_molal_volume_dimension\n        <GenericCompositeDimension: (LengthUnit^3) / AmountUnit>\n    \"\"\"\n\n    numerator: List[GenericDimension] = field(default_factory=list)\n    denominator: List[GenericDimension] = field(default_factory=list)\n\n    def to_si(self) -> \"CompositeDimension\":\n        \"\"\"\n        Create a CompositeDimension with SI units.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     KELVIN = \"K\"\n            ...     @classmethod\n            ...     def si(cls): return cls.KELVIN\n            >>> class TimeUnit(MeasurementUnit):\n            ...     SECOND = \"s\"\n            ...     @classmethod\n            ...     def si(cls): return cls.SECOND\n            >>> class LengthUnit(MeasurementUnit):\n            ...     METER = \"m\"\n            ...     @classmethod\n            ...     def si(cls): return cls.METER\n            >>> (TemperatureUnit * LengthUnit / TimeUnit).to_si()\n            <CompositeDimension: K * m / s>\n        \"\"\"\n        return CompositeDimension(\n            [n.to_si() for n in self.numerator], [d.to_si() for d in self.denominator]\n        )\n\n    def simplify(self) -> None:\n        \"\"\"\n        Simplify the composite by merging common dimensions.\n\n        Examples:\n            >>> class PressureUnit(AliasMeasurementUnit): ...\n\n            >>> class TemperatureUnit(MeasurementUnit): ...\n\n            >>> class LengthUnit(MeasurementUnit): ...\n\n            >>> class TimeUnit(MeasurementUnit): ...\n\n            >>> composite = (PressureUnit**(-2)) / (TemperatureUnit**(-1))\n            >>> composite\n            <GenericCompositeDimension: (PressureUnit^-2) / (TemperatureUnit^-1)>\n            >>> composite.simplify()\n            >>> composite\n            <GenericCompositeDimension: TemperatureUnit / (PressureUnit^2)>\n\n            >>> composite = PressureUnit * LengthUnit * PressureUnit / TimeUnit\n            >>> composite\n            <GenericCompositeDimension: LengthUnit * PressureUnit * PressureUnit / TimeUnit>\n            >>> composite.simplify()\n            >>> composite\n            <GenericCompositeDimension: (PressureUnit^2) * LengthUnit / TimeUnit>\n        \"\"\"\n        exponents: Dict[MeasurementUnitType, float] = {}\n        for n in self.numerator:\n            if n.unit_type in exponents:\n                exponents[n.unit_type] += n.power\n            else:\n                exponents[n.unit_type] = n.power\n\n        for d in self.denominator:\n            if d.unit_type in exponents:\n                exponents[d.unit_type] -= d.power\n            else:\n                exponents[d.unit_type] = 0 - d.power\n\n        numerator = []\n        denominator = []\n        for unit_type, exponent in exponents.items():\n            if exponent > 0:\n                numerator.append(GenericDimension(unit_type) ** exponent)\n            elif exponent < 0:\n                denominator.append(GenericDimension(unit_type) ** abs(exponent))\n\n        self.numerator = numerator\n        self.denominator = denominator\n\n    def simplified(self) -> \"GenericCompositeDimension\":\n        \"\"\"\n        Returns a simplified version of this composite generic as a new object.\n\n        Examples:\n            >>> class PressureUnit(AliasMeasurementUnit): ...\n\n            >>> class TemperatureUnit(MeasurementUnit): ...\n\n            >>> class LengthUnit(MeasurementUnit): ...\n\n            >>> class TimeUnit(MeasurementUnit): ...\n\n            >>> composite = (PressureUnit**(-2)) / (TemperatureUnit**(-1))\n            >>> composite\n            <GenericCompositeDimension: (PressureUnit^-2) / (TemperatureUnit^-1)>\n            >>> composite.simplified()\n            <GenericCompositeDimension: TemperatureUnit / (PressureUnit^2)>\n\n            >>> composite = PressureUnit * LengthUnit * PressureUnit /TimeUnit\n            >>> composite\n            <GenericCompositeDimension: LengthUnit * PressureUnit * PressureUnit / TimeUnit>\n            >>> composite.simplified()\n            <GenericCompositeDimension: (PressureUnit^2) * LengthUnit / TimeUnit>\n        \"\"\"\n        copy = replace(self)\n        copy.simplify()\n        return copy\n\n    def analyse(self) -> None:\n        \"\"\"\n        Analyse this composite by replacing its alias units with their aliased units.\n\n        Examples:\n            >>> class MassUnit(MeasurementUnit): ...\n            >>> class LengthUnit(MeasurementUnit): ...\n            >>> class TimeUnit(MeasurementUnit): ...\n\n            >>> class PressureUnit(AliasMeasurementUnit):\n            ...     @classmethod\n            ...     def aliased_generic_descriptor(cls) -> GenericCompositeDimension:\n            ...         return MassUnit / LengthUnit / (TimeUnit**2)\n\n            >>> composite = PressureUnit / LengthUnit\n            >>> composite\n            <GenericCompositeDimension: PressureUnit / LengthUnit>\n\n            >>> composite.analyse()\n            >>> composite\n            <GenericCompositeDimension: MassUnit / (TimeUnit^2) / LengthUnit / LengthUnit>\n        \"\"\"\n        for n in self.numerator:\n            if issubclass(n.unit_type, AliasMeasurementUnit):\n                aliased = n.unit_type.aliased_generic_descriptor() ** n.power\n                if isinstance(aliased, GenericDimension):\n                    self.numerator.append(aliased)\n                elif isinstance(aliased, GenericCompositeDimension):\n                    self.numerator.extend(aliased.numerator)\n                    self.denominator.extend(aliased.denominator)\n\n                self.numerator.remove(n)\n\n        for d in self.denominator:\n            if issubclass(d.unit_type, AliasMeasurementUnit):\n                aliased = d.unit_type.aliased_generic_descriptor() ** d.power\n                if isinstance(aliased, GenericDimension):\n                    self.denominator.append(aliased)\n                elif isinstance(aliased, GenericCompositeDimension):\n                    self.denominator.extend(aliased.numerator)\n                    self.numerator.extend(aliased.denominator)\n\n                self.denominator.remove(d)\n\n    def analysed(self) -> \"GenericCompositeDimension\":\n        \"\"\"\n        Returns an analysed version of this composite generic as a new object.\n\n        Examples:\n            >>> class MassUnit(MeasurementUnit): ...\n            >>> class LengthUnit(MeasurementUnit): ...\n            >>> class TimeUnit(MeasurementUnit): ...\n\n            >>> class PressureUnit(AliasMeasurementUnit):\n            ...     @classmethod\n            ...     def aliased_generic_descriptor(cls) -> GenericCompositeDimension:\n            ...         return MassUnit / LengthUnit / (TimeUnit**2)\n\n            >>> composite = PressureUnit / LengthUnit\n            >>> composite\n            <GenericCompositeDimension: PressureUnit / LengthUnit>\n\n            >>> composite.analysed()\n            <GenericCompositeDimension: MassUnit / (TimeUnit^2) / LengthUnit / LengthUnit>\n        \"\"\"\n        copy = replace(self)\n        copy.analyse()\n        return copy\n\n    def inverse_generic(self):\n        \"\"\"\n        Create a generic composite with inverse units.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit): ...\n            >>> class TimeUnit(MeasurementUnit): ...\n\n            >>> (LengthUnit / TimeUnit).inverse_generic()\n            <GenericCompositeDimension: TimeUnit / LengthUnit>\n        \"\"\"\n        return GenericCompositeDimension(\n            self._denominator_copy(), self._numerator_copy()\n        )\n\n    def is_equivalent(self, other: GenericUnitDescriptor) -> bool:\n        \"\"\"\n        Returns True if this generic is equivalent to the given one, False otherwise.\n\n        A generic can be equivalent with another generic if the latter or the former\n        is an alias.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit): ...\n            >>> class MassUnit(MeasurementUnit): ...\n            >>> class TimeUnit(MeasurementUnit): ...\n            >>> class ForceUnit(AliasMeasurementUnit):\n            ...     @classmethod\n            ...     def aliased_generic_descriptor(cls):\n            ...         return MassUnit * LengthUnit / (TimeUnit**2)\n\n            >>> ForceUnit.is_equivalent(MassUnit * LengthUnit / (TimeUnit**2))\n            True\n\n            >>> class EnergyUnit(AliasMeasurementUnit):\n            ...     @classmethod\n            ...     def aliased_generic_descriptor(cls):\n            ...         return ForceUnit * LengthUnit\n\n            >>> EnergyUnit.is_equivalent(MassUnit * (LengthUnit**2) / (TimeUnit**2))\n            True\n        \"\"\"\n        if isinstance(other, MeasurementUnitType):\n            if (\n                self.denominator == []\n                and len(self.numerator) == 1\n                and self.numerator[0].is_equivalent(other)\n            ):\n                return True\n\n            if issubclass(other, AliasMeasurementUnit):\n                return other.aliased_generic_descriptor().is_equivalent(self)  # type: ignore[attr-defined]\n\n        elif isinstance(other, GenericDimension):\n            if (\n                self.denominator == []\n                and len(self.numerator) == 1\n                and self.numerator[0].is_equivalent(other)\n            ):\n                return True\n\n            if issubclass(other.unit_type, AliasMeasurementUnit):\n                return (\n                    other.unit_type.aliased_generic_descriptor() ** other.power\n                ).is_equivalent(self)\n\n        elif isinstance(other, GenericCompositeDimension):\n            _generic = other.analysed().simplified()\n            _self = self.analysed().simplified()\n\n            return Counter(_self.numerator) == Counter(_generic.numerator) and (\n                Counter(_self.denominator) == Counter(_generic.denominator)\n            )\n\n        return False\n\n    def has_no_units(self) -> bool:\n        \"\"\"\n        Returns True if the generic composite dimension does not have any units, False\n        otherwise.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit): ...\n\n            >>> GenericCompositeDimension().has_no_units()\n            True\n            >>> GenericCompositeDimension([LengthUnit]).has_no_units()\n            False\n        \"\"\"\n        return len(self.denominator) == 0 and len(self.numerator) == 0\n\n    def _numerator_copy(self) -> List[GenericDimension]:\n        return [replace(n) for n in self.numerator]\n\n    def _denominator_copy(self) -> List[GenericDimension]:\n        return [replace(d) for d in self.denominator]\n\n    def __mul__(self, generic: GenericUnitDescriptor) -> \"GenericCompositeDimension\":\n        \"\"\"\n        Defines multiplication between GenericCompositeDimension(s) and other generic\n        descriptors.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit): ...\n            >>> class TimeUnit(MeasurementUnit): ...\n            >>> class LengthUnit(MeasurementUnit): ...\n            >>> (TemperatureUnit / LengthUnit) * TimeUnit\n            <GenericCompositeDimension: TemperatureUnit * TimeUnit / LengthUnit>\n        \"\"\"\n        numerator = self.numerator.copy()\n        denominator = self.denominator.copy()\n        if isinstance(generic, GenericCompositeDimension):\n            numerator.extend(generic.numerator)\n            denominator.extend(generic.denominator)\n            return GenericCompositeDimension(\n                numerator=numerator, denominator=denominator\n            )\n\n        if isinstance(generic, GenericDimension):\n            numerator.append(generic)\n            return GenericCompositeDimension(\n                numerator=numerator, denominator=denominator\n            )\n\n        if isinstance(generic, MeasurementUnitType):\n            numerator.append(GenericDimension(generic))\n            return GenericCompositeDimension(\n                numerator=numerator, denominator=denominator\n            )\n        raise DescriptorBinaryOperationError(f\"cannot multiply {self} with {generic}. \")\n\n    def __truediv__(\n        self, generic: GenericUnitDescriptor\n    ) -> \"GenericCompositeDimension\":\n        \"\"\"\n        Defines division between GenericCompositeDimension(s) and other generic\n        descriptors.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit): ...\n            >>> class TimeUnit(MeasurementUnit): ...\n            >>> class LengthUnit(MeasurementUnit): ...\n            >>> (TemperatureUnit * LengthUnit) / TimeUnit\n            <GenericCompositeDimension: LengthUnit * TemperatureUnit / TimeUnit>\n        \"\"\"\n        numerator = self.numerator.copy()\n        denominator = self.denominator.copy()\n        if isinstance(generic, GenericCompositeDimension):\n            numerator.extend(generic.denominator)\n            denominator.extend(generic.numerator)\n            return GenericCompositeDimension(\n                numerator=numerator, denominator=denominator\n            )\n        if isinstance(generic, GenericDimension):\n            denominator.append(generic)\n            return GenericCompositeDimension(\n                numerator=numerator, denominator=denominator\n            )\n        if isinstance(generic, MeasurementUnitType):\n            denominator.append(GenericDimension(generic))\n            return GenericCompositeDimension(\n                numerator=numerator, denominator=denominator\n            )\n        raise DescriptorBinaryOperationError(f\"cannot divide {self} with {generic}. \")\n\n    def __pow__(self, power: float) -> \"GenericCompositeDimension\":\n        \"\"\"\n        Defines exponentiation for GenericCompositeDimension(s).\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit): ...\n            >>> class TimeUnit(MeasurementUnit): ...\n\n            >>> (TemperatureUnit / TimeUnit)**2\n            <GenericCompositeDimension: (TemperatureUnit^2) / (TimeUnit^2)>\n        \"\"\"\n        if not isinstance(power, (float, int)):\n            raise DescriptorExponentError(\n                f\"invalid exponent: {{ value: {power}, type: {type(power)} }};\"\n                \" expected float or int. \"\n            )\n        numerator = [n**power for n in self._numerator_copy()]\n        denominator = [d**power for d in self._denominator_copy()]\n        return GenericCompositeDimension(numerator, denominator)\n\n    def __eq__(self, generic) -> bool:\n        \"\"\"\n        Defines equality for GenericCompositeDimension(s).\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit): ...\n            >>> class TimeUnit(MeasurementUnit): ...\n            >>> (TemperatureUnit / TimeUnit) != (TimeUnit / TemperatureUnit)\n            True\n        \"\"\"\n        if not isinstance(generic, GenericCompositeDimension):\n            return False\n        return Counter(self.numerator) == Counter(generic.numerator) and (\n            Counter(self.denominator) == Counter(generic.denominator)\n        )\n\n    def __hash__(self) -> int:\n        return hash(str(self))\n\n    def __str__(self) -> str:\n        numerators = \" * \".join(sorted([str(n) for n in self.numerator]))\n        denominators = \" / \".join(sorted([str(d) for d in self.denominator]))\n        if len(denominators) > 0:\n            denominators = \" / \" + denominators\n        return numerators + denominators\n\n    def __repr__(self) -> str:\n        numerators = \" * \".join(sorted([str(n) for n in self.numerator]))\n        denominators = \" / \".join(sorted([str(d) for d in self.denominator]))\n        if len(denominators) > 0:\n            denominators = \" / \" + denominators\n        return f\"<GenericCompositeDimension: {numerators + denominators}>\"\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericCompositeDimension.__eq__","title":"__eq__(generic)","text":"

    Defines equality for GenericCompositeDimension(s).

    Examples:

    >>> class TemperatureUnit(MeasurementUnit): ...\n>>> class TimeUnit(MeasurementUnit): ...\n>>> (TemperatureUnit / TimeUnit) != (TimeUnit / TemperatureUnit)\nTrue\n
    Source code in src/property_utils/units/descriptors.py
    def __eq__(self, generic) -> bool:\n    \"\"\"\n    Defines equality for GenericCompositeDimension(s).\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit): ...\n        >>> class TimeUnit(MeasurementUnit): ...\n        >>> (TemperatureUnit / TimeUnit) != (TimeUnit / TemperatureUnit)\n        True\n    \"\"\"\n    if not isinstance(generic, GenericCompositeDimension):\n        return False\n    return Counter(self.numerator) == Counter(generic.numerator) and (\n        Counter(self.denominator) == Counter(generic.denominator)\n    )\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericCompositeDimension.__mul__","title":"__mul__(generic)","text":"

    Defines multiplication between GenericCompositeDimension(s) and other generic descriptors.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit): ...\n>>> class TimeUnit(MeasurementUnit): ...\n>>> class LengthUnit(MeasurementUnit): ...\n>>> (TemperatureUnit / LengthUnit) * TimeUnit\n<GenericCompositeDimension: TemperatureUnit * TimeUnit / LengthUnit>\n
    Source code in src/property_utils/units/descriptors.py
    def __mul__(self, generic: GenericUnitDescriptor) -> \"GenericCompositeDimension\":\n    \"\"\"\n    Defines multiplication between GenericCompositeDimension(s) and other generic\n    descriptors.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit): ...\n        >>> class TimeUnit(MeasurementUnit): ...\n        >>> class LengthUnit(MeasurementUnit): ...\n        >>> (TemperatureUnit / LengthUnit) * TimeUnit\n        <GenericCompositeDimension: TemperatureUnit * TimeUnit / LengthUnit>\n    \"\"\"\n    numerator = self.numerator.copy()\n    denominator = self.denominator.copy()\n    if isinstance(generic, GenericCompositeDimension):\n        numerator.extend(generic.numerator)\n        denominator.extend(generic.denominator)\n        return GenericCompositeDimension(\n            numerator=numerator, denominator=denominator\n        )\n\n    if isinstance(generic, GenericDimension):\n        numerator.append(generic)\n        return GenericCompositeDimension(\n            numerator=numerator, denominator=denominator\n        )\n\n    if isinstance(generic, MeasurementUnitType):\n        numerator.append(GenericDimension(generic))\n        return GenericCompositeDimension(\n            numerator=numerator, denominator=denominator\n        )\n    raise DescriptorBinaryOperationError(f\"cannot multiply {self} with {generic}. \")\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericCompositeDimension.__pow__","title":"__pow__(power)","text":"

    Defines exponentiation for GenericCompositeDimension(s).

    Examples:

    >>> class TemperatureUnit(MeasurementUnit): ...\n>>> class TimeUnit(MeasurementUnit): ...\n
    >>> (TemperatureUnit / TimeUnit)**2\n<GenericCompositeDimension: (TemperatureUnit^2) / (TimeUnit^2)>\n
    Source code in src/property_utils/units/descriptors.py
    def __pow__(self, power: float) -> \"GenericCompositeDimension\":\n    \"\"\"\n    Defines exponentiation for GenericCompositeDimension(s).\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit): ...\n        >>> class TimeUnit(MeasurementUnit): ...\n\n        >>> (TemperatureUnit / TimeUnit)**2\n        <GenericCompositeDimension: (TemperatureUnit^2) / (TimeUnit^2)>\n    \"\"\"\n    if not isinstance(power, (float, int)):\n        raise DescriptorExponentError(\n            f\"invalid exponent: {{ value: {power}, type: {type(power)} }};\"\n            \" expected float or int. \"\n        )\n    numerator = [n**power for n in self._numerator_copy()]\n    denominator = [d**power for d in self._denominator_copy()]\n    return GenericCompositeDimension(numerator, denominator)\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericCompositeDimension.__truediv__","title":"__truediv__(generic)","text":"

    Defines division between GenericCompositeDimension(s) and other generic descriptors.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit): ...\n>>> class TimeUnit(MeasurementUnit): ...\n>>> class LengthUnit(MeasurementUnit): ...\n>>> (TemperatureUnit * LengthUnit) / TimeUnit\n<GenericCompositeDimension: LengthUnit * TemperatureUnit / TimeUnit>\n
    Source code in src/property_utils/units/descriptors.py
    def __truediv__(\n    self, generic: GenericUnitDescriptor\n) -> \"GenericCompositeDimension\":\n    \"\"\"\n    Defines division between GenericCompositeDimension(s) and other generic\n    descriptors.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit): ...\n        >>> class TimeUnit(MeasurementUnit): ...\n        >>> class LengthUnit(MeasurementUnit): ...\n        >>> (TemperatureUnit * LengthUnit) / TimeUnit\n        <GenericCompositeDimension: LengthUnit * TemperatureUnit / TimeUnit>\n    \"\"\"\n    numerator = self.numerator.copy()\n    denominator = self.denominator.copy()\n    if isinstance(generic, GenericCompositeDimension):\n        numerator.extend(generic.denominator)\n        denominator.extend(generic.numerator)\n        return GenericCompositeDimension(\n            numerator=numerator, denominator=denominator\n        )\n    if isinstance(generic, GenericDimension):\n        denominator.append(generic)\n        return GenericCompositeDimension(\n            numerator=numerator, denominator=denominator\n        )\n    if isinstance(generic, MeasurementUnitType):\n        denominator.append(GenericDimension(generic))\n        return GenericCompositeDimension(\n            numerator=numerator, denominator=denominator\n        )\n    raise DescriptorBinaryOperationError(f\"cannot divide {self} with {generic}. \")\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericCompositeDimension.analyse","title":"analyse()","text":"

    Analyse this composite by replacing its alias units with their aliased units.

    Examples:

    >>> class MassUnit(MeasurementUnit): ...\n>>> class LengthUnit(MeasurementUnit): ...\n>>> class TimeUnit(MeasurementUnit): ...\n
    >>> class PressureUnit(AliasMeasurementUnit):\n...     @classmethod\n...     def aliased_generic_descriptor(cls) -> GenericCompositeDimension:\n...         return MassUnit / LengthUnit / (TimeUnit**2)\n
    >>> composite = PressureUnit / LengthUnit\n>>> composite\n<GenericCompositeDimension: PressureUnit / LengthUnit>\n
    >>> composite.analyse()\n>>> composite\n<GenericCompositeDimension: MassUnit / (TimeUnit^2) / LengthUnit / LengthUnit>\n
    Source code in src/property_utils/units/descriptors.py
    def analyse(self) -> None:\n    \"\"\"\n    Analyse this composite by replacing its alias units with their aliased units.\n\n    Examples:\n        >>> class MassUnit(MeasurementUnit): ...\n        >>> class LengthUnit(MeasurementUnit): ...\n        >>> class TimeUnit(MeasurementUnit): ...\n\n        >>> class PressureUnit(AliasMeasurementUnit):\n        ...     @classmethod\n        ...     def aliased_generic_descriptor(cls) -> GenericCompositeDimension:\n        ...         return MassUnit / LengthUnit / (TimeUnit**2)\n\n        >>> composite = PressureUnit / LengthUnit\n        >>> composite\n        <GenericCompositeDimension: PressureUnit / LengthUnit>\n\n        >>> composite.analyse()\n        >>> composite\n        <GenericCompositeDimension: MassUnit / (TimeUnit^2) / LengthUnit / LengthUnit>\n    \"\"\"\n    for n in self.numerator:\n        if issubclass(n.unit_type, AliasMeasurementUnit):\n            aliased = n.unit_type.aliased_generic_descriptor() ** n.power\n            if isinstance(aliased, GenericDimension):\n                self.numerator.append(aliased)\n            elif isinstance(aliased, GenericCompositeDimension):\n                self.numerator.extend(aliased.numerator)\n                self.denominator.extend(aliased.denominator)\n\n            self.numerator.remove(n)\n\n    for d in self.denominator:\n        if issubclass(d.unit_type, AliasMeasurementUnit):\n            aliased = d.unit_type.aliased_generic_descriptor() ** d.power\n            if isinstance(aliased, GenericDimension):\n                self.denominator.append(aliased)\n            elif isinstance(aliased, GenericCompositeDimension):\n                self.denominator.extend(aliased.numerator)\n                self.numerator.extend(aliased.denominator)\n\n            self.denominator.remove(d)\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericCompositeDimension.analysed","title":"analysed()","text":"

    Returns an analysed version of this composite generic as a new object.

    Examples:

    >>> class MassUnit(MeasurementUnit): ...\n>>> class LengthUnit(MeasurementUnit): ...\n>>> class TimeUnit(MeasurementUnit): ...\n
    >>> class PressureUnit(AliasMeasurementUnit):\n...     @classmethod\n...     def aliased_generic_descriptor(cls) -> GenericCompositeDimension:\n...         return MassUnit / LengthUnit / (TimeUnit**2)\n
    >>> composite = PressureUnit / LengthUnit\n>>> composite\n<GenericCompositeDimension: PressureUnit / LengthUnit>\n
    >>> composite.analysed()\n<GenericCompositeDimension: MassUnit / (TimeUnit^2) / LengthUnit / LengthUnit>\n
    Source code in src/property_utils/units/descriptors.py
    def analysed(self) -> \"GenericCompositeDimension\":\n    \"\"\"\n    Returns an analysed version of this composite generic as a new object.\n\n    Examples:\n        >>> class MassUnit(MeasurementUnit): ...\n        >>> class LengthUnit(MeasurementUnit): ...\n        >>> class TimeUnit(MeasurementUnit): ...\n\n        >>> class PressureUnit(AliasMeasurementUnit):\n        ...     @classmethod\n        ...     def aliased_generic_descriptor(cls) -> GenericCompositeDimension:\n        ...         return MassUnit / LengthUnit / (TimeUnit**2)\n\n        >>> composite = PressureUnit / LengthUnit\n        >>> composite\n        <GenericCompositeDimension: PressureUnit / LengthUnit>\n\n        >>> composite.analysed()\n        <GenericCompositeDimension: MassUnit / (TimeUnit^2) / LengthUnit / LengthUnit>\n    \"\"\"\n    copy = replace(self)\n    copy.analyse()\n    return copy\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericCompositeDimension.has_no_units","title":"has_no_units()","text":"

    Returns True if the generic composite dimension does not have any units, False otherwise.

    Examples:

    >>> class LengthUnit(MeasurementUnit): ...\n
    >>> GenericCompositeDimension().has_no_units()\nTrue\n>>> GenericCompositeDimension([LengthUnit]).has_no_units()\nFalse\n
    Source code in src/property_utils/units/descriptors.py
    def has_no_units(self) -> bool:\n    \"\"\"\n    Returns True if the generic composite dimension does not have any units, False\n    otherwise.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit): ...\n\n        >>> GenericCompositeDimension().has_no_units()\n        True\n        >>> GenericCompositeDimension([LengthUnit]).has_no_units()\n        False\n    \"\"\"\n    return len(self.denominator) == 0 and len(self.numerator) == 0\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericCompositeDimension.inverse_generic","title":"inverse_generic()","text":"

    Create a generic composite with inverse units.

    Examples:

    >>> class LengthUnit(MeasurementUnit): ...\n>>> class TimeUnit(MeasurementUnit): ...\n
    >>> (LengthUnit / TimeUnit).inverse_generic()\n<GenericCompositeDimension: TimeUnit / LengthUnit>\n
    Source code in src/property_utils/units/descriptors.py
    def inverse_generic(self):\n    \"\"\"\n    Create a generic composite with inverse units.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit): ...\n        >>> class TimeUnit(MeasurementUnit): ...\n\n        >>> (LengthUnit / TimeUnit).inverse_generic()\n        <GenericCompositeDimension: TimeUnit / LengthUnit>\n    \"\"\"\n    return GenericCompositeDimension(\n        self._denominator_copy(), self._numerator_copy()\n    )\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericCompositeDimension.is_equivalent","title":"is_equivalent(other)","text":"

    Returns True if this generic is equivalent to the given one, False otherwise.

    A generic can be equivalent with another generic if the latter or the former is an alias.

    Examples:

    >>> class LengthUnit(MeasurementUnit): ...\n>>> class MassUnit(MeasurementUnit): ...\n>>> class TimeUnit(MeasurementUnit): ...\n>>> class ForceUnit(AliasMeasurementUnit):\n...     @classmethod\n...     def aliased_generic_descriptor(cls):\n...         return MassUnit * LengthUnit / (TimeUnit**2)\n
    >>> ForceUnit.is_equivalent(MassUnit * LengthUnit / (TimeUnit**2))\nTrue\n
    >>> class EnergyUnit(AliasMeasurementUnit):\n...     @classmethod\n...     def aliased_generic_descriptor(cls):\n...         return ForceUnit * LengthUnit\n
    >>> EnergyUnit.is_equivalent(MassUnit * (LengthUnit**2) / (TimeUnit**2))\nTrue\n
    Source code in src/property_utils/units/descriptors.py
    def is_equivalent(self, other: GenericUnitDescriptor) -> bool:\n    \"\"\"\n    Returns True if this generic is equivalent to the given one, False otherwise.\n\n    A generic can be equivalent with another generic if the latter or the former\n    is an alias.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit): ...\n        >>> class MassUnit(MeasurementUnit): ...\n        >>> class TimeUnit(MeasurementUnit): ...\n        >>> class ForceUnit(AliasMeasurementUnit):\n        ...     @classmethod\n        ...     def aliased_generic_descriptor(cls):\n        ...         return MassUnit * LengthUnit / (TimeUnit**2)\n\n        >>> ForceUnit.is_equivalent(MassUnit * LengthUnit / (TimeUnit**2))\n        True\n\n        >>> class EnergyUnit(AliasMeasurementUnit):\n        ...     @classmethod\n        ...     def aliased_generic_descriptor(cls):\n        ...         return ForceUnit * LengthUnit\n\n        >>> EnergyUnit.is_equivalent(MassUnit * (LengthUnit**2) / (TimeUnit**2))\n        True\n    \"\"\"\n    if isinstance(other, MeasurementUnitType):\n        if (\n            self.denominator == []\n            and len(self.numerator) == 1\n            and self.numerator[0].is_equivalent(other)\n        ):\n            return True\n\n        if issubclass(other, AliasMeasurementUnit):\n            return other.aliased_generic_descriptor().is_equivalent(self)  # type: ignore[attr-defined]\n\n    elif isinstance(other, GenericDimension):\n        if (\n            self.denominator == []\n            and len(self.numerator) == 1\n            and self.numerator[0].is_equivalent(other)\n        ):\n            return True\n\n        if issubclass(other.unit_type, AliasMeasurementUnit):\n            return (\n                other.unit_type.aliased_generic_descriptor() ** other.power\n            ).is_equivalent(self)\n\n    elif isinstance(other, GenericCompositeDimension):\n        _generic = other.analysed().simplified()\n        _self = self.analysed().simplified()\n\n        return Counter(_self.numerator) == Counter(_generic.numerator) and (\n            Counter(_self.denominator) == Counter(_generic.denominator)\n        )\n\n    return False\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericCompositeDimension.simplified","title":"simplified()","text":"

    Returns a simplified version of this composite generic as a new object.

    Examples:

    >>> class PressureUnit(AliasMeasurementUnit): ...\n
    >>> class TemperatureUnit(MeasurementUnit): ...\n
    >>> class LengthUnit(MeasurementUnit): ...\n
    >>> class TimeUnit(MeasurementUnit): ...\n
    >>> composite = (PressureUnit**(-2)) / (TemperatureUnit**(-1))\n>>> composite\n<GenericCompositeDimension: (PressureUnit^-2) / (TemperatureUnit^-1)>\n>>> composite.simplified()\n<GenericCompositeDimension: TemperatureUnit / (PressureUnit^2)>\n
    >>> composite = PressureUnit * LengthUnit * PressureUnit /TimeUnit\n>>> composite\n<GenericCompositeDimension: LengthUnit * PressureUnit * PressureUnit / TimeUnit>\n>>> composite.simplified()\n<GenericCompositeDimension: (PressureUnit^2) * LengthUnit / TimeUnit>\n
    Source code in src/property_utils/units/descriptors.py
    def simplified(self) -> \"GenericCompositeDimension\":\n    \"\"\"\n    Returns a simplified version of this composite generic as a new object.\n\n    Examples:\n        >>> class PressureUnit(AliasMeasurementUnit): ...\n\n        >>> class TemperatureUnit(MeasurementUnit): ...\n\n        >>> class LengthUnit(MeasurementUnit): ...\n\n        >>> class TimeUnit(MeasurementUnit): ...\n\n        >>> composite = (PressureUnit**(-2)) / (TemperatureUnit**(-1))\n        >>> composite\n        <GenericCompositeDimension: (PressureUnit^-2) / (TemperatureUnit^-1)>\n        >>> composite.simplified()\n        <GenericCompositeDimension: TemperatureUnit / (PressureUnit^2)>\n\n        >>> composite = PressureUnit * LengthUnit * PressureUnit /TimeUnit\n        >>> composite\n        <GenericCompositeDimension: LengthUnit * PressureUnit * PressureUnit / TimeUnit>\n        >>> composite.simplified()\n        <GenericCompositeDimension: (PressureUnit^2) * LengthUnit / TimeUnit>\n    \"\"\"\n    copy = replace(self)\n    copy.simplify()\n    return copy\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericCompositeDimension.simplify","title":"simplify()","text":"

    Simplify the composite by merging common dimensions.

    Examples:

    >>> class PressureUnit(AliasMeasurementUnit): ...\n
    >>> class TemperatureUnit(MeasurementUnit): ...\n
    >>> class LengthUnit(MeasurementUnit): ...\n
    >>> class TimeUnit(MeasurementUnit): ...\n
    >>> composite = (PressureUnit**(-2)) / (TemperatureUnit**(-1))\n>>> composite\n<GenericCompositeDimension: (PressureUnit^-2) / (TemperatureUnit^-1)>\n>>> composite.simplify()\n>>> composite\n<GenericCompositeDimension: TemperatureUnit / (PressureUnit^2)>\n
    >>> composite = PressureUnit * LengthUnit * PressureUnit / TimeUnit\n>>> composite\n<GenericCompositeDimension: LengthUnit * PressureUnit * PressureUnit / TimeUnit>\n>>> composite.simplify()\n>>> composite\n<GenericCompositeDimension: (PressureUnit^2) * LengthUnit / TimeUnit>\n
    Source code in src/property_utils/units/descriptors.py
    def simplify(self) -> None:\n    \"\"\"\n    Simplify the composite by merging common dimensions.\n\n    Examples:\n        >>> class PressureUnit(AliasMeasurementUnit): ...\n\n        >>> class TemperatureUnit(MeasurementUnit): ...\n\n        >>> class LengthUnit(MeasurementUnit): ...\n\n        >>> class TimeUnit(MeasurementUnit): ...\n\n        >>> composite = (PressureUnit**(-2)) / (TemperatureUnit**(-1))\n        >>> composite\n        <GenericCompositeDimension: (PressureUnit^-2) / (TemperatureUnit^-1)>\n        >>> composite.simplify()\n        >>> composite\n        <GenericCompositeDimension: TemperatureUnit / (PressureUnit^2)>\n\n        >>> composite = PressureUnit * LengthUnit * PressureUnit / TimeUnit\n        >>> composite\n        <GenericCompositeDimension: LengthUnit * PressureUnit * PressureUnit / TimeUnit>\n        >>> composite.simplify()\n        >>> composite\n        <GenericCompositeDimension: (PressureUnit^2) * LengthUnit / TimeUnit>\n    \"\"\"\n    exponents: Dict[MeasurementUnitType, float] = {}\n    for n in self.numerator:\n        if n.unit_type in exponents:\n            exponents[n.unit_type] += n.power\n        else:\n            exponents[n.unit_type] = n.power\n\n    for d in self.denominator:\n        if d.unit_type in exponents:\n            exponents[d.unit_type] -= d.power\n        else:\n            exponents[d.unit_type] = 0 - d.power\n\n    numerator = []\n    denominator = []\n    for unit_type, exponent in exponents.items():\n        if exponent > 0:\n            numerator.append(GenericDimension(unit_type) ** exponent)\n        elif exponent < 0:\n            denominator.append(GenericDimension(unit_type) ** abs(exponent))\n\n    self.numerator = numerator\n    self.denominator = denominator\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericCompositeDimension.to_si","title":"to_si()","text":"

    Create a CompositeDimension with SI units.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     KELVIN = \"K\"\n...     @classmethod\n...     def si(cls): return cls.KELVIN\n>>> class TimeUnit(MeasurementUnit):\n...     SECOND = \"s\"\n...     @classmethod\n...     def si(cls): return cls.SECOND\n>>> class LengthUnit(MeasurementUnit):\n...     METER = \"m\"\n...     @classmethod\n...     def si(cls): return cls.METER\n>>> (TemperatureUnit * LengthUnit / TimeUnit).to_si()\n<CompositeDimension: K * m / s>\n
    Source code in src/property_utils/units/descriptors.py
    def to_si(self) -> \"CompositeDimension\":\n    \"\"\"\n    Create a CompositeDimension with SI units.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     KELVIN = \"K\"\n        ...     @classmethod\n        ...     def si(cls): return cls.KELVIN\n        >>> class TimeUnit(MeasurementUnit):\n        ...     SECOND = \"s\"\n        ...     @classmethod\n        ...     def si(cls): return cls.SECOND\n        >>> class LengthUnit(MeasurementUnit):\n        ...     METER = \"m\"\n        ...     @classmethod\n        ...     def si(cls): return cls.METER\n        >>> (TemperatureUnit * LengthUnit / TimeUnit).to_si()\n        <CompositeDimension: K * m / s>\n    \"\"\"\n    return CompositeDimension(\n        [n.to_si() for n in self.numerator], [d.to_si() for d in self.denominator]\n    )\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericDimension","title":"GenericDimension dataclass","text":"

    Represents a generic property unit or a generic property unit to some power.

    e.g. a generic dimension can be a temperature dimension or a volume dimension (length dimension to the 3rd power).

    Examples:

    >>> class MassUnit(MeasurementUnit): ...\n>>> MassUnit**2\n<GenericDimension: MassUnit^2>\n
    Source code in src/property_utils/units/descriptors.py
    @dataclass\nclass GenericDimension:\n    \"\"\"\n    Represents a generic property unit or a generic property unit to some power.\n\n    e.g. a generic dimension can be a temperature dimension or a volume dimension\n    (length dimension to the 3rd power).\n\n    Examples:\n        >>> class MassUnit(MeasurementUnit): ...\n        >>> MassUnit**2\n        <GenericDimension: MassUnit^2>\n    \"\"\"\n\n    unit_type: MeasurementUnitType\n    power: float = 1\n\n    def __init__(self, unit_type: MeasurementUnitType, power: float = 1) -> None:\n        if not isinstance(power, (float, int)):\n            raise DescriptorExponentError(\n                f\"invalid exponent: {{ value: {power}, type: {type(power)} }};\"\n                \" expected float or int. \"\n            )\n        self.unit_type = unit_type\n        self.power = power\n\n    def to_si(self) -> \"Dimension\":\n        \"\"\"\n        Create a Dimension with SI units.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     CELCIUS = \"C\"\n            ...     KELVIN = \"K\"\n            ...     @classmethod\n            ...     def si(cls): return cls.KELVIN\n            >>> (TemperatureUnit**2).to_si()\n            <Dimension: K^2>\n        \"\"\"\n        return Dimension(self.unit_type.to_si(), self.power)\n\n    def inverse_generic(self) -> \"GenericCompositeDimension\":\n        \"\"\"\n        Create a generic composite with inverse units.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit): ...\n            >>> (LengthUnit**2).inverse_generic()\n            <GenericCompositeDimension:  / (LengthUnit^2)>\n        \"\"\"\n        return GenericCompositeDimension([], [replace(self)])\n\n    # pylint: disable=too-many-return-statements\n    def is_equivalent(self, other: GenericUnitDescriptor) -> bool:\n        \"\"\"\n        Returns True if this generic is equivalent to the given one, False otherwise.\n\n        A generic can be equivalent with another generic if the latter or the former\n        is an alias.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit): ...\n            >>> class MassUnit(MeasurementUnit): ...\n            >>> class TimeUnit(MeasurementUnit): ...\n            >>> class ForceUnit(AliasMeasurementUnit):\n            ...     @classmethod\n            ...     def aliased_generic_descriptor(cls):\n            ...         return MassUnit * LengthUnit / (TimeUnit**2)\n\n            >>> ForceUnit.is_equivalent(MassUnit * LengthUnit / (TimeUnit**2))\n            True\n\n            >>> class EnergyUnit(AliasMeasurementUnit):\n            ...     @classmethod\n            ...     def aliased_generic_descriptor(cls):\n            ...         return ForceUnit * LengthUnit\n\n            >>> EnergyUnit.is_equivalent(MassUnit * (LengthUnit**2) / (TimeUnit**2))\n            True\n        \"\"\"\n        if isinstance(other, MeasurementUnitType):\n            if self.unit_type == other and self.power == 1:\n                return True\n\n            if issubclass(other, AliasMeasurementUnit):\n                return other.aliased_generic_descriptor().is_equivalent(self)  # type: ignore[attr-defined]\n\n        elif isinstance(other, GenericDimension):\n            if self.unit_type == other.unit_type and self.power == other.power:\n                return True\n\n            if issubclass(other.unit_type, AliasMeasurementUnit):\n                return (\n                    other.unit_type.aliased_generic_descriptor() ** other.power\n                ).is_equivalent(self)\n\n            if issubclass(self.unit_type, AliasMeasurementUnit):\n                return (\n                    self.unit_type.aliased_generic_descriptor() ** self.power\n                ).is_equivalent(other)\n\n        elif isinstance(other, GenericCompositeDimension):\n            if (\n                other.denominator == []\n                and len(other.numerator) == 1\n                and other.numerator[0].is_equivalent(self)\n            ):\n                return True\n\n            if issubclass(self.unit_type, AliasMeasurementUnit):\n                return (\n                    self.unit_type.aliased_generic_descriptor() ** self.power\n                ).is_equivalent(other)\n\n        return False\n\n    def __mul__(self, generic: GenericUnitDescriptor) -> \"GenericCompositeDimension\":\n        \"\"\"\n        Defines multiplication between GenericDimension(s) and other generic\n        descriptors.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit): ...\n            >>> class TimeUnit(MeasurementUnit): ...\n            >>> (TemperatureUnit**2) * TimeUnit\n            <GenericCompositeDimension: (TemperatureUnit^2) * TimeUnit>\n        \"\"\"\n        if isinstance(generic, GenericCompositeDimension):\n            numerator = generic.numerator.copy()\n            denominator = generic.denominator.copy()\n            numerator.append(self)\n            return GenericCompositeDimension(\n                numerator=numerator, denominator=denominator\n            )\n        if isinstance(generic, GenericDimension):\n            return GenericCompositeDimension(numerator=[self, generic])\n        if isinstance(generic, MeasurementUnitType):\n            return GenericCompositeDimension(\n                numerator=[self, GenericDimension(generic)]\n            )\n        raise DescriptorBinaryOperationError(f\"cannot multiply {self} with {generic}. \")\n\n    def __truediv__(\n        self, generic: GenericUnitDescriptor\n    ) -> \"GenericCompositeDimension\":\n        \"\"\"\n        Defines division between GenericDimension(s) and other generic descriptors.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit): ...\n            >>> class TimeUnit(MeasurementUnit): ...\n            >>> TemperatureUnit / (TimeUnit**2)\n            <GenericCompositeDimension: TemperatureUnit / (TimeUnit^2)>\n        \"\"\"\n        if isinstance(generic, GenericCompositeDimension):\n            numerator = generic.denominator.copy()\n            denominator = generic.numerator.copy()\n            numerator.append(self)\n            return GenericCompositeDimension(\n                numerator=numerator, denominator=denominator\n            )\n        if isinstance(generic, GenericDimension):\n            return GenericCompositeDimension(numerator=[self], denominator=[generic])\n        if isinstance(generic, MeasurementUnitType):\n            return GenericCompositeDimension(\n                numerator=[self], denominator=[GenericDimension(generic)]\n            )\n        raise DescriptorBinaryOperationError(f\"cannot divide {self} with {generic}. \")\n\n    def __pow__(self, power: float) -> \"GenericDimension\":\n        \"\"\"\n        Defines exponentiation of GenericDimension.\n\n        Examples:\n            >>> class TimeUnit(MeasurementUnit): ...\n            >>> (TimeUnit**2)**3\n            <GenericDimension: TimeUnit^6>\n        \"\"\"\n        if not isinstance(power, (float, int)):\n            raise DescriptorExponentError(\n                f\"invalid exponent: {{ value: {power}, type: {type(power)} }};\"\n                \" expected float or int. \"\n            )\n        self.power *= power\n        return self\n\n    def __eq__(self, generic) -> bool:\n        \"\"\"\n        Defines equality for GenericDimension(s).\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit): ...\n            >>> (TemperatureUnit**2) != TemperatureUnit\n            True\n        \"\"\"\n        if not isinstance(generic, GenericDimension):\n            return False\n        return self.unit_type == generic.unit_type and self.power == generic.power\n\n    def __hash__(self) -> int:\n        return hash(str(self))\n\n    def __str__(self) -> str:\n        s = self.unit_type.__name__\n        if self.power != 1:\n            return f\"({s}^{self.power})\"\n        return s\n\n    def __repr__(self) -> str:\n        if self.power != 1:\n            return f\"<GenericDimension: {self.unit_type.__name__}^{self.power}>\"\n        return f\"<GenericDimension: {self.unit_type.__name__}>\"\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericDimension.__eq__","title":"__eq__(generic)","text":"

    Defines equality for GenericDimension(s).

    Examples:

    >>> class TemperatureUnit(MeasurementUnit): ...\n>>> (TemperatureUnit**2) != TemperatureUnit\nTrue\n
    Source code in src/property_utils/units/descriptors.py
    def __eq__(self, generic) -> bool:\n    \"\"\"\n    Defines equality for GenericDimension(s).\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit): ...\n        >>> (TemperatureUnit**2) != TemperatureUnit\n        True\n    \"\"\"\n    if not isinstance(generic, GenericDimension):\n        return False\n    return self.unit_type == generic.unit_type and self.power == generic.power\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericDimension.__mul__","title":"__mul__(generic)","text":"

    Defines multiplication between GenericDimension(s) and other generic descriptors.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit): ...\n>>> class TimeUnit(MeasurementUnit): ...\n>>> (TemperatureUnit**2) * TimeUnit\n<GenericCompositeDimension: (TemperatureUnit^2) * TimeUnit>\n
    Source code in src/property_utils/units/descriptors.py
    def __mul__(self, generic: GenericUnitDescriptor) -> \"GenericCompositeDimension\":\n    \"\"\"\n    Defines multiplication between GenericDimension(s) and other generic\n    descriptors.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit): ...\n        >>> class TimeUnit(MeasurementUnit): ...\n        >>> (TemperatureUnit**2) * TimeUnit\n        <GenericCompositeDimension: (TemperatureUnit^2) * TimeUnit>\n    \"\"\"\n    if isinstance(generic, GenericCompositeDimension):\n        numerator = generic.numerator.copy()\n        denominator = generic.denominator.copy()\n        numerator.append(self)\n        return GenericCompositeDimension(\n            numerator=numerator, denominator=denominator\n        )\n    if isinstance(generic, GenericDimension):\n        return GenericCompositeDimension(numerator=[self, generic])\n    if isinstance(generic, MeasurementUnitType):\n        return GenericCompositeDimension(\n            numerator=[self, GenericDimension(generic)]\n        )\n    raise DescriptorBinaryOperationError(f\"cannot multiply {self} with {generic}. \")\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericDimension.__pow__","title":"__pow__(power)","text":"

    Defines exponentiation of GenericDimension.

    Examples:

    >>> class TimeUnit(MeasurementUnit): ...\n>>> (TimeUnit**2)**3\n<GenericDimension: TimeUnit^6>\n
    Source code in src/property_utils/units/descriptors.py
    def __pow__(self, power: float) -> \"GenericDimension\":\n    \"\"\"\n    Defines exponentiation of GenericDimension.\n\n    Examples:\n        >>> class TimeUnit(MeasurementUnit): ...\n        >>> (TimeUnit**2)**3\n        <GenericDimension: TimeUnit^6>\n    \"\"\"\n    if not isinstance(power, (float, int)):\n        raise DescriptorExponentError(\n            f\"invalid exponent: {{ value: {power}, type: {type(power)} }};\"\n            \" expected float or int. \"\n        )\n    self.power *= power\n    return self\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericDimension.__truediv__","title":"__truediv__(generic)","text":"

    Defines division between GenericDimension(s) and other generic descriptors.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit): ...\n>>> class TimeUnit(MeasurementUnit): ...\n>>> TemperatureUnit / (TimeUnit**2)\n<GenericCompositeDimension: TemperatureUnit / (TimeUnit^2)>\n
    Source code in src/property_utils/units/descriptors.py
    def __truediv__(\n    self, generic: GenericUnitDescriptor\n) -> \"GenericCompositeDimension\":\n    \"\"\"\n    Defines division between GenericDimension(s) and other generic descriptors.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit): ...\n        >>> class TimeUnit(MeasurementUnit): ...\n        >>> TemperatureUnit / (TimeUnit**2)\n        <GenericCompositeDimension: TemperatureUnit / (TimeUnit^2)>\n    \"\"\"\n    if isinstance(generic, GenericCompositeDimension):\n        numerator = generic.denominator.copy()\n        denominator = generic.numerator.copy()\n        numerator.append(self)\n        return GenericCompositeDimension(\n            numerator=numerator, denominator=denominator\n        )\n    if isinstance(generic, GenericDimension):\n        return GenericCompositeDimension(numerator=[self], denominator=[generic])\n    if isinstance(generic, MeasurementUnitType):\n        return GenericCompositeDimension(\n            numerator=[self], denominator=[GenericDimension(generic)]\n        )\n    raise DescriptorBinaryOperationError(f\"cannot divide {self} with {generic}. \")\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericDimension.inverse_generic","title":"inverse_generic()","text":"

    Create a generic composite with inverse units.

    Examples:

    >>> class LengthUnit(MeasurementUnit): ...\n>>> (LengthUnit**2).inverse_generic()\n<GenericCompositeDimension:  / (LengthUnit^2)>\n
    Source code in src/property_utils/units/descriptors.py
    def inverse_generic(self) -> \"GenericCompositeDimension\":\n    \"\"\"\n    Create a generic composite with inverse units.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit): ...\n        >>> (LengthUnit**2).inverse_generic()\n        <GenericCompositeDimension:  / (LengthUnit^2)>\n    \"\"\"\n    return GenericCompositeDimension([], [replace(self)])\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericDimension.is_equivalent","title":"is_equivalent(other)","text":"

    Returns True if this generic is equivalent to the given one, False otherwise.

    A generic can be equivalent with another generic if the latter or the former is an alias.

    Examples:

    >>> class LengthUnit(MeasurementUnit): ...\n>>> class MassUnit(MeasurementUnit): ...\n>>> class TimeUnit(MeasurementUnit): ...\n>>> class ForceUnit(AliasMeasurementUnit):\n...     @classmethod\n...     def aliased_generic_descriptor(cls):\n...         return MassUnit * LengthUnit / (TimeUnit**2)\n
    >>> ForceUnit.is_equivalent(MassUnit * LengthUnit / (TimeUnit**2))\nTrue\n
    >>> class EnergyUnit(AliasMeasurementUnit):\n...     @classmethod\n...     def aliased_generic_descriptor(cls):\n...         return ForceUnit * LengthUnit\n
    >>> EnergyUnit.is_equivalent(MassUnit * (LengthUnit**2) / (TimeUnit**2))\nTrue\n
    Source code in src/property_utils/units/descriptors.py
    def is_equivalent(self, other: GenericUnitDescriptor) -> bool:\n    \"\"\"\n    Returns True if this generic is equivalent to the given one, False otherwise.\n\n    A generic can be equivalent with another generic if the latter or the former\n    is an alias.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit): ...\n        >>> class MassUnit(MeasurementUnit): ...\n        >>> class TimeUnit(MeasurementUnit): ...\n        >>> class ForceUnit(AliasMeasurementUnit):\n        ...     @classmethod\n        ...     def aliased_generic_descriptor(cls):\n        ...         return MassUnit * LengthUnit / (TimeUnit**2)\n\n        >>> ForceUnit.is_equivalent(MassUnit * LengthUnit / (TimeUnit**2))\n        True\n\n        >>> class EnergyUnit(AliasMeasurementUnit):\n        ...     @classmethod\n        ...     def aliased_generic_descriptor(cls):\n        ...         return ForceUnit * LengthUnit\n\n        >>> EnergyUnit.is_equivalent(MassUnit * (LengthUnit**2) / (TimeUnit**2))\n        True\n    \"\"\"\n    if isinstance(other, MeasurementUnitType):\n        if self.unit_type == other and self.power == 1:\n            return True\n\n        if issubclass(other, AliasMeasurementUnit):\n            return other.aliased_generic_descriptor().is_equivalent(self)  # type: ignore[attr-defined]\n\n    elif isinstance(other, GenericDimension):\n        if self.unit_type == other.unit_type and self.power == other.power:\n            return True\n\n        if issubclass(other.unit_type, AliasMeasurementUnit):\n            return (\n                other.unit_type.aliased_generic_descriptor() ** other.power\n            ).is_equivalent(self)\n\n        if issubclass(self.unit_type, AliasMeasurementUnit):\n            return (\n                self.unit_type.aliased_generic_descriptor() ** self.power\n            ).is_equivalent(other)\n\n    elif isinstance(other, GenericCompositeDimension):\n        if (\n            other.denominator == []\n            and len(other.numerator) == 1\n            and other.numerator[0].is_equivalent(self)\n        ):\n            return True\n\n        if issubclass(self.unit_type, AliasMeasurementUnit):\n            return (\n                self.unit_type.aliased_generic_descriptor() ** self.power\n            ).is_equivalent(other)\n\n    return False\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericDimension.to_si","title":"to_si()","text":"

    Create a Dimension with SI units.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     CELCIUS = \"C\"\n...     KELVIN = \"K\"\n...     @classmethod\n...     def si(cls): return cls.KELVIN\n>>> (TemperatureUnit**2).to_si()\n<Dimension: K^2>\n
    Source code in src/property_utils/units/descriptors.py
    def to_si(self) -> \"Dimension\":\n    \"\"\"\n    Create a Dimension with SI units.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     CELCIUS = \"C\"\n        ...     KELVIN = \"K\"\n        ...     @classmethod\n        ...     def si(cls): return cls.KELVIN\n        >>> (TemperatureUnit**2).to_si()\n        <Dimension: K^2>\n    \"\"\"\n    return Dimension(self.unit_type.to_si(), self.power)\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericUnitDescriptor","title":"GenericUnitDescriptor","text":"

    Bases: Protocol

    Descriptor for a property unit that does not have a specific unit.

    e.g. a generic descriptor can represent a Temperature unit that does not have a specific value like Celcius or Fahrenheit.

    Source code in src/property_utils/units/descriptors.py
    class GenericUnitDescriptor(Protocol):\n    \"\"\"\n    Descriptor for a property unit that does not have a specific unit.\n\n    e.g. a  generic descriptor can represent a Temperature unit that does not have a\n    specific value like Celcius or Fahrenheit.\n    \"\"\"\n\n    def to_si(self) -> \"UnitDescriptor\":\n        \"\"\"\n        Create a unit descriptor with SI units.\n        \"\"\"\n\n    def inverse_generic(self) -> \"GenericCompositeDimension\":\n        \"\"\"\n        Create a generic composite with inverse units.\n        \"\"\"\n\n    def is_equivalent(self, other: \"GenericUnitDescriptor\") -> bool:\n        \"\"\"\n        Returns True if this generic is equivalent to the given one, False otherwise.\n\n        A generic can be equivalent with another generic if the latter or the former\n        is an alias.\n        \"\"\"\n\n    def __mul__(\n        self, generic: \"GenericUnitDescriptor\"\n    ) -> \"GenericCompositeDimension\": ...\n\n    def __truediv__(\n        self, generic: \"GenericUnitDescriptor\"\n    ) -> \"GenericCompositeDimension\": ...\n\n    def __pow__(self, power: float) -> \"GenericUnitDescriptor\": ...\n\n    def __eq__(self, generic) -> bool: ...\n\n    def __hash__(self) -> int: ...\n\n    def __str__(self) -> str: ...\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericUnitDescriptor.inverse_generic","title":"inverse_generic()","text":"

    Create a generic composite with inverse units.

    Source code in src/property_utils/units/descriptors.py
    def inverse_generic(self) -> \"GenericCompositeDimension\":\n    \"\"\"\n    Create a generic composite with inverse units.\n    \"\"\"\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericUnitDescriptor.is_equivalent","title":"is_equivalent(other)","text":"

    Returns True if this generic is equivalent to the given one, False otherwise.

    A generic can be equivalent with another generic if the latter or the former is an alias.

    Source code in src/property_utils/units/descriptors.py
    def is_equivalent(self, other: \"GenericUnitDescriptor\") -> bool:\n    \"\"\"\n    Returns True if this generic is equivalent to the given one, False otherwise.\n\n    A generic can be equivalent with another generic if the latter or the former\n    is an alias.\n    \"\"\"\n
    "},{"location":"descriptors/#property_utils.units.descriptors.GenericUnitDescriptor.to_si","title":"to_si()","text":"

    Create a unit descriptor with SI units.

    Source code in src/property_utils/units/descriptors.py
    def to_si(self) -> \"UnitDescriptor\":\n    \"\"\"\n    Create a unit descriptor with SI units.\n    \"\"\"\n
    "},{"location":"descriptors/#property_utils.units.descriptors.MeasurementUnit","title":"MeasurementUnit","text":"

    Bases: Enum

    Base class for all measurement units of physical quantities.

    Each measurement-unit class is an enumeration of the available units for a quantity.

    Subclasses should only enumerate measurement units of primitive physical quantities, i.e. units that cannot be produced from other units. e.g. length is an acceptable quantity, but volume is not because its' units are produced from length units.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     CELCIUS = \"C\"\n...     KELVIN = \"K\"\n...     RANKINE = \"R\"\n...     FAHRENHEIT = \"F\"\n
    Source code in src/property_utils/units/descriptors.py
    class MeasurementUnit(Enum, metaclass=MeasurementUnitMeta):\n    \"\"\"\n    Base class for all measurement units of physical quantities.\n\n    Each measurement-unit class is an enumeration of the available units for a\n    quantity.\n\n    Subclasses should only enumerate measurement units of primitive physical\n    quantities, i.e. units that cannot be produced from other units.\n    e.g. length is an acceptable quantity, but volume is not because its' units are\n    produced from length units.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     CELCIUS = \"C\"\n        ...     KELVIN = \"K\"\n        ...     RANKINE = \"R\"\n        ...     FAHRENHEIT = \"F\"\n    \"\"\"\n\n    @classmethod\n    def si(cls) -> \"MeasurementUnit\":\n        \"\"\"\n        Returns the SI unit of this measurement unit.\n        \"\"\"\n        raise NotImplementedError\n\n    @classmethod\n    def is_non_dimensional(cls) -> bool:\n        \"\"\"\n        Implement this function for defined measurement units that are non dimensional.\n\n        Examples:\n            >>> class NonDimensionalUnit(MeasurementUnit):\n            ...     NON_DIMENSIONAL = \"\"\n            ...     @classmethod\n            ...     def is_non_dimensional(cls) -> bool: return True\n\n            >>> NonDimensionalUnit.is_non_dimensional()\n            True\n        \"\"\"\n        return False\n\n    @staticmethod\n    def from_descriptor(descriptor: UnitDescriptor) -> \"MeasurementUnit\":\n        \"\"\"\n        Create a MeasurementUnit from given descriptor.\n        If descriptor is already a MeasurementUnit, it returns the same object.\n\n        This function does not serve as a constructor for MeasurementUnit, rather it\n        is intended to be used to convert an unknown unit descriptor to a\n        MeasurementUnit.\n\n        Raises `UnitDescriptorTypeError` if given descriptor cannot be translated\n        to a MeasurementUnit instance.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     CELCIUS = \"C\"\n\n            >>> celcius = MeasurementUnit.from_descriptor(TemperatureUnit.CELCIUS**2)\n            >>> celcius\n            <TemperatureUnit: C>\n        \"\"\"\n        if isinstance(descriptor, Dimension):\n            return descriptor.unit\n        if isinstance(descriptor, MeasurementUnit):\n            return descriptor\n        raise UnitDescriptorTypeError(\n            f\"cannot create MeasurementUnit from descriptor: {descriptor}\"\n        )\n\n    def isinstance(self, generic: GenericUnitDescriptor) -> bool:\n        \"\"\"\n        Returns True if the MeasurementUnit is an instance of the generic, False\n        otherwise.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     CELCIUS = \"C\"\n\n            >>> class LengthUnit(MeasurementUnit):\n            ...     METER = \"m\"\n\n            >>> TemperatureUnit.CELCIUS.isinstance(TemperatureUnit)\n            True\n\n            >>> TemperatureUnit.CELCIUS.isinstance(LengthUnit)\n            False\n        \"\"\"\n        return type(self) == generic  # pylint: disable=unidiomatic-typecheck\n\n    def isinstance_equivalent(self, generic: GenericUnitDescriptor) -> bool:\n        \"\"\"\n        Returns True if the UnitDescriptor is an instance-equivalent of the generic,\n        False otherwise.\n\n        A unit descriptor is an instance-equivalent of a generic if the generic of the\n        unit descriptor is equivalent to the generic.\n\n        Equivalence between generics is checked with the `is_equivalent` method.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit): ...\n            >>> class AreaUnit(AliasMeasurementUnit):\n            ...     HECTARE = \"ha\"\n            ...     @classmethod\n            ...     def aliased_generic_descriptor(cls): return LengthUnit**2\n\n            >>> AreaUnit.HECTARE.isinstance_equivalent(AreaUnit)\n            True\n            >>> AreaUnit.HECTARE.isinstance_equivalent(LengthUnit**2)\n            True\n        \"\"\"\n        return self.to_generic().is_equivalent(generic)\n\n    def to_generic(self) -> GenericUnitDescriptor:\n        \"\"\"\n        Create a generic descriptor from this MeasurementUnit.\n\n        Examples:\n            >>> class AmountUnit(MeasurementUnit):\n            ...     MOL = \"mol\"\n\n            >>> AmountUnit.MOL.to_generic()\n            <MeasurementUnit: AmountUnit>\n        \"\"\"\n        return self.__class__\n\n    def inverse(self) -> \"CompositeDimension\":\n        \"\"\"\n        Create a composite with inverse units.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     KELVIN = \"K\"\n            >>> TemperatureUnit.KELVIN.inverse()\n            <CompositeDimension:  / K>\n        \"\"\"\n        return CompositeDimension([], [Dimension(self)])\n\n    def __mul__(self, descriptor: UnitDescriptor) -> \"CompositeDimension\":\n        \"\"\"\n        Defines multiplication between MeasurementUnit objects and other unit descriptors.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     FAHRENHEIT = \"F\"\n            >>> class TimeUnit(MeasurementUnit):\n            ...     HOUR = \"hr\"\n            >>> TemperatureUnit.FAHRENHEIT * TimeUnit.HOUR\n            <CompositeDimension: F * hr>\n        \"\"\"\n        if isinstance(descriptor, MeasurementUnit):\n            return Dimension(self) * Dimension(descriptor)\n        if isinstance(descriptor, (Dimension, CompositeDimension)):\n            return Dimension(self) * descriptor\n        raise DescriptorBinaryOperationError(\n            f\"cannot multiply {self} with {descriptor}. \"\n        )\n\n    def __truediv__(self, descriptor: UnitDescriptor) -> \"CompositeDimension\":\n        \"\"\"\n        Defines division between MeasurementUnit objects and other unit descriptors.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     FAHRENHEIT = \"F\"\n            >>> class TimeUnit(MeasurementUnit):\n            ...     HOUR = \"hr\"\n            >>> TemperatureUnit.FAHRENHEIT / TimeUnit.HOUR\n            <CompositeDimension: F / hr>\n        \"\"\"\n        if isinstance(descriptor, MeasurementUnit):\n            return Dimension(self) / Dimension(descriptor)\n        if isinstance(descriptor, (Dimension, CompositeDimension)):\n            return Dimension(self) / descriptor\n        raise DescriptorBinaryOperationError(\n            f\"cannot divide {self} with {descriptor}. \"\n        )\n\n    def __pow__(self, power: float) -> \"Dimension\":\n        \"\"\"\n        Defines exponentiation of MeasurementUnit objects.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit):\n            ...     FEET = \"ft\"\n            >>> LengthUnit.FEET**3\n            <Dimension: ft^3>\n        \"\"\"\n        # always keep non dimensional units to the first power\n        power = 1 if self.is_non_dimensional() else power\n\n        return Dimension(self, power)\n\n    def __hash__(self) -> int:\n        return hash(self.value)\n\n    def __repr__(self) -> str:\n        return f\"<{self.__class__.__name__}: {str(self)}>\"\n\n    def __str__(self) -> str:\n        return self.value\n
    "},{"location":"descriptors/#property_utils.units.descriptors.MeasurementUnit.__mul__","title":"__mul__(descriptor)","text":"

    Defines multiplication between MeasurementUnit objects and other unit descriptors.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     FAHRENHEIT = \"F\"\n>>> class TimeUnit(MeasurementUnit):\n...     HOUR = \"hr\"\n>>> TemperatureUnit.FAHRENHEIT * TimeUnit.HOUR\n<CompositeDimension: F * hr>\n
    Source code in src/property_utils/units/descriptors.py
    def __mul__(self, descriptor: UnitDescriptor) -> \"CompositeDimension\":\n    \"\"\"\n    Defines multiplication between MeasurementUnit objects and other unit descriptors.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     FAHRENHEIT = \"F\"\n        >>> class TimeUnit(MeasurementUnit):\n        ...     HOUR = \"hr\"\n        >>> TemperatureUnit.FAHRENHEIT * TimeUnit.HOUR\n        <CompositeDimension: F * hr>\n    \"\"\"\n    if isinstance(descriptor, MeasurementUnit):\n        return Dimension(self) * Dimension(descriptor)\n    if isinstance(descriptor, (Dimension, CompositeDimension)):\n        return Dimension(self) * descriptor\n    raise DescriptorBinaryOperationError(\n        f\"cannot multiply {self} with {descriptor}. \"\n    )\n
    "},{"location":"descriptors/#property_utils.units.descriptors.MeasurementUnit.__pow__","title":"__pow__(power)","text":"

    Defines exponentiation of MeasurementUnit objects.

    Examples:

    >>> class LengthUnit(MeasurementUnit):\n...     FEET = \"ft\"\n>>> LengthUnit.FEET**3\n<Dimension: ft^3>\n
    Source code in src/property_utils/units/descriptors.py
    def __pow__(self, power: float) -> \"Dimension\":\n    \"\"\"\n    Defines exponentiation of MeasurementUnit objects.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit):\n        ...     FEET = \"ft\"\n        >>> LengthUnit.FEET**3\n        <Dimension: ft^3>\n    \"\"\"\n    # always keep non dimensional units to the first power\n    power = 1 if self.is_non_dimensional() else power\n\n    return Dimension(self, power)\n
    "},{"location":"descriptors/#property_utils.units.descriptors.MeasurementUnit.__truediv__","title":"__truediv__(descriptor)","text":"

    Defines division between MeasurementUnit objects and other unit descriptors.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     FAHRENHEIT = \"F\"\n>>> class TimeUnit(MeasurementUnit):\n...     HOUR = \"hr\"\n>>> TemperatureUnit.FAHRENHEIT / TimeUnit.HOUR\n<CompositeDimension: F / hr>\n
    Source code in src/property_utils/units/descriptors.py
    def __truediv__(self, descriptor: UnitDescriptor) -> \"CompositeDimension\":\n    \"\"\"\n    Defines division between MeasurementUnit objects and other unit descriptors.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     FAHRENHEIT = \"F\"\n        >>> class TimeUnit(MeasurementUnit):\n        ...     HOUR = \"hr\"\n        >>> TemperatureUnit.FAHRENHEIT / TimeUnit.HOUR\n        <CompositeDimension: F / hr>\n    \"\"\"\n    if isinstance(descriptor, MeasurementUnit):\n        return Dimension(self) / Dimension(descriptor)\n    if isinstance(descriptor, (Dimension, CompositeDimension)):\n        return Dimension(self) / descriptor\n    raise DescriptorBinaryOperationError(\n        f\"cannot divide {self} with {descriptor}. \"\n    )\n
    "},{"location":"descriptors/#property_utils.units.descriptors.MeasurementUnit.from_descriptor","title":"from_descriptor(descriptor) staticmethod","text":"

    Create a MeasurementUnit from given descriptor. If descriptor is already a MeasurementUnit, it returns the same object.

    This function does not serve as a constructor for MeasurementUnit, rather it is intended to be used to convert an unknown unit descriptor to a MeasurementUnit.

    Raises UnitDescriptorTypeError if given descriptor cannot be translated to a MeasurementUnit instance.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     CELCIUS = \"C\"\n
    >>> celcius = MeasurementUnit.from_descriptor(TemperatureUnit.CELCIUS**2)\n>>> celcius\n<TemperatureUnit: C>\n
    Source code in src/property_utils/units/descriptors.py
    @staticmethod\ndef from_descriptor(descriptor: UnitDescriptor) -> \"MeasurementUnit\":\n    \"\"\"\n    Create a MeasurementUnit from given descriptor.\n    If descriptor is already a MeasurementUnit, it returns the same object.\n\n    This function does not serve as a constructor for MeasurementUnit, rather it\n    is intended to be used to convert an unknown unit descriptor to a\n    MeasurementUnit.\n\n    Raises `UnitDescriptorTypeError` if given descriptor cannot be translated\n    to a MeasurementUnit instance.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     CELCIUS = \"C\"\n\n        >>> celcius = MeasurementUnit.from_descriptor(TemperatureUnit.CELCIUS**2)\n        >>> celcius\n        <TemperatureUnit: C>\n    \"\"\"\n    if isinstance(descriptor, Dimension):\n        return descriptor.unit\n    if isinstance(descriptor, MeasurementUnit):\n        return descriptor\n    raise UnitDescriptorTypeError(\n        f\"cannot create MeasurementUnit from descriptor: {descriptor}\"\n    )\n
    "},{"location":"descriptors/#property_utils.units.descriptors.MeasurementUnit.inverse","title":"inverse()","text":"

    Create a composite with inverse units.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     KELVIN = \"K\"\n>>> TemperatureUnit.KELVIN.inverse()\n<CompositeDimension:  / K>\n
    Source code in src/property_utils/units/descriptors.py
    def inverse(self) -> \"CompositeDimension\":\n    \"\"\"\n    Create a composite with inverse units.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     KELVIN = \"K\"\n        >>> TemperatureUnit.KELVIN.inverse()\n        <CompositeDimension:  / K>\n    \"\"\"\n    return CompositeDimension([], [Dimension(self)])\n
    "},{"location":"descriptors/#property_utils.units.descriptors.MeasurementUnit.is_non_dimensional","title":"is_non_dimensional() classmethod","text":"

    Implement this function for defined measurement units that are non dimensional.

    Examples:

    >>> class NonDimensionalUnit(MeasurementUnit):\n...     NON_DIMENSIONAL = \"\"\n...     @classmethod\n...     def is_non_dimensional(cls) -> bool: return True\n
    >>> NonDimensionalUnit.is_non_dimensional()\nTrue\n
    Source code in src/property_utils/units/descriptors.py
    @classmethod\ndef is_non_dimensional(cls) -> bool:\n    \"\"\"\n    Implement this function for defined measurement units that are non dimensional.\n\n    Examples:\n        >>> class NonDimensionalUnit(MeasurementUnit):\n        ...     NON_DIMENSIONAL = \"\"\n        ...     @classmethod\n        ...     def is_non_dimensional(cls) -> bool: return True\n\n        >>> NonDimensionalUnit.is_non_dimensional()\n        True\n    \"\"\"\n    return False\n
    "},{"location":"descriptors/#property_utils.units.descriptors.MeasurementUnit.isinstance","title":"isinstance(generic)","text":"

    Returns True if the MeasurementUnit is an instance of the generic, False otherwise.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     CELCIUS = \"C\"\n
    >>> class LengthUnit(MeasurementUnit):\n...     METER = \"m\"\n
    >>> TemperatureUnit.CELCIUS.isinstance(TemperatureUnit)\nTrue\n
    >>> TemperatureUnit.CELCIUS.isinstance(LengthUnit)\nFalse\n
    Source code in src/property_utils/units/descriptors.py
    def isinstance(self, generic: GenericUnitDescriptor) -> bool:\n    \"\"\"\n    Returns True if the MeasurementUnit is an instance of the generic, False\n    otherwise.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     CELCIUS = \"C\"\n\n        >>> class LengthUnit(MeasurementUnit):\n        ...     METER = \"m\"\n\n        >>> TemperatureUnit.CELCIUS.isinstance(TemperatureUnit)\n        True\n\n        >>> TemperatureUnit.CELCIUS.isinstance(LengthUnit)\n        False\n    \"\"\"\n    return type(self) == generic  # pylint: disable=unidiomatic-typecheck\n
    "},{"location":"descriptors/#property_utils.units.descriptors.MeasurementUnit.isinstance_equivalent","title":"isinstance_equivalent(generic)","text":"

    Returns True if the UnitDescriptor is an instance-equivalent of the generic, False otherwise.

    A unit descriptor is an instance-equivalent of a generic if the generic of the unit descriptor is equivalent to the generic.

    Equivalence between generics is checked with the is_equivalent method.

    Examples:

    >>> class LengthUnit(MeasurementUnit): ...\n>>> class AreaUnit(AliasMeasurementUnit):\n...     HECTARE = \"ha\"\n...     @classmethod\n...     def aliased_generic_descriptor(cls): return LengthUnit**2\n
    >>> AreaUnit.HECTARE.isinstance_equivalent(AreaUnit)\nTrue\n>>> AreaUnit.HECTARE.isinstance_equivalent(LengthUnit**2)\nTrue\n
    Source code in src/property_utils/units/descriptors.py
    def isinstance_equivalent(self, generic: GenericUnitDescriptor) -> bool:\n    \"\"\"\n    Returns True if the UnitDescriptor is an instance-equivalent of the generic,\n    False otherwise.\n\n    A unit descriptor is an instance-equivalent of a generic if the generic of the\n    unit descriptor is equivalent to the generic.\n\n    Equivalence between generics is checked with the `is_equivalent` method.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit): ...\n        >>> class AreaUnit(AliasMeasurementUnit):\n        ...     HECTARE = \"ha\"\n        ...     @classmethod\n        ...     def aliased_generic_descriptor(cls): return LengthUnit**2\n\n        >>> AreaUnit.HECTARE.isinstance_equivalent(AreaUnit)\n        True\n        >>> AreaUnit.HECTARE.isinstance_equivalent(LengthUnit**2)\n        True\n    \"\"\"\n    return self.to_generic().is_equivalent(generic)\n
    "},{"location":"descriptors/#property_utils.units.descriptors.MeasurementUnit.si","title":"si() classmethod","text":"

    Returns the SI unit of this measurement unit.

    Source code in src/property_utils/units/descriptors.py
    @classmethod\ndef si(cls) -> \"MeasurementUnit\":\n    \"\"\"\n    Returns the SI unit of this measurement unit.\n    \"\"\"\n    raise NotImplementedError\n
    "},{"location":"descriptors/#property_utils.units.descriptors.MeasurementUnit.to_generic","title":"to_generic()","text":"

    Create a generic descriptor from this MeasurementUnit.

    Examples:

    >>> class AmountUnit(MeasurementUnit):\n...     MOL = \"mol\"\n
    >>> AmountUnit.MOL.to_generic()\n<MeasurementUnit: AmountUnit>\n
    Source code in src/property_utils/units/descriptors.py
    def to_generic(self) -> GenericUnitDescriptor:\n    \"\"\"\n    Create a generic descriptor from this MeasurementUnit.\n\n    Examples:\n        >>> class AmountUnit(MeasurementUnit):\n        ...     MOL = \"mol\"\n\n        >>> AmountUnit.MOL.to_generic()\n        <MeasurementUnit: AmountUnit>\n    \"\"\"\n    return self.__class__\n
    "},{"location":"descriptors/#property_utils.units.descriptors.MeasurementUnitMeta","title":"MeasurementUnitMeta","text":"

    Bases: EnumMeta

    Metaclass for MeasurementUnit. Defines multiplication, division and exponent operations for MeasurementUnit class (and subclasses). These operations produce GenericUnitDescriptor(s).

    Source code in src/property_utils/units/descriptors.py
    class MeasurementUnitMeta(EnumMeta):\n    \"\"\"\n    Metaclass for MeasurementUnit. Defines multiplication, division and exponent\n    operations for MeasurementUnit class (and subclasses). These operations produce\n    GenericUnitDescriptor(s).\n    \"\"\"\n\n    def to_si(cls) -> \"MeasurementUnit\":\n        \"\"\"\n        Create a MeasurementUnit with SI units.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit):\n            ...     CELCIUS = \"C\"\n            ...     KELVIN = \"K\"\n            ...     @classmethod\n            ...     def si(cls):\n            ...         return cls.KELVIN\n            >>> TemperatureUnit.to_si()\n            <TemperatureUnit: K>\n        \"\"\"\n        if hasattr(cls, \"si\"):\n            return cls.si()\n        raise NotImplementedError\n\n    def inverse_generic(cls) -> \"GenericCompositeDimension\":\n        \"\"\"\n        Create a generic composite with inverse units.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit): ...\n            >>> TemperatureUnit.inverse_generic()\n            <GenericCompositeDimension:  / TemperatureUnit>\n        \"\"\"\n        return GenericCompositeDimension([], [GenericDimension(cls)])\n\n    # pylint: disable=too-many-return-statements\n    def is_equivalent(cls, other: GenericUnitDescriptor) -> bool:\n        \"\"\"\n        Returns True if this generic is equivalent to the given one, False otherwise.\n\n        A generic can be equivalent with another generic if the latter or the former\n        is an alias.\n\n        Examples:\n            >>> class LengthUnit(MeasurementUnit): ...\n            >>> class MassUnit(MeasurementUnit): ...\n            >>> class TimeUnit(MeasurementUnit): ...\n            >>> class ForceUnit(AliasMeasurementUnit):\n            ...     @classmethod\n            ...     def aliased_generic_descriptor(cls):\n            ...         return MassUnit * LengthUnit / (TimeUnit**2)\n\n            >>> ForceUnit.is_equivalent(MassUnit * LengthUnit / (TimeUnit**2))\n            True\n\n            >>> class EnergyUnit(AliasMeasurementUnit):\n            ...     @classmethod\n            ...     def aliased_generic_descriptor(cls):\n            ...         return ForceUnit * LengthUnit\n\n            >>> EnergyUnit.is_equivalent(MassUnit * (LengthUnit**2) / (TimeUnit**2))\n            True\n        \"\"\"\n        if isinstance(other, MeasurementUnitType):\n            return cls == other\n\n        if isinstance(other, GenericDimension):\n            if cls == other.unit_type and other.power == 1:\n                return True\n\n            if issubclass(other.unit_type, AliasMeasurementUnit):\n                return (\n                    other.unit_type.aliased_generic_descriptor() ** other.power\n                ).is_equivalent(cls)\n\n            if issubclass(cls, AliasMeasurementUnit):\n                return cls.aliased_generic_descriptor().is_equivalent(other)\n\n        elif isinstance(other, GenericCompositeDimension):\n            if (\n                other.denominator == []\n                and len(other.numerator) == 1\n                and other.numerator[0].is_equivalent(cls)\n            ):\n                return True\n\n            if issubclass(cls, AliasMeasurementUnit):\n                return cls.aliased_generic_descriptor().is_equivalent(other)\n\n        return False\n\n    def __mul__(cls, other: GenericUnitDescriptor) -> \"GenericCompositeDimension\":\n        \"\"\"\n        Defines multiplication between MeasurementUnit types and other generic\n        descriptors.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit): ...\n            >>> class TimeUnit(MeasurementUnit): ...\n            >>> TemperatureUnit * TimeUnit\n            <GenericCompositeDimension: TemperatureUnit * TimeUnit>\n        \"\"\"\n        if isinstance(other, GenericCompositeDimension):\n            numerator = other.numerator.copy()\n            denominator = other.denominator.copy()\n            numerator.append(GenericDimension(cls))\n            return GenericCompositeDimension(\n                numerator=numerator, denominator=denominator\n            )\n        if isinstance(other, GenericDimension):\n            return GenericCompositeDimension(numerator=[GenericDimension(cls), other])\n        if isinstance(other, MeasurementUnitType):\n            return GenericCompositeDimension(\n                numerator=[\n                    GenericDimension(cls),\n                    GenericDimension(other),\n                ]\n            )\n        raise DescriptorBinaryOperationError(f\"cannot multiply {cls} with {other}. \")\n\n    def __truediv__(cls, other: GenericUnitDescriptor) -> \"GenericCompositeDimension\":\n        \"\"\"\n        Defines division between MeasurementUnit types and other generic\n        descriptors.\n\n        Examples:\n            >>> class TemperatureUnit(MeasurementUnit): ...\n            >>> class TimeUnit(MeasurementUnit): ...\n            >>> TemperatureUnit / TimeUnit\n            <GenericCompositeDimension: TemperatureUnit / TimeUnit>\n        \"\"\"\n        if isinstance(other, GenericCompositeDimension):\n            numerator = other.denominator.copy()\n            denominator = other.numerator.copy()\n            numerator.append(GenericDimension(cls))\n            return GenericCompositeDimension(\n                numerator=numerator, denominator=denominator\n            )\n        if isinstance(other, GenericDimension):\n            return GenericCompositeDimension(\n                numerator=[GenericDimension(cls)], denominator=[other]\n            )\n        if isinstance(other, MeasurementUnitType):\n            return GenericCompositeDimension(\n                numerator=[GenericDimension(cls)],\n                denominator=[GenericDimension(other)],\n            )\n        raise DescriptorBinaryOperationError(f\"cannot divide {cls} with {other}. \")\n\n    def __pow__(cls, power: float) -> \"GenericDimension\":\n        \"\"\"\n        Defines exponentiation of MeasurementUnit types.\n\n        Examples:\n            >>> class TimeUnit(MeasurementUnit): ...\n            >>> TimeUnit**3\n            <GenericDimension: TimeUnit^3>\n        \"\"\"\n        return GenericDimension(cls, power)\n\n    def __str__(cls) -> str:\n        return cls.__name__\n\n    def __repr__(cls) -> str:\n        return f\"<MeasurementUnit: {str(cls)}>\"\n
    "},{"location":"descriptors/#property_utils.units.descriptors.MeasurementUnitMeta.__mul__","title":"__mul__(other)","text":"

    Defines multiplication between MeasurementUnit types and other generic descriptors.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit): ...\n>>> class TimeUnit(MeasurementUnit): ...\n>>> TemperatureUnit * TimeUnit\n<GenericCompositeDimension: TemperatureUnit * TimeUnit>\n
    Source code in src/property_utils/units/descriptors.py
    def __mul__(cls, other: GenericUnitDescriptor) -> \"GenericCompositeDimension\":\n    \"\"\"\n    Defines multiplication between MeasurementUnit types and other generic\n    descriptors.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit): ...\n        >>> class TimeUnit(MeasurementUnit): ...\n        >>> TemperatureUnit * TimeUnit\n        <GenericCompositeDimension: TemperatureUnit * TimeUnit>\n    \"\"\"\n    if isinstance(other, GenericCompositeDimension):\n        numerator = other.numerator.copy()\n        denominator = other.denominator.copy()\n        numerator.append(GenericDimension(cls))\n        return GenericCompositeDimension(\n            numerator=numerator, denominator=denominator\n        )\n    if isinstance(other, GenericDimension):\n        return GenericCompositeDimension(numerator=[GenericDimension(cls), other])\n    if isinstance(other, MeasurementUnitType):\n        return GenericCompositeDimension(\n            numerator=[\n                GenericDimension(cls),\n                GenericDimension(other),\n            ]\n        )\n    raise DescriptorBinaryOperationError(f\"cannot multiply {cls} with {other}. \")\n
    "},{"location":"descriptors/#property_utils.units.descriptors.MeasurementUnitMeta.__pow__","title":"__pow__(power)","text":"

    Defines exponentiation of MeasurementUnit types.

    Examples:

    >>> class TimeUnit(MeasurementUnit): ...\n>>> TimeUnit**3\n<GenericDimension: TimeUnit^3>\n
    Source code in src/property_utils/units/descriptors.py
    def __pow__(cls, power: float) -> \"GenericDimension\":\n    \"\"\"\n    Defines exponentiation of MeasurementUnit types.\n\n    Examples:\n        >>> class TimeUnit(MeasurementUnit): ...\n        >>> TimeUnit**3\n        <GenericDimension: TimeUnit^3>\n    \"\"\"\n    return GenericDimension(cls, power)\n
    "},{"location":"descriptors/#property_utils.units.descriptors.MeasurementUnitMeta.__truediv__","title":"__truediv__(other)","text":"

    Defines division between MeasurementUnit types and other generic descriptors.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit): ...\n>>> class TimeUnit(MeasurementUnit): ...\n>>> TemperatureUnit / TimeUnit\n<GenericCompositeDimension: TemperatureUnit / TimeUnit>\n
    Source code in src/property_utils/units/descriptors.py
    def __truediv__(cls, other: GenericUnitDescriptor) -> \"GenericCompositeDimension\":\n    \"\"\"\n    Defines division between MeasurementUnit types and other generic\n    descriptors.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit): ...\n        >>> class TimeUnit(MeasurementUnit): ...\n        >>> TemperatureUnit / TimeUnit\n        <GenericCompositeDimension: TemperatureUnit / TimeUnit>\n    \"\"\"\n    if isinstance(other, GenericCompositeDimension):\n        numerator = other.denominator.copy()\n        denominator = other.numerator.copy()\n        numerator.append(GenericDimension(cls))\n        return GenericCompositeDimension(\n            numerator=numerator, denominator=denominator\n        )\n    if isinstance(other, GenericDimension):\n        return GenericCompositeDimension(\n            numerator=[GenericDimension(cls)], denominator=[other]\n        )\n    if isinstance(other, MeasurementUnitType):\n        return GenericCompositeDimension(\n            numerator=[GenericDimension(cls)],\n            denominator=[GenericDimension(other)],\n        )\n    raise DescriptorBinaryOperationError(f\"cannot divide {cls} with {other}. \")\n
    "},{"location":"descriptors/#property_utils.units.descriptors.MeasurementUnitMeta.inverse_generic","title":"inverse_generic()","text":"

    Create a generic composite with inverse units.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit): ...\n>>> TemperatureUnit.inverse_generic()\n<GenericCompositeDimension:  / TemperatureUnit>\n
    Source code in src/property_utils/units/descriptors.py
    def inverse_generic(cls) -> \"GenericCompositeDimension\":\n    \"\"\"\n    Create a generic composite with inverse units.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit): ...\n        >>> TemperatureUnit.inverse_generic()\n        <GenericCompositeDimension:  / TemperatureUnit>\n    \"\"\"\n    return GenericCompositeDimension([], [GenericDimension(cls)])\n
    "},{"location":"descriptors/#property_utils.units.descriptors.MeasurementUnitMeta.is_equivalent","title":"is_equivalent(other)","text":"

    Returns True if this generic is equivalent to the given one, False otherwise.

    A generic can be equivalent with another generic if the latter or the former is an alias.

    Examples:

    >>> class LengthUnit(MeasurementUnit): ...\n>>> class MassUnit(MeasurementUnit): ...\n>>> class TimeUnit(MeasurementUnit): ...\n>>> class ForceUnit(AliasMeasurementUnit):\n...     @classmethod\n...     def aliased_generic_descriptor(cls):\n...         return MassUnit * LengthUnit / (TimeUnit**2)\n
    >>> ForceUnit.is_equivalent(MassUnit * LengthUnit / (TimeUnit**2))\nTrue\n
    >>> class EnergyUnit(AliasMeasurementUnit):\n...     @classmethod\n...     def aliased_generic_descriptor(cls):\n...         return ForceUnit * LengthUnit\n
    >>> EnergyUnit.is_equivalent(MassUnit * (LengthUnit**2) / (TimeUnit**2))\nTrue\n
    Source code in src/property_utils/units/descriptors.py
    def is_equivalent(cls, other: GenericUnitDescriptor) -> bool:\n    \"\"\"\n    Returns True if this generic is equivalent to the given one, False otherwise.\n\n    A generic can be equivalent with another generic if the latter or the former\n    is an alias.\n\n    Examples:\n        >>> class LengthUnit(MeasurementUnit): ...\n        >>> class MassUnit(MeasurementUnit): ...\n        >>> class TimeUnit(MeasurementUnit): ...\n        >>> class ForceUnit(AliasMeasurementUnit):\n        ...     @classmethod\n        ...     def aliased_generic_descriptor(cls):\n        ...         return MassUnit * LengthUnit / (TimeUnit**2)\n\n        >>> ForceUnit.is_equivalent(MassUnit * LengthUnit / (TimeUnit**2))\n        True\n\n        >>> class EnergyUnit(AliasMeasurementUnit):\n        ...     @classmethod\n        ...     def aliased_generic_descriptor(cls):\n        ...         return ForceUnit * LengthUnit\n\n        >>> EnergyUnit.is_equivalent(MassUnit * (LengthUnit**2) / (TimeUnit**2))\n        True\n    \"\"\"\n    if isinstance(other, MeasurementUnitType):\n        return cls == other\n\n    if isinstance(other, GenericDimension):\n        if cls == other.unit_type and other.power == 1:\n            return True\n\n        if issubclass(other.unit_type, AliasMeasurementUnit):\n            return (\n                other.unit_type.aliased_generic_descriptor() ** other.power\n            ).is_equivalent(cls)\n\n        if issubclass(cls, AliasMeasurementUnit):\n            return cls.aliased_generic_descriptor().is_equivalent(other)\n\n    elif isinstance(other, GenericCompositeDimension):\n        if (\n            other.denominator == []\n            and len(other.numerator) == 1\n            and other.numerator[0].is_equivalent(cls)\n        ):\n            return True\n\n        if issubclass(cls, AliasMeasurementUnit):\n            return cls.aliased_generic_descriptor().is_equivalent(other)\n\n    return False\n
    "},{"location":"descriptors/#property_utils.units.descriptors.MeasurementUnitMeta.to_si","title":"to_si()","text":"

    Create a MeasurementUnit with SI units.

    Examples:

    >>> class TemperatureUnit(MeasurementUnit):\n...     CELCIUS = \"C\"\n...     KELVIN = \"K\"\n...     @classmethod\n...     def si(cls):\n...         return cls.KELVIN\n>>> TemperatureUnit.to_si()\n<TemperatureUnit: K>\n
    Source code in src/property_utils/units/descriptors.py
    def to_si(cls) -> \"MeasurementUnit\":\n    \"\"\"\n    Create a MeasurementUnit with SI units.\n\n    Examples:\n        >>> class TemperatureUnit(MeasurementUnit):\n        ...     CELCIUS = \"C\"\n        ...     KELVIN = \"K\"\n        ...     @classmethod\n        ...     def si(cls):\n        ...         return cls.KELVIN\n        >>> TemperatureUnit.to_si()\n        <TemperatureUnit: K>\n    \"\"\"\n    if hasattr(cls, \"si\"):\n        return cls.si()\n    raise NotImplementedError\n
    "},{"location":"descriptors/#property_utils.units.descriptors.UnitDescriptor","title":"UnitDescriptor","text":"

    Bases: Protocol

    Descriptor for a property unit that has a specific unit, e.g. cm^2 or ft^2.

    Source code in src/property_utils/units/descriptors.py
    class UnitDescriptor(Protocol):\n    \"\"\"\n    Descriptor for a property unit that has a specific unit, e.g. cm^2 or ft^2.\n    \"\"\"\n\n    def si(self) -> \"UnitDescriptor\":\n        \"\"\"\n        Returns this descriptor with SI units.\n        \"\"\"\n\n    def isinstance(self, generic: GenericUnitDescriptor) -> bool:\n        \"\"\"\n        Returns True if the UnitDescriptor is an instance of the generic, False\n        otherwise.\n\n        A unit descriptor is an instance of a generic if the generic of the unit\n        descriptor is equal to the generic.\n\n        Equality between generics is checked with the `==` operator.\n        \"\"\"\n\n    def isinstance_equivalent(self, generic: GenericUnitDescriptor) -> bool:\n        \"\"\"\n        Returns True if the UnitDescriptor is an instance-equivalent of the generic,\n        False otherwise.\n\n        A unit descriptor is an instance-equivalent of a generic if the generic of the\n        unit descriptor is equivalent to the generic.\n\n        Equivalence between generics is checked with the `is_equivalent` method.\n        \"\"\"\n\n    def to_generic(self) -> GenericUnitDescriptor:\n        \"\"\"\n        Create a generic descriptor from this UnitDescriptor.\n        \"\"\"\n\n    def inverse(self) -> \"CompositeDimension\":\n        \"\"\"\n        Create a composite with inverse units.\n        \"\"\"\n\n    def __mul__(self, descriptor: \"UnitDescriptor\") -> \"CompositeDimension\": ...\n\n    def __truediv__(self, descriptor: \"UnitDescriptor\") -> \"CompositeDimension\": ...\n\n    def __pow__(self, power: float) -> \"UnitDescriptor\": ...\n\n    def __hash__(self) -> int: ...\n\n    def __str__(self) -> str: ...\n
    "},{"location":"descriptors/#property_utils.units.descriptors.UnitDescriptor.inverse","title":"inverse()","text":"

    Create a composite with inverse units.

    Source code in src/property_utils/units/descriptors.py
    def inverse(self) -> \"CompositeDimension\":\n    \"\"\"\n    Create a composite with inverse units.\n    \"\"\"\n
    "},{"location":"descriptors/#property_utils.units.descriptors.UnitDescriptor.isinstance","title":"isinstance(generic)","text":"

    Returns True if the UnitDescriptor is an instance of the generic, False otherwise.

    A unit descriptor is an instance of a generic if the generic of the unit descriptor is equal to the generic.

    Equality between generics is checked with the == operator.

    Source code in src/property_utils/units/descriptors.py
    def isinstance(self, generic: GenericUnitDescriptor) -> bool:\n    \"\"\"\n    Returns True if the UnitDescriptor is an instance of the generic, False\n    otherwise.\n\n    A unit descriptor is an instance of a generic if the generic of the unit\n    descriptor is equal to the generic.\n\n    Equality between generics is checked with the `==` operator.\n    \"\"\"\n
    "},{"location":"descriptors/#property_utils.units.descriptors.UnitDescriptor.isinstance_equivalent","title":"isinstance_equivalent(generic)","text":"

    Returns True if the UnitDescriptor is an instance-equivalent of the generic, False otherwise.

    A unit descriptor is an instance-equivalent of a generic if the generic of the unit descriptor is equivalent to the generic.

    Equivalence between generics is checked with the is_equivalent method.

    Source code in src/property_utils/units/descriptors.py
    def isinstance_equivalent(self, generic: GenericUnitDescriptor) -> bool:\n    \"\"\"\n    Returns True if the UnitDescriptor is an instance-equivalent of the generic,\n    False otherwise.\n\n    A unit descriptor is an instance-equivalent of a generic if the generic of the\n    unit descriptor is equivalent to the generic.\n\n    Equivalence between generics is checked with the `is_equivalent` method.\n    \"\"\"\n
    "},{"location":"descriptors/#property_utils.units.descriptors.UnitDescriptor.si","title":"si()","text":"

    Returns this descriptor with SI units.

    Source code in src/property_utils/units/descriptors.py
    def si(self) -> \"UnitDescriptor\":\n    \"\"\"\n    Returns this descriptor with SI units.\n    \"\"\"\n
    "},{"location":"descriptors/#property_utils.units.descriptors.UnitDescriptor.to_generic","title":"to_generic()","text":"

    Create a generic descriptor from this UnitDescriptor.

    Source code in src/property_utils/units/descriptors.py
    def to_generic(self) -> GenericUnitDescriptor:\n    \"\"\"\n    Create a generic descriptor from this UnitDescriptor.\n    \"\"\"\n
    "},{"location":"feedback/","title":"Feedback","text":""},{"location":"feedback/#got-bugs-or-an-idea-for-a-new-feature","title":"Got bugs or an idea for a new feature?","text":"

    Great! (well, not if you've got bugs) open up an issue in the project's repo: issues.

    "},{"location":"installation/","title":"Installation","text":"

    You'll need a Python version bigger or equal to 3.8. If you're new to programming this page could help with learning resources.

    Once you've got Python setup you can install property-utils from your IDE or via pip:

    pip install property-utils\n

    "},{"location":"installation/#dependencies","title":"Dependencies","text":"

    property-utils's only dependency is the typing-extensions library.

    "},{"location":"property/","title":"property","text":"

    This module defines the Property class and property arithmetics.

    "},{"location":"property/#property_utils.properties.property.AbsoluteTemperatureUnitConverter","title":"AbsoluteTemperatureUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    Convert absolute temperature with this converter.

    Examples:

    >>> AbsoluteTemperatureUnitConverter.convert(10, AbsoluteTemperatureUnit.KELVIN, AbsoluteTemperatureUnit.RANKINE)\n18.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(AbsoluteTemperatureUnit)\nclass AbsoluteTemperatureUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    Convert absolute temperature with this converter.\n\n    Examples:\n        >>> AbsoluteTemperatureUnitConverter.convert(10, AbsoluteTemperatureUnit.KELVIN, AbsoluteTemperatureUnit.RANKINE)\n        18.0\n    \"\"\"\n\n    reference_unit = AbsoluteTemperatureUnit.KELVIN\n    conversion_map = {\n        AbsoluteTemperatureUnit.KELVIN: 1,\n        AbsoluteTemperatureUnit.RANKINE: 1.8,\n    }\n\n    @override\n    @classmethod\n    def convert(\n        cls,\n        value: float,\n        from_descriptor: UnitDescriptor,\n        to_descriptor: UnitDescriptor,\n    ) -> float:\n        if not isinstance(value, (float, int)):\n            raise UnitConversionError(f\"invalid 'value': {value}; expected numeric. \")\n        if from_descriptor.isinstance(\n            RelativeTemperatureUnit\n        ) or to_descriptor.isinstance(RelativeTemperatureUnit):\n            return RelativeTemperatureUnitConverter.convert(\n                value, from_descriptor, to_descriptor\n            )\n        return value * cls.get_factor(from_descriptor, to_descriptor)\n
    "},{"location":"property/#property_utils.properties.property.AliasEnergyUnitConverter","title":"AliasEnergyUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    Convert energy units with this converter.

    Examples:

    >>> AliasEnergyUnitConverter.convert(2500, EnergyUnit.JOULE, EnergyUnit.KILO_JOULE)\n2.5\n
    Source code in src/property_utils/units/converters.py
    @register_converter(EnergyUnit)\nclass AliasEnergyUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    Convert energy units with this converter.\n\n    Examples:\n        >>> AliasEnergyUnitConverter.convert(2500, EnergyUnit.JOULE, EnergyUnit.KILO_JOULE)\n        2.5\n    \"\"\"\n\n    reference_unit = EnergyUnit.JOULE\n    conversion_map = {\n        EnergyUnit.JOULE: 1,\n        EnergyUnit.KILO_JOULE: UnitPrefix.KILO.inverse(),\n        EnergyUnit.MEGA_JOULE: UnitPrefix.MEGA.inverse(),\n        EnergyUnit.GIGA_JOULE: UnitPrefix.GIGA.inverse(),\n        EnergyUnit.CALORIE: 1 / 4.184,\n        EnergyUnit.KILO_CALORIE: (1 / 4.184) * UnitPrefix.KILO.inverse(),\n        EnergyUnit.BTU: 1 / 1055.0,\n        EnergyUnit.ELECTRONVOLT: 6.242e18,\n        EnergyUnit.WATTHOUR: 1 / 3600,\n        EnergyUnit.KILO_WATTHOUR: (1 / 3600) * UnitPrefix.KILO.inverse(),\n    }\n
    "},{"location":"property/#property_utils.properties.property.AliasForceUnitConverter","title":"AliasForceUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    Convert force units with this converter.

    Examples:

    >>> AliasForceUnitConverter.convert(2, ForceUnit.NEWTON, ForceUnit.DYNE)\n200000.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(ForceUnit)\nclass AliasForceUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    Convert force units with this converter.\n\n    Examples:\n        >>> AliasForceUnitConverter.convert(2, ForceUnit.NEWTON, ForceUnit.DYNE)\n        200000.0\n    \"\"\"\n\n    reference_unit = ForceUnit.NEWTON\n    conversion_map = {ForceUnit.NEWTON: 1, ForceUnit.DYNE: 100_000}\n
    "},{"location":"property/#property_utils.properties.property.AliasPowerUnitConverter","title":"AliasPowerUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    Convert power units with this converter.

    Examples:

    >>> AliasPowerUnitConverter.convert(5, PowerUnit.KILO_WATT, PowerUnit.WATT)\n5000.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(PowerUnit)\nclass AliasPowerUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    Convert power units with this converter.\n\n    Examples:\n        >>> AliasPowerUnitConverter.convert(5, PowerUnit.KILO_WATT, PowerUnit.WATT)\n        5000.0\n    \"\"\"\n\n    reference_unit = PowerUnit.WATT\n    conversion_map = {\n        PowerUnit.WATT: 1,\n        PowerUnit.KILO_WATT: UnitPrefix.KILO.inverse(),\n        PowerUnit.MEGA_WATT: UnitPrefix.MEGA.inverse(),\n        PowerUnit.GIGA_WATT: UnitPrefix.GIGA.inverse(),\n    }\n
    "},{"location":"property/#property_utils.properties.property.AliasPressureUnitConverter","title":"AliasPressureUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    Convert pressure units with this converter.

    Examples:

    >>> AliasPressureUnitConverter.convert(2, PressureUnit.BAR, PressureUnit.KILO_PASCAL)\n200.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(PressureUnit)\nclass AliasPressureUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    Convert pressure units with this converter.\n\n    Examples:\n        >>> AliasPressureUnitConverter.convert(2, PressureUnit.BAR, PressureUnit.KILO_PASCAL)\n        200.0\n    \"\"\"\n\n    reference_unit = PressureUnit.BAR\n    conversion_map = {\n        PressureUnit.MILLI_BAR: UnitPrefix.MILLI.inverse(),\n        PressureUnit.BAR: 1,\n        PressureUnit.PSI: 14.5038,\n        PressureUnit.PASCAL: 100_000,\n        PressureUnit.KILO_PASCAL: 100,\n        PressureUnit.MEGA_PASCAL: 0.1,\n    }\n
    "},{"location":"property/#property_utils.properties.property.AmountUnitConverter","title":"AmountUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    Convert amount units with this converter.

    Examples:

    >>> AmountUnitConverter.convert(2000, AmountUnit.MOL, AmountUnit.KILO_MOL)\n2.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(AmountUnit)\nclass AmountUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    Convert amount units with this converter.\n\n    Examples:\n        >>> AmountUnitConverter.convert(2000, AmountUnit.MOL, AmountUnit.KILO_MOL)\n        2.0\n    \"\"\"\n\n    reference_unit = AmountUnit.MOL\n    conversion_map = {AmountUnit.MOL: 1, AmountUnit.KILO_MOL: UnitPrefix.KILO.inverse()}\n
    "},{"location":"property/#property_utils.properties.property.AreaUnitConverter","title":"AreaUnitConverter","text":"

    Bases: ExponentiatedUnitConverter

    Convert area units with this converter.

    Examples:

    >>> AreaUnitConverter.convert(1, LengthUnit.METER**2, LengthUnit.CENTI_METER**2)\n10000.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(LengthUnit**2)\nclass AreaUnitConverter(ExponentiatedUnitConverter):\n    \"\"\"\n    Convert area units with this converter.\n\n    Examples:\n        >>> AreaUnitConverter.convert(1, LengthUnit.METER**2, LengthUnit.CENTI_METER**2)\n        10000.0\n    \"\"\"\n
    "},{"location":"property/#property_utils.properties.property.ElectricCurrentUnitConverter","title":"ElectricCurrentUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    Convert electric current units with this converter.

    Examples:

    >>> ElectricCurrentUnitConverter.convert(1000, ElectricCurrentUnit.MILLI_AMPERE, ElectricCurrentUnit.AMPERE)\n1.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(ElectricCurrentUnit)\nclass ElectricCurrentUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    Convert electric current units with this converter.\n\n    Examples:\n        >>> ElectricCurrentUnitConverter.convert(1000, ElectricCurrentUnit.MILLI_AMPERE, ElectricCurrentUnit.AMPERE)\n        1.0\n    \"\"\"\n\n    reference_unit = ElectricCurrentUnit.AMPERE\n    conversion_map = {\n        ElectricCurrentUnit.MILLI_AMPERE: UnitPrefix.MILLI.inverse(),\n        ElectricCurrentUnit.AMPERE: 1,\n        ElectricCurrentUnit.KILO_AMPERE: UnitPrefix.KILO.inverse(),\n    }\n
    "},{"location":"property/#property_utils.properties.property.EnergyUnitConverter","title":"EnergyUnitConverter","text":"

    Bases: CompositeUnitConverter

    Convert energy units (mass * length^2 / time^2) with this converter.

    Examples:

    >>> from_unit = MassUnit.KILO_GRAM * (LengthUnit.METER**2) / (TimeUnit.MINUTE**2)\n>>> to_unit = MassUnit.METRIC_TONNE * (LengthUnit.CENTI_METER**2) / (TimeUnit.MINUTE**2)\n>>> EnergyUnitConverter.convert(25, from_unit, to_unit)\n250.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(EnergyUnit.aliased_generic_descriptor())\nclass EnergyUnitConverter(CompositeUnitConverter):\n    \"\"\"\n    Convert energy units (mass * length^2 / time^2) with this converter.\n\n    Examples:\n        >>> from_unit = MassUnit.KILO_GRAM * (LengthUnit.METER**2) / (TimeUnit.MINUTE**2)\n        >>> to_unit = MassUnit.METRIC_TONNE * (LengthUnit.CENTI_METER**2) / (TimeUnit.MINUTE**2)\n        >>> EnergyUnitConverter.convert(25, from_unit, to_unit)\n        250.0\n    \"\"\"\n
    "},{"location":"property/#property_utils.properties.property.ForceUnitConverter","title":"ForceUnitConverter","text":"

    Bases: CompositeUnitConverter

    Convert force units (mass * length / time^2) with this converter.

    Examples:

    >>> from_unit = MassUnit.KILO_GRAM * LengthUnit.CENTI_METER / (TimeUnit.SECOND**2)\n>>> to_unit = MassUnit.GRAM * LengthUnit.METER / (TimeUnit.SECOND**2)\n>>> ForceUnitConverter.convert(100, from_unit, to_unit)\n1000.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(ForceUnit.aliased_generic_descriptor())\nclass ForceUnitConverter(CompositeUnitConverter):\n    \"\"\"\n    Convert force units (mass * length / time^2) with this converter.\n\n    Examples:\n        >>> from_unit = MassUnit.KILO_GRAM * LengthUnit.CENTI_METER / (TimeUnit.SECOND**2)\n        >>> to_unit = MassUnit.GRAM * LengthUnit.METER / (TimeUnit.SECOND**2)\n        >>> ForceUnitConverter.convert(100, from_unit, to_unit)\n        1000.0\n    \"\"\"\n
    "},{"location":"property/#property_utils.properties.property.LengthUnitConverter","title":"LengthUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    Convert length units with this converter.

    Examples:

    >>> LengthUnitConverter.convert(2000, LengthUnit.MILLI_METER, LengthUnit.METER)\n2.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(LengthUnit)\nclass LengthUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    Convert length units with this converter.\n\n    Examples:\n        >>> LengthUnitConverter.convert(2000, LengthUnit.MILLI_METER, LengthUnit.METER)\n        2.0\n    \"\"\"\n\n    reference_unit = LengthUnit.METER\n    conversion_map = {\n        LengthUnit.MILLI_METER: UnitPrefix.MILLI.inverse(),\n        LengthUnit.CENTI_METER: UnitPrefix.CENTI.inverse(),\n        LengthUnit.METER: 1,\n        LengthUnit.KILO_METER: UnitPrefix.KILO.inverse(),\n        LengthUnit.INCH: 39.37,\n        LengthUnit.FOOT: 3.281,\n        LengthUnit.YARD: 1.094,\n        LengthUnit.MILE: 1 / 1609,\n        LengthUnit.NAUTICAL_MILE: 1 / 1852,\n    }\n
    "},{"location":"property/#property_utils.properties.property.MassUnitConverter","title":"MassUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    Convert mass units with this converter.

    Examples:

    >>> MassUnitConverter.convert(10, MassUnit.KILO_GRAM, MassUnit.GRAM)\n10000.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(MassUnit)\nclass MassUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    Convert mass units with this converter.\n\n    Examples:\n        >>> MassUnitConverter.convert(10, MassUnit.KILO_GRAM, MassUnit.GRAM)\n        10000.0\n    \"\"\"\n\n    reference_unit = MassUnit.KILO_GRAM\n    conversion_map = {\n        MassUnit.MILLI_GRAM: UnitPrefix.KILO * UnitPrefix.MILLI.inverse(),\n        MassUnit.GRAM: UnitPrefix.KILO,\n        MassUnit.KILO_GRAM: 1,\n        MassUnit.METRIC_TONNE: 1 / 1_000.0,\n        MassUnit.POUND: 2.205,\n    }\n
    "},{"location":"property/#property_utils.properties.property.PowerUnitConverter","title":"PowerUnitConverter","text":"

    Bases: CompositeUnitConverter

    Convert power units (mass * length^2 / time^3) with this converter.

    Examples:

    >>> from_unit = MassUnit.KILO_GRAM * (LengthUnit.METER**2) / (TimeUnit.MINUTE**3)\n>>> to_unit = MassUnit.METRIC_TONNE * (LengthUnit.CENTI_METER**2) / (TimeUnit.MINUTE**3)\n>>> PowerUnitConverter.convert(15, from_unit, to_unit)\n150.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(PowerUnit.aliased_generic_descriptor())\nclass PowerUnitConverter(CompositeUnitConverter):\n    \"\"\"\n    Convert power units (mass * length^2 / time^3) with this converter.\n\n    Examples:\n        >>> from_unit = MassUnit.KILO_GRAM * (LengthUnit.METER**2) / (TimeUnit.MINUTE**3)\n        >>> to_unit = MassUnit.METRIC_TONNE * (LengthUnit.CENTI_METER**2) / (TimeUnit.MINUTE**3)\n        >>> PowerUnitConverter.convert(15, from_unit, to_unit)\n        150.0\n    \"\"\"\n
    "},{"location":"property/#property_utils.properties.property.PressureUnitConverter","title":"PressureUnitConverter","text":"

    Bases: CompositeUnitConverter

    Convert pressure units (mass / length / time^2) with this converter.

    Examples:

    >>> from_unit = MassUnit.GRAM / LengthUnit.CENTI_METER / (TimeUnit.HOUR**2)\n>>> to_unit = MassUnit.KILO_GRAM / LengthUnit.METER / (TimeUnit.HOUR**2)\n>>> PressureUnitConverter.convert(50, from_unit, to_unit)\n5.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(PressureUnit.aliased_generic_descriptor())\nclass PressureUnitConverter(CompositeUnitConverter):\n    \"\"\"\n    Convert pressure units (mass / length / time^2) with this converter.\n\n    Examples:\n        >>> from_unit = MassUnit.GRAM / LengthUnit.CENTI_METER / (TimeUnit.HOUR**2)\n        >>> to_unit = MassUnit.KILO_GRAM / LengthUnit.METER / (TimeUnit.HOUR**2)\n        >>> PressureUnitConverter.convert(50, from_unit, to_unit)\n        5.0\n    \"\"\"\n
    "},{"location":"property/#property_utils.properties.property.Property","title":"Property dataclass","text":"

    A Property describes a value with a unit of measurement.

    A Property can have any 'value' or 'unit'; validations are not applied to it. For example, a Property with length units and negative value is valid.

    Source code in src/property_utils/properties/property.py
    @dataclass\nclass Property:\n    \"\"\"\n    A Property describes a value with a unit of measurement.\n\n    A Property can have any 'value' or 'unit'; validations are not applied to it.\n    For example, a Property with length units and negative value is valid.\n    \"\"\"\n\n    value: float\n    unit: UnitDescriptor\n    unit_converter: Optional[Type[UnitConverter]] = None\n    default_units: ClassVar[Optional[UnitDescriptor]] = None\n\n    def __init__(self, value: float, unit: Optional[UnitDescriptor] = None) -> None:\n        if not isinstance(value, (float, int)):\n            raise PropertyValidationError(\n                f\"cannot create Property; invalid 'value': {value}; expected numeric. \"\n            )\n\n        if unit is None and self.default_units is not None:\n            unit = self.default_units\n\n        if not isinstance(unit, (MeasurementUnit, Dimension, CompositeDimension)):\n            raise PropertyValidationError(\n                f\"cannot create Property; invalid 'unit': {unit}. Expected an instance\"\n                \" of one of: MeasurementUnit, Dimension, CompositeDimension. \"\n            )\n\n        self.value = value\n        self.unit = unit\n\n    def eq(self, other: \"Property\", *, rel_tol=1e-9, abs_tol=0) -> bool:\n        \"\"\"\n        Perform equality comparison between this and some other Property. This method\n        of testing equality is preferable to the equality operator '==' because float\n        point tolerance is taken into account.\n\n        rel_tol is the maximum difference for being considered \"close\", relative\n        to the magnitude of the input values.\n        abs_tol is the maximum difference for being considered \"close\", regardless of\n        the magnitude of the input values.\n        For the values to be considered close, the difference between them must be\n        smaller than at least one of the tolerances.\n\n        Raises `PropertyBinaryOperationError` if an error occurs during conversion\n        of other's units.\n\n        Examples:\n            >>> from property_utils.units.units import AbsoluteTemperatureUnit, LengthUnit\n            >>> T1 = Property(33.333333, AbsoluteTemperatureUnit.KELVIN)\n            >>> T2 = Property(100/3, AbsoluteTemperatureUnit.KELVIN)\n            >>> T1 == T2\n            False\n            >>> T1.eq(T2)\n            False\n            >>> T1.eq(T2, rel_tol=0.1)\n            True\n        \"\"\"\n        if not isinstance(other, Property):\n            return False\n        if not self.unit.isinstance_equivalent(other.unit.to_generic()):\n            return False\n        try:\n            prop = other.to_unit(self.unit) if self.unit != other.unit else other\n        except PropertyUtilsException as exc:\n            raise PropertyBinaryOperationError(\n                f\"during conversion of {other} to ({self.unit}) units an error occured: \",\n                exc,\n            ) from None\n        return isclose(self.value, prop.value, rel_tol=rel_tol, abs_tol=abs_tol)\n\n    def to_si(self) -> Self:\n        \"\"\"\n        Create a new property with SI units.\n\n        Raises `ImpossiblePropertyUnitConverion` if there is no converter registered\n        for the unit.\n\n        Raises `InvalidUnitConversion` if any error occurs in the unit conversion.\n\n        Examples:\n            >>> from property_utils.units.units import RelativeTemperatureUnit\n            >>> T = Property(100, RelativeTemperatureUnit.CELCIUS)\n            >>> T.to_si()\n            <Property: 373.15 K>\n        \"\"\"\n        if isinstance(self.unit, MeasurementUnit):\n            return self.to_unit(self.unit.si())\n        if isinstance(self.unit, Dimension):\n            return self.to_unit(self.unit.unit.si() ** self.unit.power)\n        if isinstance(self.unit, CompositeDimension):\n            return self.to_unit(self.unit.to_generic().to_si())\n        raise PropertyValidationError(\n            f\"cannot convert Property to SI; 'unit' is invalid: {self.unit}. \"\n        )\n\n    def to_unit(self, unit: UnitDescriptor) -> Self:\n        \"\"\"\n        Create a new property with specified unit.\n\n        Raises `PropertyUnitConversionError` if the unit is not of the same type.\n\n        Raises `ImpossiblePropertyUnitConverion` if there is no converter registered\n        for the unit.\n\n        Raises `UnitConversionError` if any error occurs in the unit conversion.\n\n        Examples:\n            >>> from property_utils.units.units import RelativeTemperatureUnit\n            >>> T = Property(100, RelativeTemperatureUnit.CELCIUS)\n            >>> T.to_unit(RelativeTemperatureUnit.FAHRENHEIT)\n            <Property: 212.0 \u00b0F>\n        \"\"\"\n        if self.unit == unit:\n            return self.__class__(unit=self.unit, value=self.value)\n\n        if not unit.isinstance_equivalent(self.unit.to_generic()):\n            raise PropertyUnitConversionError(\n                f\"cannot convert {self} to ({unit}) units; 'unit' should be an instance\"\n                f\" of {self.unit.to_generic()}. \"\n            )\n        try:\n            converter = self._converter()\n        except UndefinedConverterError:\n            raise PropertyUnitConversionError(\n                f\"cannot convert property {self} to units: {unit}; no unit converter \"\n                f\" found for {unit.to_generic()}. \"\n                \"Did you forget to @register_converter? \"\n            ) from None\n        try:\n            value = converter.convert(self.value, self.unit, unit)\n        except UnitConversionError as exc:\n            raise exc from None\n        return self.__class__(value=value, unit=unit)\n\n    def __neg__(self) -> Self:\n        \"\"\"\n        Defines negation of properties.\n\n        Examples:\n            >>> from property_utils.units.units import RelativeTemperatureUnit\n            >>> T = Property(3, RelativeTemperatureUnit.CELCIUS)\n            >>> -T\n            <Property: -3 \u00b0C>\n        \"\"\"\n        return self.__class__(-self.value, self.unit)\n\n    def __mul__(self, other) -> \"Property\":\n        \"\"\"\n        Defines multiplication between properties and numerics.\n\n        Examples:\n            >>> from property_utils.units.units import AbsoluteTemperatureUnit, LengthUnit\n            >>> T = Property(300, AbsoluteTemperatureUnit.KELVIN)\n            >>> 2*T\n            <Property: 600 K>\n            >>> A = Property(10, LengthUnit.METER**2)\n            >>> T * A\n            <Property: 3000 (m^2) * K>\n        \"\"\"\n        if isinstance(other, (float, int)):\n            return self.__class__(self.value * other, self.unit)\n        if isinstance(other, Property):\n            _other = self._unit_preconversion(other)\n            return Property(\n                self.value * _other.value, self._simplify_units(self.unit * _other.unit)\n            )\n        raise PropertyBinaryOperationError(\n            f\"cannot multiply {self} with {other}; \"\n            \"second operand must be numeric or Property. \"\n        )\n\n    def __rmul__(self, other) -> \"Property\":\n        \"\"\"\n        Defines multiplication between properties and numerics.\n\n        Examples:\n            >>> from property_utils.units.units import AbsoluteTemperatureUnit, LengthUnit\n            >>> T = Property(300, AbsoluteTemperatureUnit.KELVIN)\n            >>> 2*T\n            <Property: 600 K>\n            >>> A = Property(10, LengthUnit.METER**2)\n            >>> T * A\n            <Property: 3000 (m^2) * K>\n        \"\"\"\n        return self.__mul__(other)\n\n    def __truediv__(self, other) -> \"Property\":\n        \"\"\"\n        Defines division between properties and numerics.\n\n        Examples:\n            >>> from property_utils.units.units import AbsoluteTemperatureUnit, LengthUnit\n            >>> T = Property(500, AbsoluteTemperatureUnit.KELVIN)\n            >>> T/2\n            <Property: 250.0 K>\n            >>> A = Property(10, LengthUnit.METER**2)\n            >>> T / A\n            <Property: 50.0 K / (m^2)>\n        \"\"\"\n        if isinstance(other, (float, int)):\n            try:\n                value = self.value / other\n            except ZeroDivisionError:\n                raise PropertyBinaryOperationError(\n                    f\"cannot divide {self} with {other}; denominator is zero. \"\n                ) from None\n            return Property(value, self.unit)\n        if isinstance(other, Property):\n            _other = self._unit_preconversion(other)\n            try:\n                value = self.value / _other.value\n            except ZeroDivisionError:\n                raise PropertyBinaryOperationError(\n                    f\"cannot divide {self} with {other}; denominator's value is zero. \"\n                ) from None\n            return Property(value, self._simplify_units(self.unit / _other.unit))\n        raise PropertyBinaryOperationError(\n            f\"cannot divide {self} with {other}; \"\n            \"denominator must be numeric or Property. \"\n        )\n\n    def __rtruediv__(self, other) -> \"Property\":\n        \"\"\"\n        Defines right division between properties and numerics.\n\n        Examples:\n            >>> from property_utils.units.units import AbsoluteTemperatureUnit\n            >>> T = Property(500, AbsoluteTemperatureUnit.KELVIN)\n            >>> 100/T\n            <Property: 0.2  / K>\n        \"\"\"\n        if isinstance(other, (float, int)):\n            try:\n                value = other / self.value\n            except ZeroDivisionError:\n                raise PropertyBinaryOperationError(\n                    f\"cannot divide {self} with {other}; denominator is zero. \"\n                ) from None\n            return Property(value, self.unit.inverse())\n        if isinstance(other, Property):\n            try:\n                value = other.value / self.value\n            except ZeroDivisionError:\n                raise PropertyBinaryOperationError(\n                    f\"cannot divide {self} with {other}; denominator's value is zero. \"\n                ) from None\n            return Property(value, self._simplify_units(other.unit / self.unit))\n        raise PropertyBinaryOperationError(\n            f\"cannot divide {self} with {other}; \"\n            \"numerator must be numeric or Property. \"\n        )\n\n    def __add__(self, other) -> Self:\n        \"\"\"\n        Defines addition between properties.\n\n        Examples:\n            >>> from property_utils.units.units import LengthUnit\n            >>> x1 = Property(15, LengthUnit.METER)\n            >>> x2 = Property(5, LengthUnit.METER)\n            >>> x1 + x2\n            <Property: 20 m>\n        \"\"\"\n        if not isinstance(other, Property):\n            raise PropertyBinaryOperationError(\n                f\"cannot add {other} to ({self}); {other} is not a Property; \"\n                \"only properties can be added to properties. \"\n            )\n        if not self.unit.isinstance_equivalent(other.unit.to_generic()):\n            raise PropertyBinaryOperationError(\n                f\"cannot add ({other}) to ({self}); \"\n                f\"({other}) must have ({self.unit.to_generic()}) units. \"\n            )\n        try:\n            prop = other.to_unit(self.unit) if self.unit != other.unit else other\n        except PropertyUnitConversionError:\n            raise PropertyBinaryOperationError(\n                f\"cannot add ({other}) to ({self}); ({other}) does not have the same \"\n                f\"units as ({self}) and there is no unit converter registered for \"\n                f\"({self.unit.to_generic()}). \"\n            ) from None\n        except UnitConversionError as exc:\n            raise PropertyBinaryOperationError(\n                f\"cannot add ({other}) to ({self});\", exc\n            ) from None\n        return self.__class__(self.value + prop.value, self.unit)\n\n    def __radd__(self, other) -> Self:\n        \"\"\"\n        Defines right addition between properties.\n\n        Examples:\n            >>> from property_utils.units.units import LengthUnit\n            >>> x1 = Property(15, LengthUnit.METER)\n            >>> x2 = Property(5, LengthUnit.METER)\n            >>> x1 + x2\n            <Property: 20 m>\n        \"\"\"\n        return self.__add__(other)\n\n    def __sub__(self, other) -> Self:\n        \"\"\"\n        Defines subtraction between properties.\n\n        Examples:\n            >>> from property_utils.units.units import TimeUnit\n            >>> t1 = Property(2, TimeUnit.MINUTE)\n            >>> t2 = Property(60, TimeUnit.SECOND)\n            >>> t1 - t2\n            <Property: 1.0 min>\n        \"\"\"\n        if not isinstance(other, Property):\n            raise PropertyBinaryOperationError(\n                f\"cannot subtract {other} from ({self}); {other} is not a \"\n                \"Property; only properties can be subtracted from properties. \"\n            )\n        if not self.unit.isinstance_equivalent(other.unit.to_generic()):\n            raise PropertyBinaryOperationError(\n                f\"cannot subtract ({other}) from ({self}); \"\n                f\"({other}) must have ({self.unit.to_generic()}) units. \"\n            )\n        try:\n            prop = other.to_unit(self.unit) if self.unit != other.unit else other\n        except PropertyUnitConversionError:\n            raise PropertyBinaryOperationError(\n                f\"cannot subtract ({other}) from ({self}); ({other}) does not have the \"\n                f\"same units as ({self}) and there is no unit converter registered for \"\n                f\"({self.unit.to_generic()}). \"\n            ) from None\n        except UnitConversionError as exc:\n            raise PropertyBinaryOperationError(\n                f\"cannot subtract ({other}) from ({self});\", exc\n            ) from None\n        return self.__class__(self.value - prop.value, self.unit)\n\n    def __rsub__(self, other) -> \"Property\":\n        \"\"\"\n        Defines right subtraction between properties.\n\n        Examples:\n            >>> from property_utils.units.units import TimeUnit\n            >>> t1 = Property(2, TimeUnit.MINUTE)\n            >>> t2 = Property(60, TimeUnit.SECOND)\n            >>> t1 - t2\n            <Property: 1.0 min>\n        \"\"\"\n        if not isinstance(other, Property):\n            raise PropertyBinaryOperationError(\n                f\"cannot subtract {self} from ({other}); {other} is not a \"\n                f\"{self.__class__}; only same properties can be subtracted from each \"\n                \"other. \"\n            )\n        if not self.unit.isinstance_equivalent(other.unit.to_generic()):\n            raise PropertyBinaryOperationError(\n                f\"cannot subtract ({self}) from ({other}); \"\n                f\"({other}) must have ({self.unit.to_generic()}) units. \"\n            )\n        return other.__add__(-self)\n\n    def __pow__(self, power) -> \"Property\":\n        \"\"\"\n        Defines exponentiation for properties.\n\n        Examples:\n            >>> from property_utils.units.units import LengthUnit\n            >>> L = Property(5, LengthUnit.METER)\n            >>> L**3\n            <Property: 125 (m^3)>\n        \"\"\"\n        if not isinstance(power, (float, int)):\n            raise PropertyExponentError(\n                f\"invalid exponent: {power}; expected numeric. \"\n            )\n        return Property(self.value**power, self.unit**power)\n\n    def __eq__(self, other) -> bool:\n        \"\"\"\n        Defines equality between properties.\n        Prefer Property.eq instead.The equality operator returns False even for very\n        small differences between floating point values.\n\n        Examples:\n            >>> from property_utils.units.units import LengthUnit\n            >>> L1 = Property(500, LengthUnit.CENTI_METER)\n            >>> L2 = Property(5, LengthUnit.METER)\n            >>> L1 == L2\n            True\n\n            >>> L3 = Property(6, LengthUnit.METER)\n            >>> L2 == L3\n            False\n        \"\"\"\n        if not isinstance(other, Property):\n            return False\n        if not self.unit.isinstance_equivalent(other.unit.to_generic()):\n            return False\n        try:\n            prop = other.to_unit(self.unit) if self.unit != other.unit else other\n        except PropertyUtilsException as exc:\n            raise PropertyBinaryOperationError(\n                f\"during conversion of {other} to ({self.unit}) units an error occured: \",\n                exc,\n            ) from None\n        return self.value == prop.value\n\n    def __ne__(self, other) -> bool:\n        \"\"\"\n        Defines inequality between properties.\n        Prefer Property.eq instead.The inequality operator returns True even for very\n        small differences between floating point values.\n\n        Examples:\n            >>> from property_utils.units.units import LengthUnit\n            >>> L1 = Property(500, LengthUnit.CENTI_METER)\n            >>> L2 = Property(5, LengthUnit.METER)\n            >>> L1 != L2\n            False\n\n            >>> L3 = Property(6, LengthUnit.METER)\n            >>> L2 != L3\n            True\n        \"\"\"\n        return not self.__eq__(other)\n\n    def __gt__(self, other) -> bool:\n        \"\"\"\n        Defines comparison between properties.\n\n        Examples:\n            >>> from property_utils.units.units import RelativeTemperatureUnit\n            >>> T1 = Property(100, RelativeTemperatureUnit.CELCIUS)\n            >>> T2 = Property(213, RelativeTemperatureUnit.FAHRENHEIT)\n            >>> T1 > T2\n            False\n        \"\"\"\n        self._validate_comparison_input(other)\n        try:\n            prop = other.to_unit(self.unit) if self.unit != other.unit else other\n        except PropertyUnitConversionError:\n            raise PropertyBinaryOperationError(\n                f\"cannot compare ({other}) to ({self}); ({other}) does not have the \"\n                f\"same units as ({self}) and there is no unit converter registered for \"\n                f\"({self.unit.to_generic()}). \"\n            ) from None\n        except UnitConversionError as exc:\n            raise PropertyBinaryOperationError(\n                f\"cannot compare ({other}) to ({self});\", exc\n            ) from None\n        return self.value > prop.value\n\n    def __ge__(self, other) -> bool:\n        \"\"\"\n        Defines comparison between properties.\n\n        Examples:\n            >>> from property_utils.units.units import RelativeTemperatureUnit\n            >>> T1 = Property(100, RelativeTemperatureUnit.CELCIUS)\n            >>> T2 = Property(212, RelativeTemperatureUnit.FAHRENHEIT)\n            >>> T1 >= T2\n            True\n        \"\"\"\n        self._validate_comparison_input(other)\n        try:\n            prop = other.to_unit(self.unit) if self.unit != other.unit else other\n        except PropertyUnitConversionError:\n            raise PropertyBinaryOperationError(\n                f\"cannot compare ({other}) to ({self}); ({other}) does not have the \"\n                f\"same units as ({self}) and there is no unit converter registered for \"\n                f\"({self.unit.to_generic()}). \"\n            ) from None\n        except UnitConversionError as exc:\n            raise PropertyBinaryOperationError(\n                f\"cannot compare ({other}) to ({self});\", exc\n            ) from None\n        return self.value >= prop.value\n\n    def __lt__(self, other) -> bool:\n        \"\"\"\n        Defines comparison between properties.\n\n        Examples:\n            >>> from property_utils.units.units import RelativeTemperatureUnit\n            >>> T1 = Property(100, RelativeTemperatureUnit.CELCIUS)\n            >>> T2 = Property(213, RelativeTemperatureUnit.FAHRENHEIT)\n            >>> T1 < T2\n            True\n        \"\"\"\n        self._validate_comparison_input(other)\n        try:\n            prop = other.to_unit(self.unit) if self.unit != other.unit else other\n        except PropertyUnitConversionError:\n            raise PropertyBinaryOperationError(\n                f\"cannot compare ({other}) to ({self}); ({other}) does not have the \"\n                f\"same units as ({self}) and there is no unit converter registered for \"\n                f\"({self.unit.to_generic()}). \"\n            ) from None\n        except UnitConversionError as exc:\n            raise PropertyBinaryOperationError(\n                f\"cannot compare ({other}) to ({self});\", exc\n            ) from None\n        return self.value < prop.value\n\n    def __le__(self, other) -> bool:\n        \"\"\"\n        Defines comparison between properties.\n\n        Examples:\n            >>> from property_utils.units.units import RelativeTemperatureUnit\n            >>> T1 = Property(100, RelativeTemperatureUnit.CELCIUS)\n            >>> T2 = Property(213, RelativeTemperatureUnit.FAHRENHEIT)\n            >>> T1 <= T2\n            True\n        \"\"\"\n        self._validate_comparison_input(other)\n        try:\n            prop = other.to_unit(self.unit) if self.unit != other.unit else other\n        except PropertyUnitConversionError:\n            raise PropertyBinaryOperationError(\n                f\"cannot compare ({other}) to ({self}); ({other}) does not have the \"\n                f\"same units as ({self}) and there is no unit converter registered for \"\n                f\"({self.unit.to_generic()}). \"\n            ) from None\n        except UnitConversionError as exc:\n            raise PropertyBinaryOperationError(\n                f\"cannot compare ({other}) to ({self});\", exc\n            ) from None\n        return self.value <= prop.value\n\n    def __str__(self) -> str:\n        return f\"{self.value} {self.unit}\"\n\n    def __repr__(self) -> str:\n        return f\"<Property: {str(self)}>\"\n\n    def _converter(self) -> Type[UnitConverter]:\n        \"\"\"\n        Raises `UndefinedConverter` if a converter is not defined.\n        \"\"\"\n        if self.unit_converter is None:\n            self.unit_converter = self._get_converter()\n        return self.unit_converter\n\n    def _get_converter(self) -> Type[UnitConverter]:\n        \"\"\"\n        Raises `UndefinedConverter` if a converter is not defined.\n        \"\"\"\n        return get_converter(self.unit.to_generic())\n\n    def _validate_comparison_input(self, other) -> None:\n        \"\"\"\n        Raises `PropertyBinaryOperationError` if other is not a Property or if it does\n        not have the same unit type as this Property.\n        \"\"\"\n        if not isinstance(other, Property):\n            raise PropertyBinaryOperationError(\n                f\"cannot compare {other} to ({self}); {other} is not a Property; \"\n                \"only properties can be compared to properties. \"\n            )\n        if not self.unit.isinstance_equivalent(other.unit.to_generic()):\n            raise PropertyBinaryOperationError(\n                f\"cannot compare ({other}) to ({self}); \"\n                f\"({other}) must have ({self.unit.to_generic()}) units. \"\n            )\n\n    def _unit_preconversion(self, prop: \"Property\") -> \"Property\":\n        \"\"\"\n        Applies a conversion to the given property's units before it is multiplied or\n        divided with this unit.\n\n        The preconversion is needed to produce simplified units from the multiplication/\n        division.\n        For example, if you multiply 5 cm with 2.02 m you don't want to get the result\n        in cm * m; in order to get the result in cm^2, 2.02 m (the right operand) is\n        converted to cm first.\n        \"\"\"\n        if isinstance(prop.unit, CompositeDimension):\n            return prop.to_unit(self._composite_unit_preconversion(prop.unit))\n\n        if isinstance(prop.unit, Dimension):\n            return prop.to_unit(self._dimension_unit_preconversion(prop.unit))\n\n        if isinstance(prop.unit, MeasurementUnit):\n            return prop.to_unit(self._simple_unit_preconversion(prop.unit))\n\n        return prop\n\n    # pylint: disable=too-many-branches\n    def _composite_unit_preconversion(\n        self, unit: CompositeDimension\n    ) -> CompositeDimension:\n        \"\"\"\n        Returns the composite dimension that the given dimension should be converted to\n        before multiplication or division with this property.\n        \"\"\"\n        other = replace(unit).simplified()\n\n        if isinstance(self.unit, CompositeDimension):\n            self.unit.simplify()\n\n            for i, num in enumerate(other.numerator):\n                _n = self.unit.get_numerator(num.to_generic(), None)\n                if _n is not None:\n                    other.numerator[i] = replace(_n)\n\n                d = self.unit.get_denominator(num.to_generic(), None)\n                if d is not None:\n                    other.numerator[i] = replace(d)\n\n            for i, d in enumerate(other.denominator):\n                _d = self.unit.get_denominator(d.to_generic(), None)\n                if _d is not None:\n                    other.denominator[i] = replace(_d)\n\n                n = self.unit.get_numerator(d.to_generic(), None)\n                if n is not None:\n                    other.denominator[i] = replace(n)\n\n            return other\n\n        _self: UnitDescriptor\n        if isinstance(self.unit, MeasurementUnit):\n            _self = self.unit**1\n        elif isinstance(self.unit, Dimension):\n            _self = replace(self.unit)\n        else:\n            _self = self.unit\n\n        if isinstance(_self, Dimension):\n            for i, n in enumerate(other.numerator):\n                if n.unit.isinstance(_self.unit.to_generic()):\n                    other.numerator[i] = _self.unit ** other.numerator[i].power\n                    return other\n\n            for i, d in enumerate(other.denominator):\n                if d.unit.isinstance(_self.unit.to_generic()):\n                    other.denominator[i] = _self.unit ** other.denominator[i].power\n                    return other\n\n        return unit\n\n    def _dimension_unit_preconversion(self, unit: Dimension) -> Dimension:\n        \"\"\"\n        Returns the dimension that the given dimension should be converted to before\n        multiplication or division with this property.\n        \"\"\"\n        if isinstance(self.unit, CompositeDimension):\n            self.unit.simplify()\n\n            for d in self.unit.denominator:\n                if d.unit.isinstance(unit.unit.to_generic()):\n                    return d.unit**unit.power\n\n            for n in self.unit.numerator:\n                if n.unit.isinstance(unit.unit.to_generic()):\n                    return n.unit**unit.power\n\n        _self: UnitDescriptor\n        if isinstance(self.unit, Dimension):\n            _self = self.unit.unit\n        else:\n            _self = self.unit\n\n        if isinstance(_self, MeasurementUnit):\n            if _self.isinstance(unit.unit.to_generic()):\n                return _self**unit.power\n\n        return unit\n\n    def _simple_unit_preconversion(self, unit: MeasurementUnit) -> MeasurementUnit:\n        \"\"\"\n        Returns the unit that the given unit should be converted to before\n        multiplication or division with this property.\n        \"\"\"\n        return self._dimension_unit_preconversion(unit**1).unit\n\n    def _simplify_units(self, unit: CompositeDimension) -> UnitDescriptor:\n        \"\"\"\n        Simplifies the composite dimension and returns NON_DIMENSIONAL if the simplified\n        composite does not have units.\n        \"\"\"\n        unit = unit.simplified()\n\n        if unit.has_no_units():\n            return NonDimensionalUnit.NON_DIMENSIONAL\n\n        return unit\n
    "},{"location":"property/#property_utils.properties.property.Property.__add__","title":"__add__(other)","text":"

    Defines addition between properties.

    Examples:

    >>> from property_utils.units.units import LengthUnit\n>>> x1 = Property(15, LengthUnit.METER)\n>>> x2 = Property(5, LengthUnit.METER)\n>>> x1 + x2\n<Property: 20 m>\n
    Source code in src/property_utils/properties/property.py
    def __add__(self, other) -> Self:\n    \"\"\"\n    Defines addition between properties.\n\n    Examples:\n        >>> from property_utils.units.units import LengthUnit\n        >>> x1 = Property(15, LengthUnit.METER)\n        >>> x2 = Property(5, LengthUnit.METER)\n        >>> x1 + x2\n        <Property: 20 m>\n    \"\"\"\n    if not isinstance(other, Property):\n        raise PropertyBinaryOperationError(\n            f\"cannot add {other} to ({self}); {other} is not a Property; \"\n            \"only properties can be added to properties. \"\n        )\n    if not self.unit.isinstance_equivalent(other.unit.to_generic()):\n        raise PropertyBinaryOperationError(\n            f\"cannot add ({other}) to ({self}); \"\n            f\"({other}) must have ({self.unit.to_generic()}) units. \"\n        )\n    try:\n        prop = other.to_unit(self.unit) if self.unit != other.unit else other\n    except PropertyUnitConversionError:\n        raise PropertyBinaryOperationError(\n            f\"cannot add ({other}) to ({self}); ({other}) does not have the same \"\n            f\"units as ({self}) and there is no unit converter registered for \"\n            f\"({self.unit.to_generic()}). \"\n        ) from None\n    except UnitConversionError as exc:\n        raise PropertyBinaryOperationError(\n            f\"cannot add ({other}) to ({self});\", exc\n        ) from None\n    return self.__class__(self.value + prop.value, self.unit)\n
    "},{"location":"property/#property_utils.properties.property.Property.__eq__","title":"__eq__(other)","text":"

    Defines equality between properties. Prefer Property.eq instead.The equality operator returns False even for very small differences between floating point values.

    Examples:

    >>> from property_utils.units.units import LengthUnit\n>>> L1 = Property(500, LengthUnit.CENTI_METER)\n>>> L2 = Property(5, LengthUnit.METER)\n>>> L1 == L2\nTrue\n
    >>> L3 = Property(6, LengthUnit.METER)\n>>> L2 == L3\nFalse\n
    Source code in src/property_utils/properties/property.py
    def __eq__(self, other) -> bool:\n    \"\"\"\n    Defines equality between properties.\n    Prefer Property.eq instead.The equality operator returns False even for very\n    small differences between floating point values.\n\n    Examples:\n        >>> from property_utils.units.units import LengthUnit\n        >>> L1 = Property(500, LengthUnit.CENTI_METER)\n        >>> L2 = Property(5, LengthUnit.METER)\n        >>> L1 == L2\n        True\n\n        >>> L3 = Property(6, LengthUnit.METER)\n        >>> L2 == L3\n        False\n    \"\"\"\n    if not isinstance(other, Property):\n        return False\n    if not self.unit.isinstance_equivalent(other.unit.to_generic()):\n        return False\n    try:\n        prop = other.to_unit(self.unit) if self.unit != other.unit else other\n    except PropertyUtilsException as exc:\n        raise PropertyBinaryOperationError(\n            f\"during conversion of {other} to ({self.unit}) units an error occured: \",\n            exc,\n        ) from None\n    return self.value == prop.value\n
    "},{"location":"property/#property_utils.properties.property.Property.__ge__","title":"__ge__(other)","text":"

    Defines comparison between properties.

    Examples:

    >>> from property_utils.units.units import RelativeTemperatureUnit\n>>> T1 = Property(100, RelativeTemperatureUnit.CELCIUS)\n>>> T2 = Property(212, RelativeTemperatureUnit.FAHRENHEIT)\n>>> T1 >= T2\nTrue\n
    Source code in src/property_utils/properties/property.py
    def __ge__(self, other) -> bool:\n    \"\"\"\n    Defines comparison between properties.\n\n    Examples:\n        >>> from property_utils.units.units import RelativeTemperatureUnit\n        >>> T1 = Property(100, RelativeTemperatureUnit.CELCIUS)\n        >>> T2 = Property(212, RelativeTemperatureUnit.FAHRENHEIT)\n        >>> T1 >= T2\n        True\n    \"\"\"\n    self._validate_comparison_input(other)\n    try:\n        prop = other.to_unit(self.unit) if self.unit != other.unit else other\n    except PropertyUnitConversionError:\n        raise PropertyBinaryOperationError(\n            f\"cannot compare ({other}) to ({self}); ({other}) does not have the \"\n            f\"same units as ({self}) and there is no unit converter registered for \"\n            f\"({self.unit.to_generic()}). \"\n        ) from None\n    except UnitConversionError as exc:\n        raise PropertyBinaryOperationError(\n            f\"cannot compare ({other}) to ({self});\", exc\n        ) from None\n    return self.value >= prop.value\n
    "},{"location":"property/#property_utils.properties.property.Property.__gt__","title":"__gt__(other)","text":"

    Defines comparison between properties.

    Examples:

    >>> from property_utils.units.units import RelativeTemperatureUnit\n>>> T1 = Property(100, RelativeTemperatureUnit.CELCIUS)\n>>> T2 = Property(213, RelativeTemperatureUnit.FAHRENHEIT)\n>>> T1 > T2\nFalse\n
    Source code in src/property_utils/properties/property.py
    def __gt__(self, other) -> bool:\n    \"\"\"\n    Defines comparison between properties.\n\n    Examples:\n        >>> from property_utils.units.units import RelativeTemperatureUnit\n        >>> T1 = Property(100, RelativeTemperatureUnit.CELCIUS)\n        >>> T2 = Property(213, RelativeTemperatureUnit.FAHRENHEIT)\n        >>> T1 > T2\n        False\n    \"\"\"\n    self._validate_comparison_input(other)\n    try:\n        prop = other.to_unit(self.unit) if self.unit != other.unit else other\n    except PropertyUnitConversionError:\n        raise PropertyBinaryOperationError(\n            f\"cannot compare ({other}) to ({self}); ({other}) does not have the \"\n            f\"same units as ({self}) and there is no unit converter registered for \"\n            f\"({self.unit.to_generic()}). \"\n        ) from None\n    except UnitConversionError as exc:\n        raise PropertyBinaryOperationError(\n            f\"cannot compare ({other}) to ({self});\", exc\n        ) from None\n    return self.value > prop.value\n
    "},{"location":"property/#property_utils.properties.property.Property.__le__","title":"__le__(other)","text":"

    Defines comparison between properties.

    Examples:

    >>> from property_utils.units.units import RelativeTemperatureUnit\n>>> T1 = Property(100, RelativeTemperatureUnit.CELCIUS)\n>>> T2 = Property(213, RelativeTemperatureUnit.FAHRENHEIT)\n>>> T1 <= T2\nTrue\n
    Source code in src/property_utils/properties/property.py
    def __le__(self, other) -> bool:\n    \"\"\"\n    Defines comparison between properties.\n\n    Examples:\n        >>> from property_utils.units.units import RelativeTemperatureUnit\n        >>> T1 = Property(100, RelativeTemperatureUnit.CELCIUS)\n        >>> T2 = Property(213, RelativeTemperatureUnit.FAHRENHEIT)\n        >>> T1 <= T2\n        True\n    \"\"\"\n    self._validate_comparison_input(other)\n    try:\n        prop = other.to_unit(self.unit) if self.unit != other.unit else other\n    except PropertyUnitConversionError:\n        raise PropertyBinaryOperationError(\n            f\"cannot compare ({other}) to ({self}); ({other}) does not have the \"\n            f\"same units as ({self}) and there is no unit converter registered for \"\n            f\"({self.unit.to_generic()}). \"\n        ) from None\n    except UnitConversionError as exc:\n        raise PropertyBinaryOperationError(\n            f\"cannot compare ({other}) to ({self});\", exc\n        ) from None\n    return self.value <= prop.value\n
    "},{"location":"property/#property_utils.properties.property.Property.__lt__","title":"__lt__(other)","text":"

    Defines comparison between properties.

    Examples:

    >>> from property_utils.units.units import RelativeTemperatureUnit\n>>> T1 = Property(100, RelativeTemperatureUnit.CELCIUS)\n>>> T2 = Property(213, RelativeTemperatureUnit.FAHRENHEIT)\n>>> T1 < T2\nTrue\n
    Source code in src/property_utils/properties/property.py
    def __lt__(self, other) -> bool:\n    \"\"\"\n    Defines comparison between properties.\n\n    Examples:\n        >>> from property_utils.units.units import RelativeTemperatureUnit\n        >>> T1 = Property(100, RelativeTemperatureUnit.CELCIUS)\n        >>> T2 = Property(213, RelativeTemperatureUnit.FAHRENHEIT)\n        >>> T1 < T2\n        True\n    \"\"\"\n    self._validate_comparison_input(other)\n    try:\n        prop = other.to_unit(self.unit) if self.unit != other.unit else other\n    except PropertyUnitConversionError:\n        raise PropertyBinaryOperationError(\n            f\"cannot compare ({other}) to ({self}); ({other}) does not have the \"\n            f\"same units as ({self}) and there is no unit converter registered for \"\n            f\"({self.unit.to_generic()}). \"\n        ) from None\n    except UnitConversionError as exc:\n        raise PropertyBinaryOperationError(\n            f\"cannot compare ({other}) to ({self});\", exc\n        ) from None\n    return self.value < prop.value\n
    "},{"location":"property/#property_utils.properties.property.Property.__mul__","title":"__mul__(other)","text":"

    Defines multiplication between properties and numerics.

    Examples:

    >>> from property_utils.units.units import AbsoluteTemperatureUnit, LengthUnit\n>>> T = Property(300, AbsoluteTemperatureUnit.KELVIN)\n>>> 2*T\n<Property: 600 K>\n>>> A = Property(10, LengthUnit.METER**2)\n>>> T * A\n<Property: 3000 (m^2) * K>\n
    Source code in src/property_utils/properties/property.py
    def __mul__(self, other) -> \"Property\":\n    \"\"\"\n    Defines multiplication between properties and numerics.\n\n    Examples:\n        >>> from property_utils.units.units import AbsoluteTemperatureUnit, LengthUnit\n        >>> T = Property(300, AbsoluteTemperatureUnit.KELVIN)\n        >>> 2*T\n        <Property: 600 K>\n        >>> A = Property(10, LengthUnit.METER**2)\n        >>> T * A\n        <Property: 3000 (m^2) * K>\n    \"\"\"\n    if isinstance(other, (float, int)):\n        return self.__class__(self.value * other, self.unit)\n    if isinstance(other, Property):\n        _other = self._unit_preconversion(other)\n        return Property(\n            self.value * _other.value, self._simplify_units(self.unit * _other.unit)\n        )\n    raise PropertyBinaryOperationError(\n        f\"cannot multiply {self} with {other}; \"\n        \"second operand must be numeric or Property. \"\n    )\n
    "},{"location":"property/#property_utils.properties.property.Property.__ne__","title":"__ne__(other)","text":"

    Defines inequality between properties. Prefer Property.eq instead.The inequality operator returns True even for very small differences between floating point values.

    Examples:

    >>> from property_utils.units.units import LengthUnit\n>>> L1 = Property(500, LengthUnit.CENTI_METER)\n>>> L2 = Property(5, LengthUnit.METER)\n>>> L1 != L2\nFalse\n
    >>> L3 = Property(6, LengthUnit.METER)\n>>> L2 != L3\nTrue\n
    Source code in src/property_utils/properties/property.py
    def __ne__(self, other) -> bool:\n    \"\"\"\n    Defines inequality between properties.\n    Prefer Property.eq instead.The inequality operator returns True even for very\n    small differences between floating point values.\n\n    Examples:\n        >>> from property_utils.units.units import LengthUnit\n        >>> L1 = Property(500, LengthUnit.CENTI_METER)\n        >>> L2 = Property(5, LengthUnit.METER)\n        >>> L1 != L2\n        False\n\n        >>> L3 = Property(6, LengthUnit.METER)\n        >>> L2 != L3\n        True\n    \"\"\"\n    return not self.__eq__(other)\n
    "},{"location":"property/#property_utils.properties.property.Property.__neg__","title":"__neg__()","text":"

    Defines negation of properties.

    Examples:

    >>> from property_utils.units.units import RelativeTemperatureUnit\n>>> T = Property(3, RelativeTemperatureUnit.CELCIUS)\n>>> -T\n<Property: -3 \u00b0C>\n
    Source code in src/property_utils/properties/property.py
    def __neg__(self) -> Self:\n    \"\"\"\n    Defines negation of properties.\n\n    Examples:\n        >>> from property_utils.units.units import RelativeTemperatureUnit\n        >>> T = Property(3, RelativeTemperatureUnit.CELCIUS)\n        >>> -T\n        <Property: -3 \u00b0C>\n    \"\"\"\n    return self.__class__(-self.value, self.unit)\n
    "},{"location":"property/#property_utils.properties.property.Property.__pow__","title":"__pow__(power)","text":"

    Defines exponentiation for properties.

    Examples:

    >>> from property_utils.units.units import LengthUnit\n>>> L = Property(5, LengthUnit.METER)\n>>> L**3\n<Property: 125 (m^3)>\n
    Source code in src/property_utils/properties/property.py
    def __pow__(self, power) -> \"Property\":\n    \"\"\"\n    Defines exponentiation for properties.\n\n    Examples:\n        >>> from property_utils.units.units import LengthUnit\n        >>> L = Property(5, LengthUnit.METER)\n        >>> L**3\n        <Property: 125 (m^3)>\n    \"\"\"\n    if not isinstance(power, (float, int)):\n        raise PropertyExponentError(\n            f\"invalid exponent: {power}; expected numeric. \"\n        )\n    return Property(self.value**power, self.unit**power)\n
    "},{"location":"property/#property_utils.properties.property.Property.__radd__","title":"__radd__(other)","text":"

    Defines right addition between properties.

    Examples:

    >>> from property_utils.units.units import LengthUnit\n>>> x1 = Property(15, LengthUnit.METER)\n>>> x2 = Property(5, LengthUnit.METER)\n>>> x1 + x2\n<Property: 20 m>\n
    Source code in src/property_utils/properties/property.py
    def __radd__(self, other) -> Self:\n    \"\"\"\n    Defines right addition between properties.\n\n    Examples:\n        >>> from property_utils.units.units import LengthUnit\n        >>> x1 = Property(15, LengthUnit.METER)\n        >>> x2 = Property(5, LengthUnit.METER)\n        >>> x1 + x2\n        <Property: 20 m>\n    \"\"\"\n    return self.__add__(other)\n
    "},{"location":"property/#property_utils.properties.property.Property.__rmul__","title":"__rmul__(other)","text":"

    Defines multiplication between properties and numerics.

    Examples:

    >>> from property_utils.units.units import AbsoluteTemperatureUnit, LengthUnit\n>>> T = Property(300, AbsoluteTemperatureUnit.KELVIN)\n>>> 2*T\n<Property: 600 K>\n>>> A = Property(10, LengthUnit.METER**2)\n>>> T * A\n<Property: 3000 (m^2) * K>\n
    Source code in src/property_utils/properties/property.py
    def __rmul__(self, other) -> \"Property\":\n    \"\"\"\n    Defines multiplication between properties and numerics.\n\n    Examples:\n        >>> from property_utils.units.units import AbsoluteTemperatureUnit, LengthUnit\n        >>> T = Property(300, AbsoluteTemperatureUnit.KELVIN)\n        >>> 2*T\n        <Property: 600 K>\n        >>> A = Property(10, LengthUnit.METER**2)\n        >>> T * A\n        <Property: 3000 (m^2) * K>\n    \"\"\"\n    return self.__mul__(other)\n
    "},{"location":"property/#property_utils.properties.property.Property.__rsub__","title":"__rsub__(other)","text":"

    Defines right subtraction between properties.

    Examples:

    >>> from property_utils.units.units import TimeUnit\n>>> t1 = Property(2, TimeUnit.MINUTE)\n>>> t2 = Property(60, TimeUnit.SECOND)\n>>> t1 - t2\n<Property: 1.0 min>\n
    Source code in src/property_utils/properties/property.py
    def __rsub__(self, other) -> \"Property\":\n    \"\"\"\n    Defines right subtraction between properties.\n\n    Examples:\n        >>> from property_utils.units.units import TimeUnit\n        >>> t1 = Property(2, TimeUnit.MINUTE)\n        >>> t2 = Property(60, TimeUnit.SECOND)\n        >>> t1 - t2\n        <Property: 1.0 min>\n    \"\"\"\n    if not isinstance(other, Property):\n        raise PropertyBinaryOperationError(\n            f\"cannot subtract {self} from ({other}); {other} is not a \"\n            f\"{self.__class__}; only same properties can be subtracted from each \"\n            \"other. \"\n        )\n    if not self.unit.isinstance_equivalent(other.unit.to_generic()):\n        raise PropertyBinaryOperationError(\n            f\"cannot subtract ({self}) from ({other}); \"\n            f\"({other}) must have ({self.unit.to_generic()}) units. \"\n        )\n    return other.__add__(-self)\n
    "},{"location":"property/#property_utils.properties.property.Property.__rtruediv__","title":"__rtruediv__(other)","text":"

    Defines right division between properties and numerics.

    Examples:

    >>> from property_utils.units.units import AbsoluteTemperatureUnit\n>>> T = Property(500, AbsoluteTemperatureUnit.KELVIN)\n>>> 100/T\n<Property: 0.2  / K>\n
    Source code in src/property_utils/properties/property.py
    def __rtruediv__(self, other) -> \"Property\":\n    \"\"\"\n    Defines right division between properties and numerics.\n\n    Examples:\n        >>> from property_utils.units.units import AbsoluteTemperatureUnit\n        >>> T = Property(500, AbsoluteTemperatureUnit.KELVIN)\n        >>> 100/T\n        <Property: 0.2  / K>\n    \"\"\"\n    if isinstance(other, (float, int)):\n        try:\n            value = other / self.value\n        except ZeroDivisionError:\n            raise PropertyBinaryOperationError(\n                f\"cannot divide {self} with {other}; denominator is zero. \"\n            ) from None\n        return Property(value, self.unit.inverse())\n    if isinstance(other, Property):\n        try:\n            value = other.value / self.value\n        except ZeroDivisionError:\n            raise PropertyBinaryOperationError(\n                f\"cannot divide {self} with {other}; denominator's value is zero. \"\n            ) from None\n        return Property(value, self._simplify_units(other.unit / self.unit))\n    raise PropertyBinaryOperationError(\n        f\"cannot divide {self} with {other}; \"\n        \"numerator must be numeric or Property. \"\n    )\n
    "},{"location":"property/#property_utils.properties.property.Property.__sub__","title":"__sub__(other)","text":"

    Defines subtraction between properties.

    Examples:

    >>> from property_utils.units.units import TimeUnit\n>>> t1 = Property(2, TimeUnit.MINUTE)\n>>> t2 = Property(60, TimeUnit.SECOND)\n>>> t1 - t2\n<Property: 1.0 min>\n
    Source code in src/property_utils/properties/property.py
    def __sub__(self, other) -> Self:\n    \"\"\"\n    Defines subtraction between properties.\n\n    Examples:\n        >>> from property_utils.units.units import TimeUnit\n        >>> t1 = Property(2, TimeUnit.MINUTE)\n        >>> t2 = Property(60, TimeUnit.SECOND)\n        >>> t1 - t2\n        <Property: 1.0 min>\n    \"\"\"\n    if not isinstance(other, Property):\n        raise PropertyBinaryOperationError(\n            f\"cannot subtract {other} from ({self}); {other} is not a \"\n            \"Property; only properties can be subtracted from properties. \"\n        )\n    if not self.unit.isinstance_equivalent(other.unit.to_generic()):\n        raise PropertyBinaryOperationError(\n            f\"cannot subtract ({other}) from ({self}); \"\n            f\"({other}) must have ({self.unit.to_generic()}) units. \"\n        )\n    try:\n        prop = other.to_unit(self.unit) if self.unit != other.unit else other\n    except PropertyUnitConversionError:\n        raise PropertyBinaryOperationError(\n            f\"cannot subtract ({other}) from ({self}); ({other}) does not have the \"\n            f\"same units as ({self}) and there is no unit converter registered for \"\n            f\"({self.unit.to_generic()}). \"\n        ) from None\n    except UnitConversionError as exc:\n        raise PropertyBinaryOperationError(\n            f\"cannot subtract ({other}) from ({self});\", exc\n        ) from None\n    return self.__class__(self.value - prop.value, self.unit)\n
    "},{"location":"property/#property_utils.properties.property.Property.__truediv__","title":"__truediv__(other)","text":"

    Defines division between properties and numerics.

    Examples:

    >>> from property_utils.units.units import AbsoluteTemperatureUnit, LengthUnit\n>>> T = Property(500, AbsoluteTemperatureUnit.KELVIN)\n>>> T/2\n<Property: 250.0 K>\n>>> A = Property(10, LengthUnit.METER**2)\n>>> T / A\n<Property: 50.0 K / (m^2)>\n
    Source code in src/property_utils/properties/property.py
    def __truediv__(self, other) -> \"Property\":\n    \"\"\"\n    Defines division between properties and numerics.\n\n    Examples:\n        >>> from property_utils.units.units import AbsoluteTemperatureUnit, LengthUnit\n        >>> T = Property(500, AbsoluteTemperatureUnit.KELVIN)\n        >>> T/2\n        <Property: 250.0 K>\n        >>> A = Property(10, LengthUnit.METER**2)\n        >>> T / A\n        <Property: 50.0 K / (m^2)>\n    \"\"\"\n    if isinstance(other, (float, int)):\n        try:\n            value = self.value / other\n        except ZeroDivisionError:\n            raise PropertyBinaryOperationError(\n                f\"cannot divide {self} with {other}; denominator is zero. \"\n            ) from None\n        return Property(value, self.unit)\n    if isinstance(other, Property):\n        _other = self._unit_preconversion(other)\n        try:\n            value = self.value / _other.value\n        except ZeroDivisionError:\n            raise PropertyBinaryOperationError(\n                f\"cannot divide {self} with {other}; denominator's value is zero. \"\n            ) from None\n        return Property(value, self._simplify_units(self.unit / _other.unit))\n    raise PropertyBinaryOperationError(\n        f\"cannot divide {self} with {other}; \"\n        \"denominator must be numeric or Property. \"\n    )\n
    "},{"location":"property/#property_utils.properties.property.Property.eq","title":"eq(other, *, rel_tol=1e-09, abs_tol=0)","text":"

    Perform equality comparison between this and some other Property. This method of testing equality is preferable to the equality operator '==' because float point tolerance is taken into account.

    rel_tol is the maximum difference for being considered \"close\", relative to the magnitude of the input values. abs_tol is the maximum difference for being considered \"close\", regardless of the magnitude of the input values. For the values to be considered close, the difference between them must be smaller than at least one of the tolerances.

    Raises PropertyBinaryOperationError if an error occurs during conversion of other's units.

    Examples:

    >>> from property_utils.units.units import AbsoluteTemperatureUnit, LengthUnit\n>>> T1 = Property(33.333333, AbsoluteTemperatureUnit.KELVIN)\n>>> T2 = Property(100/3, AbsoluteTemperatureUnit.KELVIN)\n>>> T1 == T2\nFalse\n>>> T1.eq(T2)\nFalse\n>>> T1.eq(T2, rel_tol=0.1)\nTrue\n
    Source code in src/property_utils/properties/property.py
    def eq(self, other: \"Property\", *, rel_tol=1e-9, abs_tol=0) -> bool:\n    \"\"\"\n    Perform equality comparison between this and some other Property. This method\n    of testing equality is preferable to the equality operator '==' because float\n    point tolerance is taken into account.\n\n    rel_tol is the maximum difference for being considered \"close\", relative\n    to the magnitude of the input values.\n    abs_tol is the maximum difference for being considered \"close\", regardless of\n    the magnitude of the input values.\n    For the values to be considered close, the difference between them must be\n    smaller than at least one of the tolerances.\n\n    Raises `PropertyBinaryOperationError` if an error occurs during conversion\n    of other's units.\n\n    Examples:\n        >>> from property_utils.units.units import AbsoluteTemperatureUnit, LengthUnit\n        >>> T1 = Property(33.333333, AbsoluteTemperatureUnit.KELVIN)\n        >>> T2 = Property(100/3, AbsoluteTemperatureUnit.KELVIN)\n        >>> T1 == T2\n        False\n        >>> T1.eq(T2)\n        False\n        >>> T1.eq(T2, rel_tol=0.1)\n        True\n    \"\"\"\n    if not isinstance(other, Property):\n        return False\n    if not self.unit.isinstance_equivalent(other.unit.to_generic()):\n        return False\n    try:\n        prop = other.to_unit(self.unit) if self.unit != other.unit else other\n    except PropertyUtilsException as exc:\n        raise PropertyBinaryOperationError(\n            f\"during conversion of {other} to ({self.unit}) units an error occured: \",\n            exc,\n        ) from None\n    return isclose(self.value, prop.value, rel_tol=rel_tol, abs_tol=abs_tol)\n
    "},{"location":"property/#property_utils.properties.property.Property.to_si","title":"to_si()","text":"

    Create a new property with SI units.

    Raises ImpossiblePropertyUnitConverion if there is no converter registered for the unit.

    Raises InvalidUnitConversion if any error occurs in the unit conversion.

    Examples:

    >>> from property_utils.units.units import RelativeTemperatureUnit\n>>> T = Property(100, RelativeTemperatureUnit.CELCIUS)\n>>> T.to_si()\n<Property: 373.15 K>\n
    Source code in src/property_utils/properties/property.py
    def to_si(self) -> Self:\n    \"\"\"\n    Create a new property with SI units.\n\n    Raises `ImpossiblePropertyUnitConverion` if there is no converter registered\n    for the unit.\n\n    Raises `InvalidUnitConversion` if any error occurs in the unit conversion.\n\n    Examples:\n        >>> from property_utils.units.units import RelativeTemperatureUnit\n        >>> T = Property(100, RelativeTemperatureUnit.CELCIUS)\n        >>> T.to_si()\n        <Property: 373.15 K>\n    \"\"\"\n    if isinstance(self.unit, MeasurementUnit):\n        return self.to_unit(self.unit.si())\n    if isinstance(self.unit, Dimension):\n        return self.to_unit(self.unit.unit.si() ** self.unit.power)\n    if isinstance(self.unit, CompositeDimension):\n        return self.to_unit(self.unit.to_generic().to_si())\n    raise PropertyValidationError(\n        f\"cannot convert Property to SI; 'unit' is invalid: {self.unit}. \"\n    )\n
    "},{"location":"property/#property_utils.properties.property.Property.to_unit","title":"to_unit(unit)","text":"

    Create a new property with specified unit.

    Raises PropertyUnitConversionError if the unit is not of the same type.

    Raises ImpossiblePropertyUnitConverion if there is no converter registered for the unit.

    Raises UnitConversionError if any error occurs in the unit conversion.

    Examples:

    >>> from property_utils.units.units import RelativeTemperatureUnit\n>>> T = Property(100, RelativeTemperatureUnit.CELCIUS)\n>>> T.to_unit(RelativeTemperatureUnit.FAHRENHEIT)\n<Property: 212.0 \u00b0F>\n
    Source code in src/property_utils/properties/property.py
    def to_unit(self, unit: UnitDescriptor) -> Self:\n    \"\"\"\n    Create a new property with specified unit.\n\n    Raises `PropertyUnitConversionError` if the unit is not of the same type.\n\n    Raises `ImpossiblePropertyUnitConverion` if there is no converter registered\n    for the unit.\n\n    Raises `UnitConversionError` if any error occurs in the unit conversion.\n\n    Examples:\n        >>> from property_utils.units.units import RelativeTemperatureUnit\n        >>> T = Property(100, RelativeTemperatureUnit.CELCIUS)\n        >>> T.to_unit(RelativeTemperatureUnit.FAHRENHEIT)\n        <Property: 212.0 \u00b0F>\n    \"\"\"\n    if self.unit == unit:\n        return self.__class__(unit=self.unit, value=self.value)\n\n    if not unit.isinstance_equivalent(self.unit.to_generic()):\n        raise PropertyUnitConversionError(\n            f\"cannot convert {self} to ({unit}) units; 'unit' should be an instance\"\n            f\" of {self.unit.to_generic()}. \"\n        )\n    try:\n        converter = self._converter()\n    except UndefinedConverterError:\n        raise PropertyUnitConversionError(\n            f\"cannot convert property {self} to units: {unit}; no unit converter \"\n            f\" found for {unit.to_generic()}. \"\n            \"Did you forget to @register_converter? \"\n        ) from None\n    try:\n        value = converter.convert(self.value, self.unit, unit)\n    except UnitConversionError as exc:\n        raise exc from None\n    return self.__class__(value=value, unit=unit)\n
    "},{"location":"property/#property_utils.properties.property.RelativeTemperatureUnitConverter","title":"RelativeTemperatureUnitConverter","text":"

    Bases: RelativeUnitConverter

    Convert temperature units with this converter.

    Examples:

    >>> RelativeTemperatureUnitConverter.convert(100, RelativeTemperatureUnit.CELCIUS, RelativeTemperatureUnit.FAHRENHEIT)\n212.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(RelativeTemperatureUnit)\nclass RelativeTemperatureUnitConverter(RelativeUnitConverter):  # pylint: disable=too-few-public-methods\n    \"\"\"\n    Convert temperature units with this converter.\n\n    Examples:\n        >>> RelativeTemperatureUnitConverter.convert(100, RelativeTemperatureUnit.CELCIUS, RelativeTemperatureUnit.FAHRENHEIT)\n        212.0\n    \"\"\"\n\n    reference_unit = RelativeTemperatureUnit.CELCIUS\n    conversion_map = {\n        RelativeTemperatureUnit.CELCIUS: lambda t: t,\n        AbsoluteTemperatureUnit.KELVIN: lambda t: t - 273.15,\n        RelativeTemperatureUnit.FAHRENHEIT: lambda t: (t - 32) / 1.8,\n        AbsoluteTemperatureUnit.RANKINE: lambda t: (t / 1.8) - 273.15,\n    }\n    reference_conversion_map = {\n        RelativeTemperatureUnit.CELCIUS: lambda t: t,\n        AbsoluteTemperatureUnit.KELVIN: lambda t: t + 273.15,\n        RelativeTemperatureUnit.FAHRENHEIT: lambda t: (t * 1.8) + 32,\n        AbsoluteTemperatureUnit.RANKINE: lambda t: (t + 273.15) * 1.8,\n    }\n
    "},{"location":"property/#property_utils.properties.property.TimeUnitConverter","title":"TimeUnitConverter","text":"

    Bases: AbsoluteUnitConverter

    Convert time units with this converter.

    Examples:

    >>> TimeUnitConverter.convert(1, TimeUnit.HOUR, TimeUnit.SECOND)\n3600.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(TimeUnit)\nclass TimeUnitConverter(AbsoluteUnitConverter):\n    \"\"\"\n    Convert time units with this converter.\n\n    Examples:\n        >>> TimeUnitConverter.convert(1, TimeUnit.HOUR, TimeUnit.SECOND)\n        3600.0\n    \"\"\"\n\n    reference_unit = TimeUnit.SECOND\n    conversion_map = {\n        TimeUnit.MILLI_SECOND: UnitPrefix.MILLI.inverse(),\n        TimeUnit.SECOND: 1,\n        TimeUnit.MINUTE: 1 / 60.0,\n        TimeUnit.HOUR: 1 / 60.0 / 60.0,\n        TimeUnit.DAY: 1 / 60.0 / 60.0 / 24.0,\n        TimeUnit.WEEK: 1 / 60.0 / 60.0 / 24.0 / 7,\n        TimeUnit.MONTH: 1 / 60.0 / 60.0 / 24.0 / (365 / 12),\n        TimeUnit.YEAR: 1 / 60.0 / 60.0 / 24.0 / 365,\n    }\n
    "},{"location":"property/#property_utils.properties.property.UnitPrefix","title":"UnitPrefix","text":"

    Bases: float, Enum

    Enumeration of unit prefixes. Handy when converting to and fro prefixed units.

    Examples:

    >>> centimeters = 225\n>>> meters = centimeters * UnitPrefix.CENTI\n>>> meters\n2.25\n
    Source code in src/property_utils/units/converters.py
    class UnitPrefix(float, Enum):\n    \"\"\"\n    Enumeration of unit prefixes.\n    Handy when converting to and fro prefixed units.\n\n    Examples:\n        >>> centimeters = 225\n        >>> meters = centimeters * UnitPrefix.CENTI\n        >>> meters\n        2.25\n    \"\"\"\n\n    PICO = 1e-12\n    NANO = 1e-9\n    MICRO = 1e-6\n    MILLI = 1e-3\n    CENTI = 1e-2\n    DECI = 1e-1\n    DECA = 1e1\n    HECTO = 1e2\n    KILO = 1e3\n    MEGA = 1e6\n    GIGA = 1e9\n    TERA = 1e12\n\n    def inverse(self) -> float:\n        \"\"\"\n        Return the inverse of the unit prefix. Use when prefixing a unit.\n\n        Examples:\n            >>> meters = 50.26\n            >>> centimeters = meters * UnitPrefix.CENTI.inverse()\n            >>> centimeters\n            5026.0\n        \"\"\"\n        return 1 / self.value\n
    "},{"location":"property/#property_utils.properties.property.UnitPrefix.inverse","title":"inverse()","text":"

    Return the inverse of the unit prefix. Use when prefixing a unit.

    Examples:

    >>> meters = 50.26\n>>> centimeters = meters * UnitPrefix.CENTI.inverse()\n>>> centimeters\n5026.0\n
    Source code in src/property_utils/units/converters.py
    def inverse(self) -> float:\n    \"\"\"\n    Return the inverse of the unit prefix. Use when prefixing a unit.\n\n    Examples:\n        >>> meters = 50.26\n        >>> centimeters = meters * UnitPrefix.CENTI.inverse()\n        >>> centimeters\n        5026.0\n    \"\"\"\n    return 1 / self.value\n
    "},{"location":"property/#property_utils.properties.property.VolumeUnitConverter","title":"VolumeUnitConverter","text":"

    Bases: ExponentiatedUnitConverter

    Convert volume units with this converter.

    Examples:

    >>> VolumeUnitConverter.convert(1, LengthUnit.METER**3, LengthUnit.CENTI_METER**3)\n1000000.0\n
    Source code in src/property_utils/units/converters.py
    @register_converter(LengthUnit**3)\nclass VolumeUnitConverter(ExponentiatedUnitConverter):\n    \"\"\"\n    Convert volume units with this converter.\n\n    Examples:\n        >>> VolumeUnitConverter.convert(1, LengthUnit.METER**3, LengthUnit.CENTI_METER**3)\n        1000000.0\n    \"\"\"\n
    "},{"location":"property/#property_utils.properties.property.p","title":"p(value, unit=NonDimensionalUnit.NON_DIMENSIONAL)","text":"

    Create a property with a value and a unit. Default unit is non-dimensional, i.e. no unit.

    Examples:

    >>> from property_utils.units import KELVIN\n>>> p(350, KELVIN)\n<Property: 350 K>\n
    >>> p(20.23)\n<Property: 20.23 >\n
    Source code in src/property_utils/properties/property.py
    def p(\n    value: float, unit: UnitDescriptor = NonDimensionalUnit.NON_DIMENSIONAL\n) -> \"Property\":\n    \"\"\"\n    Create a property with a value and a unit.\n    Default unit is non-dimensional, i.e. no unit.\n\n    Examples:\n        >>> from property_utils.units import KELVIN\n        >>> p(350, KELVIN)\n        <Property: 350 K>\n\n        >>> p(20.23)\n        <Property: 20.23 >\n    \"\"\"\n    return Property(value, unit)\n
    "},{"location":"terminology/","title":"Terminology","text":""},{"location":"terminology/#unit-descriptors-or-just-units","title":"Unit descriptors (or just units)","text":"

    Throughout property-utils the term unit descriptor is used to denote a specific measurement unit of a physical property; it can, for example, refer to Celcius (\u00b0C) but not to temperature units in general.

    "},{"location":"terminology/#generic-unit-descriptors-or-just-generics","title":"Generic unit descriptors (or just generics)","text":"

    Throughout property-utils the term generic descriptor is used to denote a type of measurement units; it can, for example, refer to length units but not to meters, inches, etc.

    "},{"location":"usage/","title":"Usage","text":"

    This sections assumes the reader is acquainted with the terms in Terminology.

    "},{"location":"usage/#unit-arithmetics","title":"Unit arithmetics","text":""},{"location":"usage/#create-composite-units","title":"Create composite units","text":"

    Units can be created by multiplying and dividing base units:

    from property_utils.units import JOULE, MOL, KELVIN, METER\n\nthermal_capacity_units = JOULE / MOL / KELVIN\nmolar_volume_units = MOL / METER**3\nprint(\"thermal_capacity_units =\", thermal_capacity_units)\nprint(\"molar_volume_units =\", molar_volume_units)\n

    Result:

    thermal_capacity_units = J / K / mol\nmolar_volume_units = mol / (m^3)\n
    "},{"location":"usage/#compare-units","title":"Compare units","text":"

    Units can be compared with other units. The isinstance method checks if a unit belongs to some specific unit type.

    from property_utils.units import WATT, PowerUnit, EnergyUnit\n\nprint(WATT.isinstance(PowerUnit))\nprint(WATT.isinstance(EnergyUnit))\n

    Result:

    True\nFalse\n

    The isinstance_equivalent method checks if a unit is equivalent to some other generic unit.

    from property_utils.units import (\n    WATT,\n    PowerUnit,\n    EnergyUnit,\n    TimeUnit,\n    ForceUnit,\n    LengthUnit,\n    MassUnit,\n)\n\nprint(WATT.isinstance_equivalent(PowerUnit))\nprint(WATT.isinstance_equivalent(EnergyUnit / TimeUnit))\nprint(WATT.isinstance_equivalent(ForceUnit * LengthUnit / TimeUnit))\nprint(WATT.isinstance_equivalent(MassUnit * LengthUnit**2 / TimeUnit**3))\n

    Result:

    True\nTrue\nTrue\nTrue\n
    "},{"location":"usage/#si-units","title":"SI units","text":"

    Any unit can be converted to si units with the si method.

    from property_utils.units import BTU, RANKINE, FOOT, CENTI_METER, KILO_CALORIE\n\nprint((BTU / FOOT**2 / RANKINE).si())\nprint((CENTI_METER**3).si())\nprint(KILO_CALORIE.si())\n

    Result:

    J / (m^2) / K\n(m^3)\nJ\n
    "},{"location":"usage/#simplify-composite-units","title":"Simplify composite units","text":"

    Composite units may contain same units in the numerator and denominator. The simplified method removes common units from the numerator and denominator.

    from property_utils.units import METER, SECOND\n\nvelocity_units = METER / SECOND\nacceleration_units = velocity_units / SECOND\n\nprint(\"acceleration_units =\", acceleration_units)\nprint(\"acceleration_units simplified =\", acceleration_units.simplified())\n

    Result:

    acceleration_units = m / s / s\nacceleration_units simplified = m / (s^2)\n

    The simplified method also merges common units.

    from property_utils.units import METER\n\nlength_units = METER\narea_units = length_units * length_units\n\nprint(\"area_units =\", area_units)\nprint(\"area_units simplified =\", area_units.simplified())\n

    Result:

    area_units = m * m\narea_units simplified = (m^2)\n
    "},{"location":"usage/#unit-conversions","title":"Unit conversions","text":"

    Any property can be converted to chosen units with to_unit:

    from property_utils.properties import p\nfrom property_utils.units import WATT, METER, KELVIN, BTU, FOOT, RANKINE, HOUR\n\nheat_transfer_coeff = p(50, WATT / METER**2 / KELVIN)\nprint(\n    \"heat_transfer_coeff =\",\n    heat_transfer_coeff.to_unit(BTU / HOUR / FOOT**2 / RANKINE),\n)\n

    Result:

    heat_transfer_coeff = 8.805115955164156 Btu / (ft^2) / hr / \u00b0R\n

    Converting to SI units is easier with to_si:

    from property_utils.properties import p\nfrom property_utils.units import GRAM, CENTI_METER\n\narea_density = p(12, GRAM / CENTI_METER**2)\n\nprint(\"area_density =\", area_density)\nprint(\"area_density (SI) =\", area_density.to_si())\n

    Result:

    area_density = 12 g / (cm^2)\narea_density (SI) = 120.0 kg / (m^2)\n
    "},{"location":"usage/#property-arithmetics","title":"Property arithmetics","text":""},{"location":"usage/#addition-subtraction","title":"Addition - Subtraction","text":"

    Properties can be added and subtracted to and from each other:

    from property_utils.properties import p\nfrom property_utils.units import BAR\n\npressure_1 = p(15, BAR)\npressure_2 = p(2, BAR)\nprint(\"pressure_1 + pressure_2 =\", pressure_1 + pressure_2)\nprint(\"pressure_1 - pressure_2 =\", pressure_1 - pressure_2)\n

    Result:

    pressure_1 + pressure_2 = 17 bar\npressure_1 - pressure_2 = 13 bar\n

    Properties with different units can be added to each other. The result is always calculated in the units of the left operand.

    from property_utils.properties import p\nfrom property_utils.units import BAR, PSI\n\npressure_1 = p(5, BAR)\npressure_2 = p(30, PSI)\nprint(\"pressure_1 + pressure_2 =\", pressure_1 + pressure_2)\nprint(\"pressure_2 + pressure_1 =\", pressure_2 + pressure_1)\n

    Result:

    pressure_1 + pressure_2 = 7.068423447648202 bar\npressure_2 + pressure_1 = 102.519 psi\n
    "},{"location":"usage/#multiplication-division","title":"Multiplication - Division","text":"

    Properties can be multiplied and divided by numerics:

    from property_utils.properties import p\nfrom property_utils.units import KELVIN\n\ntemperature = p(773.15, KELVIN)\nprint(\"2*temperature =\", 2*temperature)\nprint(\"temperature/2 =\", temperature/2)\n

    Result:

    2*temperature = 1546.3 K\ntemperature/2 = 386.575 K\n

    Properties can also be multiplied and divided with each other:

    from property_utils.properties import p\nfrom property_utils.units import KELVIN, JOULE, KILO_GRAM\n\nthermal_capacity = p(4200, JOULE/KELVIN/KILO_GRAM)\ntemperature_diff = p(57, KELVIN)\nenthalpy = thermal_capacity * temperature_diff\nprint(\"enthalpy =\", thermal_capacity*temperature_diff)\n

    Result:

    enthalpy = 239400 J / kg\n
    "},{"location":"validated_property/","title":"validated property","text":""},{"location":"validated_property/#property_utils.properties.validated_property.ValidatedProperty","title":"ValidatedProperty dataclass","text":"

    Bases: Property

    A ValidatedProperty applies custom validations on its' value.

    Inherit from this class and implement the validate_value method to apply a validation to the property's value.

    You should also define the generic_unit_descriptor class variable. A validation is applied upon initialization for the type of the unit; if its' generic type does not match the generic_unit_descriptor a PropertyValidationError` is raised.

    default_units class variable is the default units with which properties will be created; if it is not defined the default it to use SI units.

    Examples:

    >>> from property_utils.units.units import LengthUnit, AbsoluteTemperatureUnit\n>>> class Distance(ValidatedProperty):\n...     generic_unit_descriptor = LengthUnit\n
    >>> class NauticalDistance(Distance):\n...     default_units = LengthUnit.NAUTICAL_MILE\n
    >>> Distance(5) # defaults to SI units\n<Distance: 5 m>\n>>> NauticalDistance(45.2)\n<NauticalDistance: 45.2 NM>\n
    Source code in src/property_utils/properties/validated_property.py
    @dataclass\nclass ValidatedProperty(Property):\n    \"\"\"\n    A ValidatedProperty applies custom validations on its' value.\n\n    Inherit from this class and implement the `validate_value` method to apply a\n    validation to the property's value.\n\n    You should also define the `generic_unit_descriptor` class variable. A validation\n    is applied upon initialization for the type of the unit; if its' generic type\n    does not match the `generic_unit_descriptor` a PropertyValidationError` is raised.\n\n    `default_units` class variable is the default units with which properties will be\n    created; if it is not defined the default it to use SI units.\n\n    Examples:\n        >>> from property_utils.units.units import LengthUnit, AbsoluteTemperatureUnit\n        >>> class Distance(ValidatedProperty):\n        ...     generic_unit_descriptor = LengthUnit\n\n        >>> class NauticalDistance(Distance):\n        ...     default_units = LengthUnit.NAUTICAL_MILE\n\n        >>> Distance(5) # defaults to SI units\n        <Distance: 5 m>\n        >>> NauticalDistance(45.2)\n        <NauticalDistance: 45.2 NM>\n    \"\"\"\n\n    generic_unit_descriptor: ClassVar[GenericUnitDescriptor]\n    default_units: ClassVar[Optional[UnitDescriptor]] = None\n\n    def __init__(self, value: float, unit: Optional[UnitDescriptor] = None) -> None:\n        if unit is None:\n            unit = self.default_units if self.default_units is not None else unit\n            unit = self.generic_unit_descriptor.to_si() if unit is None else unit\n\n        super().__init__(value, unit)\n        if not unit.isinstance(self.generic_unit_descriptor):\n            raise PropertyValidationError(\n                f\"cannot create {self.__class__.__name__} with {unit} units; \"\n                f\"expected {self.generic_unit_descriptor} units. \"\n            )\n\n        self.__post_init__()\n\n    def __post_init__(self) -> None:\n        self.validate_value(self.value)\n\n    @abstractmethod\n    def validate_value(self, value: float) -> None:\n        \"\"\"\n        Validate the `value` for this property. This validation takes place after\n        initialization; hence all initialized attributes are available.\n\n        The only exception this method should raise is `PropertyValidationError`.\n        \"\"\"\n\n    def __repr__(self) -> str:\n        return f\"<{self.__class__.__name__}: {self.value} {self.unit}>\"\n
    "},{"location":"validated_property/#property_utils.properties.validated_property.ValidatedProperty.validate_value","title":"validate_value(value) abstractmethod","text":"

    Validate the value for this property. This validation takes place after initialization; hence all initialized attributes are available.

    The only exception this method should raise is PropertyValidationError.

    Source code in src/property_utils/properties/validated_property.py
    @abstractmethod\ndef validate_value(self, value: float) -> None:\n    \"\"\"\n    Validate the `value` for this property. This validation takes place after\n    initialization; hence all initialized attributes are available.\n\n    The only exception this method should raise is `PropertyValidationError`.\n    \"\"\"\n
    "}]} \ No newline at end of file