158 lines
5.2 KiB
Python
158 lines
5.2 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""
|
|
pint.definitions
|
|
~~~~~~~~~
|
|
|
|
Functions and classes related to unit definitions.
|
|
|
|
:copyright: 2016 by Pint Authors, see AUTHORS for more details.
|
|
:license: BSD, see LICENSE for more details.
|
|
"""
|
|
|
|
from __future__ import (division, unicode_literals, print_function,
|
|
absolute_import)
|
|
|
|
from .converters import ScaleConverter, OffsetConverter
|
|
from .util import UnitsContainer, _is_dim, ParserHelper
|
|
from .compat import string_types
|
|
|
|
|
|
class Definition(object):
|
|
"""Base class for definitions.
|
|
|
|
:param name: name.
|
|
:param symbol: a short name or symbol for the definition
|
|
:param aliases: iterable of other names.
|
|
:param converter: an instance of Converter.
|
|
"""
|
|
|
|
def __init__(self, name, symbol, aliases, converter):
|
|
self._name = name
|
|
self._symbol = symbol
|
|
self._aliases = aliases
|
|
self._converter = converter
|
|
|
|
@property
|
|
def is_multiplicative(self):
|
|
return self._converter.is_multiplicative
|
|
|
|
@classmethod
|
|
def from_string(cls, definition):
|
|
"""Parse a definition
|
|
"""
|
|
name, definition = definition.split('=', 1)
|
|
name = name.strip()
|
|
|
|
result = [res.strip() for res in definition.split('=')]
|
|
value, aliases = result[0], tuple(result[1:])
|
|
symbol, aliases = (aliases[0], aliases[1:]) if aliases else (None,
|
|
aliases)
|
|
|
|
if name.startswith('['):
|
|
return DimensionDefinition(name, symbol, aliases, value)
|
|
elif name.endswith('-'):
|
|
name = name.rstrip('-')
|
|
return PrefixDefinition(name, symbol, aliases, value)
|
|
else:
|
|
return UnitDefinition(name, symbol, aliases, value)
|
|
|
|
@property
|
|
def name(self):
|
|
return self._name
|
|
|
|
@property
|
|
def symbol(self):
|
|
return self._symbol or self._name
|
|
|
|
@property
|
|
def has_symbol(self):
|
|
return bool(self._symbol)
|
|
|
|
@property
|
|
def aliases(self):
|
|
return self._aliases
|
|
|
|
@property
|
|
def converter(self):
|
|
return self._converter
|
|
|
|
def __str__(self):
|
|
return self.name
|
|
|
|
|
|
class PrefixDefinition(Definition):
|
|
"""Definition of a prefix.
|
|
"""
|
|
|
|
def __init__(self, name, symbol, aliases, converter):
|
|
if isinstance(converter, string_types):
|
|
converter = ScaleConverter(eval(converter))
|
|
aliases = tuple(alias.strip('-') for alias in aliases)
|
|
if symbol:
|
|
symbol = symbol.strip('-')
|
|
super(PrefixDefinition, self).__init__(name, symbol, aliases,
|
|
converter)
|
|
|
|
|
|
class UnitDefinition(Definition):
|
|
"""Definition of a unit.
|
|
|
|
:param reference: Units container with reference units.
|
|
:param is_base: indicates if it is a base unit.
|
|
"""
|
|
|
|
def __init__(self, name, symbol, aliases, converter,
|
|
reference=None, is_base=False):
|
|
self.reference = reference
|
|
self.is_base = is_base
|
|
if isinstance(converter, string_types):
|
|
if ';' in converter:
|
|
[converter, modifiers] = converter.split(';', 2)
|
|
modifiers = dict((key.strip(), eval(value)) for key, value in
|
|
(part.split(':')
|
|
for part in modifiers.split(';')))
|
|
else:
|
|
modifiers = {}
|
|
|
|
converter = ParserHelper.from_string(converter)
|
|
if all(_is_dim(key) for key in converter.keys()):
|
|
self.is_base = True
|
|
elif not any(_is_dim(key) for key in converter.keys()):
|
|
self.is_base = False
|
|
else:
|
|
raise ValueError('Cannot mix dimensions and units in the same definition. '
|
|
'Base units must be referenced only to dimensions. '
|
|
'Derived units must be referenced only to units.')
|
|
self.reference = UnitsContainer(converter)
|
|
if modifiers.get('offset', 0.) != 0.:
|
|
converter = OffsetConverter(converter.scale,
|
|
modifiers['offset'])
|
|
else:
|
|
converter = ScaleConverter(converter.scale)
|
|
|
|
super(UnitDefinition, self).__init__(name, symbol, aliases, converter)
|
|
|
|
|
|
class DimensionDefinition(Definition):
|
|
"""Definition of a dimension.
|
|
"""
|
|
|
|
def __init__(self, name, symbol, aliases, converter,
|
|
reference=None, is_base=False):
|
|
self.reference = reference
|
|
self.is_base = is_base
|
|
if isinstance(converter, string_types):
|
|
converter = ParserHelper.from_string(converter)
|
|
if not converter:
|
|
self.is_base = True
|
|
elif all(_is_dim(key) for key in converter.keys()):
|
|
self.is_base = False
|
|
else:
|
|
raise ValueError('Base dimensions must be referenced to None. '
|
|
'Derived dimensions must only be referenced '
|
|
'to dimensions.')
|
|
self.reference = UnitsContainer(converter)
|
|
|
|
super(DimensionDefinition, self).__init__(name, symbol, aliases,
|
|
converter=None)
|