예제 #1
0
    def test_log_quantity_creation(self):

        # Following Quantity Creation Pattern
        for args in (
            (4.2, "dBm"),
            (4.2, UnitsContainer(decibelmilliwatt=1)),
            (4.2, self.ureg.dBm),
        ):
            x = self.Q_(*args)
            self.assertEqual(x.magnitude, 4.2)
            self.assertEqual(x.units, UnitsContainer(decibelmilliwatt=1))

        x = self.Q_(self.Q_(4.2, "dBm"))
        self.assertEqual(x.magnitude, 4.2)
        self.assertEqual(x.units, UnitsContainer(decibelmilliwatt=1))

        x = self.Q_(4.2, UnitsContainer(decibelmilliwatt=1))
        y = self.Q_(x)
        self.assertEqual(x.magnitude, y.magnitude)
        self.assertEqual(x.units, y.units)
        self.assertIsNot(x, y)

        # Using multiplications for dB units requires autoconversion to baseunits
        new_reg = UnitRegistry(autoconvert_offset_to_baseunit=True)
        x = new_reg.Quantity("4.2 * dBm")
        self.assertEqual(x.magnitude, 4.2)
        self.assertEqual(x.units, UnitsContainer(decibelmilliwatt=1))

        with self.capture_log() as buffer:
            self.assertEqual(4.2 * new_reg.dBm,
                             new_reg.Quantity(4.2, 2 * new_reg.dBm))
            self.assertEqual(len(buffer), 1)
예제 #2
0
    def test_pickle_definition_syntax_error(self):
        # OffsetUnitCalculusError raised from a custom ureg must be pickleable even if
        # the ureg is not registered as the application ureg
        ureg = UnitRegistry(filename=None)
        ureg.define("foo = [bar]")
        ureg.define("bar = 2 foo")
        q1 = ureg.Quantity("1 foo")
        q2 = ureg.Quantity("1 bar")

        for protocol in range(pickle.HIGHEST_PROTOCOL + 1):
            for ex in [
                    DefinitionSyntaxError("foo", filename="a.txt", lineno=123),
                    RedefinitionError("foo", "bar"),
                    UndefinedUnitError("meter"),
                    DimensionalityError("a", "b", "c", "d", extra_msg=": msg"),
                    OffsetUnitCalculusError(
                        Quantity("1 kg")._units,
                        Quantity("1 s")._units),
                    OffsetUnitCalculusError(q1._units, q2._units),
            ]:
                with self.subTest(protocol=protocol, etype=type(ex)):
                    pik = pickle.dumps(ureg.Quantity("1 foo"), protocol)
                    with self.assertRaises(UndefinedUnitError):
                        pickle.loads(pik)

                    # assert False, ex.__reduce__()
                    ex2 = pickle.loads(pickle.dumps(ex, protocol))
                    assert type(ex) is type(ex2)
                    self.assertEqual(ex.args, ex2.args)
                    self.assertEqual(ex.__dict__, ex2.__dict__)
                    self.assertEqual(str(ex), str(ex2))
예제 #3
0
    def test_log_quantity_creation(self, caplog):

        # Following Quantity Creation Pattern
        for args in (
            (4.2, "dBm"),
            (4.2, UnitsContainer(decibelmilliwatt=1)),
            (4.2, self.ureg.dBm),
        ):
            x = self.Q_(*args)
            assert x.magnitude == 4.2
            assert x.units == UnitsContainer(decibelmilliwatt=1)

        x = self.Q_(self.Q_(4.2, "dBm"))
        assert x.magnitude == 4.2
        assert x.units == UnitsContainer(decibelmilliwatt=1)

        x = self.Q_(4.2, UnitsContainer(decibelmilliwatt=1))
        y = self.Q_(x)
        assert x.magnitude == y.magnitude
        assert x.units == y.units
        assert x is not y

        # Using multiplications for dB units requires autoconversion to baseunits
        new_reg = UnitRegistry(autoconvert_offset_to_baseunit=True)
        x = new_reg.Quantity("4.2 * dBm")
        assert x.magnitude == 4.2
        assert x.units == UnitsContainer(decibelmilliwatt=1)

        with caplog.at_level(logging.DEBUG):
            assert "wally" not in caplog.text
            assert 4.2 * new_reg.dBm == new_reg.Quantity(4.2, 2 * new_reg.dBm)

        assert len(caplog.records) == 1
