def test_block_comments(self): """ Test block comments in model. """ from myokit._parsing import parse_model_from_stream from myokit._parsing import Tokenizer def p(code): return parse_model_from_stream(Tokenizer(iter(code))) # Block comments c1 = ( '[[model]]', '[c]', 't = 0 bind time', ) m1 = p(c1) c2 = ( '[[model]]', '"""This is a comment"""', '[c]', 't = 0 bind time', ) m2 = p(c2) c3 = ( '[[model]]', '"""' 'This is a long', 'long', 'long', 'comment', '"""', '[c]', 't = 0 bind time', ) m3 = p(c3) self.assertEqual(m1.code(), m2.code(), m3.code())
def test_parse_variable(self): """ Tests parse_variable(), uses parse_expression() """ from myokit._parser import parse_variable from myokit._parser import Tokenizer m = myokit.Model('test_model') c = m.add_component('test_component') def p(s, name=None): parse_variable(Tokenizer(s), None, c, convert_proto_rhs=True) if name: return c.var(name) s = """ x1 = 5 """ v = p(s, 'x1') self.assertIsInstance(v, myokit.Variable) self.assertTrue(v.is_constant()) self.assertTrue(v.is_literal()) self.assertFalse(v.is_state()) self.assertFalse(v.is_intermediary()) self.assertEqual(v.unit(), None) self.assertEqual(v.rhs().unit(), None) s = """ x2 = 5 [mV] """ v = p(s, 'x2') self.assertIsInstance(v, myokit.Variable) self.assertTrue(v.is_constant()) self.assertTrue(v.is_literal()) self.assertFalse(v.is_state()) self.assertFalse(v.is_intermediary()) self.assertEqual(v.unit(), None) self.assertEqual(v.rhs().unit(), myokit.parse_unit('mV')) s = """ x3 = 5 in [mV] """ v = p(s, 'x3') self.assertIsInstance(v, myokit.Variable) self.assertTrue(v.is_constant()) self.assertTrue(v.is_literal()) self.assertFalse(v.is_state()) self.assertFalse(v.is_intermediary()) self.assertEqual(v.unit(), myokit.parse_unit('mV')) self.assertEqual(v.rhs().unit(), None) s = """ x4 = 5 [V] : This is x4 """ v = p(s, 'x4') self.assertIsInstance(v, myokit.Variable) self.assertTrue(v.is_constant()) self.assertTrue(v.is_literal()) self.assertFalse(v.is_state()) self.assertFalse(v.is_intermediary()) self.assertEqual(v.unit(), None) self.assertEqual(v.rhs().unit(), myokit.units.V) self.assertEqual(v.meta['desc'], 'This is x4')
def test_parse_user_function(self): """ Test :meth:`parse_user_function()`. """ from myokit._parsing import parse_model as p # Test basics code = ( '[[model]]', 'michael(x) = 1 + sin(x)', '[c]', 't = 0 bind time', 'x = michael(12)', ) p(code) code = ( '[[model]]', 'michael(x, y, z) = x + y / z', '[c]', 't = 0 bind time', 'x = michael(1,2,3)', ) p(code) # Duplicate name code = ( '[[model]]', 'michael(x, y, z) = x + y / z', 'michael(x, y, z) = x - y - z', '[c]', 't = 0 bind time', 'x = michael(1,2,3)', ) self.assertRaisesRegex(myokit.ParseError, 'already defined', p, code)
def test_parse_component(self): """ Test parse_component(), uses parse_variable """ from myokit._parser import parse_component as pc from myokit._parser import ParseInfo from myokit._parser import Tokenizer info = ParseInfo() info.model = m = myokit.Model('test_model') def p(s, name=None): pc(Tokenizer(s), info) if name: return m[name] s = """ [test_component] x = 5 + b b = 13 in [mV] desc: \""" This is a test component. \""" """ c = p(s, 'test_component') self.assertEqual(len(c), 1) self.assertIn('desc', c.meta) self.assertEqual(c.meta['desc'], 'This is a test component.') pass
def test_parse_alias(self): """ Test :meth:`parse_alias()`. """ from myokit._parsing import parse_model as p # Test basics code = ( '[[model]]', '[a]', 't = 10', ' bind time', '[b]', 'use a.t as time', 'b = time', '\"""', ) m = p(code) self.assertEqual(m.get('b.b').eval(), 10) # Test bad variable name code = ( '[[model]]', '[a]', 't = 10', ' bind time', '[b]', 'use t as time', 'b = time', '\"""', ) self.assertRaisesRegex(myokit.ParseError, 'fully qualified', p, code) # Test bad alias name code = ( '[[model]]', '[a]', 't = 10', ' bind time', '[b]', 'use a.t as _flbt12', 'b = time', '\"""', ) self.assertRaisesRegex(myokit.ParseError, 'invalid token', p, code) # Unknown variable code = ( '[[model]]', '[a]', 't = 10', ' bind time', '[b]', 'use a.x as time', 'b = time', '\"""', ) self.assertRaisesRegex(myokit.ParseError, 'Variable not found', p, code)
def test_parse_model_from_stream_error(self): """ Quick error testing for :meth:`parse_model_from_stream`. """ from myokit._parsing import parse_model_from_stream from myokit._parsing import Tokenizer def p(code): return parse_model_from_stream(Tokenizer(iter(code))) code = ( '[[model]]', '[c]', 't = 0 bind time', ) model = p(code) self.assertIsInstance(model, myokit.Model) # Not a model code = ( '[[muddle]]', '[c]', 't = 0 bind time', ) self.assertRaisesRegex(myokit.ParseError, r'Expecting \[\[model]]', p, code) # Double meta-data value code = ( '[[model]]', 'ax: 1', 'ax: 1', ) self.assertRaisesRegex(myokit.ParseError, 'Duplicate meta-data key', p, code) # Double initial values code = ( '[[model]]', 'a.x = 1', 'a.x = 1', ) self.assertRaisesRegex(myokit.ParseError, 'Duplicate initial value', p, code) # Unused initial values code = ( '[[model]]', 'a.x = 1', '[c]', 't = 0 bind time', ) self.assertRaisesRegex(myokit.ParseError, 'Unused initial value', p, code)
def test_parse_component(self): """ Test parse_component(), uses parse_variable """ from myokit._parsing import parse_model as p # Test basics code = ( '[[model]]', '[test]', 't = 0', ' bind time', 'x = 5 + b', ' b = 13', ' in [mV]', 'desc: \"""', 'This is a test component.', '\"""', ) m = p(code) self.assertIn('test', m) self.assertEqual( m.get('test').meta['desc'], 'This is a test component.') # Test duplicate name code = ( '[[model]]', '[test]', 't = 0', ' bind time', '[test]', 'x = 2', ) self.assertRaisesRegex(myokit.ParseError, 'Duplicate component name', p, code) # Test invalid name --> Handled by tokenizer # Test duplicate meta data key code = ( '[[model]]', '[test]', 'yes: no', 't = 0', ' bind time', 'yes: yes', '[test]', 'x = 2', ) self.assertRaisesRegex(myokit.ParseError, 'Duplicate meta-data key', p, code)
def test_parse_expression(self): """ Test parse_expression() """ from myokit import parse_expression as p from myokit import Number e = p('5') self.assertIsInstance(e, Number) self.assertEqual(e.eval(), 5.0) self.assertEqual(float(e), 5.0) e = p('5[m]') self.assertIsInstance(e, Number) self.assertEqual(e.eval(), 5.0) self.assertEqual(float(e), 5.0) self.assertEqual(e.unit(), myokit.units.m) e = p('5 [m/s]') self.assertIsInstance(e, Number) self.assertEqual(e.eval(), 5.0) self.assertEqual(float(e), 5.0) self.assertEqual(e.unit(), myokit.parse_unit('m/s')) self.assertEqual(e.unit(), myokit.units.m / myokit.units.s) e = p('+5') self.assertIsInstance(e, myokit.PrefixPlus) self.assertEqual(e.eval(), 5.0) e = p('++5') self.assertIsInstance(e, myokit.PrefixPlus) self.assertEqual(e.eval(), 5.0) e = p('-5') self.assertIsInstance(e, myokit.PrefixMinus) self.assertEqual(e.eval(), -5.0) e = p('--5') self.assertIsInstance(e, myokit.PrefixMinus) self.assertEqual(e.eval(), 5.0) e = p('5 + 2') self.assertIsInstance(e, myokit.Plus) self.assertEqual(e.eval(), 7) e = p('5 + 1 + 1') self.assertIsInstance(e, myokit.Plus) self.assertEqual(e.eval(), 7) e = p('5 - 2') self.assertIsInstance(e, myokit.Minus) self.assertEqual(e.eval(), 3) e = p('5 -- 2') self.assertIsInstance(e, myokit.Minus) self.assertEqual(e.eval(), 7) e = p('5 --+ 2') self.assertIsInstance(e, myokit.Minus) self.assertEqual(e.eval(), 7) e = p('5 --- 2') self.assertIsInstance(e, myokit.Minus) self.assertEqual(e.eval(), 3)
def test_parse_unit(self): """ Test :meth:`parse_unit` and :meth:`parse_unit_string`. """ from myokit._parsing import parse_unit_string as p # Test dimensionless self.assertEqual(p('1'), myokit.units.dimensionless) # Test bare unit self.assertEqual(p('V'), myokit.units.Volt) # Test unit with quantifier self.assertEqual(p('mV'), myokit.units.Volt / 1000) # Test multiplied units self.assertEqual(p('V*A'), myokit.units.Volt * myokit.units.Ampere) self.assertEqual(p('J/s'), myokit.units.Watt) self.assertEqual(p('1/s'), 1 / myokit.units.second) # Test units with exponents (first unit) self.assertEqual(p('m^2'), myokit.units.meter**2) self.assertEqual(p('m^-1'), 1 / myokit.units.meter) # Exponents on remaining units self.assertEqual(p('s*m^2'), myokit.units.second * myokit.units.meter**2) self.assertEqual(p('s*m^-1'), myokit.units.second / myokit.units.meter) # Test units with multipliers self.assertEqual(p('m (123)'), myokit.units.meter * 123) # Test bad unit self.assertRaisesRegex(myokit.ParseError, 'Unit not recognized', p, 'michael') self.assertRaisesRegex(myokit.ParseError, 'Unit not recognized', p, 'kg/michael') self.assertRaisesRegex(myokit.ParseError, 'Unexpected token', p, '*2') self.assertRaisesRegex(myokit.ParseError, 'Invalid unit specification', p, '2') self.assertRaisesRegex(myokit.ParseError, 'Invalid unit multiplier', p, 'm (x)')
def test_parse_variable(self): """ Test parse_variable(), uses parse_expression() """ from myokit._parsing import parse_model as p # Test basics s = ( '[[model]]', '[x]', 't = 0 bind time', ) t = p(s).get('x.t') self.assertEqual(t.name(), 't') self.assertEqual(t.qname(), 'x.t') self.assertEqual(t.unit(), None) self.assertEqual(t.binding(), 'time') s = ( '[[model]]', '[x]', 't = 0', ' bind time', ) t = p(s).get('x.t') self.assertEqual(t.name(), 't') self.assertEqual(t.qname(), 'x.t') self.assertEqual(t.unit(), None) self.assertEqual(t.binding(), 'time') s = ('[[model]]', '[x]', 't = 0 bind time', 'x1 = 5') v = p(s).get('x.x1') self.assertIsInstance(v, myokit.Variable) self.assertTrue(v.is_constant()) self.assertTrue(v.is_literal()) self.assertFalse(v.is_state()) self.assertFalse(v.is_intermediary()) self.assertEqual(v.unit(), None) self.assertEqual(v.rhs().unit(), None) s = ('[[model]]', '[x]', 't = 0 bind time', 'x2 = 5 [mV]') v = p(s).get('x.x2') self.assertIsInstance(v, myokit.Variable) self.assertTrue(v.is_constant()) self.assertTrue(v.is_literal()) self.assertFalse(v.is_state()) self.assertFalse(v.is_intermediary()) self.assertEqual(v.unit(), None) self.assertEqual(v.rhs().unit(), myokit.parse_unit('mV')) s = ( '[[model]]', '[x]', 't = 0 bind time', 'x3 = 5', ' in [mV]', ) v = p(s).get('x.x3') self.assertIsInstance(v, myokit.Variable) self.assertTrue(v.is_constant()) self.assertTrue(v.is_literal()) self.assertFalse(v.is_state()) self.assertFalse(v.is_intermediary()) self.assertEqual(v.unit(), myokit.parse_unit('mV')) self.assertEqual(v.rhs().unit(), None) s = ( '[[model]]', '[x]', 't = 0 bind time', 'x3 = 5 in [mV]', ) v = p(s).get('x.x3') self.assertIsInstance(v, myokit.Variable) self.assertTrue(v.is_constant()) self.assertTrue(v.is_literal()) self.assertFalse(v.is_state()) self.assertFalse(v.is_intermediary()) self.assertEqual(v.unit(), myokit.parse_unit('mV')) self.assertEqual(v.rhs().unit(), None) s = ( '[[model]]', '[x]', 't = 0 bind time', 'x4 = 5 [V] : This is x4', ) v = p(s).get('x.x4') self.assertIsInstance(v, myokit.Variable) self.assertTrue(v.is_constant()) self.assertTrue(v.is_literal()) self.assertFalse(v.is_state()) self.assertFalse(v.is_intermediary()) self.assertEqual(v.unit(), None) self.assertEqual(v.rhs().unit(), myokit.units.V) self.assertEqual(v.meta['desc'], 'This is x4') code = ( '[[model]]', '[x]', 't = 0 bind time', 'x = 5 label vvv', ) x = p(code).get('x.x') self.assertIsInstance(x, myokit.Variable) self.assertEqual(x.label(), 'vvv') s = ( '[[model]]', '[x]', 't = 0 bind time', 'x = 5', ' label vvv', ) x = p(code).get('x.x') self.assertIsInstance(x, myokit.Variable) self.assertEqual(x.label(), 'vvv') # Illegal lhs code = ( '[[model]]', '[x]', 't = 0 bind time', 'sin(x) = 5', ) self.assertRaisesRegex(myokit.ParseError, 'variable names or the dot', p, code) # Duplicate name code = ( '[[model]]', '[x]', 't = 0 bind time', 'x = 5', 'x = 5', ) self.assertRaisesRegex(myokit.ParseError, 'Duplicate var', p, code) # Missing initial value code = ( '[[model]]', '[x]', 't = 0 bind time', 'dot(x) = 5', ) self.assertRaisesRegex(myokit.ParseError, 'Missing initial', p, code) # Duplicate meta code = ( '[[model]]', '[x]', 't = 0 bind time', ' yes: really', ' yes: no', ) self.assertRaisesRegex(myokit.ParseError, 'Duplicate meta-data key', p, code) # Duplicate unit code = ( '[[model]]', '[x]', 't = 0 bind time', ' in [s]', ' in [s]', ) self.assertRaisesRegex(myokit.ParseError, 'Duplicate variable unit', p, code)
def test_parse_expression(self): # Test parse_expression() from myokit import parse_expression as p from myokit import Number e = p('5') self.assertIsInstance(e, Number) self.assertEqual(e.eval(), 5.0) self.assertEqual(float(e), 5.0) e = p('5[m]') self.assertIsInstance(e, Number) self.assertEqual(e.eval(), 5.0) self.assertEqual(float(e), 5.0) self.assertEqual(e.unit(), myokit.units.m) e = p('5 [m/s]') self.assertIsInstance(e, Number) self.assertEqual(e.eval(), 5.0) self.assertEqual(float(e), 5.0) self.assertEqual(e.unit(), myokit.parse_unit('m/s')) self.assertEqual(e.unit(), myokit.units.m / myokit.units.s) e = p('+5') self.assertIsInstance(e, myokit.PrefixPlus) self.assertEqual(e.eval(), 5.0) e = p('++5') self.assertIsInstance(e, myokit.PrefixPlus) self.assertEqual(e.eval(), 5.0) e = p('-5') self.assertIsInstance(e, myokit.PrefixMinus) self.assertEqual(e.eval(), -5.0) e = p('--5') self.assertIsInstance(e, myokit.PrefixMinus) self.assertEqual(e.eval(), 5.0) e = p('5 + 2') self.assertIsInstance(e, myokit.Plus) self.assertEqual(e.eval(), 7) e = p('5 + 1 + 1') self.assertIsInstance(e, myokit.Plus) self.assertEqual(e.eval(), 7) e = p('5 - 2') self.assertIsInstance(e, myokit.Minus) self.assertEqual(e.eval(), 3) e = p('5 -- 2') self.assertIsInstance(e, myokit.Minus) self.assertEqual(e.eval(), 7) e = p('5 --+ 2') self.assertIsInstance(e, myokit.Minus) self.assertEqual(e.eval(), 7) e = p('5 --- 2') self.assertIsInstance(e, myokit.Minus) self.assertEqual(e.eval(), 3) # Etc etc etc # Test bad value self.assertRaises(myokit.ParseError, p, '5 beans')