diff options
author | Hernan Grecco <hernan.grecco@gmail.com> | 2014-03-24 18:46:45 -0300 |
---|---|---|
committer | Hernan Grecco <hernan.grecco@gmail.com> | 2014-03-24 18:54:45 -0300 |
commit | 17fc8731abe2d01c8b5cb03cd1b83c12b6bd029e (patch) | |
tree | 78de85c895e49b6d7230854d4b21cdc6df9d9eb9 | |
parent | caaf23e2af78c7aca99f74541e2bd7f79df3246c (diff) | |
download | pint-17fc8731abe2d01c8b5cb03cd1b83c12b6bd029e.tar.gz |
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
-rw-r--r-- | pint/testsuite/test_unit.py | 26 | ||||
-rw-r--r-- | pint/unit.py | 39 |
2 files changed, 58 insertions, 7 deletions
diff --git a/pint/testsuite/test_unit.py b/pint/testsuite/test_unit.py index 192af78..64de85c 100644 --- a/pint/testsuite/test_unit.py +++ b/pint/testsuite/test_unit.py @@ -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): diff --git a/pint/unit.py b/pint/unit.py index 4122b69..31046b6 100644 --- a/pint/unit.py +++ b/pint/unit.py @@ -173,6 +173,10 @@ class Definition(object): 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) |