예제 #4
0
def validate_numeric_distance(user_input,answer):
    
    from quantulum import parser
    from pint import UnitRegistry,UndefinedUnitError
    
    right_answer = answer
    ureg = UnitRegistry()
    
    try:
        user_input =parser.parse(user_input)
        answer = parser.parse(answer)
        
        unit_input_unit = user_input[0].unit.name.replace("-","_").replace(" ","_") # normalizing of unit names
        answer_unit = answer[0].unit.name.replace("-","_").replace(" ","_") # normalizing of unit names
        quantity1 = ureg.Quantity(user_input[0].value,ureg.parse_expression(str(unit_input_unit))).to('kilometers')
        quantity2 = ureg.Quantity(answer[0].value,ureg.parse_expression(str(answer_unit))).to('kilometers')
         
        percentage_variation = quantity1.magnitude/quantity2.magnitude
        
        if percentage_variation == 1.0 :
            return supporting_list[random.randint(1,len(supporting_list)-1)]
        elif (percentage_variation >=.96 and percentage_variation <= 1.03 ) :
            return supporting_list[random.randint(1,len(supporting_list)-1)] + \
                    " Your answer is in well accepted range. Still if you are curious the exact Value is "+ right_answer
        else:
            return "the right answer is " + right_answer
        
    except UndefinedUnitError:
        return " Distance is expressed in meters,kilometers,miles,astronomical unit,light year"
    except BaseException as e :
        logger.info("exception : %s",e)
        return "the right answer is " + right_answer
예제 #5
0
    def test_issue468(self):
        ureg = UnitRegistry()

        @ureg.wraps(('kg'), 'meter')
        def f(x):
            return x

        x = ureg.Quantity(1., 'meter')
        y = f(x)
        z = x * y
        self.assertEquals(z, ureg.Quantity(1., 'meter * kilogram'))
예제 #6
0
    def test_issue468(self):
        ureg = UnitRegistry()

        @ureg.wraps(("kg"), "meter")
        def f(x):
            return x

        x = ureg.Quantity(1.0, "meter")
        y = f(x)
        z = x * y
        self.assertEqual(z, ureg.Quantity(1.0, "meter * kilogram"))
예제 #7
0
 def test_issue25(self):
     x = ParserHelper.from_string("10 %")
     self.assertEqual(x, ParserHelper(10, {"%": 1}))
     x = ParserHelper.from_string("10 ‰")
     self.assertEqual(x, ParserHelper(10, {"‰": 1}))
     ureg = UnitRegistry()
     ureg.define("percent = [fraction]; offset: 0 = %")
     ureg.define("permille = percent / 10 = ‰")
     x = ureg.parse_expression("10 %")
     self.assertEqual(x, ureg.Quantity(10, {"%": 1}))
     y = ureg.parse_expression("10 ‰")
     self.assertEqual(y, ureg.Quantity(10, {"‰": 1}))
     self.assertEqual(x.to("‰"), ureg.Quantity(1, {"‰": 1}))
예제 #8
0
 def test_issue25(self):
     x = ParserHelper.from_string('10 %')
     self.assertEqual(x, ParserHelper(10, {'%': 1}))
     x = ParserHelper.from_string('10 ‰')
     self.assertEqual(x, ParserHelper(10, {'‰': 1}))
     ureg = UnitRegistry()
     ureg.define('percent = [fraction]; offset: 0 = %')
     ureg.define('permille = percent / 10 = ‰')
     x = ureg.parse_expression('10 %')
     self.assertEqual(x, ureg.Quantity(10, {'%': 1}))
     y = ureg.parse_expression('10 ‰')
     self.assertEqual(y, ureg.Quantity(10, {'‰': 1}))
     self.assertEqual(x.to('‰'), ureg.Quantity(1, {'‰': 1}))
예제 #9
0
    def test_quantity_hash(self):
        x = self.QP_("4.2", "meter")
        x2 = self.QP_("4200", "millimeter")
        y = self.QP_("2", "second")
        z = self.QP_("0.5", "hertz")
        self.assertEqual(hash(x), hash(x2))

        # Dimensionless equality
        self.assertEqual(hash(y * z), hash(1.0))

        # Dimensionless equality from a different unit registry
        ureg2 = UnitRegistry(force_ndarray=self.FORCE_NDARRAY)
        y2 = ureg2.Quantity(self.NON_INT_TYPE("2"), "second")
        z2 = ureg2.Quantity(self.NON_INT_TYPE("0.5"), "hertz")
        self.assertEqual(hash(y * z), hash(y2 * z2))
