myokit 1.33.9__py3-none-any.whl → 1.35.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- myokit/__init__.py +9 -36
- myokit/__main__.py +76 -142
- myokit/_aux.py +62 -16
- myokit/_bin/example.mmt +1 -2
- myokit/_bin/install-win/menu.json +7 -7
- myokit/_config.py +22 -31
- myokit/_datablock.py +30 -74
- myokit/_datalog.py +49 -72
- myokit/_err.py +25 -24
- myokit/_expressions.py +50 -68
- myokit/_io.py +15 -27
- myokit/_model_api.py +453 -249
- myokit/_myokit_version.py +1 -5
- myokit/_parsing.py +38 -44
- myokit/_progress.py +5 -8
- myokit/_protocol.py +99 -9
- myokit/_sim/__init__.py +7 -24
- myokit/_sim/cable.c +6 -8
- myokit/_sim/cable.py +6 -8
- myokit/_sim/cmodel.h +125 -70
- myokit/_sim/cmodel.py +12 -14
- myokit/_sim/compiler.py +1 -4
- myokit/_sim/cvodessim.c +196 -118
- myokit/_sim/cvodessim.py +130 -103
- myokit/_sim/differential.hpp +4 -4
- myokit/_sim/fiber_tissue.c +4 -8
- myokit/_sim/fiber_tissue.py +11 -13
- myokit/_sim/jacobian.cpp +2 -2
- myokit/_sim/jacobian.py +11 -8
- myokit/_sim/mcl.h +53 -55
- myokit/_sim/opencl.py +21 -27
- myokit/_sim/openclsim.c +3 -7
- myokit/_sim/openclsim.cl +3 -3
- myokit/_sim/openclsim.py +49 -40
- myokit/_sim/pacing.h +36 -16
- myokit/_sim/rhs.c +6 -13
- myokit/_sim/rhs.py +5 -14
- myokit/_sim/sundials.py +1 -4
- myokit/_system.py +10 -16
- myokit/_unit.py +4 -13
- myokit/float.py +0 -3
- myokit/formats/__init__.py +8 -10
- myokit/formats/ansic/__init__.py +0 -3
- myokit/formats/ansic/_ewriter.py +2 -4
- myokit/formats/ansic/_exporter.py +1 -4
- myokit/formats/ansic/template/cable.c +4 -4
- myokit/formats/ansic/template/euler.c +5 -5
- myokit/formats/ansic/template/sim.c +6 -6
- myokit/formats/axon/__init__.py +1 -3
- myokit/formats/axon/_abf.py +12 -17
- myokit/formats/axon/_atf.py +5 -6
- myokit/formats/axon/_importer.py +0 -3
- myokit/formats/cellml/__init__.py +0 -3
- myokit/formats/cellml/_ewriter.py +3 -6
- myokit/formats/cellml/_exporter.py +3 -6
- myokit/formats/cellml/_importer.py +1 -4
- myokit/formats/cellml/v1/__init__.py +0 -4
- myokit/formats/cellml/v1/_api.py +8 -11
- myokit/formats/cellml/v1/_parser.py +2 -5
- myokit/formats/cellml/v1/_writer.py +2 -11
- myokit/formats/cellml/v2/__init__.py +0 -3
- myokit/formats/cellml/v2/_api.py +8 -17
- myokit/formats/cellml/v2/_parser.py +2 -5
- myokit/formats/cellml/v2/_writer.py +1 -4
- myokit/formats/channelml/__init__.py +0 -3
- myokit/formats/channelml/_importer.py +11 -21
- myokit/formats/cpp/__init__.py +1 -3
- myokit/formats/cpp/_ewriter.py +0 -3
- myokit/formats/cuda/__init__.py +0 -3
- myokit/formats/cuda/_ewriter.py +2 -4
- myokit/formats/cuda/_exporter.py +0 -3
- myokit/formats/cuda/template/kernel.cu +8 -5
- myokit/formats/easyml/__init__.py +0 -3
- myokit/formats/easyml/_ewriter.py +9 -11
- myokit/formats/easyml/_exporter.py +2 -5
- myokit/formats/html/__init__.py +0 -3
- myokit/formats/html/_exporter.py +0 -3
- myokit/formats/html/_flatten.py +5 -21
- myokit/formats/latex/__init__.py +0 -3
- myokit/formats/latex/_ewriter.py +1 -4
- myokit/formats/latex/_exporter.py +4 -6
- myokit/formats/mathml/__init__.py +0 -3
- myokit/formats/mathml/_ewriter.py +2 -11
- myokit/formats/mathml/_parser.py +4 -6
- myokit/formats/matlab/__init__.py +0 -3
- myokit/formats/matlab/_ewriter.py +1 -4
- myokit/formats/matlab/_exporter.py +2 -5
- myokit/formats/matlab/template/main.m +3 -2
- myokit/formats/opencl/__init__.py +0 -3
- myokit/formats/opencl/_ewriter.py +2 -4
- myokit/formats/opencl/_exporter.py +2 -5
- myokit/formats/opencl/template/cable.c +10 -10
- myokit/formats/opencl/template/kernel.cl +1 -1
- myokit/formats/opencl/template/minilog.py +1 -1
- myokit/formats/python/__init__.py +0 -3
- myokit/formats/python/_ewriter.py +2 -5
- myokit/formats/python/_exporter.py +0 -3
- myokit/formats/python/template/sim.py +14 -14
- myokit/formats/sbml/__init__.py +0 -3
- myokit/formats/sbml/_api.py +50 -44
- myokit/formats/sbml/_importer.py +1 -4
- myokit/formats/sbml/_parser.py +2 -5
- myokit/formats/stan/__init__.py +0 -3
- myokit/formats/stan/_ewriter.py +2 -4
- myokit/formats/stan/_exporter.py +2 -5
- myokit/formats/stan/template/cell.stan +3 -3
- myokit/formats/sympy/__init__.py +0 -3
- myokit/formats/sympy/_ereader.py +1 -4
- myokit/formats/sympy/_ewriter.py +2 -5
- myokit/formats/wcp/__init__.py +0 -3
- myokit/formats/wcp/_wcp.py +2 -8
- myokit/formats/xml/__init__.py +0 -3
- myokit/formats/xml/_exporter.py +0 -3
- myokit/formats/xml/_split.py +0 -3
- myokit/gui/__init__.py +80 -246
- myokit/gui/datablock_viewer.py +103 -86
- myokit/gui/datalog_viewer.py +214 -66
- myokit/gui/explorer.py +15 -21
- myokit/gui/ide.py +171 -144
- myokit/gui/progress.py +9 -9
- myokit/gui/source.py +406 -375
- myokit/gui/vargrapher.py +2 -12
- myokit/lib/deps.py +12 -13
- myokit/lib/guess.py +3 -4
- myokit/lib/hh.py +20 -18
- myokit/lib/markov.py +21 -20
- myokit/lib/multi.py +1 -3
- myokit/lib/plots.py +20 -9
- myokit/pacing.py +0 -3
- myokit/pype.py +7 -18
- myokit/tests/__init__.py +3 -6
- myokit/tests/ansic_event_based_pacing.py +1 -4
- myokit/tests/ansic_fixed_form_pacing.py +3 -6
- myokit/tests/data/beeler-1977-model-compare-b.mmt +2 -2
- myokit/tests/data/clancy-1999-fitting.mmt +1 -0
- myokit/tests/test_aux.py +13 -28
- myokit/tests/test_cellml_v1_api.py +4 -19
- myokit/tests/test_cellml_v1_parser.py +0 -15
- myokit/tests/test_cellml_v1_writer.py +0 -9
- myokit/tests/test_cellml_v2_api.py +4 -19
- myokit/tests/test_cellml_v2_parser.py +0 -15
- myokit/tests/test_cellml_v2_writer.py +0 -9
- myokit/tests/test_cmodel.py +16 -22
- myokit/tests/test_compiler_detection.py +1 -11
- myokit/tests/test_component.py +108 -56
- myokit/tests/test_config.py +34 -67
- myokit/tests/test_datablock.py +1 -9
- myokit/tests/test_datalog.py +19 -24
- myokit/tests/test_dependency_checking.py +8 -23
- myokit/tests/test_expressions.py +0 -9
- myokit/tests/test_float.py +1 -5
- myokit/tests/test_formats.py +0 -9
- myokit/tests/test_formats_axon.py +1 -9
- myokit/tests/test_formats_cellml.py +0 -15
- myokit/tests/test_formats_channelml.py +0 -15
- myokit/tests/test_formats_easyml.py +0 -14
- myokit/tests/test_formats_exporters.py +1 -16
- myokit/tests/test_formats_expression_writers.py +1 -17
- myokit/tests/test_formats_html.py +0 -3
- myokit/tests/test_formats_importers.py +1 -16
- myokit/tests/test_formats_mathml_content.py +0 -9
- myokit/tests/test_formats_mathml_presentation.py +0 -9
- myokit/tests/test_formats_opencl.py +0 -10
- myokit/tests/test_formats_sbml.py +0 -15
- myokit/tests/test_formats_sympy.py +0 -9
- myokit/tests/test_formats_wcp.py +1 -3
- myokit/tests/test_io.py +27 -27
- myokit/tests/test_jacobian_calculator.py +6 -14
- myokit/tests/test_jacobian_tracer.py +0 -9
- myokit/tests/test_lib_deps.py +0 -9
- myokit/tests/test_lib_guess.py +0 -9
- myokit/tests/test_lib_hh.py +18 -12
- myokit/tests/test_lib_markov.py +21 -13
- myokit/tests/test_lib_multi.py +0 -9
- myokit/tests/test_lib_plots.py +13 -8
- myokit/tests/test_meta.py +0 -3
- myokit/tests/test_model.py +390 -96
- myokit/tests/test_model_building.py +44 -96
- myokit/tests/test_opencl_info.py +5 -14
- myokit/tests/test_pacing_factory.py +0 -3
- myokit/tests/test_pacing_system_c.py +1 -23
- myokit/tests/test_pacing_system_py.py +0 -9
- myokit/tests/test_parsing.py +139 -56
- myokit/tests/test_progress_reporters.py +0 -3
- myokit/tests/test_protocol.py +0 -9
- myokit/tests/test_protocol_floating_point.py +1 -10
- myokit/tests/test_protocol_time_series.py +82 -0
- myokit/tests/test_pype.py +0 -9
- myokit/tests/test_quantity.py +0 -9
- myokit/tests/test_rhs_benchmarker.py +1 -9
- myokit/tests/test_sbml_api.py +27 -42
- myokit/tests/test_sbml_parser.py +4 -19
- myokit/tests/test_simulation_1d.py +45 -25
- myokit/tests/test_simulation_cvodes.py +321 -55
- myokit/tests/test_simulation_cvodes_from_disk.py +0 -3
- myokit/tests/test_simulation_fiber_tissue.py +39 -12
- myokit/tests/test_simulation_log_interval.py +1 -431
- myokit/tests/test_simulation_opencl.py +69 -48
- myokit/tests/test_simulation_opencl_log_interval.py +1 -3
- myokit/tests/test_simulation_opencl_vs_cvode.py +1 -10
- myokit/tests/test_simulation_opencl_vs_sim1d.py +1 -10
- myokit/tests/test_system_info.py +1 -11
- myokit/tests/test_tools.py +0 -9
- myokit/tests/test_unit.py +1 -10
- myokit/tests/test_user_functions.py +0 -10
- myokit/tests/test_variable.py +231 -27
- myokit/tools.py +5 -21
- myokit/units.py +5 -3
- {myokit-1.33.9.dist-info → myokit-1.35.0.dist-info}/METADATA +12 -15
- myokit-1.35.0.dist-info/RECORD +391 -0
- {myokit-1.33.9.dist-info → myokit-1.35.0.dist-info}/WHEEL +1 -1
- {myokit-1.33.9.dist-info → myokit-1.35.0.dist-info}/entry_points.txt +0 -1
- myokit/_exec_new.py +0 -15
- myokit/_exec_old.py +0 -15
- myokit/_sim/cvodesim.c +0 -1551
- myokit/_sim/cvodesim.py +0 -674
- myokit/_sim/icsim.cpp +0 -563
- myokit/_sim/icsim.py +0 -363
- myokit/_sim/psim.cpp +0 -656
- myokit/_sim/psim.py +0 -493
- myokit/lib/common.py +0 -1094
- myokit/tests/test_lib_common.py +0 -130
- myokit/tests/test_simulation_cvode.py +0 -612
- myokit/tests/test_simulation_ic.py +0 -108
- myokit/tests/test_simulation_p.py +0 -223
- myokit-1.33.9.dist-info/RECORD +0 -403
- /myokit/formats/opencl/template/{test → test.sh} +0 -0
- {myokit-1.33.9.dist-info → myokit-1.35.0.dist-info}/LICENSE.txt +0 -0
- {myokit-1.33.9.dist-info → myokit-1.35.0.dist-info}/top_level.txt +0 -0
|
@@ -2,27 +2,15 @@
|
|
|
2
2
|
#
|
|
3
3
|
# Tests the model building API.
|
|
4
4
|
#
|
|
5
|
+
# NOTE: THESE TESTS SHOULD SLOWLY BE MERGED INTO test_model, test_variable, etc
|
|
6
|
+
#
|
|
7
|
+
#
|
|
5
8
|
# This file is part of Myokit.
|
|
6
9
|
# See http://myokit.org for copyright, sharing, and licensing details.
|
|
7
10
|
#
|
|
8
|
-
from __future__ import absolute_import, division
|
|
9
|
-
from __future__ import print_function, unicode_literals
|
|
10
|
-
|
|
11
11
|
import myokit
|
|
12
12
|
import unittest
|
|
13
13
|
|
|
14
|
-
# Strings in Python 2 and 3
|
|
15
|
-
try:
|
|
16
|
-
basestring
|
|
17
|
-
except NameError:
|
|
18
|
-
basestring = str
|
|
19
|
-
|
|
20
|
-
# Unit testing in Python 2 and 3
|
|
21
|
-
try:
|
|
22
|
-
unittest.TestCase.assertRaisesRegex
|
|
23
|
-
except AttributeError:
|
|
24
|
-
unittest.TestCase.assertRaisesRegex = unittest.TestCase.assertRaisesRegexp
|
|
25
|
-
|
|
26
14
|
# Further model API tests are found in:
|
|
27
15
|
# - test_dependency_checking.py
|
|
28
16
|
|
|
@@ -33,13 +21,23 @@ class ModelBuildTest(unittest.TestCase):
|
|
|
33
21
|
# Create a model
|
|
34
22
|
m = myokit.Model('LotkaVolterra')
|
|
35
23
|
|
|
36
|
-
# Add
|
|
24
|
+
# Add engine component
|
|
25
|
+
E = m.add_component('engine')
|
|
26
|
+
self.assertEqual(len(m), 1)
|
|
27
|
+
time = E.add_variable('time')
|
|
28
|
+
time.set_rhs(0)
|
|
29
|
+
self.assertIsNone(time.binding())
|
|
30
|
+
time.set_binding('time')
|
|
31
|
+
self.assertIsNotNone(time.binding())
|
|
32
|
+
|
|
33
|
+
# Add the first test component
|
|
37
34
|
X = m.add_component('X')
|
|
35
|
+
self.assertNotEqual(E, X)
|
|
38
36
|
self.assertEqual(X.qname(), 'X')
|
|
39
37
|
self.assertEqual(X.parent(), m)
|
|
40
38
|
self.assertIsInstance(X, myokit.Component)
|
|
41
39
|
self.assertIn(X.qname(), m)
|
|
42
|
-
self.assertEqual(len(m),
|
|
40
|
+
self.assertEqual(len(m), 2)
|
|
43
41
|
|
|
44
42
|
# Add variable a
|
|
45
43
|
self.assertFalse(X.has_variable('a'))
|
|
@@ -111,7 +109,7 @@ class ModelBuildTest(unittest.TestCase):
|
|
|
111
109
|
self.assertFalse(x.is_intermediary())
|
|
112
110
|
self.assertFalse(x.is_constant())
|
|
113
111
|
self.assertEqual(x.lhs(), myokit.Derivative(myokit.Name(x)))
|
|
114
|
-
self.assertEqual(x.
|
|
112
|
+
self.assertEqual(x.index(), 0)
|
|
115
113
|
|
|
116
114
|
# Test demoting, promoting
|
|
117
115
|
x.demote()
|
|
@@ -133,10 +131,32 @@ class ModelBuildTest(unittest.TestCase):
|
|
|
133
131
|
self.assertFalse(x.is_constant())
|
|
134
132
|
self.assertEqual(x.lhs(), myokit.Derivative(myokit.Name(x)))
|
|
135
133
|
|
|
134
|
+
# Set number initial value
|
|
135
|
+
x.demote()
|
|
136
|
+
x.promote(1)
|
|
137
|
+
self.assertEqual(x.initial_value(as_float=True), 1)
|
|
138
|
+
|
|
139
|
+
# Set constant expression initial value
|
|
140
|
+
x.set_initial_value(myokit.Name(b))
|
|
141
|
+
self.assertEqual(x.initial_value(as_float=True), 2)
|
|
142
|
+
self.assertEqual(x.initial_value(), myokit.Name(b))
|
|
143
|
+
|
|
144
|
+
# Non-constant expression initial value can be set, but isn't valid
|
|
145
|
+
m.validate()
|
|
146
|
+
b.promote()
|
|
147
|
+
self.assertRaisesRegex(
|
|
148
|
+
myokit.IntegrityError, 'not constant', m.validate)
|
|
149
|
+
b.demote()
|
|
150
|
+
|
|
151
|
+
# Set literal valued expression initial value
|
|
152
|
+
x.demote()
|
|
153
|
+
x.promote('1 + 2')
|
|
154
|
+
self.assertEqual(x.initial_value(as_float=True), 3)
|
|
155
|
+
|
|
136
156
|
# Add second component, variables
|
|
137
157
|
Y = m.add_component('Y')
|
|
138
158
|
self.assertNotEqual(X, Y)
|
|
139
|
-
self.assertEqual(len(m),
|
|
159
|
+
self.assertEqual(len(m), 3)
|
|
140
160
|
c = Y.add_variable('c')
|
|
141
161
|
c.set_rhs(myokit.Minus(myokit.Name(a), myokit.Number(1)))
|
|
142
162
|
d = Y.add_variable('d')
|
|
@@ -152,7 +172,7 @@ class ModelBuildTest(unittest.TestCase):
|
|
|
152
172
|
myokit.Name(y)
|
|
153
173
|
)
|
|
154
174
|
))
|
|
155
|
-
x.
|
|
175
|
+
x.set_initial_value(10)
|
|
156
176
|
self.assertEqual(x.rhs().code(), 'X.a * X.x - X.b * X.x * Y.y')
|
|
157
177
|
y.set_rhs(myokit.Plus(
|
|
158
178
|
myokit.Multiply(
|
|
@@ -163,14 +183,14 @@ class ModelBuildTest(unittest.TestCase):
|
|
|
163
183
|
myokit.Name(y)
|
|
164
184
|
)
|
|
165
185
|
))
|
|
166
|
-
y.
|
|
186
|
+
y.set_initial_value(5)
|
|
167
187
|
self.assertEqual(y.rhs().code(), '-Y.c * Y.y + Y.d * X.x * Y.y')
|
|
168
188
|
|
|
169
189
|
# Add ano component, variables
|
|
170
190
|
Z = m.add_component('Z')
|
|
171
191
|
self.assertNotEqual(X, Z)
|
|
172
192
|
self.assertNotEqual(Y, Z)
|
|
173
|
-
self.assertEqual(len(m),
|
|
193
|
+
self.assertEqual(len(m), 4)
|
|
174
194
|
t = Z.add_variable('total')
|
|
175
195
|
self.assertEqual(t.name(), 'total')
|
|
176
196
|
self.assertEqual(t.qname(), 'Z.total')
|
|
@@ -185,18 +205,6 @@ class ModelBuildTest(unittest.TestCase):
|
|
|
185
205
|
self.assertEqual(t.rhs().code(Y), 'X.x + y')
|
|
186
206
|
self.assertEqual(t.rhs().code(Z), 'X.x + Y.y')
|
|
187
207
|
|
|
188
|
-
# Add engine component
|
|
189
|
-
E = m.add_component('engine')
|
|
190
|
-
self.assertNotEqual(X, E)
|
|
191
|
-
self.assertNotEqual(Y, E)
|
|
192
|
-
self.assertNotEqual(Z, E)
|
|
193
|
-
self.assertEqual(len(m), 4)
|
|
194
|
-
time = E.add_variable('time')
|
|
195
|
-
time.set_rhs(0)
|
|
196
|
-
self.assertIsNone(time.binding())
|
|
197
|
-
time.set_binding('time')
|
|
198
|
-
self.assertIsNotNone(time.binding())
|
|
199
|
-
|
|
200
208
|
# Check state
|
|
201
209
|
state = [i for i in m.states()]
|
|
202
210
|
self.assertEqual(len(state), 2)
|
|
@@ -277,10 +285,10 @@ class ModelBuildTest(unittest.TestCase):
|
|
|
277
285
|
|
|
278
286
|
# Test dependency mapping
|
|
279
287
|
def has(var, *dps):
|
|
280
|
-
lst = vrs[m.get(var).lhs() if isinstance(var,
|
|
288
|
+
lst = vrs[m.get(var).lhs() if isinstance(var, str) else var]
|
|
281
289
|
self.assertEqual(len(lst), len(dps))
|
|
282
290
|
for d in dps:
|
|
283
|
-
d = m.get(d).lhs() if isinstance(d,
|
|
291
|
+
d = m.get(d).lhs() if isinstance(d, str) else d
|
|
284
292
|
self.assertIn(d, lst)
|
|
285
293
|
|
|
286
294
|
vrs = m.map_shallow_dependencies(omit_states=False)
|
|
@@ -355,16 +363,6 @@ class ModelBuildTest(unittest.TestCase):
|
|
|
355
363
|
code2 = m.clone().code()
|
|
356
364
|
self.assertEqual(code1, code2)
|
|
357
365
|
|
|
358
|
-
def test_resolve(self):
|
|
359
|
-
# Test if an error is raised when a variable can't be resolved.
|
|
360
|
-
|
|
361
|
-
m = myokit.Model('Resolve')
|
|
362
|
-
c = m.add_component('c')
|
|
363
|
-
p = c.add_variable('p')
|
|
364
|
-
q = c.add_variable('q')
|
|
365
|
-
p.set_rhs('10 * q')
|
|
366
|
-
self.assertRaises(myokit.ParseError, q.set_rhs, '10 * r')
|
|
367
|
-
|
|
368
366
|
def test_scope(self):
|
|
369
367
|
# Test if illegal references are detected.
|
|
370
368
|
|
|
@@ -436,56 +434,6 @@ class ModelBuildTest(unittest.TestCase):
|
|
|
436
434
|
self.assertRaises(myokit.InvalidNameError, v1.add_variable, 'not')
|
|
437
435
|
self.assertRaises(myokit.InvalidNameError, v1.add_variable, 'in')
|
|
438
436
|
|
|
439
|
-
def test_unused_and_cycles(self):
|
|
440
|
-
# Test unused variable and cycle detection.
|
|
441
|
-
|
|
442
|
-
m = myokit.Model('LotkaVolterra')
|
|
443
|
-
c0 = m.add_component('c0')
|
|
444
|
-
t = c0.add_variable('time')
|
|
445
|
-
t.set_rhs(myokit.Number(0))
|
|
446
|
-
t.set_binding('time')
|
|
447
|
-
c1 = m.add_component('c1')
|
|
448
|
-
m.add_component('c2')
|
|
449
|
-
c1_a = c1.add_variable('a')
|
|
450
|
-
c1_b = c1.add_variable('b')
|
|
451
|
-
c1_a.promote(1.0)
|
|
452
|
-
c1_a.set_rhs(myokit.Multiply(myokit.Name(c1_a), myokit.Number(0.5)))
|
|
453
|
-
c1_b.set_rhs(myokit.Multiply(myokit.Name(c1_a), myokit.Number(1.0)))
|
|
454
|
-
# b is unused, test if found
|
|
455
|
-
m.validate()
|
|
456
|
-
w = m.warnings()
|
|
457
|
-
self.assertEqual(len(w), 1)
|
|
458
|
-
self.assertEqual(type(w[0]), myokit.UnusedVariableError)
|
|
459
|
-
# b is used by c, c is unused, test if found
|
|
460
|
-
c1_c = c1.add_variable('c')
|
|
461
|
-
c1_c.set_rhs(myokit.Name(c1_b))
|
|
462
|
-
m.validate()
|
|
463
|
-
w = m.warnings()
|
|
464
|
-
self.assertEqual(len(w), 2)
|
|
465
|
-
self.assertEqual(type(w[0]), myokit.UnusedVariableError)
|
|
466
|
-
self.assertEqual(type(w[1]), myokit.UnusedVariableError)
|
|
467
|
-
# Test 1:1 cycle
|
|
468
|
-
c1_b.set_rhs(myokit.Name(c1_b))
|
|
469
|
-
self.assertRaises(myokit.CyclicalDependencyError, m.validate)
|
|
470
|
-
# Test longer cycles
|
|
471
|
-
c1_b.set_rhs(myokit.Multiply(myokit.Number(10), myokit.Name(c1_c)))
|
|
472
|
-
self.assertRaises(myokit.CyclicalDependencyError, m.validate)
|
|
473
|
-
# Reset
|
|
474
|
-
c1_b.set_rhs(myokit.Multiply(myokit.Name(c1_a), myokit.Number(1.0)))
|
|
475
|
-
m.validate()
|
|
476
|
-
# Test cycle involving state variable
|
|
477
|
-
c1_a.set_rhs(myokit.Name(c1_b))
|
|
478
|
-
m.validate()
|
|
479
|
-
c1_b.set_rhs(myokit.Multiply(myokit.Name(c1_a), myokit.Name(c1_b)))
|
|
480
|
-
self.assertRaises(myokit.CyclicalDependencyError, m.validate)
|
|
481
|
-
c1_b.set_rhs(myokit.Multiply(myokit.Name(c1_a), myokit.Name(c1_c)))
|
|
482
|
-
c1_c.set_rhs(myokit.Multiply(myokit.Name(c1_a), myokit.Number(3)))
|
|
483
|
-
m.validate()
|
|
484
|
-
w = m.warnings()
|
|
485
|
-
self.assertEqual(len(w), 0)
|
|
486
|
-
c1_c.set_rhs(myokit.Multiply(myokit.Name(c1_a), myokit.Name(c1_b)))
|
|
487
|
-
self.assertRaises(myokit.CyclicalDependencyError, m.validate)
|
|
488
|
-
|
|
489
437
|
|
|
490
438
|
if __name__ == '__main__':
|
|
491
439
|
unittest.main()
|
myokit/tests/test_opencl_info.py
CHANGED
|
@@ -5,21 +5,12 @@
|
|
|
5
5
|
# This file is part of Myokit.
|
|
6
6
|
# See http://myokit.org for copyright, sharing, and licensing details.
|
|
7
7
|
#
|
|
8
|
-
from __future__ import absolute_import, division
|
|
9
|
-
from __future__ import print_function, unicode_literals
|
|
10
|
-
|
|
11
8
|
import unittest
|
|
12
9
|
|
|
13
10
|
import myokit
|
|
14
11
|
|
|
15
12
|
from myokit.tests import TemporaryDirectory, OpenCL_FOUND
|
|
16
13
|
|
|
17
|
-
# Strings in Python2 and Python3
|
|
18
|
-
try:
|
|
19
|
-
basestring
|
|
20
|
-
except NameError:
|
|
21
|
-
basestring = str
|
|
22
|
-
|
|
23
14
|
|
|
24
15
|
@unittest.skipIf(not OpenCL_FOUND, 'OpenCL not found on this system.')
|
|
25
16
|
class OpenCLTest(unittest.TestCase):
|
|
@@ -35,12 +26,12 @@ class OpenCLTest(unittest.TestCase):
|
|
|
35
26
|
# Tests the method to query the current device
|
|
36
27
|
self.assertIsInstance(
|
|
37
28
|
myokit.OpenCL.current_info(), myokit.OpenCLPlatformInfo)
|
|
38
|
-
self.assertIsInstance(myokit.OpenCL.current_info(True),
|
|
29
|
+
self.assertIsInstance(myokit.OpenCL.current_info(True), str)
|
|
39
30
|
|
|
40
31
|
def test_info(self):
|
|
41
32
|
# Tests the method to query the current device
|
|
42
33
|
self.assertIsInstance(myokit.OpenCL.info(), myokit.OpenCLInfo)
|
|
43
|
-
self.assertIsInstance(myokit.OpenCL.info(True),
|
|
34
|
+
self.assertIsInstance(myokit.OpenCL.info(True), str)
|
|
44
35
|
|
|
45
36
|
def test_load_save_selection(self):
|
|
46
37
|
# Tests the load_selection method
|
|
@@ -83,9 +74,9 @@ class OpenCLTest(unittest.TestCase):
|
|
|
83
74
|
item = info[0]
|
|
84
75
|
self.assertEqual(len(item), 3)
|
|
85
76
|
platform, device, specs = item
|
|
86
|
-
self.assertIsInstance(platform,
|
|
87
|
-
self.assertIsInstance(device,
|
|
88
|
-
self.assertIsInstance(specs,
|
|
77
|
+
self.assertIsInstance(platform, str)
|
|
78
|
+
self.assertIsInstance(device, str)
|
|
79
|
+
self.assertIsInstance(specs, str)
|
|
89
80
|
|
|
90
81
|
def test_supported(self):
|
|
91
82
|
# Tested as condition to get in, so must be true
|
|
@@ -5,9 +5,6 @@
|
|
|
5
5
|
# This file is part of Myokit.
|
|
6
6
|
# See http://myokit.org for copyright, sharing, and licensing details.
|
|
7
7
|
#
|
|
8
|
-
from __future__ import absolute_import, division
|
|
9
|
-
from __future__ import print_function, unicode_literals
|
|
10
|
-
|
|
11
8
|
import unittest
|
|
12
9
|
import numpy as np
|
|
13
10
|
|
|
@@ -16,12 +13,6 @@ import myokit
|
|
|
16
13
|
from myokit.tests.ansic_event_based_pacing import AnsicEventBasedPacing
|
|
17
14
|
from myokit.tests.ansic_fixed_form_pacing import AnsicFixedFormPacing
|
|
18
15
|
|
|
19
|
-
# Unit testing in Python 2 and 3
|
|
20
|
-
try:
|
|
21
|
-
unittest.TestCase.assertRaisesRegex
|
|
22
|
-
except AttributeError:
|
|
23
|
-
unittest.TestCase.assertRaisesRegex = unittest.TestCase.assertRaisesRegexp
|
|
24
|
-
|
|
25
16
|
|
|
26
17
|
class EventBasedPacingAnsicTest(unittest.TestCase):
|
|
27
18
|
"""
|
|
@@ -144,24 +135,11 @@ class FixedFormPacingAnsicTest(unittest.TestCase):
|
|
|
144
135
|
import sys
|
|
145
136
|
sys.exit(1)
|
|
146
137
|
|
|
147
|
-
# Test input checking
|
|
148
|
-
times = 1
|
|
149
|
-
values = [1, 2]
|
|
150
|
-
self.assertRaises(Exception, AnsicFixedFormPacing)
|
|
151
|
-
self.assertRaises(Exception, AnsicFixedFormPacing, 1)
|
|
152
|
-
self.assertRaises(Exception, AnsicFixedFormPacing, 1, 2)
|
|
153
|
-
self.assertRaises(Exception, AnsicFixedFormPacing, [1], [2])
|
|
154
|
-
self.assertRaises(
|
|
155
|
-
Exception, AnsicFixedFormPacing, [1, 2], [2])
|
|
156
|
-
self.assertRaises(
|
|
157
|
-
Exception, AnsicFixedFormPacing, [2, 1], [2, 2])
|
|
158
|
-
AnsicFixedFormPacing([1, 2], [1, 2])
|
|
159
|
-
|
|
160
138
|
# Test with small lists
|
|
161
139
|
values = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
|
|
162
140
|
times = [0, 0, 1, 1, 1, 2, 2, 2, 3, 4, 5, 7]
|
|
163
141
|
values = list(range(len(times)))
|
|
164
|
-
pacing = AnsicFixedFormPacing(times, values)
|
|
142
|
+
pacing = AnsicFixedFormPacing(myokit.TimeSeriesProtocol(times, values))
|
|
165
143
|
|
|
166
144
|
def test(value, index):
|
|
167
145
|
self.assertEqual(pacing.pace(value), index)
|
|
@@ -5,19 +5,10 @@
|
|
|
5
5
|
# This file is part of Myokit.
|
|
6
6
|
# See http://myokit.org for copyright, sharing, and licensing details.
|
|
7
7
|
#
|
|
8
|
-
from __future__ import absolute_import, division
|
|
9
|
-
from __future__ import print_function, unicode_literals
|
|
10
|
-
|
|
11
8
|
import unittest
|
|
12
9
|
|
|
13
10
|
import myokit
|
|
14
11
|
|
|
15
|
-
# Unit testing in Python 2 and 3
|
|
16
|
-
try:
|
|
17
|
-
unittest.TestCase.assertRaisesRegex
|
|
18
|
-
except AttributeError:
|
|
19
|
-
unittest.TestCase.assertRaisesRegex = unittest.TestCase.assertRaisesRegexp
|
|
20
|
-
|
|
21
12
|
|
|
22
13
|
class EventBasedPacingPythonTest(unittest.TestCase):
|
|
23
14
|
"""
|
myokit/tests/test_parsing.py
CHANGED
|
@@ -6,9 +6,6 @@
|
|
|
6
6
|
# This file is part of Myokit.
|
|
7
7
|
# See http://myokit.org for copyright, sharing, and licensing details.
|
|
8
8
|
#
|
|
9
|
-
from __future__ import absolute_import, division
|
|
10
|
-
from __future__ import print_function, unicode_literals
|
|
11
|
-
|
|
12
9
|
import os
|
|
13
10
|
import unittest
|
|
14
11
|
|
|
@@ -17,18 +14,6 @@ import myokit.units
|
|
|
17
14
|
|
|
18
15
|
from myokit.tests import DIR_DATA, TemporaryDirectory
|
|
19
16
|
|
|
20
|
-
# Unit testing in Python 2 and 3
|
|
21
|
-
try:
|
|
22
|
-
unittest.TestCase.assertRaisesRegex
|
|
23
|
-
except AttributeError:
|
|
24
|
-
unittest.TestCase.assertRaisesRegex = unittest.TestCase.assertRaisesRegexp
|
|
25
|
-
|
|
26
|
-
# Strings in Python 2 and 3
|
|
27
|
-
try:
|
|
28
|
-
basestring
|
|
29
|
-
except NameError: # pragma: no python 2 cover
|
|
30
|
-
basestring = str
|
|
31
|
-
|
|
32
17
|
|
|
33
18
|
class TokenizerTest(unittest.TestCase):
|
|
34
19
|
"""
|
|
@@ -223,6 +208,7 @@ class PhasedParseTest(unittest.TestCase):
|
|
|
223
208
|
"""
|
|
224
209
|
Tests several phases of parsing.
|
|
225
210
|
"""
|
|
211
|
+
|
|
226
212
|
def test_segment_parsing(self):
|
|
227
213
|
# Test :meth:`parse_model()`.
|
|
228
214
|
from myokit._parsing import parse
|
|
@@ -907,29 +893,29 @@ class PhasedParseTest(unittest.TestCase):
|
|
|
907
893
|
'[[script]]',
|
|
908
894
|
)
|
|
909
895
|
script = parse_script(code)
|
|
910
|
-
self.assertIsInstance(script,
|
|
896
|
+
self.assertIsInstance(script, str)
|
|
911
897
|
script = parse_script(''.join(code))
|
|
912
|
-
self.assertIsInstance(script,
|
|
898
|
+
self.assertIsInstance(script, str)
|
|
913
899
|
|
|
914
900
|
code = (
|
|
915
901
|
'[[script]]\n',
|
|
916
902
|
)
|
|
917
903
|
script = parse_script(code)
|
|
918
|
-
self.assertIsInstance(script,
|
|
904
|
+
self.assertIsInstance(script, str)
|
|
919
905
|
|
|
920
906
|
code = (
|
|
921
907
|
'[[script]]\n',
|
|
922
908
|
'print("hi")',
|
|
923
909
|
)
|
|
924
910
|
script = parse_script(code)
|
|
925
|
-
self.assertIsInstance(script,
|
|
911
|
+
self.assertIsInstance(script, str)
|
|
926
912
|
|
|
927
913
|
code = (
|
|
928
914
|
'[[script]]\n',
|
|
929
915
|
'print("hi")\n',
|
|
930
916
|
)
|
|
931
917
|
script = parse_script(code)
|
|
932
|
-
self.assertIsInstance(script,
|
|
918
|
+
self.assertIsInstance(script, str)
|
|
933
919
|
|
|
934
920
|
# Not a script
|
|
935
921
|
code = (
|
|
@@ -1229,7 +1215,12 @@ class PhasedParseTest(unittest.TestCase):
|
|
|
1229
1215
|
|
|
1230
1216
|
|
|
1231
1217
|
class ModelParseTest(unittest.TestCase):
|
|
1218
|
+
"""
|
|
1219
|
+
Test parsing models.
|
|
1220
|
+
"""
|
|
1221
|
+
|
|
1232
1222
|
def test_model_creation(self):
|
|
1223
|
+
# Basic model creation via the parser
|
|
1233
1224
|
m = myokit.load_model(os.path.join(DIR_DATA, 'lr-1991.mmt'))
|
|
1234
1225
|
|
|
1235
1226
|
# Test components
|
|
@@ -1263,36 +1254,14 @@ class ModelParseTest(unittest.TestCase):
|
|
|
1263
1254
|
1,
|
|
1264
1255
|
0.0057,
|
|
1265
1256
|
0.0002]
|
|
1257
|
+
self.assertEqual(len(values), m.count_states())
|
|
1258
|
+
|
|
1259
|
+
# Test initial value parsing
|
|
1266
1260
|
out = ', '.join([str(x) for x in m.states()])
|
|
1267
1261
|
ref = ', '.join(states)
|
|
1268
1262
|
self.assertEqual(ref, out)
|
|
1269
|
-
for
|
|
1270
|
-
self.assertEqual(
|
|
1271
|
-
|
|
1272
|
-
# Test state parsing / setting
|
|
1273
|
-
m.set_state(values)
|
|
1274
|
-
for k, eq in enumerate(m.inits()):
|
|
1275
|
-
self.assertEqual(eq.rhs.eval(), values[k])
|
|
1276
|
-
s = dict(zip(states, values))
|
|
1277
|
-
m.set_state(s)
|
|
1278
|
-
for k, eq in enumerate(m.inits()):
|
|
1279
|
-
self.assertEqual(eq.rhs.eval(), values[k])
|
|
1280
|
-
s = '\n'.join([str(a) + '=' + str(b) for a, b in s.items()])
|
|
1281
|
-
m.set_state(s)
|
|
1282
|
-
for k, eq in enumerate(m.inits()):
|
|
1283
|
-
self.assertEqual(eq.rhs.eval(), values[k])
|
|
1284
|
-
|
|
1285
|
-
# Test cloning
|
|
1286
|
-
try:
|
|
1287
|
-
m2 = m.clone()
|
|
1288
|
-
except Exception as e:
|
|
1289
|
-
s = m.code(line_numbers=True)
|
|
1290
|
-
print('\n')
|
|
1291
|
-
print(s)
|
|
1292
|
-
print('-' * 80)
|
|
1293
|
-
print(myokit.format_parse_error(e, s.splitlines()))
|
|
1294
|
-
raise e
|
|
1295
|
-
self.assertEqual(m.code(), m2.code())
|
|
1263
|
+
for val, ref in zip(m.initial_values(as_floats=True), values):
|
|
1264
|
+
self.assertEqual(val, ref)
|
|
1296
1265
|
|
|
1297
1266
|
def test_unresolved_reference_error(self):
|
|
1298
1267
|
# Test unresolved reference errors.
|
|
@@ -1354,19 +1323,21 @@ class ModelParseTest(unittest.TestCase):
|
|
|
1354
1323
|
# Test evaluation
|
|
1355
1324
|
x = m.get('test.x')
|
|
1356
1325
|
y = m.get('test.y')
|
|
1357
|
-
s = m.
|
|
1358
|
-
i = m.get('membrane.V').
|
|
1326
|
+
s = m.initial_values(as_floats=True)
|
|
1327
|
+
i = m.get('membrane.V').index()
|
|
1359
1328
|
# Test x, xo, y, yo
|
|
1329
|
+
|
|
1330
|
+
v = myokit.Name(m.get('membrane.V'))
|
|
1360
1331
|
s[i] = -80
|
|
1361
|
-
m.
|
|
1332
|
+
m.set_initial_values(s)
|
|
1362
1333
|
self.assertEqual(x.rhs().eval(), 3)
|
|
1363
1334
|
self.assertEqual(y.rhs().eval(), 2)
|
|
1364
1335
|
s[i] = -10
|
|
1365
|
-
m.
|
|
1336
|
+
m.set_initial_values(s)
|
|
1366
1337
|
self.assertEqual(x.rhs().eval(), 2)
|
|
1367
1338
|
self.assertEqual(y.rhs().eval(), 2)
|
|
1368
1339
|
s[i] = 30
|
|
1369
|
-
m.
|
|
1340
|
+
m.set_initial_values(s)
|
|
1370
1341
|
self.assertEqual(x.rhs().eval(), 1)
|
|
1371
1342
|
self.assertEqual(y.rhs().eval(), 1)
|
|
1372
1343
|
# Test code() output by cloning
|
|
@@ -1387,13 +1358,50 @@ class ModelParseTest(unittest.TestCase):
|
|
|
1387
1358
|
dot(p) = 1
|
|
1388
1359
|
dot(q) = 2
|
|
1389
1360
|
"""
|
|
1390
|
-
myokit.
|
|
1361
|
+
m = myokit.parse_model(code)
|
|
1362
|
+
self.assertEqual(m.get('c.p').initial_value(), myokit.Number(1))
|
|
1363
|
+
self.assertEqual(m.get('c.q').initial_value().code(), '10 * 2')
|
|
1364
|
+
|
|
1365
|
+
# initial expression
|
|
1366
|
+
code = """
|
|
1367
|
+
[[model]]
|
|
1368
|
+
c.q = 10 * 2 + c.p
|
|
1369
|
+
c.r = c.p + c.a
|
|
1370
|
+
|
|
1371
|
+
[engine]
|
|
1372
|
+
time = 0 bind time
|
|
1373
|
+
|
|
1374
|
+
[c]
|
|
1375
|
+
p = 0.5
|
|
1376
|
+
dot(q) = 2
|
|
1377
|
+
dot(r) = 1
|
|
1378
|
+
a = p + 1
|
|
1379
|
+
"""
|
|
1380
|
+
m = myokit.parse_model(code)
|
|
1381
|
+
self.assertEqual(
|
|
1382
|
+
m.get('c.q').initial_value().code(), '10 * 2 + c.p')
|
|
1391
1383
|
|
|
1392
|
-
#
|
|
1384
|
+
# initial expression with just literals
|
|
1385
|
+
code = """
|
|
1386
|
+
[[model]]
|
|
1387
|
+
c.q = 10 * exp(2)
|
|
1388
|
+
|
|
1389
|
+
[engine]
|
|
1390
|
+
time = 0 bind time
|
|
1391
|
+
|
|
1392
|
+
[c]
|
|
1393
|
+
p = 0.5
|
|
1394
|
+
dot(q) = 2
|
|
1395
|
+
"""
|
|
1396
|
+
m = myokit.parse_model(code)
|
|
1397
|
+
self.assertEqual(
|
|
1398
|
+
m.get('c.q').initial_value().code(), '10 * exp(2)')
|
|
1399
|
+
|
|
1400
|
+
# non-existent variable in initial value
|
|
1393
1401
|
code = """
|
|
1394
1402
|
[[model]]
|
|
1395
1403
|
c.p = 1.0
|
|
1396
|
-
c.q = 10 * 2 + b
|
|
1404
|
+
c.q = 10 * 2 + c.b
|
|
1397
1405
|
|
|
1398
1406
|
[engine]
|
|
1399
1407
|
time = 0 bind time
|
|
@@ -1402,7 +1410,82 @@ class ModelParseTest(unittest.TestCase):
|
|
|
1402
1410
|
dot(p) = 1
|
|
1403
1411
|
dot(q) = 2
|
|
1404
1412
|
"""
|
|
1405
|
-
self.
|
|
1413
|
+
self.assertRaisesRegex(
|
|
1414
|
+
myokit.ParseError, 'Unresolved reference', myokit.parse, code)
|
|
1415
|
+
|
|
1416
|
+
# initial expression using child variables should fail
|
|
1417
|
+
code = """
|
|
1418
|
+
[[model]]
|
|
1419
|
+
c.q = a
|
|
1420
|
+
|
|
1421
|
+
[engine]
|
|
1422
|
+
time = 0 bind time
|
|
1423
|
+
|
|
1424
|
+
[c]
|
|
1425
|
+
p = 0.5
|
|
1426
|
+
dot(q) = 2
|
|
1427
|
+
a = 10 * 2 + p
|
|
1428
|
+
"""
|
|
1429
|
+
self.assertRaisesRegex(
|
|
1430
|
+
myokit.ParseError, 'Unresolved reference', myokit.parse, code)
|
|
1431
|
+
|
|
1432
|
+
# non-constant initial value
|
|
1433
|
+
code = """
|
|
1434
|
+
[[model]]
|
|
1435
|
+
c.p = engine.time
|
|
1436
|
+
|
|
1437
|
+
[engine]
|
|
1438
|
+
time = 0 bind time
|
|
1439
|
+
|
|
1440
|
+
[c]
|
|
1441
|
+
dot(p) = 1
|
|
1442
|
+
"""
|
|
1443
|
+
self.assertRaisesRegex(
|
|
1444
|
+
myokit.ParseError, 'is not constant', myokit.parse, code)
|
|
1445
|
+
|
|
1446
|
+
# indirect non-constant initial value
|
|
1447
|
+
code = """
|
|
1448
|
+
[[model]]
|
|
1449
|
+
c.p = c.r
|
|
1450
|
+
c.q = 1
|
|
1451
|
+
|
|
1452
|
+
[engine]
|
|
1453
|
+
time = 0 bind time
|
|
1454
|
+
|
|
1455
|
+
[c]
|
|
1456
|
+
dot(p) = 1
|
|
1457
|
+
dot(q) = 2
|
|
1458
|
+
r = 2 * q
|
|
1459
|
+
"""
|
|
1460
|
+
self.assertRaisesRegex(
|
|
1461
|
+
myokit.ParseError, 'is not constant', myokit.parse, code)
|
|
1462
|
+
|
|
1463
|
+
# looks like it shouldn't be constant, but it is!
|
|
1464
|
+
code = """
|
|
1465
|
+
[[model]]
|
|
1466
|
+
c.p = dot(c.p)
|
|
1467
|
+
|
|
1468
|
+
[engine]
|
|
1469
|
+
time = 0 bind time
|
|
1470
|
+
|
|
1471
|
+
[c]
|
|
1472
|
+
dot(p) = 0
|
|
1473
|
+
"""
|
|
1474
|
+
# Treat all state variables as non-constant
|
|
1475
|
+
self.assertRaisesRegex(
|
|
1476
|
+
myokit.ParseError, 'is not constant', myokit.parse, code)
|
|
1477
|
+
|
|
1478
|
+
# Initial value cycles are caught in validation
|
|
1479
|
+
code = """
|
|
1480
|
+
[[model]]
|
|
1481
|
+
x.x = x.x
|
|
1482
|
+
|
|
1483
|
+
[x]
|
|
1484
|
+
dot(x) = x
|
|
1485
|
+
t = 0 bind time
|
|
1486
|
+
"""
|
|
1487
|
+
self.assertRaisesRegex(
|
|
1488
|
+
myokit.ParseError, 'is not constant', myokit.parse, code)
|
|
1406
1489
|
|
|
1407
1490
|
def test_aliases(self):
|
|
1408
1491
|
code = """
|
|
@@ -5,9 +5,6 @@
|
|
|
5
5
|
# This file is part of Myokit.
|
|
6
6
|
# See http://myokit.org for copyright, sharing, and licensing details.
|
|
7
7
|
#
|
|
8
|
-
from __future__ import absolute_import, division
|
|
9
|
-
from __future__ import print_function, unicode_literals
|
|
10
|
-
|
|
11
8
|
import unittest
|
|
12
9
|
import re
|
|
13
10
|
import time
|
myokit/tests/test_protocol.py
CHANGED
|
@@ -5,9 +5,6 @@
|
|
|
5
5
|
# This file is part of Myokit.
|
|
6
6
|
# See http://myokit.org for copyright, sharing, and licensing details.
|
|
7
7
|
#
|
|
8
|
-
from __future__ import absolute_import, division
|
|
9
|
-
from __future__ import print_function, unicode_literals
|
|
10
|
-
|
|
11
8
|
import pickle
|
|
12
9
|
import unittest
|
|
13
10
|
|
|
@@ -15,12 +12,6 @@ import myokit
|
|
|
15
12
|
|
|
16
13
|
from myokit.tests import WarningCollector
|
|
17
14
|
|
|
18
|
-
# Unit testing in Python 2 and 3
|
|
19
|
-
try:
|
|
20
|
-
unittest.TestCase.assertRaisesRegex
|
|
21
|
-
except AttributeError:
|
|
22
|
-
unittest.TestCase.assertRaisesRegex = unittest.TestCase.assertRaisesRegexp
|
|
23
|
-
|
|
24
15
|
|
|
25
16
|
class ProtocolTest(unittest.TestCase):
|
|
26
17
|
"""
|