Merged systems into UnitRegistry
This commit is contained in:
parent
5218647d54
commit
f9729fa802
@ -174,13 +174,13 @@ class _Quantity(SharedRegistryObject):
|
|||||||
def unitless(self):
|
def unitless(self):
|
||||||
"""Return true if the quantity does not have units.
|
"""Return true if the quantity does not have units.
|
||||||
"""
|
"""
|
||||||
return not bool(self.to_base_units()._units)
|
return not bool(self.to_root_units()._units)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def dimensionless(self):
|
def dimensionless(self):
|
||||||
"""Return true if the quantity is dimensionless.
|
"""Return true if the quantity is dimensionless.
|
||||||
"""
|
"""
|
||||||
tmp = self.to_base_units()
|
tmp = self.to_root_units()
|
||||||
|
|
||||||
return not bool(tmp.dimensionality)
|
return not bool(tmp.dimensionality)
|
||||||
|
|
||||||
@ -243,6 +243,26 @@ class _Quantity(SharedRegistryObject):
|
|||||||
|
|
||||||
return self.__class__(magnitude, other)
|
return self.__class__(magnitude, other)
|
||||||
|
|
||||||
|
def ito_root_units(self):
|
||||||
|
"""Return Quantity rescaled to base units
|
||||||
|
"""
|
||||||
|
|
||||||
|
_, other = self._REGISTRY._get_root_units(self._units)
|
||||||
|
|
||||||
|
self._magnitude = self._convert_magnitude(other)
|
||||||
|
self._units = other
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def to_root_units(self):
|
||||||
|
"""Return Quantity rescaled to base units
|
||||||
|
"""
|
||||||
|
_, other = self._REGISTRY._get_root_units(self._units)
|
||||||
|
|
||||||
|
magnitude = self._convert_magnitude_not_inplace(other)
|
||||||
|
|
||||||
|
return self.__class__(magnitude, other)
|
||||||
|
|
||||||
def ito_base_units(self):
|
def ito_base_units(self):
|
||||||
"""Return Quantity rescaled to base units
|
"""Return Quantity rescaled to base units
|
||||||
"""
|
"""
|
||||||
@ -263,6 +283,7 @@ class _Quantity(SharedRegistryObject):
|
|||||||
|
|
||||||
return self.__class__(magnitude, other)
|
return self.__class__(magnitude, other)
|
||||||
|
|
||||||
|
|
||||||
def to_compact(self, unit=None):
|
def to_compact(self, unit=None):
|
||||||
"""Return Quantity rescaled to compact, human-readable units.
|
"""Return Quantity rescaled to compact, human-readable units.
|
||||||
|
|
||||||
@ -603,14 +624,14 @@ class _Quantity(SharedRegistryObject):
|
|||||||
if not self._ok_for_muldiv(no_offset_units_self):
|
if not self._ok_for_muldiv(no_offset_units_self):
|
||||||
raise OffsetUnitCalculusError(self._units, other._units)
|
raise OffsetUnitCalculusError(self._units, other._units)
|
||||||
elif no_offset_units_self == 1 and len(self._units) == 1:
|
elif no_offset_units_self == 1 and len(self._units) == 1:
|
||||||
self.ito_base_units()
|
self.ito_root_units()
|
||||||
|
|
||||||
no_offset_units_other = len(other._get_non_multiplicative_units())
|
no_offset_units_other = len(other._get_non_multiplicative_units())
|
||||||
|
|
||||||
if not other._ok_for_muldiv(no_offset_units_other):
|
if not other._ok_for_muldiv(no_offset_units_other):
|
||||||
raise OffsetUnitCalculusError(self._units, other._units)
|
raise OffsetUnitCalculusError(self._units, other._units)
|
||||||
elif no_offset_units_other == 1 and len(other._units) == 1:
|
elif no_offset_units_other == 1 and len(other._units) == 1:
|
||||||
other.ito_base_units()
|
other.ito_root_units()
|
||||||
|
|
||||||
self._magnitude = magnitude_op(self._magnitude, other._magnitude)
|
self._magnitude = magnitude_op(self._magnitude, other._magnitude)
|
||||||
self._units = units_op(self._units, other._units)
|
self._units = units_op(self._units, other._units)
|
||||||
@ -665,14 +686,14 @@ class _Quantity(SharedRegistryObject):
|
|||||||
if not self._ok_for_muldiv(no_offset_units_self):
|
if not self._ok_for_muldiv(no_offset_units_self):
|
||||||
raise OffsetUnitCalculusError(self._units, other._units)
|
raise OffsetUnitCalculusError(self._units, other._units)
|
||||||
elif no_offset_units_self == 1 and len(self._units) == 1:
|
elif no_offset_units_self == 1 and len(self._units) == 1:
|
||||||
new_self = self.to_base_units()
|
new_self = self.to_root_units()
|
||||||
|
|
||||||
no_offset_units_other = len(other._get_non_multiplicative_units())
|
no_offset_units_other = len(other._get_non_multiplicative_units())
|
||||||
|
|
||||||
if not other._ok_for_muldiv(no_offset_units_other):
|
if not other._ok_for_muldiv(no_offset_units_other):
|
||||||
raise OffsetUnitCalculusError(self._units, other._units)
|
raise OffsetUnitCalculusError(self._units, other._units)
|
||||||
elif no_offset_units_other == 1 and len(other._units) == 1:
|
elif no_offset_units_other == 1 and len(other._units) == 1:
|
||||||
other = other.to_base_units()
|
other = other.to_root_units()
|
||||||
|
|
||||||
magnitude = magnitude_op(new_self._magnitude, other._magnitude)
|
magnitude = magnitude_op(new_self._magnitude, other._magnitude)
|
||||||
units = units_op(new_self._units, other._units)
|
units = units_op(new_self._units, other._units)
|
||||||
@ -718,7 +739,7 @@ class _Quantity(SharedRegistryObject):
|
|||||||
if not self._ok_for_muldiv(no_offset_units_self):
|
if not self._ok_for_muldiv(no_offset_units_self):
|
||||||
raise OffsetUnitCalculusError(self._units, '')
|
raise OffsetUnitCalculusError(self._units, '')
|
||||||
elif no_offset_units_self == 1 and len(self._units) == 1:
|
elif no_offset_units_self == 1 and len(self._units) == 1:
|
||||||
self = self.to_base_units()
|
self = self.to_root_units()
|
||||||
|
|
||||||
return self.__class__(other_magnitude / self._magnitude, 1 / self._units)
|
return self.__class__(other_magnitude / self._magnitude, 1 / self._units)
|
||||||
|
|
||||||
@ -732,7 +753,7 @@ class _Quantity(SharedRegistryObject):
|
|||||||
if not self._ok_for_muldiv(no_offset_units_self):
|
if not self._ok_for_muldiv(no_offset_units_self):
|
||||||
raise OffsetUnitCalculusError(self._units, '')
|
raise OffsetUnitCalculusError(self._units, '')
|
||||||
elif no_offset_units_self == 1 and len(self._units) == 1:
|
elif no_offset_units_self == 1 and len(self._units) == 1:
|
||||||
self = self.to_base_units()
|
self = self.to_root_units()
|
||||||
|
|
||||||
return self.__class__(other_magnitude // self._magnitude, 1 / self._units)
|
return self.__class__(other_magnitude // self._magnitude, 1 / self._units)
|
||||||
|
|
||||||
@ -803,12 +824,12 @@ class _Quantity(SharedRegistryObject):
|
|||||||
else:
|
else:
|
||||||
if not self._is_multiplicative:
|
if not self._is_multiplicative:
|
||||||
if self._REGISTRY.autoconvert_offset_to_baseunit:
|
if self._REGISTRY.autoconvert_offset_to_baseunit:
|
||||||
new_self = self.to_base_units()
|
new_self = self.to_root_units()
|
||||||
else:
|
else:
|
||||||
raise OffsetUnitCalculusError(self._units)
|
raise OffsetUnitCalculusError(self._units)
|
||||||
|
|
||||||
if getattr(other, 'dimensionless', False):
|
if getattr(other, 'dimensionless', False):
|
||||||
units = new_self._units ** other.to_base_units().magnitude
|
units = new_self._units ** other.to_root_units().magnitude
|
||||||
elif not getattr(other, 'dimensionless', True):
|
elif not getattr(other, 'dimensionless', True):
|
||||||
raise DimensionalityError(self._units, 'dimensionless')
|
raise DimensionalityError(self._units, 'dimensionless')
|
||||||
else:
|
else:
|
||||||
@ -828,7 +849,7 @@ class _Quantity(SharedRegistryObject):
|
|||||||
if isinstance(self._magnitude, ndarray):
|
if isinstance(self._magnitude, ndarray):
|
||||||
if np.size(self._magnitude) > 1:
|
if np.size(self._magnitude) > 1:
|
||||||
raise DimensionalityError(self._units, 'dimensionless')
|
raise DimensionalityError(self._units, 'dimensionless')
|
||||||
new_self = self.to_base_units()
|
new_self = self.to_root_units()
|
||||||
return other**new_self._magnitude
|
return other**new_self._magnitude
|
||||||
|
|
||||||
def __abs__(self):
|
def __abs__(self):
|
||||||
@ -880,8 +901,8 @@ class _Quantity(SharedRegistryObject):
|
|||||||
if self.dimensionality != other.dimensionality:
|
if self.dimensionality != other.dimensionality:
|
||||||
raise DimensionalityError(self._units, other._units,
|
raise DimensionalityError(self._units, other._units,
|
||||||
self.dimensionality, other.dimensionality)
|
self.dimensionality, other.dimensionality)
|
||||||
return op(self.to_base_units().magnitude,
|
return op(self.to_root_units().magnitude,
|
||||||
other.to_base_units().magnitude)
|
other.to_root_units().magnitude)
|
||||||
|
|
||||||
__lt__ = lambda self, other: self.compare(other, op=operator.lt)
|
__lt__ = lambda self, other: self.compare(other, op=operator.lt)
|
||||||
__le__ = lambda self, other: self.compare(other, op=operator.le)
|
__le__ = lambda self, other: self.compare(other, op=operator.le)
|
||||||
@ -1089,9 +1110,9 @@ class _Quantity(SharedRegistryObject):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
if isinstance(value, self.__class__):
|
if isinstance(value, self.__class__):
|
||||||
factor = self.__class__(value.magnitude, value._units / self._units).to_base_units()
|
factor = self.__class__(value.magnitude, value._units / self._units).to_root_units()
|
||||||
else:
|
else:
|
||||||
factor = self.__class__(value, self._units ** (-1)).to_base_units()
|
factor = self.__class__(value, self._units ** (-1)).to_root_units()
|
||||||
|
|
||||||
if isinstance(factor, self.__class__):
|
if isinstance(factor, self.__class__):
|
||||||
if not factor.dimensionless:
|
if not factor.dimensionless:
|
||||||
@ -1170,7 +1191,7 @@ class _Quantity(SharedRegistryObject):
|
|||||||
if unt == 'radian':
|
if unt == 'radian':
|
||||||
mobjs.append(getattr(other, 'magnitude', other))
|
mobjs.append(getattr(other, 'magnitude', other))
|
||||||
else:
|
else:
|
||||||
factor, units = self._REGISTRY._get_base_units(unt)
|
factor, units = self._REGISTRY._get_root_units(unt)
|
||||||
if units and units != UnitsContainer({'radian': 1}):
|
if units and units != UnitsContainer({'radian': 1}):
|
||||||
raise DimensionalityError(units, dst_units)
|
raise DimensionalityError(units, dst_units)
|
||||||
mobjs.append(getattr(other, 'magnitude', other) * factor)
|
mobjs.append(getattr(other, 'magnitude', other) * factor)
|
||||||
|
134
pint/systems.py
134
pint/systems.py
@ -370,108 +370,48 @@ class System(object):
|
|||||||
return system
|
return system
|
||||||
|
|
||||||
|
|
||||||
#: These dictionaries will be part of the registry
|
class GSManager(object):
|
||||||
#: :type: dict[str, Group | System]
|
|
||||||
_groups_systems = dict()
|
|
||||||
_root_group = Group('root', _groups_systems)
|
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
#: :type: dict[str, Group | System]
|
||||||
|
self._groups_systems = dict()
|
||||||
|
self._root_group = Group('root', self._groups_systems)
|
||||||
|
|
||||||
# These methods will be included in the registry, upgrading the existing ones.
|
def get_group(self, name, create_if_needed=True):
|
||||||
|
"""Return a Group.
|
||||||
|
|
||||||
def get_group(registry, name, create_if_needed=True):
|
:param name: Name of the group.
|
||||||
"""Return a Group.
|
:param create_if_needed: Create a group if not Found. If False, raise an Exception.
|
||||||
|
:return: Group
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return self._groups_systems[name]
|
||||||
|
except KeyError:
|
||||||
|
if create_if_needed:
|
||||||
|
if name == 'root':
|
||||||
|
raise ValueError('The name root is reserved.')
|
||||||
|
return Group(name, self._groups_systems)
|
||||||
|
else:
|
||||||
|
raise KeyError('No group %s found.' % name)
|
||||||
|
|
||||||
:param registry:
|
def get_system(self, name, create_if_needed=True):
|
||||||
:param name: Name of the group to be
|
"""Return a Group.
|
||||||
:param create_if_needed: Create a group if not Found. If False, raise an Exception.
|
|
||||||
:return: Group
|
|
||||||
"""
|
|
||||||
if name == 'root':
|
|
||||||
raise ValueError('The name root is reserved.')
|
|
||||||
|
|
||||||
try:
|
:param name: Name of the system
|
||||||
return _groups_systems[name]
|
:param create_if_needed: Create a group if not Found. If False, raise an Exception.
|
||||||
except KeyError:
|
:return: System
|
||||||
if create_if_needed:
|
"""
|
||||||
return Group(name, _groups_systems)
|
|
||||||
else:
|
|
||||||
raise KeyError('No group %s found.' % name)
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
return self._groups_systems[name]
|
||||||
|
except KeyError:
|
||||||
|
if create_if_needed:
|
||||||
|
return System(name, self._groups_systems)
|
||||||
|
else:
|
||||||
|
raise KeyError('No system found named %s.' % name)
|
||||||
|
|
||||||
def get_system(registry, name, create_if_needed=True):
|
def __getitem__(self, item):
|
||||||
"""Return a Group.
|
if item in self._groups_systems:
|
||||||
|
return self._groups_systems[item]
|
||||||
|
|
||||||
:param registry:
|
raise KeyError('No group or system found named %s.' % item)
|
||||||
:param name: Name of the group to be
|
|
||||||
:param create_if_needed: Create a group if not Found. If False, raise an Exception.
|
|
||||||
:return: System
|
|
||||||
"""
|
|
||||||
|
|
||||||
try:
|
|
||||||
return _groups_systems[name]
|
|
||||||
except KeyError:
|
|
||||||
if create_if_needed:
|
|
||||||
return System(name, _groups_systems)
|
|
||||||
else:
|
|
||||||
raise KeyError('No system %s found.' % name)
|
|
||||||
|
|
||||||
|
|
||||||
def get_compatible_units(registry, input_units, group_or_system=None):
|
|
||||||
"""
|
|
||||||
:param registry:
|
|
||||||
:param input_units:
|
|
||||||
:param group_or_system:
|
|
||||||
:type group_or_system: Group | System
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
ret = registry.get_compatible_units(input_units)
|
|
||||||
|
|
||||||
if not group_or_system:
|
|
||||||
return ret
|
|
||||||
|
|
||||||
members = _groups_systems[group_or_system].members
|
|
||||||
|
|
||||||
# This will not be necessary after integration with the registry as it has a strings intermediate
|
|
||||||
members = frozenset((getattr(registry, member) for member in members))
|
|
||||||
|
|
||||||
return ret.intersection(members)
|
|
||||||
|
|
||||||
|
|
||||||
# Current get_base_units will be renamed to get_root_units
|
|
||||||
#
|
|
||||||
# Not sure yet how to deal with the cache.
|
|
||||||
# Should we cache get_root_units, get_base_units or both?
|
|
||||||
# - get_base_units will need to be invalidated when the system is changed (How often will this happen?)
|
|
||||||
# - get_root_units will not need to be invalidated.
|
|
||||||
|
|
||||||
def get_base_units(registry, input_units, check_nonmult=True, system=None):
|
|
||||||
"""
|
|
||||||
:param registry:
|
|
||||||
:param input_units:
|
|
||||||
:param check_nonmult:
|
|
||||||
:param system: System
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
factor, units = registry.get_base_units(input_units, check_nonmult)
|
|
||||||
|
|
||||||
if not system:
|
|
||||||
return factor, units
|
|
||||||
|
|
||||||
# This will not be necessary after integration with the registry as it has a UnitsContainer intermediate
|
|
||||||
units = to_units_container(units, registry)
|
|
||||||
|
|
||||||
destination_units = UnitsContainer()
|
|
||||||
|
|
||||||
bu = _groups_systems[system].base_units
|
|
||||||
|
|
||||||
for unit, value in units.items():
|
|
||||||
if unit in bu:
|
|
||||||
new_unit = bu[unit]
|
|
||||||
new_unit = to_units_container(new_unit, registry)
|
|
||||||
destination_units *= new_unit ** value
|
|
||||||
else:
|
|
||||||
destination_units *= UnitsContainer({unit: value})
|
|
||||||
|
|
||||||
base_factor = registry.convert(factor, units, destination_units)
|
|
||||||
|
|
||||||
return base_factor, destination_units
|
|
||||||
|
@ -4,7 +4,7 @@ from __future__ import division, unicode_literals, print_function, absolute_impo
|
|||||||
|
|
||||||
|
|
||||||
from pint import UnitRegistry
|
from pint import UnitRegistry
|
||||||
from pint.systems import Group, get_compatible_units, get_group, System, get_base_units
|
from pint.systems import Group, System
|
||||||
|
|
||||||
from pint.testsuite import QuantityTestCase
|
from pint.testsuite import QuantityTestCase
|
||||||
|
|
||||||
@ -187,9 +187,9 @@ class TestGroup(QuantityTestCase):
|
|||||||
def test_get_compatible_units(self):
|
def test_get_compatible_units(self):
|
||||||
ureg = UnitRegistry()
|
ureg = UnitRegistry()
|
||||||
|
|
||||||
g = get_group(ureg, 'imperial')
|
g = ureg.get_group('imperial')
|
||||||
g.add_units('inch', 'yard', 'pint')
|
g.add_units('inch', 'yard', 'pint')
|
||||||
c = get_compatible_units(ureg, 'meter', 'imperial')
|
c = ureg.get_compatible_units('meter', 'imperial')
|
||||||
self.assertEqual(c, frozenset([ureg.inch, ureg.yard]))
|
self.assertEqual(c, frozenset([ureg.inch, ureg.yard]))
|
||||||
|
|
||||||
|
|
||||||
@ -238,10 +238,10 @@ class TestSystem(QuantityTestCase):
|
|||||||
sysname = 'mysys1'
|
sysname = 'mysys1'
|
||||||
ureg = UnitRegistry()
|
ureg = UnitRegistry()
|
||||||
|
|
||||||
g = get_group(ureg, 'imperial')
|
g = ureg.get_group('imperial')
|
||||||
|
|
||||||
g.add_units('inch', 'yard', 'pint')
|
g.add_units('inch', 'yard', 'pint')
|
||||||
c = get_compatible_units(ureg, 'meter', 'imperial')
|
c = ureg.get_compatible_units('meter', 'imperial')
|
||||||
self.assertEqual(c, frozenset([ureg.inch, ureg.yard]))
|
self.assertEqual(c, frozenset([ureg.inch, ureg.yard]))
|
||||||
|
|
||||||
lines = ['@system %s using imperial' % sysname,
|
lines = ['@system %s using imperial' % sysname,
|
||||||
@ -249,7 +249,7 @@ class TestSystem(QuantityTestCase):
|
|||||||
]
|
]
|
||||||
|
|
||||||
s = System.from_lines(lines, lambda x: x, g._groups_systems)
|
s = System.from_lines(lines, lambda x: x, g._groups_systems)
|
||||||
c = get_compatible_units(ureg, 'meter', sysname)
|
c = ureg.get_compatible_units('meter', sysname)
|
||||||
self.assertEqual(c, frozenset([ureg.inch, ureg.yard]))
|
self.assertEqual(c, frozenset([ureg.inch, ureg.yard]))
|
||||||
|
|
||||||
def test_get_base_units(self):
|
def test_get_base_units(self):
|
||||||
@ -257,7 +257,7 @@ class TestSystem(QuantityTestCase):
|
|||||||
|
|
||||||
ureg = UnitRegistry()
|
ureg = UnitRegistry()
|
||||||
|
|
||||||
g = get_group(ureg, 'imperial')
|
g = ureg.get_group('imperial')
|
||||||
g.add_units('inch', 'yard', 'pint')
|
g.add_units('inch', 'yard', 'pint')
|
||||||
|
|
||||||
lines = ['@system %s using imperial' % sysname,
|
lines = ['@system %s using imperial' % sysname,
|
||||||
@ -267,11 +267,11 @@ class TestSystem(QuantityTestCase):
|
|||||||
s = System.from_lines(lines, ureg.get_base_units, g._groups_systems)
|
s = System.from_lines(lines, ureg.get_base_units, g._groups_systems)
|
||||||
|
|
||||||
# base_factor, destination_units
|
# base_factor, destination_units
|
||||||
c = get_base_units(ureg, 'inch', system=sysname)
|
c = ureg.get_base_units('inch', system=sysname)
|
||||||
self.assertAlmostEqual(c[0], 1)
|
self.assertAlmostEqual(c[0], 1)
|
||||||
self.assertEqual(c[1], {'inch': 1})
|
self.assertEqual(c[1], {'inch': 1})
|
||||||
|
|
||||||
c = get_base_units(ureg, 'cm', system=sysname)
|
c = ureg.get_base_units('cm', system=sysname)
|
||||||
self.assertAlmostEqual(c[0], 1./2.54)
|
self.assertAlmostEqual(c[0], 1./2.54)
|
||||||
self.assertEqual(c[1], {'inch': 1})
|
self.assertEqual(c[1], {'inch': 1})
|
||||||
|
|
||||||
@ -280,9 +280,9 @@ class TestSystem(QuantityTestCase):
|
|||||||
|
|
||||||
ureg = UnitRegistry()
|
ureg = UnitRegistry()
|
||||||
|
|
||||||
g = get_group(ureg, 'imperial')
|
g = ureg.get_group('imperial')
|
||||||
g.add_units('inch', 'yard', 'pint')
|
g.add_units('inch', 'yard', 'pint')
|
||||||
c = get_compatible_units(ureg, 'meter', 'imperial')
|
c = ureg.get_compatible_units('meter', 'imperial')
|
||||||
|
|
||||||
lines = ['@system %s using imperial' % sysname,
|
lines = ['@system %s using imperial' % sysname,
|
||||||
'pint:meter',
|
'pint:meter',
|
||||||
@ -291,19 +291,19 @@ class TestSystem(QuantityTestCase):
|
|||||||
s = System.from_lines(lines, ureg.get_base_units, g._groups_systems)
|
s = System.from_lines(lines, ureg.get_base_units, g._groups_systems)
|
||||||
|
|
||||||
# base_factor, destination_units
|
# base_factor, destination_units
|
||||||
c = get_base_units(ureg, 'inch', system=sysname)
|
c = ureg.get_base_units('inch', system=sysname)
|
||||||
self.assertAlmostEqual(c[0], 0.326, places=3)
|
self.assertAlmostEqual(c[0], 0.326, places=3)
|
||||||
self.assertEqual(c[1], {'pint': 1./3})
|
self.assertEqual(c[1], {'pint': 1./3})
|
||||||
|
|
||||||
c = get_base_units(ureg, 'cm', system=sysname)
|
c = ureg.get_base_units('cm', system=sysname)
|
||||||
self.assertAlmostEqual(c[0], 0.1283, places=3)
|
self.assertAlmostEqual(c[0], 0.1283, places=3)
|
||||||
self.assertEqual(c[1], {'pint': 1./3})
|
self.assertEqual(c[1], {'pint': 1./3})
|
||||||
|
|
||||||
c = get_base_units(ureg, 'inch**2', system=sysname)
|
c = ureg.get_base_units('inch**2', system=sysname)
|
||||||
self.assertAlmostEqual(c[0], 0.326**2, places=3)
|
self.assertAlmostEqual(c[0], 0.326**2, places=3)
|
||||||
self.assertEqual(c[1], {'pint': 2./3})
|
self.assertEqual(c[1], {'pint': 2./3})
|
||||||
|
|
||||||
c = get_base_units(ureg, 'cm**2', system=sysname)
|
c = ureg.get_base_units('cm**2', system=sysname)
|
||||||
self.assertAlmostEqual(c[0], 0.1283**2, places=3)
|
self.assertAlmostEqual(c[0], 0.1283**2, places=3)
|
||||||
self.assertEqual(c[1], {'pint': 2./3})
|
self.assertEqual(c[1], {'pint': 2./3})
|
||||||
|
|
||||||
@ -312,7 +312,7 @@ class TestSystem(QuantityTestCase):
|
|||||||
|
|
||||||
ureg = UnitRegistry()
|
ureg = UnitRegistry()
|
||||||
|
|
||||||
g = get_group(ureg, 'imperial')
|
g = ureg.get_group('imperial')
|
||||||
g.add_units('inch', 'yard', 'pint')
|
g.add_units('inch', 'yard', 'pint')
|
||||||
|
|
||||||
lines = ['@system %s using imperial' % sysname,
|
lines = ['@system %s using imperial' % sysname,
|
||||||
@ -322,10 +322,10 @@ class TestSystem(QuantityTestCase):
|
|||||||
s = System.from_lines(lines, ureg.get_base_units, g._groups_systems)
|
s = System.from_lines(lines, ureg.get_base_units, g._groups_systems)
|
||||||
|
|
||||||
# base_factor, destination_units
|
# base_factor, destination_units
|
||||||
c = get_base_units(ureg, 'inch', system=sysname)
|
c = ureg.get_base_units('inch', system=sysname)
|
||||||
self.assertAlmostEqual(c[0], 0.0568, places=3)
|
self.assertAlmostEqual(c[0], 0.0568, places=3)
|
||||||
self.assertEqual(c[1], {'mph': 1, 'second': 1})
|
self.assertEqual(c[1], {'mph': 1, 'second': 1})
|
||||||
|
|
||||||
c = get_base_units(ureg, 'kph', system=sysname)
|
c = ureg.get_base_units('kph', system=sysname)
|
||||||
self.assertAlmostEqual(c[0], .6214, places=4)
|
self.assertAlmostEqual(c[0], .6214, places=4)
|
||||||
self.assertEqual(c[1], {'mph': 1})
|
self.assertEqual(c[1], {'mph': 1})
|
||||||
|
120
pint/unit.py
120
pint/unit.py
@ -37,6 +37,7 @@ from .errors import (DimensionalityError, UndefinedUnitError,
|
|||||||
DefinitionSyntaxError, RedefinitionError)
|
DefinitionSyntaxError, RedefinitionError)
|
||||||
|
|
||||||
from .pint_eval import build_eval_tree
|
from .pint_eval import build_eval_tree
|
||||||
|
from . import systems
|
||||||
|
|
||||||
class _Unit(SharedRegistryObject):
|
class _Unit(SharedRegistryObject):
|
||||||
"""Implements a class to describe a unit supporting math operations.
|
"""Implements a class to describe a unit supporting math operations.
|
||||||
@ -265,6 +266,9 @@ class UnitRegistry(object):
|
|||||||
#: Map dimension name (string) to its definition (DimensionDefinition).
|
#: Map dimension name (string) to its definition (DimensionDefinition).
|
||||||
self._dimensions = {}
|
self._dimensions = {}
|
||||||
|
|
||||||
|
#: :type: systems.GSManager
|
||||||
|
self._gsmanager = systems.GSManager()
|
||||||
|
|
||||||
#: Map unit name (string) to its definition (UnitDefinition).
|
#: Map unit name (string) to its definition (UnitDefinition).
|
||||||
#: Might contain prefixed units.
|
#: Might contain prefixed units.
|
||||||
self._units = {}
|
self._units = {}
|
||||||
@ -289,6 +293,9 @@ class UnitRegistry(object):
|
|||||||
#: Maps dimensionality (UnitsContainer) to Units (str)
|
#: Maps dimensionality (UnitsContainer) to Units (str)
|
||||||
self._dimensional_equivalents = dict()
|
self._dimensional_equivalents = dict()
|
||||||
|
|
||||||
|
#: Maps dimensionality (UnitsContainer) to Dimensionality (UnitsContainer)
|
||||||
|
self._root_units_cache = dict()
|
||||||
|
|
||||||
#: Maps dimensionality (UnitsContainer) to Dimensionality (UnitsContainer)
|
#: Maps dimensionality (UnitsContainer) to Dimensionality (UnitsContainer)
|
||||||
self._base_units_cache = dict()
|
self._base_units_cache = dict()
|
||||||
|
|
||||||
@ -344,6 +351,25 @@ class UnitRegistry(object):
|
|||||||
self.Unit.default_format = value
|
self.Unit.default_format = value
|
||||||
self.Quantity.default_format = value
|
self.Quantity.default_format = value
|
||||||
|
|
||||||
|
def get_group(self, name, create_if_needed=True):
|
||||||
|
"""Return a Group.
|
||||||
|
|
||||||
|
:param name: Name of the group to be
|
||||||
|
:param create_if_needed: Create a group if not Found. If False, raise an Exception.
|
||||||
|
:return: Group
|
||||||
|
"""
|
||||||
|
return self._gsmanager.get_group(name, create_if_needed)
|
||||||
|
|
||||||
|
def get_system(self, name, create_if_needed=True):
|
||||||
|
"""Return a Group.
|
||||||
|
|
||||||
|
:param registry:
|
||||||
|
:param name: Name of the group to be
|
||||||
|
:param create_if_needed: Create a group if not Found. If False, raise an Exception.
|
||||||
|
:return: System
|
||||||
|
"""
|
||||||
|
return self._gsmanager.get_system(name, create_if_needed)
|
||||||
|
|
||||||
def add_context(self, context):
|
def add_context(self, context):
|
||||||
"""Add a context object to the registry.
|
"""Add a context object to the registry.
|
||||||
|
|
||||||
@ -611,10 +637,10 @@ class UnitRegistry(object):
|
|||||||
try:
|
try:
|
||||||
uc = ParserHelper.from_word(unit_name)
|
uc = ParserHelper.from_word(unit_name)
|
||||||
|
|
||||||
bu = self._get_base_units(uc)
|
bu = self._get_root_units(uc)
|
||||||
di = self._get_dimensionality(uc)
|
di = self._get_dimensionality(uc)
|
||||||
|
|
||||||
self._base_units_cache[uc] = bu
|
self._root_units_cache[uc] = bu
|
||||||
self._dimensionality_cache[uc] = di
|
self._dimensionality_cache[uc] = di
|
||||||
|
|
||||||
if not prefixed:
|
if not prefixed:
|
||||||
@ -726,8 +752,8 @@ class UnitRegistry(object):
|
|||||||
if reg.reference is not None:
|
if reg.reference is not None:
|
||||||
self._get_dimensionality_recurse(reg.reference, exp2, accumulator)
|
self._get_dimensionality_recurse(reg.reference, exp2, accumulator)
|
||||||
|
|
||||||
def get_base_units(self, input_units, check_nonmult=True):
|
def get_root_units(self, input_units, check_nonmult=True):
|
||||||
"""Convert unit or dict of units to the base units.
|
"""Convert unit or dict of units to the root units.
|
||||||
|
|
||||||
If any unit is non multiplicative and check_converter is True,
|
If any unit is non multiplicative and check_converter is True,
|
||||||
then None is returned as the multiplicative factor.
|
then None is returned as the multiplicative factor.
|
||||||
@ -741,12 +767,12 @@ class UnitRegistry(object):
|
|||||||
"""
|
"""
|
||||||
input_units = to_units_container(input_units)
|
input_units = to_units_container(input_units)
|
||||||
|
|
||||||
f, units = self._get_base_units(input_units, check_nonmult=True)
|
f, units = self._get_root_units(input_units, check_nonmult)
|
||||||
|
|
||||||
return f, self.Unit(units)
|
return f, self.Unit(units)
|
||||||
|
|
||||||
def _get_base_units(self, input_units, check_nonmult=True):
|
def _get_root_units(self, input_units, check_nonmult=True):
|
||||||
"""Convert unit or dict of units to the base units.
|
"""Convert unit or dict of units to the root units.
|
||||||
|
|
||||||
If any unit is non multiplicative and check_converter is True,
|
If any unit is non multiplicative and check_converter is True,
|
||||||
then None is returned as the multiplicative factor.
|
then None is returned as the multiplicative factor.
|
||||||
@ -762,11 +788,11 @@ class UnitRegistry(object):
|
|||||||
return 1., UnitsContainer()
|
return 1., UnitsContainer()
|
||||||
|
|
||||||
# The cache is only done for check_nonmult=True
|
# The cache is only done for check_nonmult=True
|
||||||
if check_nonmult and input_units in self._base_units_cache:
|
if check_nonmult and input_units in self._root_units_cache:
|
||||||
return self._base_units_cache[input_units]
|
return self._root_units_cache[input_units]
|
||||||
|
|
||||||
accumulators = [1., defaultdict(float)]
|
accumulators = [1., defaultdict(float)]
|
||||||
self._get_base_units_recurse(input_units, 1.0, accumulators)
|
self._get_root_units_recurse(input_units, 1.0, accumulators)
|
||||||
|
|
||||||
factor = accumulators[0]
|
factor = accumulators[0]
|
||||||
units = UnitsContainer(dict((k, v) for k, v in accumulators[1].items()
|
units = UnitsContainer(dict((k, v) for k, v in accumulators[1].items()
|
||||||
@ -780,7 +806,63 @@ class UnitRegistry(object):
|
|||||||
|
|
||||||
return factor, units
|
return factor, units
|
||||||
|
|
||||||
def _get_base_units_recurse(self, ref, exp, accumulators):
|
def get_base_units(self, input_units, check_nonmult=True, system=None):
|
||||||
|
"""Convert unit or dict of units to the base units.
|
||||||
|
|
||||||
|
If any unit is non multiplicative and check_converter is True,
|
||||||
|
then None is returned as the multiplicative factor.
|
||||||
|
|
||||||
|
:param input_units: units
|
||||||
|
:type input_units: UnitsContainer or str
|
||||||
|
:param check_nonmult: if True, None will be returned as the
|
||||||
|
multiplicative factor if a non-multiplicative
|
||||||
|
units is found in the final Units.
|
||||||
|
:return: multiplicative factor, base units
|
||||||
|
"""
|
||||||
|
input_units = to_units_container(input_units)
|
||||||
|
|
||||||
|
f, units = self._get_base_units(input_units, check_nonmult, system)
|
||||||
|
|
||||||
|
return f, self.Unit(units)
|
||||||
|
|
||||||
|
def _get_base_units(self, input_units, check_nonmult=True, system=None):
|
||||||
|
"""
|
||||||
|
:param registry:
|
||||||
|
:param input_units:
|
||||||
|
:param check_nonmult:
|
||||||
|
:param system: System
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
|
||||||
|
# The cache is only done for check_nonmult=True
|
||||||
|
if check_nonmult and input_units in self._base_units_cache:
|
||||||
|
return self._base_units_cache[input_units]
|
||||||
|
|
||||||
|
factor, units = self.get_root_units(input_units, check_nonmult)
|
||||||
|
|
||||||
|
if not system:
|
||||||
|
return factor, units
|
||||||
|
|
||||||
|
# This will not be necessary after integration with the registry as it has a UnitsContainer intermediate
|
||||||
|
units = to_units_container(units, self)
|
||||||
|
|
||||||
|
destination_units = UnitsContainer()
|
||||||
|
|
||||||
|
bu = self._gsmanager.get_system(system, False).base_units
|
||||||
|
|
||||||
|
for unit, value in units.items():
|
||||||
|
if unit in bu:
|
||||||
|
new_unit = bu[unit]
|
||||||
|
new_unit = to_units_container(new_unit, self)
|
||||||
|
destination_units *= new_unit ** value
|
||||||
|
else:
|
||||||
|
destination_units *= UnitsContainer({unit: value})
|
||||||
|
|
||||||
|
base_factor = self.convert(factor, units, destination_units)
|
||||||
|
|
||||||
|
return base_factor, destination_units
|
||||||
|
|
||||||
|
def _get_root_units_recurse(self, ref, exp, accumulators):
|
||||||
for key in ref:
|
for key in ref:
|
||||||
exp2 = exp*ref[key]
|
exp2 = exp*ref[key]
|
||||||
key = self.get_name(key)
|
key = self.get_name(key)
|
||||||
@ -790,19 +872,19 @@ class UnitRegistry(object):
|
|||||||
else:
|
else:
|
||||||
accumulators[0] *= reg._converter.scale ** exp2
|
accumulators[0] *= reg._converter.scale ** exp2
|
||||||
if reg.reference is not None:
|
if reg.reference is not None:
|
||||||
self._get_base_units_recurse(reg.reference, exp2,
|
self._get_root_units_recurse(reg.reference, exp2,
|
||||||
accumulators)
|
accumulators)
|
||||||
|
|
||||||
def get_compatible_units(self, input_units):
|
def get_compatible_units(self, input_units, group_or_system=None):
|
||||||
"""
|
"""
|
||||||
"""
|
"""
|
||||||
input_units = to_units_container(input_units)
|
input_units = to_units_container(input_units)
|
||||||
|
|
||||||
equiv = self._get_compatible_units(input_units)
|
equiv = self._get_compatible_units(input_units, group_or_system)
|
||||||
|
|
||||||
return frozenset(self.Unit(eq) for eq in equiv)
|
return frozenset(self.Unit(eq) for eq in equiv)
|
||||||
|
|
||||||
def _get_compatible_units(self, input_units):
|
def _get_compatible_units(self, input_units, group_or_system=None):
|
||||||
"""
|
"""
|
||||||
"""
|
"""
|
||||||
if not input_units:
|
if not input_units:
|
||||||
@ -819,7 +901,11 @@ class UnitRegistry(object):
|
|||||||
for node in nodes:
|
for node in nodes:
|
||||||
ret |= self._dimensional_equivalents[node]
|
ret |= self._dimensional_equivalents[node]
|
||||||
|
|
||||||
return frozenset(ret)
|
if group_or_system:
|
||||||
|
members = self._gsmanager[group_or_system].members
|
||||||
|
return frozenset(ret.intersection(members))
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
def convert(self, value, src, dst, inplace=False):
|
def convert(self, value, src, dst, inplace=False):
|
||||||
"""Convert value from some source to destination units.
|
"""Convert value from some source to destination units.
|
||||||
@ -927,7 +1013,7 @@ class UnitRegistry(object):
|
|||||||
|
|
||||||
# Here src and dst have only multiplicative units left. Thus we can
|
# Here src and dst have only multiplicative units left. Thus we can
|
||||||
# convert with a factor.
|
# convert with a factor.
|
||||||
factor, units = self._get_base_units(src / dst)
|
factor, units = self._get_root_units(src / dst)
|
||||||
|
|
||||||
# factor is type float and if our magnitude is type Decimal then
|
# factor is type float and if our magnitude is type Decimal then
|
||||||
# must first convert to Decimal before we can '*' the values
|
# must first convert to Decimal before we can '*' the values
|
||||||
|
Loading…
Reference in New Issue
Block a user