예제 #10
0
 def test_pickle_crash_measurement(self, protocol):
     ureg = UnitRegistry(None)
     ureg.define("foo = []")
     m = ureg.Quantity(123, "foo").plus_minus(10)
     b = pickle.dumps(m, protocol)
     with pytest.raises(UndefinedUnitError):
         pickle.loads(b)
예제 #11
0
    def test_stack_contexts(self):
        ureg = UnitRegistry("""
            a = [dim1]
            b = 1/2 a
            c = 1/3 a
            d = [dim2]

            @context c1
                b = 1/4 a
                c = 1/6 a
                [dim1]->[dim2]: value * 2 d/a
            @end
            @context c2
                b = 1/5 a
                [dim1]->[dim2]: value * 3 d/a
            @end
            """.splitlines())
        q = ureg.Quantity(1, "a")
        assert q.to("b").magnitude == 2
        assert q.to("c").magnitude == 3
        assert q.to("b", "c1").magnitude == 4
        assert q.to("c", "c1").magnitude == 6
        assert q.to("d", "c1").magnitude == 2
        assert q.to("b", "c2").magnitude == 5
        assert q.to("c", "c2").magnitude == 3
        assert q.to("d", "c2").magnitude == 3
        assert q.to("b", "c1", "c2").magnitude == 5  # c2 takes precedence
        assert q.to("c", "c1",
                    "c2").magnitude == 6  # c2 doesn't change it, so use c1
        assert q.to("d", "c1", "c2").magnitude == 3  # c2 takes precedence
예제 #12
0
def convert(fromunit, tounit, value, fstep=1, timestep=4):
    """ Converts values between units

    Parameters
    ----------
    fromunit : str
        Unit to convert from
    tounit : str
        Unit to convert to
    value : scalar
        The value to convert
    fstep : int
        The sampling frame step of the simulation in nanoseconds
    timestep : int
        The timestep of the simulation in femtoseconds

    Returns
    -------
    conv : scalra
        The converted value
    """

    ureg = UnitRegistry()
    ureg.define('frame = {} * ns'.format(fstep))
    ureg.define('step = ({} / 1000000) * ns = timestep'.format(timestep))

    q = ureg.Quantity(value, fromunit)
    convval = q.to(tounit)
    if convval.units == 'frame' or convval.units == 'step':
        vals = np.round(convval.magnitude).astype(int)
        if vals.size == 1:  # Fix for PyEMMA tica. remove in future
            return int(vals)
        return vals
    else:
        return convval.magnitude
예제 #13
0
파일: unit.py 프로젝트: tomalrussell/smif
class UnitAdaptor(Adaptor):
    """Scalar conversion of units
    """
    def __init__(self, name):
        self._register = UnitRegistry()
        super().__init__(name)

    def before_model_run(self, data_handle: DataHandle):
        """Register unit definitions in registry before model run
        """
        units = data_handle.read_unit_definitions()
        for unit in units:
            self._register.define(unit)

    def convert(self, data_array, to_spec, coefficients):
        data = data_array.data
        from_spec = data_array.spec

        try:
            quantity = self._register.Quantity(data, from_spec.unit)
        except UndefinedUnitError:
            raise ValueError('Cannot convert from undefined unit {}'.format(
                from_spec.unit))

        try:
            converted_quantity = quantity.to(to_spec.unit)
        except UndefinedUnitError as ex:
            raise ValueError('Cannot convert undefined unit {}'.format(
                to_spec.unit)) from ex
        except DimensionalityError as ex:
            msg = 'Cannot convert unit from {} to {}'
            raise ValueError(msg.format(from_spec.unit, to_spec.unit)) from ex

        return converted_quantity.magnitude

    def get_coefficients(self, data_handle, from_spec, to_spec):
        # override with no-op - all the work is done in convert with scalar operations
        pass

    def generate_coefficients(self, from_spec, to_spec):
        # override with no-op - all the work is done in convert with scalar operations
        pass

    def parse_unit(self, unit_string):
        """Parse a unit string (abbreviation or full) into a Unit object

        Parameters
        ----------
        unit : str

        Returns
        -------
        quantity : :class:`pint.Unit`
        """
        try:
            unit = self._register.parse_units(unit_string)
        except UndefinedUnitError:
            self.logger.warning("Unrecognised unit: %s", unit_string)
            unit = None
        return unit
