def test_func_converters(): Quantity.reset_prefs() def from_dB(value): return 10**(value/20) def to_dB(value): return 20*math.log10(value) vconverter = UnitConversion('V', 'dBV', from_dB, to_dB) assert str(vconverter) == 'V ← from_dB(dBV), dBV ← to_dB(V)' assert str(vconverter.convert(Quantity('100mV'))) == '-20 dBV' assert str(vconverter.convert(Quantity('-20dBV'))) == '100 mV' aconverter = UnitConversion('A', 'dBA', from_dB, to_dB) assert str(aconverter) == 'A ← from_dB(dBA), dBA ← to_dB(A)' assert str(aconverter.convert(Quantity('100mA'))) == '-20 dBA' assert str(aconverter.convert(Quantity('-20dBA'))) == '100 mA' assert '{:pdBV}'.format(Quantity('100mV')) == '-20 dBV' assert '{:pdBV}'.format(Quantity('10V')) == '20 dBV' assert '{:pV}'.format(Quantity('-20 dBV')) == '0.1 V' assert '{:pV}'.format(Quantity('20 dBV')) == '10 V' assert '{:pdBA}'.format(Quantity('100mA')) == '-20 dBA' assert '{:pdBA}'.format(Quantity('10A')) == '20 dBA' assert '{:pA}'.format(Quantity('-20 dBA')) == '0.1 A' assert '{:pA}'.format(Quantity('20 dBA')) == '10 A'
def test_writer_prec(): Quantity.reset_prefs() for line in data2.splitlines(): v, p0, p1, p2, p3, p4 = [c.strip() for c in line.strip().split(';')] print('Trying: v={v}, p0={p0}, p1={p1}, p2={p2}, p3={p3}, p4={p4}'. format(**locals())) q = Quantity(v) res = q.binary(prec=0) exp = '{v}: expected <{p0}>, got <{res}>.'.format(**locals()) assert res == p0, exp res = q.binary(prec=1) exp = '{v}: expected <{p1}>, got <{res}>.'.format(**locals()) assert res == p1, exp res = q.binary(prec=2) exp = '{v}: expected <{p2}>, got <{res}>.'.format(**locals()) assert res == p2, exp res = q.binary(prec=3) exp = '{v}: expected <{p3}>, got <{res}>.'.format(**locals()) assert res == p3, exp res = q.binary(prec=4) exp = '{v}: expected <{p4}>, got <{res}>.'.format(**locals()) assert res == p4, exp
def test_linear_conversion(): Quantity.reset_prefs() conversion = UnitConversion('USD', 'BTC', 100000) assert str(conversion) == 'USD ← 100000*BTC' result = conversion.convert(1, 'BTC', 'USD') assert str(result) == '100 kUSD' result = conversion.convert(1, 'USD', 'BTC') assert str(result) == '10 uBTC' result = conversion.convert(from_units='BTC', to_units='USD') assert str(result) == '100 kUSD' result = conversion.convert(from_units='USD', to_units='BTC') assert str(result) == '10 uBTC' result = conversion.convert('BTC') assert str(result) == '100 kUSD' result = conversion.convert('USD') assert str(result) == '10 uBTC' result = conversion.convert(10) assert str(result) == '1 MUSD' dollar = Quantity('200000 USD') bitcoin = conversion.convert(dollar) assert str(bitcoin) == '2 BTC' dollar = conversion.convert(bitcoin) assert str(dollar) == '200 kUSD'
def test_time(): Quantity.reset_prefs() with Quantity.prefs( spacer=None, show_label=None, label_fmt=None, label_fmt_full=None, ignore_sf=True ): q=Quantity('86400 s') assert q.render() == '86.4 ks' assert q.render(scale='sec') == '86.4 ksec' assert q.render(scale='min') == '1.44 kmin' assert q.render(scale='hr') == '24 hr' assert q.render(scale='hour') == '24 hour' assert q.render(scale='day') == '1 day' q=Quantity('1 day', scale='s') assert q.render() == '86.4 ks' q=Quantity('24 hour', scale='s') assert q.render() == '86.4 ks' q=Quantity('24 hr', scale='s') assert q.render() == '86.4 ks' q=Quantity('60 min', scale='s') assert q.render() == '3.6 ks' q=Quantity('60 sec', scale='s') assert q.render() == '60 s'
def test_billow(): Quantity.reset_prefs() qs = Quantity.extract(r""" C3 = 250.7nF f_corner (f₀) = 500mHz w_corner (ω₀) = 2*pi*f_corner 'rads/s' Aw = C3*sqrt(w_corner) '√Ω' """, predefined=dict(sqrt=math.sqrt)) C3 = qs.pop('C3') assert str(C3) == '250.7 nF' assert C3.units == 'F' assert C3.name == 'C3' f_corner = qs.pop('f_corner') assert str(f_corner) == '500 mHz' assert f_corner.units == 'Hz' assert f_corner.name == 'f₀' w_corner = qs.pop('w_corner') assert str(w_corner) == '3.1416 rads/s' assert w_corner.units == 'rads/s' assert w_corner.name == 'ω₀' Aw = qs.pop('Aw') assert str(Aw) == '444.35 n√Ω' assert Aw.units == '√Ω' assert Aw.name == 'Aw' assert not qs
def test_affiliate(): Quantity.reset_prefs() qs = Quantity.extract(r""" This is a non conforming line. Fin = 10MHz -- input frequency -- Fin = 10MHz -- input frequency Tstop = 5/Fin "s" -- stop time This is a non conforming line. """) f_in = qs.pop('Fin') assert f_in.is_close(Quantity(1e7, 'Hz'), check_units=True) assert f_in.is_close(1e7) assert f_in.units == 'Hz' assert f_in.name == 'Fin' assert f_in.desc == 'input frequency' t_stop = qs.pop('Tstop') assert t_stop.is_close(Quantity(5 / f_in, 's'), check_units=True) assert t_stop.is_close(5 / f_in) assert t_stop.units == 's' assert t_stop.name == 'Tstop' assert t_stop.desc == 'stop time' assert not qs
def test_reader(): Quantity.reset_prefs() with Quantity.prefs(known_units='Zippy'): for line in data1.splitlines(): v, s1, s2, s3, s4, s5 = [ c.strip() for c in line.strip().split(';') ] print('Trying: v={v}, s1={s1}, s2={s2}, s3={s3}, s4={s4}, s5={s5}'. format(**locals())) q = Quantity(v, binary=True) res = str(q) exp = '{v}: expected <{s1}>, got <{res}>.'.format(**locals()) assert s1 == res, exp res = q.binary() exp = '{v}: expected <{s2}>, got <{res}>.'.format(**locals()) assert s2 == res, exp res = q.binary(prec=4, strip_zeros=False) exp = '{v}: expected <{s3}>, got <{res}>.'.format(**locals()) assert s3 == res, exp res = q.binary(strip_zeros=True, strip_radix=False, show_units=False) exp = '{v}: expected <{s4}>, got <{res}>.'.format(**locals()) assert s4 == res, exp res = q.binary(prec='full', strip_zeros=False) exp = '{v}: expected <{s5}>, got <{res}>.'.format(**locals()) assert s5 == res, exp
def test_prefs_defaults(): Quantity.reset_prefs() Quantity.set_prefs(spacer='-', map_sf=dict(k='K')) assert Quantity.get_pref('spacer') == '-' assert Quantity.get_pref('map_sf') == dict(k='K') class Foo(Quantity): pass assert Foo.get_pref('spacer') == '-' assert Foo.get_pref('map_sf') == dict(k='K') Foo.set_prefs(spacer='~', map_sf={}) assert Foo.get_pref('spacer') == '~' assert Foo.get_pref('map_sf') == dict() assert Quantity.get_pref('spacer') == '-' assert Quantity.get_pref('map_sf') == dict(k='K') with Quantity.prefs(spacer=None, map_sf=None): assert Quantity.get_pref('spacer') == ' ' assert Quantity.get_pref('map_sf') == {} assert Quantity.get_pref('spacer') == '-' assert Quantity.get_pref('map_sf') == dict(k='K') Quantity.set_prefs(spacer=None, map_sf=None)
def test_README(): if sys.version_info < (3, 6): # code used in doctests assumes python3.6 return Quantity.reset_prefs() rv = doctest.testfile('../README.rst', optionflags=doctest.ELLIPSIS) assert rv.failed == 0 assert rv.attempted == 29
def test_basilica(): Quantity.reset_prefs() qs = Quantity.extract('XAU = 1.9 k$/oz # price of gold on 23 July 2020') xau = qs.pop('XAU') assert xau.is_close(Quantity(1900, '$/oz'), check_units=True) assert xau.is_close(1900) assert xau.units == '$/oz' assert xau.name == 'XAU' assert xau.desc == 'price of gold on 23 July 2020' assert not qs
def test_anatomy(): Quantity.reset_prefs() qs = Quantity.extract( r""" Rin = ∞Ω -- input resistance """, ) Rin = qs.pop('Rin') assert float(Rin) == float('inf') assert Rin.units == 'Ω' assert Rin.is_infinite() == 'inf' assert not qs
def test_bulletin(): Quantity.reset_prefs() qs = Quantity.extract(r""" Fclk = 50MHz # clock frequency """) f_clk = qs.pop('Fclk') assert f_clk.is_close(Quantity(5e7, 'Hz'), check_units=True) assert f_clk.is_close(5e7) assert f_clk.units == 'Hz' assert f_clk.name == 'Fclk' assert f_clk.desc == 'clock frequency' assert not qs
def test_deduce(): Quantity.reset_prefs() qs = Quantity.extract(r""" Fclk = 50MHz """) f_clk = qs.pop('Fclk') assert f_clk.is_close(Quantity(5e7, 'Hz'), check_units=True) assert f_clk.is_close(5e7) assert f_clk.units == 'Hz' assert f_clk.name == 'Fclk' assert f_clk.desc == '' assert not qs
def test_wager(): Quantity.reset_prefs() qs = Quantity.extract(r""" Fclk ($F_{\rm clk}$) = 50MHz -- clock frequency """) f_clk = qs.pop('Fclk') assert f_clk.is_close(Quantity(5e7, 'Hz'), check_units=True) assert f_clk.is_close(5e7) assert f_clk.units == 'Hz' assert f_clk.name == r'$F_{\rm clk}$' assert f_clk.desc == 'clock frequency' assert not qs
def test_disallow(): Quantity.reset_prefs() qs = Quantity.extract( r""" rate = 64GiB/s -- bit rate """, binary=True, ) rate = qs.pop('rate') assert float(rate) == 68719476736 assert rate.units == 'B/s' assert not qs
def test_sagan(): Quantity.reset_prefs() qs = Quantity.extract(r""" Carl Sagan's frequencies -- These are the frequencies that Carl Sagan asserted were of -- high interest to SETI. f_hy ($f_{\rm hy}$) = 1420.405751786 MHz -- Hydrogen line frequency f_sagan1 ($f_{\rm sagan1}$) = pi*f_hy "Hz" -- Sagan's first frequency f_sagan2 ($f_{\rm sagan2}$) = 2*pi*f_hy "Hz" -- Sagan's second frequency f_sagan2x ($f_{\rm sagan2}$) = tau*f_hy "Hz" -- Sagan's second frequency half_c ($\frac{c}{2}$) = c/2 "m/s" -- Half the speed of light a_string (a string) = 'a string' -- yep, its a string a_dict (a dict) = {0:0, 1:1} -- yep, its a dict """) f_hy = qs.pop('f_hy') assert f_hy.is_close(Quantity(1.420405751786e9, 'Hz'), check_units=True) assert f_hy.is_close(1.420405751786e9) assert f_hy.units == 'Hz' assert f_hy.name == r'$f_{\rm hy}$' assert f_hy.desc == 'Hydrogen line frequency' f_sagan1 = qs.pop('f_sagan1') assert f_sagan1.is_close(Quantity(pi * 1.420405751786e9, 'Hz'), check_units=True) assert f_sagan1.is_close(pi * 1.420405751786e9) assert f_sagan1.units == 'Hz' assert f_sagan1.name == r'$f_{\rm sagan1}$' assert f_sagan1.desc == "Sagan's first frequency" f_sagan2 = qs.pop('f_sagan2') assert f_sagan2.is_close(Quantity(2 * pi * 1.420405751786e9, 'Hz'), check_units=True) assert f_sagan2.is_close(2 * pi * 1.420405751786e9) assert f_sagan2.units == 'Hz' assert f_sagan2.name == r'$f_{\rm sagan2}$' assert f_sagan2.desc == "Sagan's second frequency" f_sagan2x = qs.pop('f_sagan2x') assert f_sagan2x.is_close(Quantity(2 * pi * 1.420405751786e9, 'Hz'), check_units=True) assert f_sagan2x.is_close(2 * pi * 1.420405751786e9) assert f_sagan2x.units == 'Hz' assert f_sagan2x.name == r'$f_{\rm sagan2}$' assert f_sagan2x.desc == "Sagan's second frequency" half_c = qs.pop('half_c') assert half_c.is_close(Quantity('c') / 2, check_units=True) assert half_c.is_close(Quantity('c') / 2) assert half_c.units == 'm/s' assert half_c.name == r'$\frac{c}{2}$' assert half_c.desc == "Half the speed of light" a_string = qs.pop('a_string') assert a_string == 'a string' a_dict = qs.pop('a_dict') assert a_dict == {0: 0, 1: 1} assert not qs
def test_scale(): Quantity.reset_prefs() Quantity.set_prefs(spacer=None, show_label=None, label_fmt=None, label_fmt_full=None) q1 = Quantity('3ns') q2 = Quantity('2') v2 = 2 assert str(q1.scale(q2)) == '6 ns' assert repr(q1.scale(q2)) == "Quantity('6 ns')" assert str(q1.scale(v2)) == '6 ns' assert repr(q1.scale(v2)) == "Quantity('6 ns')" q1.name = 'period' q3 = q1.scale(q2).name == 'period' q1.desc = 'duration of one cycle' assert q1.scale(q2).name == 'period' assert q1.scale(q2).desc == 'duration of one cycle' class Dollars(Quantity): units = '$' prec = 2 form = 'fixed' show_commas = True minus = Quantity.minus_sign strip_zeros = False class Cents(Dollars): units = '¢' prec = 0 print(UnitConversion(Dollars, Cents, 0.01)) total = Dollars(1) assert str(total) == '$1.00' total = total.scale(1000000) assert str(total) == '$1,000,000.00' class WholeDollars(Dollars): prec = 0 total = WholeDollars(20) assert str(total) == '$20' total = total.scale(1000000) assert str(total) == '$20,000,000' total = total.scale(5, Dollars) assert str(total) == '$100,000,000.00' total = total.scale(Cents) assert str(total) == '10,000,000,000 ¢' assert type(total) == Cents
def test_simple_scaling(): Quantity.reset_prefs() with Quantity.prefs( spacer=None, show_label=None, label_fmt=None, label_fmt_full=None ): q=Quantity('1kg', scale=2) qs=Quantity('2ms') assert q.render() == '2 kg' assert qs.render() == '2 ms' assert q.render(scale=0.001) == '2 g' assert str(q.scale(0.001)) == '2 g' assert q.render(scale=qs) == '4 g' assert str(q.scale(qs)) == '4 g' with pytest.raises(KeyError) as exception: q.render(scale='fuzz') assert str(exception.value) == "unable to convert between 'fuzz' and 'g'." assert isinstance(exception.value, UnknownConversion) assert isinstance(exception.value, QuantiPhyError) assert isinstance(exception.value, KeyError) assert exception.value.args == ('fuzz', 'g') with pytest.raises(KeyError) as exception: q.scale('fuzz') assert str(exception.value) == "unable to convert between 'fuzz' and 'g'." assert isinstance(exception.value, UnknownConversion) assert isinstance(exception.value, QuantiPhyError) assert isinstance(exception.value, KeyError) assert exception.value.args == ('fuzz', 'g') q=Quantity('1', units='g', scale=1000) assert q.render() == '1 kg' assert q.render(scale=(0.0022046, 'lbs')) == '2.2046 lbs' assert str(q.scale((0.0022046, 'lbs'))) == '2.2046 lbs' q=Quantity('1', units='g', scale=qs) assert q.render() == '2 mg' q=Quantity('1', scale=(1000, 'g')) assert q.render() == '1 kg' assert q.render(scale=lambda v, u: (0.0022046*v, 'lbs')) == '2.2046 lbs' def dB(v, u): return 20*math.log(v, 10), 'dB'+u def adB(v, u): return pow(10, v/20), u[2:] if u.startswith('dB') else u q=Quantity('-40 dBV', scale=adB) assert q.render() == '10 mV' assert q.render(scale=dB) == '-40 dBV' assert str(q.scale(dB)) == '-40 dBV'
def test_workout(): Quantity.reset_prefs() qs = Quantity.extract(r""" Fclk = 50MHz -- clock frequency This is an arbitrary line of text. This is an line of text that: triggers the line processing but still should be ignored.. """) f_clk = qs.pop('Fclk') assert f_clk.is_close(Quantity(5e7, 'Hz'), check_units=True) assert f_clk.is_close(5e7) assert f_clk.units == 'Hz' assert f_clk.name == 'Fclk' assert f_clk.desc == 'clock frequency' assert not qs
def test_add(): Quantity.reset_prefs() total = Quantity(0, '$') for contribution in [1.23, 4.56, 7.89]: total = total.add(contribution) assert total.render() == '$13.68' for contribution in [1.23, 4.56, 8.89]: total = total.add(contribution, check_units=True) assert total.render() == '$28.36' for contribution in [1.23, 4.56, 9.89]: total = total.add(Quantity(contribution, '$'), check_units=True) assert total.render() == '$44.04' try: total = total.add(Quantity(contribution, 'lbs'), check_units=True) assert False except TypeError: assert True
def test_invention(): Quantity.reset_prefs() qs = Quantity.extract(r""" Fin = 10MHz -- input frequency Tstop = 5/Fin -- stop time """) f_in = qs.pop('Fin') assert f_in.is_close(Quantity(1e7, 'Hz'), check_units=True) assert f_in.is_close(1e7) assert f_in.units == 'Hz' assert f_in.name == 'Fin' assert f_in.desc == 'input frequency' t_stop = qs.pop('Tstop') assert t_stop.is_close(Quantity(5 / f_in, ''), check_units=True) assert t_stop.is_close(5 / f_in) assert t_stop.units == '' assert t_stop.name == 'Tstop' assert t_stop.desc == 'stop time' assert not qs
def test_assign_rec(): Quantity.reset_prefs() with Quantity.prefs( assign_rec= r'(?P<name>\w+?)\s*=\s*(?P<val>\w*)(\s+(--)\s*(?P<desc>.*?))?\Z'): qs = Quantity.extract(r""" -- The Hydrogen Line bad = -- Also known as the 21 cm line = bad -- The spectral line associated with a spin flip. f_hy = 1420MHz -- Hydrogen line frequency """) f_hy = qs.pop('f_hy') assert f_hy.is_close(Quantity(1.42e9, 'Hz'), check_units=True) assert f_hy.is_close(1.42e9) assert f_hy.units == 'Hz' assert f_hy.name == 'f_hy' assert f_hy.desc == 'Hydrogen line frequency' assert not qs
def test_manual(): if sys.version_info < (3, 6): # code used in doctests assumes python3.6 return Quantity.reset_prefs() expected_test_count = { '../doc/index.rst': 31, '../doc/user.rst': 368, '../doc/api.rst': 0, '../doc/examples.rst': 36, '../doc/accessories.rst': 12, '../doc/releases.rst': 0, } found = glob.glob('../doc/*.rst') for f in found: assert f in expected_test_count, f for path, tests in expected_test_count.items(): rv = doctest.testfile(path, optionflags=doctest.ELLIPSIS) assert rv.failed == 0, path assert rv.attempted == tests, path
def test_mass(): Quantity.reset_prefs() with Quantity.prefs( spacer=None, show_label=None, label_fmt=None, label_fmt_full=None, ignore_sf=False ): q=Quantity('1 g') assert q.render() == '1 g' assert q.render(scale='oz') == '35.274 moz' assert q.render(scale='lb') == '2.2046 mlb' assert q.render(scale='lbs') == '2.2046 mlbs' q=Quantity('1 oz', scale='g') assert q.render() == '28.35 g' q=Quantity('1 lb', scale='g') assert q.render() == '453.59 g' q=Quantity('1 lbs', scale='g') assert q.render() == '453.59 g'
def test_format(): Quantity.reset_prefs() print(Quantity._preferences) Quantity.set_prefs(spacer=None, show_label=None, label_fmt=None, label_fmt_full=None, show_desc=False) q=Quantity('f = 1420.405751786 MHz -- frequency of hydrogen line') assert '{}'.format(q) == '1.4204 GHz' assert '{:.8}'.format(q) == '1.42040575 GHz' assert '{:.8s}'.format(q) == '1.42040575 GHz' assert '{:.8S}'.format(q) == 'f = 1.42040575 GHz' assert '{:.8q}'.format(q) == '1.42040575 GHz' assert '{:.8Q}'.format(q) == 'f = 1.42040575 GHz' assert '{:r}'.format(q) == '1.4204G' assert '{:R}'.format(q) == 'f = 1.4204G' assert '{:u}'.format(q) == 'Hz' assert '{:f}'.format(q) == '1420405751.786' assert '{:F}'.format(q) == 'f = 1420405751.786' assert '{:e}'.format(q) == '1.4204e+09' assert '{:E}'.format(q) == 'f = 1.4204e+09' assert '{:g}'.format(q) == '1.4204e+09' assert '{:G}'.format(q) == 'f = 1.4204e+09' assert '{:n}'.format(q) == 'f' assert '{:d}'.format(q) == 'frequency of hydrogen line' assert '{:p}'.format(q) == '1420405751.786 Hz' assert '{:,p}'.format(q) == '1,420,405,751.786 Hz' assert '{:P}'.format(q) == 'f = 1420405751.786 Hz' assert '{:,P}'.format(q) == 'f = 1,420,405,751.786 Hz' assert '{:#.3q}'.format(q) == '1.420 GHz' assert '{:#p}'.format(q) == '1420405751.7860 Hz' assert '{:.0q}'.format(q) == '1 GHz' assert '{:.0p}'.format(q) == '1420405752 Hz' assert '{:#.0q}'.format(q) == '1 GHz' assert '{:#.0p}'.format(q) == '1420405752. Hz' q=Quantity('2ns') assert float(q) == 2e-9 with pytest.raises(ValueError) as exception: q = Quantity('1ns') '{:z}'.format(q) assert exception.value.args[0] == "Unknown format code 'z' for object of type 'float'"
def test_subclass_conversion(): Quantity.reset_prefs() class Bitcoin(Quantity): units = 'BTC' form = 'fixed' prec = 2 show_commas = True class Satoshi(Quantity): units = 'sat' form = 'fixed' prec = 3 show_commas = True conversion = UnitConversion(Bitcoin, Satoshi, 1e-8) assert str(conversion) == 'BTC ← 1e-08*sat' result = conversion.convert(1, 'BTC', 'sat') assert str(result) == '100 Msat' result = conversion.convert(1, 'sat', 'BTC') assert str(result) == '10 nBTC'
# encoding: utf8 from parametrize_from_file import parametrize, Namespace import pytest from functools import partial from voluptuous import Schema, Optional, Required from quantiphy import Quantity Quantity.reset_prefs() def name_from_dict_keys(cases): return [{**v, 'name': k} for k, v in cases.items()] parametrize_from_file = partial(parametrize, preprocess=name_from_dict_keys) with_quantiphy = Namespace('from quantiphy import Quantity') # Schema for test cases # Errors are indicated by a lack of a tests field. schema = Schema({ Required('name'): str, Required('given'): str, Optional('prefs', default='{}'): eval, Optional('tests', default={}): { str: { str: str } },
def test_socialist(): Quantity.reset_prefs() qs = Quantity.extract(r""" # Fclk = 50MHz -- clock frequency """) assert not qs
def test_stumble(): Quantity.reset_prefs() qs = Quantity.extract(r""" // Fclk = 50MHz -- clock frequency """) assert not qs
def test_hussy(): Quantity.reset_prefs() qs = Quantity.extract(r""" This is a non conforming line. """) assert not qs