Merged systems into UnitRegistry
This commit is contained in:
parent
5218647d54
commit
f9729fa802
@ -174,13 +174,13 @@ class _Quantity(SharedRegistryObject):
|
||||
def unitless(self):
|
||||
"""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
|
||||
def dimensionless(self):
|
||||
"""Return true if the quantity is dimensionless.
|
||||
"""
|
||||
tmp = self.to_base_units()
|
||||
tmp = self.to_root_units()
|
||||
|
||||
return not bool(tmp.dimensionality)
|
||||
|
||||
@ -243,6 +243,26 @@ class _Quantity(SharedRegistryObject):
|
||||
|
||||
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):
|
||||
"""Return Quantity rescaled to base units
|
||||
"""
|
||||
@ -263,6 +283,7 @@ class _Quantity(SharedRegistryObject):
|
||||
|
||||
return self.__class__(magnitude, other)
|
||||
|
||||
|
||||
def to_compact(self, unit=None):
|
||||
"""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):
|
||||
raise OffsetUnitCalculusError(self._units, other._units)
|
||||
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())
|
||||
|
||||
if not other._ok_for_muldiv(no_offset_units_other):
|
||||
raise OffsetUnitCalculusError(self._units, other._units)
|
||||
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._units = units_op(self._units, other._units)
|
||||
@ -665,14 +686,14 @@ class _Quantity(SharedRegistryObject):
|
||||
if not self._ok_for_muldiv(no_offset_units_self):
|
||||
raise OffsetUnitCalculusError(self._units, other._units)
|
||||
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())
|
||||
|
||||
if not other._ok_for_muldiv(no_offset_units_other):
|
||||
raise OffsetUnitCalculusError(self._units, other._units)
|
||||
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)
|
||||
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):
|
||||
raise OffsetUnitCalculusError(self._units, '')
|
||||
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)
|
||||
|
||||
@ -732,7 +753,7 @@ class _Quantity(SharedRegistryObject):
|
||||
if not self._ok_for_muldiv(no_offset_units_self):
|
||||
raise OffsetUnitCalculusError(self._units, '')
|
||||
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)
|
||||
|
||||
@ -803,12 +824,12 @@ class _Quantity(SharedRegistryObject):
|
||||
else:
|
||||
if not self._is_multiplicative:
|
||||
if self._REGISTRY.autoconvert_offset_to_baseunit:
|
||||
new_self = self.to_base_units()
|
||||
new_self = self.to_root_units()
|
||||
else:
|
||||
raise OffsetUnitCalculusError(self._units)
|
||||
|
||||
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):
|
||||
raise DimensionalityError(self._units, 'dimensionless')
|
||||
else:
|
||||
@ -828,7 +849,7 @@ class _Quantity(SharedRegistryObject):
|
||||
if isinstance(self._magnitude, ndarray):
|
||||
if np.size(self._magnitude) > 1:
|
||||
raise DimensionalityError(self._units, 'dimensionless')
|
||||
new_self = self.to_base_units()
|
||||
new_self = self.to_root_units()
|
||||
return other**new_self._magnitude
|
||||
|
||||
def __abs__(self):
|
||||
@ -880,8 +901,8 @@ class _Quantity(SharedRegistryObject):
|
||||
if self.dimensionality != other.dimensionality:
|
||||
raise DimensionalityError(self._units, other._units,
|
||||
self.dimensionality, other.dimensionality)
|
||||
return op(self.to_base_units().magnitude,
|
||||
other.to_base_units().magnitude)
|
||||
return op(self.to_root_units().magnitude,
|
||||
other.to_root_units().magnitude)
|
||||
|
||||
__lt__ = lambda self, other: self.compare(other, op=operator.lt)
|
||||
__le__ = lambda self, other: self.compare(other, op=operator.le)
|
||||
@ -1089,9 +1110,9 @@ class _Quantity(SharedRegistryObject):
|
||||
|
||||
try:
|
||||
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:
|
||||
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 not factor.dimensionless:
|
||||
@ -1170,7 +1191,7 @@ class _Quantity(SharedRegistryObject):
|
||||
if unt == 'radian':
|
||||
mobjs.append(getattr(other, 'magnitude', other))
|
||||
else:
|
||||
factor, units = self._REGISTRY._get_base_units(unt)
|
||||
factor, units = self._REGISTRY._get_root_units(unt)
|
||||
if units and units != UnitsContainer({'radian': 1}):
|
||||
raise DimensionalityError(units, dst_units)
|
||||
mobjs.append(getattr(other, 'magnitude', other) * factor)
|
||||
|
100
pint/systems.py
100
pint/systems.py
@ -370,108 +370,48 @@ class System(object):
|
||||
return system
|
||||
|
||||
|
||||
#: These dictionaries will be part of the registry
|
||||
#: :type: dict[str, Group | System]
|
||||
_groups_systems = dict()
|
||||
_root_group = Group('root', _groups_systems)
|
||||
class GSManager(object):
|
||||
|
||||
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(registry, name, create_if_needed=True):
|
||||
def get_group(self, name, create_if_needed=True):
|
||||
"""Return a Group.
|
||||
|
||||
:param registry:
|
||||
:param name: Name of the group to be
|
||||
:param name: Name of the 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:
|
||||
return _groups_systems[name]
|
||||
return self._groups_systems[name]
|
||||
except KeyError:
|
||||
if create_if_needed:
|
||||
return Group(name, _groups_systems)
|
||||
if name == 'root':
|
||||
raise ValueError('The name root is reserved.')
|
||||
return Group(name, self._groups_systems)
|
||||
else:
|
||||
raise KeyError('No group %s found.' % name)
|
||||
|
||||
|
||||
def get_system(registry, name, create_if_needed=True):
|
||||
def get_system(self, name, create_if_needed=True):
|
||||
"""Return a Group.
|
||||
|
||||
:param registry:
|
||||
:param name: Name of the group to be
|
||||
:param name: Name of the system
|
||||
:param create_if_needed: Create a group if not Found. If False, raise an Exception.
|
||||
:return: System
|
||||
"""
|
||||
|
||||
try:
|
||||
return _groups_systems[name]
|
||||
return self._groups_systems[name]
|
||||
except KeyError:
|
||||
if create_if_needed:
|
||||
return System(name, _groups_systems)
|
||||
return System(name, self._groups_systems)
|
||||
else:
|
||||
raise KeyError('No system %s found.' % name)
|
||||
raise KeyError('No system found named %s.' % name)
|
||||
|
||||
def __getitem__(self, item):
|
||||
if item in self._groups_systems:
|
||||
return self._groups_systems[item]
|
||||
|
||||
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
|
||||
raise KeyError('No group or system found named %s.' % item)
|
||||
|
@ -4,7 +4,7 @@ from __future__ import division, unicode_literals, print_function, absolute_impo
|
||||
|
||||
|
||||
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
|
||||
|
||||
@ -187,9 +187,9 @@ class TestGroup(QuantityTestCase):
|
||||
def test_get_compatible_units(self):
|
||||
ureg = UnitRegistry()
|
||||
|
||||
g = get_group(ureg, 'imperial')
|
||||
g = ureg.get_group('imperial')
|
||||
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]))
|
||||
|
||||
|
||||
@ -238,10 +238,10 @@ class TestSystem(QuantityTestCase):
|
||||
sysname = 'mysys1'
|
||||
ureg = UnitRegistry()
|
||||
|
||||
g = get_group(ureg, 'imperial')
|
||||
g = ureg.get_group('imperial')
|
||||
|
||||
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]))
|
||||
|
||||
lines = ['@system %s using imperial' % sysname,
|
||||
@ -249,7 +249,7 @@ class TestSystem(QuantityTestCase):
|
||||
]
|
||||
|
||||
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]))
|
||||
|
||||
def test_get_base_units(self):
|
||||
@ -257,7 +257,7 @@ class TestSystem(QuantityTestCase):
|
||||
|
||||
ureg = UnitRegistry()
|
||||
|
||||
g = get_group(ureg, 'imperial')
|
||||
g = ureg.get_group('imperial')
|
||||
g.add_units('inch', 'yard', 'pint')
|
||||
|
||||
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)
|
||||
|
||||
# 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.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.assertEqual(c[1], {'inch': 1})
|
||||
|
||||
@ -280,9 +280,9 @@ class TestSystem(QuantityTestCase):
|
||||
|
||||
ureg = UnitRegistry()
|
||||
|
||||
g = get_group(ureg, 'imperial')
|
||||
g = ureg.get_group('imperial')
|
||||
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,
|
||||
'pint:meter',
|
||||
@ -291,19 +291,19 @@ class TestSystem(QuantityTestCase):
|
||||
s = System.from_lines(lines, ureg.get_base_units, g._groups_systems)
|
||||
|
||||
# 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.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.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.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.assertEqual(c[1], {'pint': 2./3})
|
||||
|
||||
@ -312,7 +312,7 @@ class TestSystem(QuantityTestCase):
|
||||
|
||||
ureg = UnitRegistry()
|
||||
|
||||
g = get_group(ureg, 'imperial')
|
||||
g = ureg.get_group('imperial')
|
||||
g.add_units('inch', 'yard', 'pint')
|
||||
|
||||
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)
|
||||
|
||||
# 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.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.assertEqual(c[1], {'mph': 1})
|
||||
|
120
pint/unit.py
120
pint/unit.py
@ -37,6 +37,7 @@ from .errors import (DimensionalityError, UndefinedUnitError,
|
||||
DefinitionSyntaxError, RedefinitionError)
|
||||
|
||||
from .pint_eval import build_eval_tree
|
||||
from . import systems
|
||||
|
||||
class _Unit(SharedRegistryObject):
|
||||
"""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).
|
||||
self._dimensions = {}
|
||||
|
||||
#: :type: systems.GSManager
|
||||
self._gsmanager = systems.GSManager()
|
||||
|
||||
#: Map unit name (string) to its definition (UnitDefinition).
|
||||
#: Might contain prefixed units.
|
||||
self._units = {}
|
||||
@ -289,6 +293,9 @@ class UnitRegistry(object):
|
||||
#: Maps dimensionality (UnitsContainer) to Units (str)
|
||||
self._dimensional_equivalents = dict()
|
||||
|
||||
#: Maps dimensionality (UnitsContainer) to Dimensionality (UnitsContainer)
|
||||
self._root_units_cache = dict()
|
||||
|
||||
#: Maps dimensionality (UnitsContainer) to Dimensionality (UnitsContainer)
|
||||
self._base_units_cache = dict()
|
||||
|
||||
@ -344,6 +351,25 @@ class UnitRegistry(object):
|
||||
self.Unit.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):
|
||||
"""Add a context object to the registry.
|
||||
|
||||
@ -611,10 +637,10 @@ class UnitRegistry(object):
|
||||
try:
|
||||
uc = ParserHelper.from_word(unit_name)
|
||||
|
||||
bu = self._get_base_units(uc)
|
||||
bu = self._get_root_units(uc)
|
||||
di = self._get_dimensionality(uc)
|
||||
|
||||
self._base_units_cache[uc] = bu
|
||||
self._root_units_cache[uc] = bu
|
||||
self._dimensionality_cache[uc] = di
|
||||
|
||||
if not prefixed:
|
||||
@ -726,8 +752,8 @@ class UnitRegistry(object):
|
||||
if reg.reference is not None:
|
||||
self._get_dimensionality_recurse(reg.reference, exp2, accumulator)
|
||||
|
||||
def get_base_units(self, input_units, check_nonmult=True):
|
||||
"""Convert unit or dict of units to the base units.
|
||||
def get_root_units(self, input_units, check_nonmult=True):
|
||||
"""Convert unit or dict of units to the root units.
|
||||
|
||||
If any unit is non multiplicative and check_converter is True,
|
||||
then None is returned as the multiplicative factor.
|
||||
@ -741,12 +767,12 @@ class UnitRegistry(object):
|
||||
"""
|
||||
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)
|
||||
|
||||
def _get_base_units(self, input_units, check_nonmult=True):
|
||||
"""Convert unit or dict of units to the base units.
|
||||
def _get_root_units(self, input_units, check_nonmult=True):
|
||||
"""Convert unit or dict of units to the root units.
|
||||
|
||||
If any unit is non multiplicative and check_converter is True,
|
||||
then None is returned as the multiplicative factor.
|
||||
@ -762,11 +788,11 @@ class UnitRegistry(object):
|
||||
return 1., UnitsContainer()
|
||||
|
||||
# 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]
|
||||
if check_nonmult and input_units in self._root_units_cache:
|
||||
return self._root_units_cache[input_units]
|
||||
|
||||
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]
|
||||
units = UnitsContainer(dict((k, v) for k, v in accumulators[1].items()
|
||||
@ -780,7 +806,63 @@ class UnitRegistry(object):
|
||||
|
||||
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:
|
||||
exp2 = exp*ref[key]
|
||||
key = self.get_name(key)
|
||||
@ -790,19 +872,19 @@ class UnitRegistry(object):
|
||||
else:
|
||||
accumulators[0] *= reg._converter.scale ** exp2
|
||||
if reg.reference is not None:
|
||||
self._get_base_units_recurse(reg.reference, exp2,
|
||||
self._get_root_units_recurse(reg.reference, exp2,
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
def _get_compatible_units(self, input_units):
|
||||
def _get_compatible_units(self, input_units, group_or_system=None):
|
||||
"""
|
||||
"""
|
||||
if not input_units:
|
||||
@ -819,7 +901,11 @@ class UnitRegistry(object):
|
||||
for node in nodes:
|
||||
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):
|
||||
"""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
|
||||
# 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
|
||||
# must first convert to Decimal before we can '*' the values
|
||||
|
Loading…
Reference in New Issue
Block a user