예제 #14
0
    def handle_matches(self, match):
        """
        Returns a response statement from a matched input statement.

        :param match: It is a valid matched pattern from the input statement
        :type: `_sre.SRE_Match`
        """
        response = Statement(text='')

        from_parsed = match.group("from")
        target_parsed = match.group("target")
        n_statement = match.group("number")

        if n_statement == 'a' or n_statement == 'an':
            n_statement = '1.0'

        n = mathparse.parse(n_statement, self.language.ISO_639.upper())

        ureg = UnitRegistry()
        from_parsed, target_parsed = self.get_valid_units(
            ureg, from_parsed, target_parsed)

        if from_parsed is None or target_parsed is None:
            response.confidence = 0.0
        else:
            from_value = ureg.Quantity(float(n), from_parsed)
            target_value = from_value.to(target_parsed)
            response.confidence = 1.0
            response.text = str(target_value.magnitude)

        return response
예제 #15
0
 def test_pickle_crash(self, protocol):
     ureg = UnitRegistry(None)
     ureg.define("foo = []")
     q = ureg.Quantity(123, "foo")
     b = pickle.dumps(q, protocol)
     self.assertRaises(UndefinedUnitError, pickle.loads, b)
     b = pickle.dumps(q.units, protocol)
     self.assertRaises(UndefinedUnitError, pickle.loads, b)
예제 #16
0
 def test_issue1062_issue1097(self):
     # Must not be used by any other tests
     ureg = UnitRegistry()
     assert "nanometer" not in ureg._units
     for i in range(5):
         ctx = Context.from_lines(["@context _", "cal = 4 J"])
         with ureg.context("sp", ctx):
             q = ureg.Quantity(1, "nm")
             q.to("J")
예제 #17
0
 def _getmemory(self):
     ureg = UnitRegistry()
     total_memory = int(
         ureg.Quantity(psutil.virtual_memory().total,
                       ureg.byte).to('MiB').magnitude)
     nr_devices = len(self._getdevices())
     if nr_devices != 0:
         return int(total_memory / nr_devices)
     else:
         return None
예제 #18
0
def convert(fromunit, tounit, value, fstep=1):
    ureg = UnitRegistry()
    ureg.define('frame = {} * ns = step'.format(fstep))

    q = ureg.Quantity(value, fromunit)
    convval = q.to(tounit)
    if convval.units == 'frame':
        return np.round(convval.magnitude).astype(int)
    else:
        return convval.magnitude
예제 #19
0
    def test_issue104(self):
        ureg = UnitRegistry()

        x = [ureg('1 meter'), ureg('1 meter'), ureg('1 meter')]
        y = [ureg('1 meter')] * 3

        def summer(values):
            if not values:
                return 0
            total = values[0]
            for v in values[1:]:
                total += v

            return total

        self.assertQuantityAlmostEqual(summer(x), ureg.Quantity(3, 'meter'))
        self.assertQuantityAlmostEqual(x[0], ureg.Quantity(1, 'meter'))
        self.assertQuantityAlmostEqual(summer(y), ureg.Quantity(3, 'meter'))
        self.assertQuantityAlmostEqual(y[0], ureg.Quantity(1, 'meter'))
예제 #20
0
 def test_pickle_crash(self, protocol):
     ureg = UnitRegistry(None)
     ureg.define("foo = []")
     q = ureg.Quantity(123, "foo")
     b = pickle.dumps(q, protocol)
     with pytest.raises(UndefinedUnitError):
         pickle.loads(b)
     b = pickle.dumps(q.units, protocol)
     with pytest.raises(UndefinedUnitError):
         pickle.loads(b)
예제 #21
0
def _conv_units_np(values, units_in, units_out, units_scalef=None):
    """
    return a copy of numpy array values, with units converted from units_in to units_out
    """
    ureg = UnitRegistry()
    values_in_pint = ureg.Quantity(values, ureg(_clean_units(units_in)))
    if units_scalef is not None:
        values_in_pint *= ureg(_clean_units(units_scalef))
    values_out_pint = values_in_pint.to(_clean_units(units_out))
    return values_out_pint.magnitude
