deb-python-pint/pint/definitions.py

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)