Raise exception or warn upon redefinition of units.

In the DEFAULT_REGISTRY, an exception (ValueError) is raised.
In any other registry, issue a warning

The behaviour can be chaged using the `on_redefinition` argument in
the constructor.

Close #108
This commit is contained in:
Hernan Grecco 2014-03-24 18:46:45 -03:00
parent caaf23e2af
commit 17fc8731ab
2 changed files with 58 additions and 7 deletions

View File

@ -4,6 +4,7 @@ from __future__ import division, unicode_literals, print_function, absolute_impo
import math
import copy
import warnings
import operator as op
from pint.unit import (ScaleConverter, OffsetConverter, UnitsContainer,
@ -495,6 +496,20 @@ class TestEquivalents(TestCase):
self.assertEqual(ureg.parse_units(''), UnitsContainer())
self.assertRaises(ValueError, ureg.parse_units, '2 * meter')
def test_redefinition(self):
d = UnitRegistry().define
with warnings.catch_warnings(record=True) as w:
d('meter = [time]')
d('kilo- = 1000')
d('[speed] = [length]')
# aliases
d('bla = 3.2 meter = inch')
d('myk- = 1000 = kilo-')
self.assertEqual(len(w), 5)
class TestRegistryWithDefaultRegistry(TestRegistry):
@ -512,6 +527,17 @@ class TestRegistryWithDefaultRegistry(TestRegistry):
q = y['meter']
self.assertIsInstance(y, UnitRegistry)
def test_redefinition(self):
d = self.ureg.define
self.assertRaises(ValueError, d, 'meter = [time]')
self.assertRaises(ValueError, d, 'kilo- = 1000')
self.assertRaises(ValueError, d, '[speed] = [length]')
# aliases
self.assertIn('inch', self.ureg._units)
self.assertRaises(ValueError, d, 'bla = 3.2 meter = inch')
self.assertRaises(ValueError, d, 'myk- = 1000 = kilo-')
class TestErrors(unittest.TestCase):

View File

@ -172,6 +172,10 @@ class Definition(object):
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
@ -388,12 +392,16 @@ class UnitRegistry(object):
:param force_ndarray: convert any input, scalar or not to a numpy.ndarray.
:param default_to_delta: In the context of a multiplication of units, interpret
non-multiplicative units as their *delta* counterparts.
:param on_redefinition: action to take in case a unit is redefined.
'warn', 'raise', 'ignore'
:type on_redefintion: str
"""
def __init__(self, filename='', force_ndarray=False, default_to_delta=True):
def __init__(self, filename='', force_ndarray=False, default_to_delta=True, on_redefinition='warn'):
self.Quantity = build_quantity_class(self, force_ndarray)
self.Measurement = build_measurement_class(self, force_ndarray)
self._on_redefinition = on_redefinition
#: Map dimension name (string) to its definition (DimensionDefinition).
self._dimensions = {}
@ -592,8 +600,11 @@ class UnitRegistry(object):
d = self._units
if definition.is_base:
for dimension in definition.reference.keys():
if dimension != '[]' and dimension in self._dimensions:
raise ValueError('Only one unit per dimension can be a base unit.')
if dimension in self._dimensions:
if dimension != '[]':
raise ValueError('Only one unit per dimension can be a base unit.')
continue
self.define(DimensionDefinition(dimension, '', (), None, is_base=True))
elif isinstance(definition, PrefixDefinition):
@ -601,15 +612,26 @@ class UnitRegistry(object):
else:
raise TypeError('{0} is not a valid definition.'.format(definition))
d[definition.name] = definition
def _adder(key, value, action=self._on_redefinition, selected_dict=d):
if key in selected_dict:
if action == 'raise':
raise ValueError("Cannot redefine '%s' (%s) in the default registry"
% (key, type(value)))
elif action == 'warn':
logger.warning("Redefining '%s' (%s)", key, type(value))
if definition.symbol:
d[definition.symbol] = definition
selected_dict[key] = value
_adder(definition.name, definition)
if definition.has_symbol:
_adder(definition.symbol, definition)
for alias in definition.aliases:
if ' ' in alias:
logger.warn('Alias cannot contain a space: ' + alias)
d[alias] = definition
_adder(alias, definition)
if isinstance(definition.converter, OffsetConverter):
d_name = 'delta_' + definition.name
@ -1180,10 +1202,13 @@ class LazyRegistry(object):
def __init(self):
args, kwargs = self.__dict__['params']
kwargs['on_redefinition'] = 'raise'
self.__class__ = UnitRegistry
self.__init__(*args, **kwargs)
def __getattr__(self, item):
if item == '_on_redefinition':
return 'raise'
self.__init()
return getattr(self, item)