예제 #22
0
 def test_micro_creation(self):
     ureg = UnitRegistry()
     try:
         # Check if the install supports unicode, travis python27 seems to
         # support it...
         if (sys.version_info < (3, 0)):
             'µ'.decode('utf-8')
     except UnicodeEncodeError:
         self.assertRaises(UndefinedUnitError, ureg.Quantity, 2, 'µm')
     else:
         ureg.Quantity(2, 'µm')
 def setup_class(self):
     #
     ureg = UnitRegistry()
     ureg.define('micron = um')
     self.ureg = ureg
     #
     self.convert_value_test = [
         (0.0, 'degC', 'degK', ureg.Quantity(0.0, 'degC').to('degK')),
         (1.0, 'psi', 'SI', ureg.Quantity(1, 'psi').to_base_units()),
         (1.0, 'cP', 'dyne*s/cm^2', ureg.Quantity(1.0,
                                                  'cP').to('dyne*s/cm^2')),
         (1000.0, 'microns', 'SI', ureg.Quantity(1000,
                                                 'microns').to_base_units())
     ]
     #
     self._convertion_factor_test = [
         ('psi', 'kN/m^2', ureg('psi').to('kN/m^2').magnitude),
         ('lbf', 'N', ureg('lbf').to('N').magnitude),
         ('micron', 'SI', ureg('micron').to('m').magnitude),
         ('ml/min', 'SI', ureg('ml/min').to('m^3/sec').magnitude)
     ]
예제 #24
0
    def test_redefine(self):
        ureg = UnitRegistry("""
            foo = [d] = f = foo_alias
            bar = 2 foo = b = bar_alias
            baz = 3 bar = _ = baz_alias
            asd = 4 baz

            @context c
                # Note how we're redefining a symbol, not the base name, as a
                # function of another name
                b = 5 f
            """.splitlines())
        # Units that are somehow directly or indirectly defined as a function of the
        # overridden unit are also affected
        foo = ureg.Quantity(1, "foo")
        bar = ureg.Quantity(1, "bar")
        asd = ureg.Quantity(1, "asd")

        # Test without context before and after, to verify that the cache and units have
        # not been polluted
        for enable_ctx in (False, True, False):
            with self.subTest(enable_ctx):
                if enable_ctx:
                    ureg.enable_contexts("c")
                    k = 5
                else:
                    k = 2

                self.assertEqual(foo.to("b").magnitude, 1 / k)
                self.assertEqual(foo.to("bar").magnitude, 1 / k)
                self.assertEqual(foo.to("bar_alias").magnitude, 1 / k)
                self.assertEqual(foo.to("baz").magnitude, 1 / k / 3)
                self.assertEqual(bar.to("foo").magnitude, k)
                self.assertEqual(bar.to("baz").magnitude, 1 / 3)
                self.assertEqual(asd.to("foo").magnitude, 4 * 3 * k)
                self.assertEqual(asd.to("bar").magnitude, 4 * 3)
                self.assertEqual(asd.to("baz").magnitude, 4)

            ureg.disable_contexts()
예제 #25
0
 def test_default_formatting(self):
     ureg = UnitRegistry()
     x = ureg.Quantity(4.12345678, UnitsContainer(meter=2, kilogram=1, second=-1))
     for spec, result in (('L', r'4.12345678 \frac{kilogram \cdot meter^{2}}{second}'),
                          ('P', '4.12345678 kilogram·meter²/second'),
                          ('H', '4.12345678 kilogram meter<sup>2</sup>/second'),
                          ('C', '4.12345678 kilogram*meter**2/second'),
                          ('~', '4.12345678 kg * m ** 2 / s'),
                          ('L~', r'4.12345678 \frac{kg \cdot m^{2}}{s}'),
                          ('P~', '4.12345678 kg·m²/s'),
                          ('H~', '4.12345678 kg m<sup>2</sup>/s'),
                          ('C~', '4.12345678 kg*m**2/s'),
                          ):
         ureg.default_format = spec
         self.assertEqual('{0}'.format(x), result)
예제 #26
0
    def depths(self):
        if self.__depths is None:
            var = None
            for v in ['depth', 'deptht']:
                if v in self._dataset.variables:
                    var = self._dataset.variables[v]
                    break

            ureg = UnitRegistry()
            unit = ureg.parse_units(var.units.lower())
            self.__depths = ureg.Quantity(var[:],
                                          unit).to(ureg.meters).magnitude
            self.__depths.flags.writeable = False

        return self.__depths
예제 #27
0
def _isclose_one_var(var1, var2, rtol, atol):
    """Return true if netCDF vars var1 and var2 are close."""
    logger = logging.getLogger(__name__)

    # further comparisons do not make sense if shapes differ
    if var1.shape != var2.shape:
        logger.info(
            "    var1.shape %s != var2.shape %s for %s",
            var1.shape,
            var2.shape,
            var1.name,
        )
        return False

    res = True

    vals1 = var1[:]
    msv1 = getattr(var1, "_FillValue", None)
    vals2 = var2[:]
    msv2 = getattr(var2, "_FillValue", None)

    if ((vals1 == msv1) != (vals2 == msv2)).any():
        logger.info("    _FillValue pattern mismatch for %s", var1.name)
        res = False

    vals1 = np.where((vals1 == msv1) | (vals2 == msv2), np.nan, vals1)
    vals2 = np.where((vals1 == msv1) | (vals2 == msv2), np.nan, vals2)

    # if units are present and differ, convert vals1 to units of var2
    # this feature is not supported for udunits type time units
    if hasattr(var1, "units") and hasattr(var2, "units"):
        if "since" not in var1.units and "since" not in var2.units:
            ureg = UnitRegistry()
            if ureg(var1.units) != ureg(var2.units):
                vals1 = ureg.Quantity(vals1,
                                      var1.units).to(var2.units).magnitude
        else:
            if var1.units != var2.units:
                msg = "time-like units disagree '%s' != '%s'" % (var1.units,
                                                                 var2.units)
                raise ValueError(msg)

    if not _isclose_one_var_core(vals1, vals2, rtol=rtol, atol=atol):
        logger.info("    %s vals not close", var1.name)
        res = False

    return res
예제 #28
0
    def test_err_cyclic_dependency(self):
        ureg = UnitRegistry("""
            foo = [d]
            bar = foo
            baz = bar

            @context c
                bar = baz
            @end
            """.splitlines())
        # TODO align this exception and the one you get when you implement a cyclic
        #      dependency within the base registry. Ideally this exception should be
        #      raised by enable_contexts.
        ureg.enable_contexts("c")
        q = ureg.Quantity("bar")
        with self.assertRaises(RecursionError):
            q.to("foo")
예제 #29
0
def convert(unit_one, unit_two, value):
    """Will be a conversion function to convert units of measurement.
    This is entirely test based on a pint example, don't use this
    code for anything ever. Also need to make this user friendly.
    It currently doesn't say the units in a easily readable way."""
    ureg = UnitRegistry()

    try:
        converted = ureg.Quantity(value + ' * ' + unit_one).to(unit_two)
    except Exception as err:
        return Response('Unable to convert ' + unit_one + ' to ' + unit_two +
                        ' [This API is in Beta]',
                        mimetype='text/plain')

    return Response(value + unit_one + ' to ' + unit_two + ' is ' +
                    str(round(converted, 2)) + ' [This API is in Beta]',
                    mimetype='text/plain')
예제 #30
0
def convert_units(dataset, in_unit, out_unit):
    """Convert units of *dataset*."""
    from pint import UnitRegistry

    ureg = UnitRegistry()
    # Commented because buggy: race condition ?
    # ureg.define("degree_Celsius = degC = Celsius = C = CELSIUS")
    in_unit = ureg.parse_expression(in_unit, False)
    if out_unit in ['CELSIUS', 'C', 'Celsius', 'celsius']:
        dest_unit = ureg.degC
    else:
        dest_unit = ureg.parse_expression(out_unit, False)
    data = ureg.Quantity(dataset, in_unit)
    attrs = dataset.attrs
    dataset = data.to(dest_unit).magnitude
    dataset.attrs = attrs
    dataset.attrs["units"] = out_unit
    return dataset
예제 #31
0
                'units': str(self.units)}

    def make_resizable(self):
        self._magnitude = ResizableArray(self._magnitude)

    def append(self, item):
        mag = item.value_in(self.units)
        self._magnitude.append(mag)

    def extend(self, items):
        from . import array
        mags = array(items).value_in(self.units)
        self._magnitude.append(mags)

# monkeypatch pint's unit registry to return BuckyballQuantities
ureg.Quantity = MdtQuantity
ureg.Unit = MdtUnit

# These synonyms are here solely so that we can write descriptive docstrings
# TODO: use typing module to turn these into real abstract types

class Scalar(MdtQuantity):
    """ A scalar quantity (i.e., a single floating point number) with attached units
    """
    def __init__(self, *args):
        raise NotImplementedError('This is an abstract class - use MdtQuantity instead')


class Vector(MdtQuantity):
    """ A vector quantity (i.e., a list of floats) with attached units, which behaves like a
    1-dimensional numpy array